]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #74333 - poliorcetics:std-alloc-unsafe-op-in-unsafe-fn, r=LukasKalbertodt
authorManish Goregaokar <manishsmail@gmail.com>
Sun, 19 Jul 2020 14:02:22 +0000 (07:02 -0700)
committerGitHub <noreply@github.com>
Sun, 19 Jul 2020 14:02:22 +0000 (07:02 -0700)
Deny unsafe operations in unsafe functions in libstd/alloc.rs

Partial fix of #73904.

This encloses `unsafe` operations in `unsafe fn` in `libstd/alloc.rs`.

@rustbot modify labels: F-unsafe-block-in-unsafe-fn

1093 files changed:
.github/workflows/ci.yml
.gitmodules
CONTRIBUTING.md
Cargo.lock
Cargo.toml
RELEASES.md
config.toml.example
rustfmt.toml
src/backtrace [new submodule]
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/builder/tests.rs
src/bootstrap/cc_detect.rs
src/bootstrap/channel.rs
src/bootstrap/check.rs
src/bootstrap/clean.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/flags.rs
src/bootstrap/install.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/sanity.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/bootstrap/util.rs
src/ci/azure-pipelines/auto.yml
src/ci/docker/README.md
src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile [new file with mode: 0644]
src/ci/docker/host-x86_64/dist-riscv64-linux/build-toolchains.sh [new file with mode: 0755]
src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh [new file with mode: 0644]
src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config [new file with mode: 0644]
src/ci/docker/host-x86_64/dist-various-1/Dockerfile
src/ci/docker/host-x86_64/dist-various-1/build-riscv-toolchain.sh [deleted file]
src/ci/docker/host-x86_64/dist-various-1/crosstool-ng.sh [deleted file]
src/ci/docker/host-x86_64/dist-various-1/riscv64-unknown-linux-gnu.config [deleted file]
src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile [new file with mode: 0644]
src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
src/ci/docker/host-x86_64/i686-gnu/Dockerfile
src/ci/docker/scripts/illumos-toolchain.sh [new file with mode: 0644]
src/ci/exec-with-shell.py [deleted file]
src/ci/github-actions/ci.yml
src/ci/scripts/install-msys2.sh
src/doc/rustdoc/src/unstable-features.md
src/doc/unstable-book/src/language-features/doc-spotlight.md [new file with mode: 0644]
src/liballoc/collections/btree/map.rs
src/liballoc/collections/btree/navigate.rs
src/liballoc/collections/btree/node.rs
src/liballoc/collections/btree/set.rs
src/liballoc/lib.rs
src/liballoc/sync.rs
src/liballoc/task.rs
src/libcore/convert/mod.rs
src/libcore/fmt/mod.rs
src/libcore/future/future.rs
src/libcore/hint.rs
src/libcore/intrinsics.rs
src/libcore/iter/mod.rs
src/libcore/iter/traits/accum.rs
src/libcore/iter/traits/double_ended.rs
src/libcore/iter/traits/iterator.rs
src/libcore/iter/traits/marker.rs
src/libcore/lazy.rs [new file with mode: 0644]
src/libcore/lib.rs
src/libcore/macros/mod.rs
src/libcore/marker.rs
src/libcore/mem/mod.rs
src/libcore/num/mod.rs
src/libcore/ops/function.rs
src/libcore/option.rs
src/libcore/panicking.rs
src/libcore/ptr/const_ptr.rs
src/libcore/ptr/mut_ptr.rs
src/libcore/ptr/non_null.rs
src/libcore/slice/mod.rs
src/libcore/str/mod.rs
src/libcore/task/mod.rs
src/libcore/task/ready.rs [new file with mode: 0644]
src/libcore/tests/lazy.rs [new file with mode: 0644]
src/libcore/tests/lib.rs
src/libcore/time.rs
src/libpanic_abort/Cargo.toml
src/libpanic_abort/lib.rs
src/libpanic_unwind/lib.rs
src/libproc_macro/lib.rs
src/librustc_ast/expand/allocator.rs
src/librustc_ast/lib.rs
src/librustc_ast/util/comments.rs
src/librustc_ast/util/comments/tests.rs
src/librustc_ast/util/lev_distance.rs
src/librustc_ast/util/lev_distance/tests.rs
src/librustc_ast_lowering/expr.rs
src/librustc_ast_lowering/item.rs
src/librustc_ast_passes/feature_gate.rs
src/librustc_ast_pretty/pprust.rs
src/librustc_attr/builtin.rs
src/librustc_builtin_macros/deriving/bounds.rs
src/librustc_builtin_macros/deriving/clone.rs
src/librustc_builtin_macros/deriving/cmp/eq.rs
src/librustc_builtin_macros/deriving/cmp/ord.rs
src/librustc_builtin_macros/deriving/cmp/partial_eq.rs
src/librustc_builtin_macros/deriving/cmp/partial_ord.rs
src/librustc_builtin_macros/deriving/debug.rs
src/librustc_builtin_macros/deriving/decodable.rs
src/librustc_builtin_macros/deriving/default.rs
src/librustc_builtin_macros/deriving/encodable.rs
src/librustc_builtin_macros/deriving/generic/mod.rs
src/librustc_builtin_macros/deriving/generic/ty.rs
src/librustc_builtin_macros/deriving/hash.rs
src/librustc_builtin_macros/deriving/mod.rs
src/librustc_builtin_macros/format.rs
src/librustc_builtin_macros/global_allocator.rs
src/librustc_builtin_macros/proc_macro_harness.rs
src/librustc_builtin_macros/test.rs
src/librustc_builtin_macros/test_harness.rs
src/librustc_codegen_llvm/attributes.rs
src/librustc_codegen_llvm/base.rs
src/librustc_codegen_llvm/builder.rs
src/librustc_codegen_llvm/callee.rs
src/librustc_codegen_llvm/consts.rs
src/librustc_codegen_llvm/coverageinfo/mapgen.rs [new file with mode: 0644]
src/librustc_codegen_llvm/coverageinfo/mod.rs
src/librustc_codegen_llvm/debuginfo/metadata.rs
src/librustc_codegen_llvm/debuginfo/mod.rs
src/librustc_codegen_llvm/debuginfo/namespace.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_llvm/llvm/ffi.rs
src/librustc_codegen_llvm/llvm/mod.rs
src/librustc_codegen_ssa/Cargo.toml
src/librustc_codegen_ssa/back/link.rs
src/librustc_codegen_ssa/back/rpath.rs
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/coverageinfo/map.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_codegen_ssa/mir/constant.rs
src/librustc_codegen_ssa/mono_item.rs
src/librustc_codegen_ssa/traits/coverageinfo.rs
src/librustc_codegen_ssa/traits/intrinsic.rs
src/librustc_codegen_ssa/traits/statics.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_error_codes/error_codes.rs
src/librustc_error_codes/error_codes/E0671.md
src/librustc_error_codes/error_codes/E0704.md
src/librustc_error_codes/error_codes/E0705.md
src/librustc_error_codes/error_codes/E0710.md
src/librustc_error_codes/error_codes/E0715.md
src/librustc_error_codes/error_codes/E0716.md
src/librustc_error_codes/error_codes/E0723.md
src/librustc_error_codes/error_codes/E0769.md [new file with mode: 0644]
src/librustc_error_codes/error_codes/E0770.md [new file with mode: 0644]
src/librustc_errors/lib.rs
src/librustc_expand/base.rs
src/librustc_expand/build.rs
src/librustc_expand/proc_macro_server.rs
src/librustc_feature/active.rs
src/librustc_hir/fake_lang_items.rs [new file with mode: 0644]
src/librustc_hir/hir.rs
src/librustc_hir/lang_items.rs
src/librustc_hir/lib.rs
src/librustc_hir_pretty/lib.rs
src/librustc_incremental/assert_module_sources.rs
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_index/Cargo.toml
src/librustc_index/bit_set.rs
src/librustc_index/lib.rs
src/librustc_infer/infer/error_reporting/mod.rs
src/librustc_infer/infer/error_reporting/need_type_info.rs
src/librustc_infer/infer/mod.rs
src/librustc_infer/lib.rs
src/librustc_interface/lib.rs
src/librustc_interface/passes.rs
src/librustc_interface/queries.rs
src/librustc_interface/tests.rs
src/librustc_interface/util.rs
src/librustc_lint/array_into_iter.rs
src/librustc_lint/builtin.rs
src/librustc_lint/context.rs
src/librustc_lint/late.rs
src/librustc_lint/lib.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_llvm/build.rs
src/librustc_llvm/lib.rs
src/librustc_macros/src/symbols.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/link_args.rs
src/librustc_metadata/locator.rs
src/librustc_metadata/rmeta/decoder/cstore_impl.rs
src/librustc_metadata/rmeta/encoder.rs
src/librustc_middle/arena.rs
src/librustc_middle/dep_graph/dep_node.rs
src/librustc_middle/hir/mod.rs
src/librustc_middle/hir/place.rs [new file with mode: 0644]
src/librustc_middle/lib.rs
src/librustc_middle/middle/exported_symbols.rs
src/librustc_middle/mir/coverage/mod.rs
src/librustc_middle/mir/interpret/queries.rs
src/librustc_middle/mir/interpret/value.rs
src/librustc_middle/mir/mono.rs
src/librustc_middle/mir/query.rs
src/librustc_middle/mir/traversal.rs
src/librustc_middle/query/mod.rs
src/librustc_middle/traits/mod.rs
src/librustc_middle/traits/structural_impls.rs
src/librustc_middle/ty/codec.rs
src/librustc_middle/ty/consts.rs
src/librustc_middle/ty/consts/int.rs [new file with mode: 0644]
src/librustc_middle/ty/consts/kind.rs [new file with mode: 0644]
src/librustc_middle/ty/context.rs
src/librustc_middle/ty/instance.rs
src/librustc_middle/ty/layout.rs
src/librustc_middle/ty/mod.rs
src/librustc_middle/ty/print/pretty.rs
src/librustc_middle/ty/query/keys.rs
src/librustc_middle/ty/query/on_disk_cache.rs
src/librustc_middle/ty/query/profiling_support.rs
src/librustc_middle/ty/query/values.rs
src/librustc_middle/ty/relate.rs
src/librustc_middle/ty/structural_impls.rs
src/librustc_middle/ty/sty.rs
src/librustc_middle/ty/util.rs
src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
src/librustc_mir/borrow_check/diagnostics/mod.rs
src/librustc_mir/borrow_check/diagnostics/move_errors.rs
src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll.rs
src/librustc_mir/borrow_check/type_check/input_output.rs
src/librustc_mir/borrow_check/type_check/mod.rs
src/librustc_mir/borrow_check/universal_regions.rs
src/librustc_mir/const_eval/eval_queries.rs
src/librustc_mir/const_eval/machine.rs
src/librustc_mir/dataflow/framework/cursor.rs
src/librustc_mir/dataflow/framework/engine.rs
src/librustc_mir/dataflow/framework/visitor.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/intrinsics.rs
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/interpret/validity.rs
src/librustc_mir/lib.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/monomorphize/partitioning.rs
src/librustc_mir/transform/check_consts/qualifs.rs
src/librustc_mir/transform/check_consts/validation.rs
src/librustc_mir/transform/check_unsafety.rs
src/librustc_mir/transform/const_prop.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/instrument_coverage.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/util/pretty.rs
src/librustc_mir_build/build/expr/into.rs
src/librustc_mir_build/build/mod.rs
src/librustc_mir_build/hair/cx/block.rs
src/librustc_mir_build/hair/cx/expr.rs
src/librustc_mir_build/hair/cx/mod.rs
src/librustc_mir_build/hair/pattern/check_match.rs
src/librustc_mir_build/hair/pattern/mod.rs
src/librustc_mir_build/hair/util.rs
src/librustc_mir_build/lib.rs
src/librustc_parse/parser/attr.rs
src/librustc_parse/parser/mod.rs
src/librustc_parse/parser/stmt.rs
src/librustc_passes/check_attr.rs
src/librustc_passes/dead.rs
src/librustc_passes/intrinsicck.rs
src/librustc_passes/lang_items.rs
src/librustc_passes/lib.rs
src/librustc_passes/liveness.rs
src/librustc_passes/reachable.rs
src/librustc_passes/stability.rs
src/librustc_passes/weak_lang_items.rs
src/librustc_plugin_impl/load.rs
src/librustc_privacy/lib.rs
src/librustc_query_system/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/imports.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_resolve/late/lifetimes.rs
src/librustc_resolve/lib.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_session/cgu_reuse_tracker.rs
src/librustc_session/config.rs
src/librustc_session/options.rs
src/librustc_session/session.rs
src/librustc_span/lib.rs
src/librustc_span/symbol.rs
src/librustc_symbol_mangling/lib.rs
src/librustc_symbol_mangling/test.rs
src/librustc_target/lib.rs
src/librustc_target/spec/linux_kernel_base.rs
src/librustc_target/spec/mod.rs
src/librustc_trait_selection/autoderef.rs
src/librustc_trait_selection/traits/error_reporting/mod.rs
src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs
src/librustc_trait_selection/traits/error_reporting/suggestions.rs
src/librustc_trait_selection/traits/fulfill.rs
src/librustc_trait_selection/traits/on_unimplemented.rs
src/librustc_trait_selection/traits/project.rs
src/librustc_trait_selection/traits/select/mod.rs
src/librustc_trait_selection/traits/wf.rs
src/librustc_ty/instance.rs
src/librustc_typeck/Cargo.toml
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/expr.rs
src/librustc_typeck/check/generator_interior.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/check/pat.rs
src/librustc_typeck/check/place_op.rs
src/librustc_typeck/check/regionck.rs
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/collect/type_of.rs
src/librustc_typeck/expr_use_visitor.rs
src/librustc_typeck/mem_categorization.rs
src/librustdoc/clean/cfg.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/externalfiles.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/highlight/tests.rs [new file with mode: 0644]
src/librustdoc/html/layout.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/markdown/tests.rs
src/librustdoc/html/render.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/normalize.css
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/source-script.js
src/librustdoc/html/static/themes/ayu.css [new file with mode: 0644]
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/html/static_files.rs
src/librustdoc/lib.rs
src/librustdoc/markdown.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/libstd/Cargo.toml
src/libstd/backtrace.rs
src/libstd/build.rs
src/libstd/env.rs
src/libstd/ffi/c_str.rs
src/libstd/io/mod.rs
src/libstd/io/stdio.rs
src/libstd/keyword_docs.rs
src/libstd/lazy.rs [new file with mode: 0644]
src/libstd/lib.rs
src/libstd/panicking.rs
src/libstd/sync/condvar.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/once.rs
src/libstd/sys/cloudabi/mod.rs
src/libstd/sys/hermit/fast_thread_local.rs [deleted file]
src/libstd/sys/hermit/mod.rs
src/libstd/sys/hermit/thread_local.rs [deleted file]
src/libstd/sys/hermit/thread_local_dtor.rs [new file with mode: 0644]
src/libstd/sys/hermit/thread_local_key.rs [new file with mode: 0644]
src/libstd/sys/mod.rs
src/libstd/sys/sgx/abi/mod.rs
src/libstd/sys/sgx/abi/usercalls/mod.rs
src/libstd/sys/sgx/condvar.rs
src/libstd/sys/sgx/mod.rs
src/libstd/sys/sgx/thread.rs
src/libstd/sys/sgx/thread_local.rs [deleted file]
src/libstd/sys/sgx/thread_local_key.rs [new file with mode: 0644]
src/libstd/sys/sgx/waitqueue.rs
src/libstd/sys/unix/args.rs
src/libstd/sys/unix/fast_thread_local.rs [deleted file]
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/process/process_fuchsia.rs
src/libstd/sys/unix/process/process_unix.rs
src/libstd/sys/unix/thread_local.rs [deleted file]
src/libstd/sys/unix/thread_local_dtor.rs [new file with mode: 0644]
src/libstd/sys/unix/thread_local_key.rs [new file with mode: 0644]
src/libstd/sys/unsupported/alloc.rs [new file with mode: 0644]
src/libstd/sys/unsupported/args.rs [new file with mode: 0644]
src/libstd/sys/unsupported/cmath.rs [new file with mode: 0644]
src/libstd/sys/unsupported/common.rs [new file with mode: 0644]
src/libstd/sys/unsupported/condvar.rs [new file with mode: 0644]
src/libstd/sys/unsupported/env.rs [new file with mode: 0644]
src/libstd/sys/unsupported/fs.rs [new file with mode: 0644]
src/libstd/sys/unsupported/io.rs [new file with mode: 0644]
src/libstd/sys/unsupported/mod.rs [new file with mode: 0644]
src/libstd/sys/unsupported/mutex.rs [new file with mode: 0644]
src/libstd/sys/unsupported/net.rs [new file with mode: 0644]
src/libstd/sys/unsupported/os.rs [new file with mode: 0644]
src/libstd/sys/unsupported/path.rs [new file with mode: 0644]
src/libstd/sys/unsupported/pipe.rs [new file with mode: 0644]
src/libstd/sys/unsupported/process.rs [new file with mode: 0644]
src/libstd/sys/unsupported/rwlock.rs [new file with mode: 0644]
src/libstd/sys/unsupported/stack_overflow.rs [new file with mode: 0644]
src/libstd/sys/unsupported/stdio.rs [new file with mode: 0644]
src/libstd/sys/unsupported/thread.rs [new file with mode: 0644]
src/libstd/sys/unsupported/thread_local_dtor.rs [new file with mode: 0644]
src/libstd/sys/unsupported/thread_local_key.rs [new file with mode: 0644]
src/libstd/sys/unsupported/time.rs [new file with mode: 0644]
src/libstd/sys/vxworks/fast_thread_local.rs [deleted file]
src/libstd/sys/vxworks/mod.rs
src/libstd/sys/vxworks/process/process_common.rs
src/libstd/sys/vxworks/thread_local.rs [deleted file]
src/libstd/sys/vxworks/thread_local_dtor.rs [new file with mode: 0644]
src/libstd/sys/vxworks/thread_local_key.rs [new file with mode: 0644]
src/libstd/sys/wasi/mod.rs
src/libstd/sys/wasm/cmath.rs [deleted file]
src/libstd/sys/wasm/condvar.rs [deleted file]
src/libstd/sys/wasm/fast_thread_local.rs [deleted file]
src/libstd/sys/wasm/fs.rs [deleted file]
src/libstd/sys/wasm/io.rs [deleted file]
src/libstd/sys/wasm/memchr.rs [deleted file]
src/libstd/sys/wasm/mod.rs
src/libstd/sys/wasm/mutex.rs [deleted file]
src/libstd/sys/wasm/net.rs [deleted file]
src/libstd/sys/wasm/os.rs [deleted file]
src/libstd/sys/wasm/path.rs [deleted file]
src/libstd/sys/wasm/pipe.rs [deleted file]
src/libstd/sys/wasm/process.rs [deleted file]
src/libstd/sys/wasm/rwlock.rs [deleted file]
src/libstd/sys/wasm/stack_overflow.rs [deleted file]
src/libstd/sys/wasm/stdio.rs [deleted file]
src/libstd/sys/wasm/thread_local.rs [deleted file]
src/libstd/sys/wasm/time.rs [deleted file]
src/libstd/sys/windows/fast_thread_local.rs [deleted file]
src/libstd/sys/windows/mod.rs
src/libstd/sys/windows/path.rs
src/libstd/sys/windows/path/tests.rs [new file with mode: 0644]
src/libstd/sys/windows/process.rs
src/libstd/sys/windows/thread_local.rs [deleted file]
src/libstd/sys/windows/thread_local_dtor.rs [new file with mode: 0644]
src/libstd/sys/windows/thread_local_key.rs [new file with mode: 0644]
src/libstd/sys_common/backtrace.rs
src/libstd/sys_common/mod.rs
src/libstd/sys_common/mutex.rs
src/libstd/sys_common/thread_local.rs [deleted file]
src/libstd/sys_common/thread_local_dtor.rs [new file with mode: 0644]
src/libstd/sys_common/thread_local_key.rs [new file with mode: 0644]
src/libstd/thread/local.rs
src/libstd/thread/mod.rs
src/libtest/Cargo.toml
src/libtest/helpers/concurrency.rs
src/libtest/helpers/isatty.rs
src/libunwind/lib.rs
src/llvm-project
src/rustllvm/CoverageMappingWrapper.cpp [new file with mode: 0644]
src/rustllvm/RustWrapper.cpp
src/rustllvm/rustllvm.h
src/stage0.txt
src/test/codegen/atomic-operations.rs [new file with mode: 0644]
src/test/codegen/issue-44056-macos-tls-align.rs
src/test/codegen/repr-transparent-aggregates-1.rs
src/test/compile-fail/asm-src-loc-codegen-units.rs
src/test/compile-fail/empty-extern-arg.rs
src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs
src/test/incremental/callee_caller_cross_crate/b.rs
src/test/incremental/change_add_field/struct_point.rs
src/test/incremental/change_crate_order/main.rs
src/test/incremental/change_private_fn/struct_point.rs
src/test/incremental/change_private_fn_cc/struct_point.rs
src/test/incremental/change_private_impl_method/struct_point.rs
src/test/incremental/change_private_impl_method_cc/struct_point.rs
src/test/incremental/change_pub_inherent_method_body/struct_point.rs
src/test/incremental/change_pub_inherent_method_sig/struct_point.rs
src/test/incremental/dirty_clean.rs
src/test/incremental/hashes/call_expressions.rs
src/test/incremental/hashes/closure_expressions.rs
src/test/incremental/hashes/enum_constructors.rs
src/test/incremental/hashes/exported_vs_not.rs
src/test/incremental/hashes/for_loops.rs
src/test/incremental/hashes/function_interfaces.rs
src/test/incremental/hashes/if_expressions.rs
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/inline_asm.rs
src/test/incremental/hashes/let_expressions.rs
src/test/incremental/hashes/loop_expressions.rs
src/test/incremental/hashes/match_expressions.rs
src/test/incremental/hashes/panic_exprs.rs
src/test/incremental/hashes/struct_constructors.rs
src/test/incremental/hashes/unary_and_binary_exprs.rs
src/test/incremental/hashes/while_let_loops.rs
src/test/incremental/hashes/while_loops.rs
src/test/incremental/hello_world.rs
src/test/incremental/ich_method_call_trait_scope.rs
src/test/incremental/rlib_cross_crate/b.rs
src/test/incremental/string_constant.rs
src/test/incremental/struct_add_field.rs
src/test/incremental/struct_change_field_name.rs
src/test/incremental/struct_change_field_type.rs
src/test/incremental/struct_change_field_type_cross_crate/b.rs
src/test/incremental/struct_change_nothing.rs
src/test/incremental/struct_remove_field.rs
src/test/incremental/type_alias_cross_crate/b.rs
src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff
src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/const_prop_fails_gracefully/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/control-flow-simplification/rustc.hello.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref/rustc.main.PromoteTemps.diff
src/test/mir-opt/const_prop/ref_deref_project/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref_project/rustc.main.PromoteTemps.diff
src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/inline/inline-retag/rustc.bar.Inline.after.mir
src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff
src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff
src/test/mir-opt/issue-49232/rustc.main.mir_map.0.mir
src/test/mir-opt/issue-73223/32bit/rustc.main.PreCodegen.diff
src/test/mir-opt/issue-73223/32bit/rustc.main.SimplifyArmIdentity.diff
src/test/mir-opt/issue-73223/64bit/rustc.main.PreCodegen.diff
src/test/mir-opt/issue-73223/64bit/rustc.main.SimplifyArmIdentity.diff
src/test/mir-opt/match_false_edges/rustc.full_tested_match.PromoteTemps.after.mir
src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir
src/test/pretty/issue-4264.pp
src/test/pretty/issue-73626.rs [new file with mode: 0644]
src/test/run-make-fulldeps/compiler-rt-works-on-mingw/Makefile
src/test/run-make-fulldeps/include_bytes_deps/Makefile
src/test/run-make-fulldeps/instrument-coverage/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/main.rs [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/prettify_json.py [new file with mode: 0644]
src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt [new file with mode: 0644]
src/test/run-make-fulldeps/intrinsic-unreachable/Makefile
src/test/run-make-fulldeps/issue-37839/Makefile
src/test/run-make-fulldeps/issue-37893/Makefile
src/test/run-make-fulldeps/issue-51671/Makefile
src/test/run-make-fulldeps/libs-search-path/Makefile [deleted file]
src/test/run-make-fulldeps/libs-search-path/empty.rs [deleted file]
src/test/run-make-fulldeps/redundant-libs/Makefile
src/test/run-make-fulldeps/rustdoc-determinism/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-determinism/bar.rs [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-determinism/foo.rs [new file with mode: 0644]
src/test/run-make-fulldeps/symbol-visibility/Makefile
src/test/run-make-fulldeps/tools.mk
src/test/run-make-fulldeps/used/Makefile
src/test/run-make/static-pie/test-aslr.rs
src/test/rustdoc-ui/check-doc-alias-attr.rs [deleted file]
src/test/rustdoc-ui/check-doc-alias-attr.stderr [deleted file]
src/test/rustdoc-ui/error-in-impl-trait/README.md [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/async.rs [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/async.stderr [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/closure.rs [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/closure.stderr [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs [new file with mode: 0644]
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr [new file with mode: 0644]
src/test/rustdoc-ui/impl-fn-nesting.rs [new file with mode: 0644]
src/test/rustdoc-ui/impl-fn-nesting.stderr [new file with mode: 0644]
src/test/rustdoc-ui/infinite-recursive-type.rs [new file with mode: 0644]
src/test/rustdoc-ui/infinite-recursive-type.stderr [new file with mode: 0644]
src/test/rustdoc-ui/intra-links-private.rs
src/test/rustdoc/doc-spotlight.rs [new file with mode: 0644]
src/test/rustdoc/impl-trait-alias.rs [new file with mode: 0644]
src/test/rustdoc/internal.rs
src/test/rustdoc/intra-doc-crate/additional_doc.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/module.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/basic.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/hidden.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/macro.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/module.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/submodule-inner.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/submodule-outer.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-crate/traits.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc-link-mod-ambiguity.rs [new file with mode: 0644]
src/test/rustdoc/intra-link-prim-precedence.rs
src/test/rustdoc/macro-in-async-block.rs [new file with mode: 0644]
src/test/rustdoc/macro-in-closure.rs
src/test/rustdoc/return-impl-trait.rs [new file with mode: 0644]
src/test/ui-fulldeps/macro-crate-rlib.rs
src/test/ui-fulldeps/macro-crate-rlib.stderr
src/test/ui/asm/type-check-1.stderr
src/test/ui/associated-types/associated-types-unsized.stderr
src/test/ui/associated-types/defaults-suitability.stderr
src/test/ui/associated-types/defaults-unsound-62211-1.stderr
src/test/ui/associated-types/defaults-unsound-62211-2.stderr
src/test/ui/associated-types/issue-63593.stderr
src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr
src/test/ui/async-await/issue-70818.stderr
src/test/ui/async-await/issue-72590-type-error-sized.stderr
src/test/ui/bad/bad-method-typaram-kind.stderr
src/test/ui/bad/bad-sized.stderr
src/test/ui/bound-suggestions.stderr
src/test/ui/box-into-boxed-slice-fail.stderr
src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
src/test/ui/chalkify/impl_wf.stderr
src/test/ui/check-doc-alias-attr.rs [new file with mode: 0644]
src/test/ui/check-doc-alias-attr.stderr [new file with mode: 0644]
src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
src/test/ui/closures/closure-bounds-subtype.stderr
src/test/ui/const-generics/array-size-in-generic-struct-param.stderr
src/test/ui/const-generics/const-param-type-depends-on-const-param.rs [new file with mode: 0644]
src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr [new file with mode: 0644]
src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-62878.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-62878.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-68596.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71169.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71169.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71381.rs
src/test/ui/const-generics/issues/issue-71381.stderr
src/test/ui/const-generics/issues/issue-71611.rs
src/test/ui/const-generics/issues/issue-71611.stderr
src/test/ui/const-generics/issues/issue-73120.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-73491.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-73508.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-73508.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-74101.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-74255.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-61936.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-63695.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-67144-1.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-67144-2.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-69816.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-70217.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-70507.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-70586.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-71348.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-71382.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-71382.stderr [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-71805.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/issue-73730.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/non-local.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/qpath.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/simple.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/type-mismatch.rs [new file with mode: 0644]
src/test/ui/const-generics/type-dependent/type-mismatch.stderr [new file with mode: 0644]
src/test/ui/const-generics/unknown_adt.rs [new file with mode: 0644]
src/test/ui/const-generics/unknown_adt.stderr [new file with mode: 0644]
src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs
src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr [new file with mode: 0644]
src/test/ui/consts/const-option.rs [new file with mode: 0644]
src/test/ui/consts/const-unsized.stderr
src/test/ui/consts/const_unsafe_unreachable.rs [new file with mode: 0644]
src/test/ui/consts/const_unsafe_unreachable_ub.rs [new file with mode: 0644]
src/test/ui/consts/const_unsafe_unreachable_ub.stderr [new file with mode: 0644]
src/test/ui/consts/duration-consts-2.rs [new file with mode: 0644]
src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs
src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr
src/test/ui/dep-graph/dep-graph-caller-callee.rs
src/test/ui/dep-graph/dep-graph-caller-callee.stderr
src/test/ui/dep-graph/dep-graph-struct-signature.rs
src/test/ui/dep-graph/dep-graph-struct-signature.stderr
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr
src/test/ui/dep-graph/dep-graph-trait-impl.rs
src/test/ui/dep-graph/dep-graph-trait-impl.stderr
src/test/ui/dep-graph/dep-graph-type-alias.rs
src/test/ui/dep-graph/dep-graph-type-alias.stderr
src/test/ui/dst/dst-bad-assign-2.stderr
src/test/ui/dst/dst-bad-assign-3.stderr
src/test/ui/dst/dst-bad-assign.stderr
src/test/ui/dst/dst-bad-deep-2.stderr
src/test/ui/dst/dst-bad-deep.stderr
src/test/ui/dst/dst-object-from-unsized-type.stderr
src/test/ui/dst/dst-sized-trait-param.stderr
src/test/ui/empty/empty-struct-braces-expr.stderr
src/test/ui/empty/empty-struct-braces-pat-1.stderr
src/test/ui/empty/empty-struct-braces-pat-2.stderr
src/test/ui/empty/empty-struct-braces-pat-3.stderr
src/test/ui/error-codes/E0277.stderr
src/test/ui/error-codes/E0423.stderr
src/test/ui/error-codes/E0478.stderr
src/test/ui/extern/extern-prelude-no-speculative.rs
src/test/ui/extern/extern-types-unsized.stderr
src/test/ui/extern/issue-36122-accessing-externed-dst.stderr
src/test/ui/feature-gates/feature-gate-doc_spotlight.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr
src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
src/test/ui/feature-gates/feature-gate-unsized_locals.stderr
src/test/ui/generator/discriminant.rs
src/test/ui/generator/sized-yield.stderr
src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr
src/test/ui/hygiene/unpretty-debug.stdout
src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
src/test/ui/issues/auxiliary/issue-73112.rs [new file with mode: 0644]
src/test/ui/issues/issue-10412.stderr
src/test/ui/issues/issue-14366.stderr
src/test/ui/issues/issue-15756.stderr
src/test/ui/issues/issue-17651.stderr
src/test/ui/issues/issue-18919.stderr
src/test/ui/issues/issue-19086.stderr
src/test/ui/issues/issue-19380.stderr
src/test/ui/issues/issue-20005.stderr
src/test/ui/issues/issue-20433.stderr
src/test/ui/issues/issue-20605.stderr
src/test/ui/issues/issue-22874.stderr
src/test/ui/issues/issue-23281.stderr
src/test/ui/issues/issue-24446.stderr
src/test/ui/issues/issue-27060-2.stderr
src/test/ui/issues/issue-27078.stderr
src/test/ui/issues/issue-30355.stderr
src/test/ui/issues/issue-34334.rs
src/test/ui/issues/issue-34334.stderr
src/test/ui/issues/issue-35988.stderr
src/test/ui/issues/issue-38954.stderr
src/test/ui/issues/issue-41229-ref-str.stderr
src/test/ui/issues/issue-42312.stderr
src/test/ui/issues/issue-54410.stderr
src/test/ui/issues/issue-5883.stderr
src/test/ui/issues/issue-59020.rs
src/test/ui/issues/issue-63983.stderr
src/test/ui/issues/issue-64792-bad-unicode-ctor.stderr
src/test/ui/issues/issue-65673.stderr
src/test/ui/issues/issue-73112.rs [new file with mode: 0644]
src/test/ui/issues/issue-73112.stderr [new file with mode: 0644]
src/test/ui/issues/issue-73886.rs [new file with mode: 0644]
src/test/ui/issues/issue-73886.stderr [new file with mode: 0644]
src/test/ui/issues/issue-74086.rs [new file with mode: 0644]
src/test/ui/issues/issue-74086.stderr [new file with mode: 0644]
src/test/ui/issues/issue-9396.rs
src/test/ui/kindck/kindck-impl-type-params.nll.stderr
src/test/ui/kindck/kindck-impl-type-params.stderr
src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr
src/test/ui/lazy_normalization_consts/issue-57739.stderr
src/test/ui/lazy_normalization_consts/trait-resolution-breakage.rs [new file with mode: 0644]
src/test/ui/lazy_normalization_consts/unevaluated-consts.rs [new file with mode: 0644]
src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
src/test/ui/lint/lint-ctypes-73747.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-fn.rs
src/test/ui/lint/lint-ctypes-fn.stderr
src/test/ui/lint/lint-ctypes.rs
src/test/ui/lint/lint-ctypes.stderr
src/test/ui/lint/uninitialized-zeroed.rs
src/test/ui/lint/uninitialized-zeroed.stderr
src/test/ui/mismatched_types/cast-rfc0401.stderr
src/test/ui/missing/missing-fields-in-struct-pattern.rs
src/test/ui/missing/missing-fields-in-struct-pattern.stderr
src/test/ui/mpsc_stress.rs
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/parser/recover-from-bad-variant.stderr
src/test/ui/pattern/const-pat-ice.stderr
src/test/ui/phantom-oibit.stderr
src/test/ui/print_type_sizes/niche-filling.stdout
src/test/ui/range/range-1.stderr
src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
src/test/ui/regions/regions-wf-trait-object.stderr
src/test/ui/resolve/issue-18252.stderr
src/test/ui/resolve/issue-19452.stderr
src/test/ui/resolve/issue-39226.stderr
src/test/ui/resolve/issue-5035-2.stderr
src/test/ui/resolve/issue-6702.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/resolve/privacy-struct-ctor.stderr
src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr
src/test/ui/sleep.rs
src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
src/test/ui/str/str-array-assignment.stderr
src/test/ui/str/str-mut-idx.stderr
src/test/ui/substs-ppaux.normal.stderr
src/test/ui/substs-ppaux.verbose.stderr
src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
src/test/ui/suggestions/issue-61226.stderr
src/test/ui/suggestions/path-by-value.stderr
src/test/ui/suggestions/restrict-type-argument.stderr
src/test/ui/tcp-stress.rs
src/test/ui/traits/cycle-cache-err-60010.stderr
src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr
src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr
src/test/ui/traits/trait-suggest-where-clause.stderr
src/test/ui/trivial-bounds/trivial-bounds-leak.stderr
src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
src/test/ui/type-sizes.rs
src/test/ui/type/type-check/issue-41314.rs
src/test/ui/type/type-check/issue-41314.stderr
src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
src/test/ui/typeck/typeck_type_placeholder_item.rs
src/test/ui/typeck/typeck_type_placeholder_item.stderr
src/test/ui/union/union-fields-2.stderr
src/test/ui/union/union-sized-field.stderr
src/test/ui/union/union-unsized.stderr
src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr
src/test/ui/unsized-locals/issue-30276.stderr
src/test/ui/unsized-locals/issue-50940-with-feature.stderr
src/test/ui/unsized-locals/issue-50940.stderr
src/test/ui/unsized-locals/unsized-exprs.stderr
src/test/ui/unsized-locals/unsized-exprs3.stderr
src/test/ui/unsized/unsized-bare-typaram.stderr
src/test/ui/unsized/unsized-enum.stderr
src/test/ui/unsized/unsized-enum2.stderr
src/test/ui/unsized/unsized-fn-param.stderr
src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
src/test/ui/unsized/unsized-struct.stderr
src/test/ui/unsized/unsized-trait-impl-self-type.stderr
src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
src/test/ui/unsized3.stderr
src/test/ui/unsized5.stderr
src/test/ui/unsized6.stderr
src/test/ui/unsized7.stderr
src/test/ui/wf/wf-array-elem-sized.stderr
src/test/ui/wf/wf-enum-fields-struct-variant.stderr
src/test/ui/wf/wf-fn-where-clause.stderr
src/test/ui/wf/wf-in-fn-type-arg.stderr
src/test/ui/wf/wf-in-fn-type-ret.stderr
src/test/ui/wf/wf-in-fn-type-static.stderr
src/test/ui/wf/wf-in-obj-type-static.stderr
src/test/ui/wf/wf-in-obj-type-trait.stderr
src/test/ui/wf/wf-struct-field.stderr
src/test/ui/xcrate/xcrate-unit-struct.stderr
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md
src/tools/clippy/.github/workflows/clippy_bors.yml
src/tools/clippy/CHANGELOG.md
src/tools/clippy/CONTRIBUTING.md
src/tools/clippy/clippy_lints/src/arithmetic.rs
src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
src/tools/clippy/clippy_lints/src/assign_ops.rs
src/tools/clippy/clippy_lints/src/atomic_ordering.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/await_holding_lock.rs
src/tools/clippy/clippy_lints/src/bit_mask.rs
src/tools/clippy/clippy_lints/src/booleans.rs
src/tools/clippy/clippy_lints/src/bytecount.rs
src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
src/tools/clippy/clippy_lints/src/collapsible_if.rs
src/tools/clippy/clippy_lints/src/comparison_chain.rs
src/tools/clippy/clippy_lints/src/consts.rs
src/tools/clippy/clippy_lints/src/copies.rs
src/tools/clippy/clippy_lints/src/default_trait_access.rs
src/tools/clippy/clippy_lints/src/deprecated_lints.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
src/tools/clippy/clippy_lints/src/duration_subsec.rs
src/tools/clippy/clippy_lints/src/entry.rs
src/tools/clippy/clippy_lints/src/eq_op.rs
src/tools/clippy/clippy_lints/src/erasing_op.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
src/tools/clippy/clippy_lints/src/float_literal.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/format.rs
src/tools/clippy/clippy_lints/src/formatting.rs
src/tools/clippy/clippy_lints/src/functions.rs
src/tools/clippy/clippy_lints/src/get_last_with_len.rs
src/tools/clippy/clippy_lints/src/identity_op.rs
src/tools/clippy/clippy_lints/src/if_let_mutex.rs
src/tools/clippy/clippy_lints/src/if_let_some_result.rs
src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
src/tools/clippy/clippy_lints/src/indexing_slicing.rs
src/tools/clippy/clippy_lints/src/infinite_iter.rs
src/tools/clippy/clippy_lints/src/integer_division.rs
src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/let_and_return.rs
src/tools/clippy/clippy_lints/src/let_if_seq.rs
src/tools/clippy/clippy_lints/src/let_underscore.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/literal_representation.rs
src/tools/clippy/clippy_lints/src/loops.rs
src/tools/clippy/clippy_lints/src/map_clone.rs
src/tools/clippy/clippy_lints/src/map_identity.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/map_unit_fn.rs
src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/mem_discriminant.rs
src/tools/clippy/clippy_lints/src/mem_forget.rs
src/tools/clippy/clippy_lints/src/mem_replace.rs
src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
src/tools/clippy/clippy_lints/src/minmax.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/misc_early.rs
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
src/tools/clippy/clippy_lints/src/mut_key.rs
src/tools/clippy/clippy_lints/src/mut_mut.rs
src/tools/clippy/clippy_lints/src/mut_reference.rs
src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
src/tools/clippy/clippy_lints/src/mutex_atomic.rs
src/tools/clippy/clippy_lints/src/needless_bool.rs
src/tools/clippy/clippy_lints/src/needless_borrow.rs
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
src/tools/clippy/clippy_lints/src/needless_update.rs
src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
src/tools/clippy/clippy_lints/src/neg_multiply.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/no_effect.rs
src/tools/clippy/clippy_lints/src/non_copy_const.rs
src/tools/clippy/clippy_lints/src/non_expressive_names.rs
src/tools/clippy/clippy_lints/src/open_options.rs
src/tools/clippy/clippy_lints/src/option_if_let_else.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/precedence.rs
src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs [deleted file]
src/tools/clippy/clippy_lints/src/regex.rs
src/tools/clippy/clippy_lints/src/repeat_once.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/shadow.rs
src/tools/clippy/clippy_lints/src/strings.rs
src/tools/clippy/clippy_lints/src/swap.rs
src/tools/clippy/clippy_lints/src/temporary_assignment.rs
src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_lints/src/transmute.rs
src/tools/clippy/clippy_lints/src/transmuting_null.rs
src/tools/clippy/clippy_lints/src/try_err.rs
src/tools/clippy/clippy_lints/src/types.rs
src/tools/clippy/clippy_lints/src/unnamed_address.rs
src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
src/tools/clippy/clippy_lints/src/unwrap.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/clippy/clippy_lints/src/useless_conversion.rs
src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
src/tools/clippy/clippy_lints/src/utils/attrs.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/higher.rs
src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
src/tools/clippy/clippy_lints/src/utils/inspector.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/mod.rs
src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs
src/tools/clippy/clippy_lints/src/utils/paths.rs
src/tools/clippy/clippy_lints/src/utils/sugg.rs
src/tools/clippy/clippy_lints/src/utils/usage.rs
src/tools/clippy/clippy_lints/src/vec.rs
src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_lints/src/zero_div_zero.rs
src/tools/clippy/doc/common_tools_writing_lints.md
src/tools/clippy/src/driver.rs
src/tools/clippy/src/lintlist/mod.rs
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/attrs.rs
src/tools/clippy/tests/ui/attrs.stderr
src/tools/clippy/tests/ui/clone_on_copy.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/clone_on_copy.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/clone_on_copy.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/collapsible_else_if.stderr
src/tools/clippy/tests/ui/collapsible_if.stderr
src/tools/clippy/tests/ui/deprecated.rs
src/tools/clippy/tests/ui/deprecated.stderr
src/tools/clippy/tests/ui/find_map.rs
src/tools/clippy/tests/ui/find_map.stderr
src/tools/clippy/tests/ui/floating_point_hypot.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_hypot.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_hypot.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_log.fixed
src/tools/clippy/tests/ui/floating_point_log.rs
src/tools/clippy/tests/ui/floating_point_log.stderr
src/tools/clippy/tests/ui/floating_point_logbase.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_logbase.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_logbase.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_mul_add.fixed
src/tools/clippy/tests/ui/floating_point_mul_add.rs
src/tools/clippy/tests/ui/floating_point_mul_add.stderr
src/tools/clippy/tests/ui/floating_point_powf.fixed
src/tools/clippy/tests/ui/floating_point_powf.rs
src/tools/clippy/tests/ui/floating_point_powf.stderr
src/tools/clippy/tests/ui/floating_point_powi.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_powi.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_powi.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_rad.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_rad.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/floating_point_rad.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/map_flatten.fixed
src/tools/clippy/tests/ui/map_flatten.rs
src/tools/clippy/tests/ui/map_flatten.stderr
src/tools/clippy/tests/ui/map_identity.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/map_identity.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/map_identity.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs
src/tools/clippy/tests/ui/option_if_let_else.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/option_if_let_else.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/option_if_let_else.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/range_plus_minus_one.fixed
src/tools/clippy/tests/ui/range_plus_minus_one.rs
src/tools/clippy/tests/ui/range_plus_minus_one.stderr
src/tools/clippy/tests/ui/redundant_pattern_matching.fixed
src/tools/clippy/tests/ui/redundant_pattern_matching.rs
src/tools/clippy/tests/ui/redundant_pattern_matching.stderr
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs
src/tools/clippy/tests/ui/regex.rs
src/tools/clippy/tests/ui/repeat_once.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/repeat_once.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/repeat_once.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/single_match_else.rs
src/tools/clippy/tests/ui/single_match_else.stderr
src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
src/tools/clippy/tests/ui/unnecessary_clone.rs
src/tools/clippy/tests/ui/unnecessary_clone.stderr
src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
src/tools/clippy/tests/ui/unnecessary_sort_by.rs
src/tools/clippy/tests/ui/unnested_or_patterns3.rs [new file with mode: 0644]
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/error_index_generator/main.rs
src/tools/miri
src/tools/rust-demangler/Cargo.toml [new file with mode: 0644]
src/tools/rust-demangler/main.rs [new file with mode: 0644]
src/tools/rustc-std-workspace-std/lib.rs
src/tools/tidy/src/deps.rs
src/tools/tidy/src/error_codes_check.rs
src/tools/tidy/src/lib.rs
src/tools/tidy/src/style.rs

index a38761d166567119be2d78247446cbaa875adf22..86de37820003ae425f59eee735e23666f7099015 100644 (file)
@@ -26,7 +26,7 @@ name: CI
       - "**"
 defaults:
   run:
-    shell: "python src/ci/exec-with-shell.py {0}"
+    shell: bash
 jobs:
   pr:
     name: PR
@@ -54,7 +54,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -154,7 +153,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -297,6 +295,9 @@ jobs:
           - name: dist-powerpc64le-linux
             os: ubuntu-latest-xl
             env: {}
+          - name: dist-riscv64-linux
+            os: ubuntu-latest-xl
+            env: {}
           - name: dist-s390x-linux
             os: ubuntu-latest-xl
             env: {}
@@ -309,6 +310,9 @@ jobs:
           - name: dist-x86_64-freebsd
             os: ubuntu-latest-xl
             env: {}
+          - name: dist-x86_64-illumos
+            os: ubuntu-latest-xl
+            env: {}
           - name: dist-x86_64-linux
             os: ubuntu-latest-xl
             env: {}
@@ -466,7 +470,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -592,7 +595,6 @@ jobs:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
       - name: checkout the source code
         uses: actions/checkout@v1
         with:
@@ -688,6 +690,7 @@ jobs:
           fetch-depth: 2
       - name: publish toolstate
         run: src/ci/publish_toolstate.sh
+        shell: bash
         env:
           TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
         if: success() && !env.SKIP_JOB
index 5c0ab737f63dbd7da7c41695f382a9a2a275f1b6..b914b7d6fa12961cb20f627f0a2133715e86c481 100644 (file)
@@ -44,3 +44,6 @@
 [submodule "src/tools/rust-analyzer"]
        path = src/tools/rust-analyzer
        url = https://github.com/rust-analyzer/rust-analyzer.git
+[submodule "src/backtrace"]
+       path = src/backtrace
+       url = https://github.com/rust-lang/backtrace-rs.git
index aad495fa3fae6e4b04d95230bee6655795d99792..2a4c42ea0a456555e9afb33d57d17272985f355f 100644 (file)
@@ -4,5 +4,12 @@ Thank you for your interest in contributing to Rust!
 
 To get started, read the [Getting Started] guide in the [rustc-dev-guide].
 
+## Bug reports
+
+Did a compiler error message tell you to come here? If you want to create an ICE report,
+refer to [this section][contributing-bug-reports] and [open an issue][issue template].
+
 [Getting Started]: https://rustc-dev-guide.rust-lang.org/getting-started.html
 [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
+[contributing-bug-reports]: https://rustc-dev-guide.rust-lang.org/contributing.html#bug-reports
+[issue template]: https://github.com/rust-lang/rust/issues/new/choose
index 905f523aa53d666f67571b835d419e68ba8991bb..34a33eca3f40b7c635b79dfbf7b1bc0f416c8497 100644 (file)
@@ -1,10 +1,26 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
 [[package]]
-name = "adler32"
-version = "1.0.3"
+name = "addr2line"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
+dependencies = [
+ "compiler_builtins",
+ "gimli",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "adler"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
+checksum = "ccc9a9dd069569f212bc4330af9f17c4afb5e8ce185e83dbb14f1349dda18b10"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
 
 [[package]]
 name = "aho-corasick"
@@ -94,6 +110,12 @@ dependencies = [
  "nodrop",
 ]
 
+[[package]]
+name = "arrayvec"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
+
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -119,28 +141,14 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
 
 [[package]]
 name = "backtrace"
-version = "0.3.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
+version = "0.3.50"
 dependencies = [
- "backtrace-sys",
+ "addr2line",
  "cfg-if",
- "compiler_builtins",
  "libc",
+ "miniz_oxide",
+ "object",
  "rustc-demangle",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "backtrace-sys"
-version = "0.1.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fbebbe1c9d1f383a9cc7e8ccdb471b91c8d024ee9c2ca5b5346121fe8b4399"
-dependencies = [
- "cc",
- "compiler_builtins",
- "libc",
- "rustc-std-workspace-core",
 ]
 
 [[package]]
@@ -164,7 +172,7 @@ version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.4.7",
  "constant_time_eq",
 ]
 
@@ -682,9 +690,9 @@ dependencies = [
 
 [[package]]
 name = "crc32fast"
-version = "1.1.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192"
+checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
 dependencies = [
  "cfg-if",
 ]
@@ -714,7 +722,7 @@ version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
 dependencies = [
- "arrayvec",
+ "arrayvec 0.4.7",
  "cfg-if",
  "crossbeam-utils 0.6.5",
  "lazy_static",
@@ -1017,9 +1025,9 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
 
 [[package]]
 name = "flate2"
-version = "1.0.12"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3"
+checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
 dependencies = [
  "cfg-if",
  "crc32fast",
@@ -1153,6 +1161,17 @@ dependencies = [
  "wasi",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
 [[package]]
 name = "git2"
 version = "0.13.5"
@@ -1813,11 +1832,14 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.3.5"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625"
+checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
 dependencies = [
- "adler32",
+ "adler",
+ "compiler_builtins",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
 ]
 
 [[package]]
@@ -1949,6 +1971,17 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "object"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.1.0"
@@ -2050,6 +2083,7 @@ dependencies = [
 name = "panic_abort"
 version = "0.0.0"
 dependencies = [
+ "cfg-if",
  "compiler_builtins",
  "core",
  "libc",
@@ -2135,6 +2169,12 @@ dependencies = [
  "winapi 0.3.8",
 ]
 
+[[package]]
+name = "pathdiff"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877630b3de15c0b64cc52f659345724fbf6bdad9bd9566699fc53688f3c34a34"
+
 [[package]]
 name = "percent-encoding"
 version = "1.0.1"
@@ -2781,6 +2821,13 @@ dependencies = [
  "rls-span",
 ]
 
+[[package]]
+name = "rust-demangler"
+version = "0.0.0"
+dependencies = [
+ "rustc-demangle",
+]
+
 [[package]]
 name = "rustbook"
 version = "0.1.0"
@@ -3311,6 +3358,7 @@ dependencies = [
  "log",
  "memmap",
  "num_cpus",
+ "pathdiff",
  "rustc_apfloat",
  "rustc_ast",
  "rustc_attr",
@@ -3494,8 +3542,8 @@ dependencies = [
 name = "rustc_index"
 version = "0.0.0"
 dependencies = [
+ "arrayvec 0.5.1",
  "rustc_serialize",
- "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3996,6 +4044,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
+ "rustc_hir_pretty",
  "rustc_index",
  "rustc_infer",
  "rustc_middle",
@@ -4324,8 +4373,8 @@ dependencies = [
 name = "std"
 version = "0.0.0"
 dependencies = [
+ "addr2line",
  "alloc",
- "backtrace",
  "cfg-if",
  "compiler_builtins",
  "core",
@@ -4334,10 +4383,13 @@ dependencies = [
  "hashbrown",
  "hermit-abi",
  "libc",
+ "miniz_oxide",
+ "object",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
  "rand 0.7.3",
+ "rustc-demangle",
  "unwind",
  "wasi",
 ]
@@ -4545,6 +4597,7 @@ dependencies = [
 name = "test"
 version = "0.0.0"
 dependencies = [
+ "cfg-if",
  "core",
  "getopts",
  "libc",
index be15e50e2bcca07d92d6615542914b4c0ba112f7..9429e063b51106e35e9d19aa6eb89a91e242eba4 100644 (file)
@@ -17,6 +17,7 @@ members = [
   "src/tools/remote-test-client",
   "src/tools/remote-test-server",
   "src/tools/rust-installer",
+  "src/tools/rust-demangler",
   "src/tools/cargo",
   "src/tools/rustdoc",
   "src/tools/rls",
@@ -79,5 +80,11 @@ 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' }
 
+# This crate's integration with libstd is a bit wonky, so we use a submodule
+# instead of a crates.io dependency. Make sure everything else in the repo is
+# also using the submodule, however, so we can avoid duplicate copies of the
+# source code for this crate.
+backtrace = { path = "src/backtrace" }
+
 [patch."https://github.com/rust-lang/rust-clippy"]
 clippy_lints = { path = "src/tools/clippy/clippy_lints" }
index 977796c66132e938331b62bf88cc2bcbc3143611..f36cdee0975a0394a0e866418fb3c894be2bcc01 100644 (file)
@@ -47,7 +47,7 @@ Libraries
   // Prints "abcdefghijklmnopqrstuvwxyz"
   ```
 - [`OsString` now implements `FromStr`.][71662]
-- [The `saturating_neg` method as been added to all signed integer primitive
+- [The `saturating_neg` method has been added to all signed integer primitive
   types, and the `saturating_abs` method has been added for all integer
   primitive types.][71886]
 - [`Arc<T>`, `Rc<T>` now implement  `From<Cow<'_, T>>`, and `Box` now
@@ -82,6 +82,9 @@ Stabilized APIs
 Cargo
 -----
 
+- [Cargo uses the `embed-bitcode` flag to optimize disk usage and build
+  time.][cargo/8066]
+
 Misc
 ----
 - [Rustdoc now supports strikethrough text in Markdown.][71928] E.g.
@@ -97,12 +100,18 @@ Compatibility Notes
 - [Rustdoc's CLI's extra error exit codes have been removed.][71900] These were
   previously undocumented and not intended for public use. Rustdoc still provides
   a non-zero exit code on errors.
+- [Rustc's `lto` flag is incompatible with the new `embed-bitcode=no`.][71848]
+  This may cause issues if LTO is enabled through `RUSTFLAGS` or `cargo rustc`
+  flags while cargo is adding `embed-bitcode` itself. The recommended way to
+  control LTO is with Cargo profiles, either in `Cargo.toml` or `.cargo/config`,
+  or by setting `CARGO_PROFILE_<name>_LTO` in the environment.
 
 Internals Only
 --------------
 - [Make clippy a git subtree instead of a git submodule][70655]
 - [Unify the undo log of all snapshot types][69464]
 
+[71848]: https://github.com/rust-lang/rust/issues/71848/
 [73420]: https://github.com/rust-lang/rust/issues/73420/
 [72324]: https://github.com/rust-lang/rust/pull/72324/
 [71843]: https://github.com/rust-lang/rust/pull/71843/
@@ -129,6 +138,7 @@ Internals Only
 [69813]: https://github.com/rust-lang/rust/pull/69813/
 [69464]: https://github.com/rust-lang/rust/pull/69464/
 [68717]: https://github.com/rust-lang/rust/pull/68717/
+[cargo/8066]: https://github.com/rust-lang/cargo/pull/8066
 [`Arc::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.as_ptr
 [`BTreeMap::remove_entry`]: https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.remove_entry
 [`Rc::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.as_ptr
index 79e4e46d85ba344ea441ea279ae17923903610e2..01952b21ba4b1fe9a07f76b246b65e3a0151760c 100644 (file)
 # desired in distributions, for example.
 #rpath = true
 
-# Emits extraneous output from tests to ensure that failures of the test
-# harness are debuggable just from logfiles.
+# Emits extra output from tests so test failures are debuggable just from logfiles.
 #verbose-tests = false
 
 # Flag indicating whether tests are compiled with optimizations (the -O flag).
index c76a75fa07bb0361eee0acda48734f8c58c797a2..b16aecc463c9191c591d0c135ab50e975afc1000 100644 (file)
@@ -30,6 +30,7 @@ ignore = [
     "src/tools/rust-analyzer",
     "src/tools/rust-installer",
     "src/tools/rustfmt",
+    "src/backtrace",
 
     # We do not format this file as it is externally sourced and auto-generated.
     "src/libstd/sys/cloudabi/abi/cloudabi.rs",
diff --git a/src/backtrace b/src/backtrace
new file mode 160000 (submodule)
index 0000000..8f89434
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 8f89434446f72f27f8145d8bbc1a302c6ef29d1e
index 1dfa635c694acdc06bcb3f256e8fe267014d06d6..c3f1bac177de7dd6695196a0b12cc2ca69048cc5 100644 (file)
@@ -349,6 +349,7 @@ class RustBuild(object):
         self.use_vendored_sources = ''
         self.verbose = False
         self.git_version = None
+        self.nix_deps_dir = None
 
     def download_stage0(self):
         """Fetch the build system for Rust, written in Rust
@@ -388,8 +389,12 @@ class RustBuild(object):
             filename = "rustc-{}-{}{}".format(rustc_channel, self.build,
                                               tarball_suffix)
             self._download_stage0_helper(filename, "rustc", tarball_suffix)
-            self.fix_executable("{}/bin/rustc".format(self.bin_root()))
-            self.fix_executable("{}/bin/rustdoc".format(self.bin_root()))
+            self.fix_bin_or_dylib("{}/bin/rustc".format(self.bin_root()))
+            self.fix_bin_or_dylib("{}/bin/rustdoc".format(self.bin_root()))
+            lib_dir = "{}/lib".format(self.bin_root())
+            for lib in os.listdir(lib_dir):
+                if lib.endswith(".so"):
+                    self.fix_bin_or_dylib("{}/{}".format(lib_dir, lib))
             with output(self.rustc_stamp()) as rust_stamp:
                 rust_stamp.write(self.date)
 
@@ -408,7 +413,7 @@ class RustBuild(object):
             filename = "cargo-{}-{}{}".format(cargo_channel, self.build,
                                               tarball_suffix)
             self._download_stage0_helper(filename, "cargo", tarball_suffix)
-            self.fix_executable("{}/bin/cargo".format(self.bin_root()))
+            self.fix_bin_or_dylib("{}/bin/cargo".format(self.bin_root()))
             with output(self.cargo_stamp()) as cargo_stamp:
                 cargo_stamp.write(self.date)
 
@@ -421,8 +426,8 @@ class RustBuild(object):
                 [channel, date] = rustfmt_channel.split('-', 1)
                 filename = "rustfmt-{}-{}{}".format(channel, self.build, tarball_suffix)
                 self._download_stage0_helper(filename, "rustfmt-preview", tarball_suffix, date)
-                self.fix_executable("{}/bin/rustfmt".format(self.bin_root()))
-                self.fix_executable("{}/bin/cargo-fmt".format(self.bin_root()))
+                self.fix_bin_or_dylib("{}/bin/rustfmt".format(self.bin_root()))
+                self.fix_bin_or_dylib("{}/bin/cargo-fmt".format(self.bin_root()))
                 with output(self.rustfmt_stamp()) as rustfmt_stamp:
                     rustfmt_stamp.write(self.date + self.rustfmt_channel)
 
@@ -440,12 +445,12 @@ class RustBuild(object):
             get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
         unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose)
 
-    @staticmethod
-    def fix_executable(fname):
-        """Modifies the interpreter section of 'fname' to fix the dynamic linker
+    def fix_bin_or_dylib(self, fname):
+        """Modifies the interpreter section of 'fname' to fix the dynamic linker,
+        or the RPATH section, to fix the dynamic library search path
 
         This method is only required on NixOS and uses the PatchELF utility to
-        change the dynamic linker of ELF executables.
+        change the interpreter/RPATH of ELF executables.
 
         Please see https://nixos.org/patchelf.html for more information
         """
@@ -472,38 +477,61 @@ class RustBuild(object):
         nix_os_msg = "info: you seem to be running NixOS. Attempting to patch"
         print(nix_os_msg, fname)
 
-        try:
-            interpreter = subprocess.check_output(
-                ["patchelf", "--print-interpreter", fname])
-            interpreter = interpreter.strip().decode(default_encoding)
-        except subprocess.CalledProcessError as reason:
-            print("warning: failed to call patchelf:", reason)
-            return
-
-        loader = interpreter.split("/")[-1]
-
-        try:
-            ldd_output = subprocess.check_output(
-                ['ldd', '/run/current-system/sw/bin/sh'])
-            ldd_output = ldd_output.strip().decode(default_encoding)
-        except subprocess.CalledProcessError as reason:
-            print("warning: unable to call ldd:", reason)
-            return
-
-        for line in ldd_output.splitlines():
-            libname = line.split()[0]
-            if libname.endswith(loader):
-                loader_path = libname[:len(libname) - len(loader)]
-                break
+        # Only build `stage0/.nix-deps` once.
+        nix_deps_dir = self.nix_deps_dir
+        if not nix_deps_dir:
+            nix_deps_dir = "{}/.nix-deps".format(self.bin_root())
+            if not os.path.exists(nix_deps_dir):
+                os.makedirs(nix_deps_dir)
+
+            nix_deps = [
+                # Needed for the path of `ld-linux.so` (via `nix-support/dynamic-linker`).
+                "stdenv.cc.bintools",
+
+                # Needed as a system dependency of `libLLVM-*.so`.
+                "zlib",
+
+                # Needed for patching ELF binaries (see doc comment above).
+                "patchelf",
+            ]
+
+            # Run `nix-build` to "build" each dependency (which will likely reuse
+            # the existing `/nix/store` copy, or at most download a pre-built copy).
+            # Importantly, we don't rely on `nix-build` printing the `/nix/store`
+            # path on stdout, but use `-o` to symlink it into `stage0/.nix-deps/$dep`,
+            # ensuring garbage collection will never remove the `/nix/store` path
+            # (which would break our patched binaries that hardcode those paths).
+            for dep in nix_deps:
+                try:
+                    subprocess.check_output([
+                        "nix-build", "<nixpkgs>",
+                        "-A", dep,
+                        "-o", "{}/{}".format(nix_deps_dir, dep),
+                    ])
+                except subprocess.CalledProcessError as reason:
+                    print("warning: failed to call nix-build:", reason)
+                    return
+
+            self.nix_deps_dir = nix_deps_dir
+
+        patchelf = "{}/patchelf/bin/patchelf".format(nix_deps_dir)
+
+        if fname.endswith(".so"):
+            # Dynamic library, patch RPATH to point to system dependencies.
+            dylib_deps = ["zlib"]
+            rpath_entries = [
+                # Relative default, all binary and dynamic libraries we ship
+                # appear to have this (even when `../lib` is redundant).
+                "$ORIGIN/../lib",
+            ] + ["{}/{}/lib".format(nix_deps_dir, dep) for dep in dylib_deps]
+            patchelf_args = ["--set-rpath", ":".join(rpath_entries)]
         else:
-            print("warning: unable to find the path to the dynamic linker")
-            return
-
-        correct_interpreter = loader_path + loader
+            bintools_dir = "{}/stdenv.cc.bintools".format(nix_deps_dir)
+            with open("{}/nix-support/dynamic-linker".format(bintools_dir)) as dynamic_linker:
+                patchelf_args = ["--set-interpreter", dynamic_linker.read().rstrip()]
 
         try:
-            subprocess.check_output(
-                ["patchelf", "--set-interpreter", correct_interpreter, fname])
+            subprocess.check_output([patchelf] + patchelf_args + [fname])
         except subprocess.CalledProcessError as reason:
             print("warning: failed to call patchelf:", reason)
             return
index 557fb1aa550a5862b70910fd697b2978c3595d58..70e5f6ac26fc13c8b0479192cff2f9df709e3639 100644 (file)
@@ -16,6 +16,7 @@
 use crate::cache::{Cache, Interned, INTERNER};
 use crate::check;
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::dist;
 use crate::doc;
 use crate::flags::Subcommand;
@@ -86,8 +87,8 @@ fn make_run(_run: RunConfig<'_>) {
 
 pub struct RunConfig<'a> {
     pub builder: &'a Builder<'a>,
-    pub host: Interned<String>,
-    pub target: Interned<String>,
+    pub host: TargetSelection,
+    pub target: TargetSelection,
     pub path: PathBuf,
 }
 
@@ -369,6 +370,7 @@ macro_rules! describe {
                 tool::Cargo,
                 tool::Rls,
                 tool::RustAnalyzer,
+                tool::RustDemangler,
                 tool::Rustdoc,
                 tool::Clippy,
                 tool::CargoClippy,
@@ -576,7 +578,7 @@ fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
     /// not take `Compiler` since all `Compiler` instances are meant to be
     /// obtained through this function, since it ensures that they are valid
     /// (i.e., built and assembled).
-    pub fn compiler(&self, stage: u32, host: Interned<String>) -> Compiler {
+    pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler {
         self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
     }
 
@@ -594,8 +596,8 @@ pub fn compiler(&self, stage: u32, host: Interned<String>) -> Compiler {
     pub fn compiler_for(
         &self,
         stage: u32,
-        host: Interned<String>,
-        target: Interned<String>,
+        host: TargetSelection,
+        target: TargetSelection,
     ) -> Compiler {
         if self.build.force_use_stage1(Compiler { stage, host }, target) {
             self.compiler(1, self.config.build)
@@ -610,15 +612,11 @@ pub fn sysroot(&self, compiler: Compiler) -> Interned<PathBuf> {
 
     /// Returns the libdir where the standard library and other artifacts are
     /// found for a compiler's sysroot.
-    pub fn sysroot_libdir(
-        &self,
-        compiler: Compiler,
-        target: Interned<String>,
-    ) -> Interned<PathBuf> {
+    pub fn sysroot_libdir(&self, compiler: Compiler, target: TargetSelection) -> Interned<PathBuf> {
         #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         struct Libdir {
             compiler: Compiler,
-            target: Interned<String>,
+            target: TargetSelection,
         }
         impl Step for Libdir {
             type Output = Interned<PathBuf>;
@@ -633,7 +631,7 @@ fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> {
                     .sysroot(self.compiler)
                     .join(lib)
                     .join("rustlib")
-                    .join(self.target)
+                    .join(self.target.triple)
                     .join("lib");
                 let _ = fs::remove_dir_all(&sysroot);
                 t!(fs::create_dir_all(&sysroot));
@@ -656,7 +654,7 @@ pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
                 Some(relative_libdir) if compiler.stage >= 1 => {
                     self.sysroot(compiler).join(relative_libdir)
                 }
-                _ => self.sysroot(compiler).join(libdir(&compiler.host)),
+                _ => self.sysroot(compiler).join(libdir(compiler.host)),
             }
         }
     }
@@ -668,11 +666,11 @@ pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
     /// Windows.
     pub fn libdir_relative(&self, compiler: Compiler) -> &Path {
         if compiler.is_snapshot(self) {
-            libdir(&self.config.build).as_ref()
+            libdir(self.config.build).as_ref()
         } else {
             match self.config.libdir_relative() {
                 Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
-                _ => libdir(&compiler.host).as_ref(),
+                _ => libdir(compiler.host).as_ref(),
             }
         }
     }
@@ -707,7 +705,7 @@ pub fn rustc(&self, compiler: Compiler) -> PathBuf {
         if compiler.is_snapshot(self) {
             self.initial_rustc.clone()
         } else {
-            self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host))
+            self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
         }
     }
 
@@ -725,7 +723,11 @@ pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
             .env("CFG_RELEASE_CHANNEL", &self.config.channel)
             .env("RUSTDOC_REAL", self.rustdoc(compiler))
             .env("RUSTDOC_CRATE_VERSION", self.rust_version())
-            .env("RUSTC_BOOTSTRAP", "1");
+            .env("RUSTC_BOOTSTRAP", "1")
+            .arg("-Winvalid_codeblock_attributes");
+        if self.config.deny_warnings {
+            cmd.arg("-Dwarnings");
+        }
 
         // Remove make-related flags that can cause jobserver problems.
         cmd.env_remove("MAKEFLAGS");
@@ -741,7 +743,7 @@ pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
     ///
     /// Note that this returns `None` if LLVM is disabled, or if we're in a
     /// check build or dry-run, where there's no need to build all of LLVM.
-    fn llvm_config(&self, target: Interned<String>) -> Option<PathBuf> {
+    fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> {
         if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run {
             let llvm_config = self.ensure(native::Llvm { target });
             if llvm_config.is_file() {
@@ -763,7 +765,7 @@ pub fn cargo(
         compiler: Compiler,
         mode: Mode,
         source_type: SourceType,
-        target: Interned<String>,
+        target: TargetSelection,
         cmd: &str,
     ) -> Cargo {
         let mut cargo = Command::new(&self.initial_cargo);
@@ -773,7 +775,8 @@ pub fn cargo(
             let my_out = match mode {
                 // This is the intended out directory for compiler documentation.
                 Mode::Rustc | Mode::ToolRustc | Mode::Codegen => self.compiler_doc_out(target),
-                _ => self.crate_doc_out(target),
+                Mode::Std => out_dir.join(target.triple).join("doc"),
+                _ => panic!("doc mode {:?} not expected", mode),
             };
             let rustdoc = self.rustdoc(compiler);
             self.clear_if_dirty(&my_out, &rustdoc);
@@ -794,7 +797,7 @@ pub fn cargo(
         }
 
         if cmd != "install" {
-            cargo.arg("--target").arg(target);
+            cargo.arg("--target").arg(target.rustc_target_arg());
         } else {
             assert_eq!(target, compiler.host);
         }
@@ -820,7 +823,7 @@ pub fn cargo(
             compiler.stage
         };
 
-        let mut rustflags = Rustflags::new(&target);
+        let mut rustflags = Rustflags::new(target);
         if stage != 0 {
             if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
                 cargo.args(s.split_whitespace());
@@ -837,7 +840,7 @@ pub fn cargo(
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
         // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
         // #71458.
-        let rustdocflags = rustflags.clone();
+        let mut rustdocflags = rustflags.clone();
 
         if let Ok(s) = env::var("CARGOFLAGS") {
             cargo.args(s.split_whitespace());
@@ -993,7 +996,7 @@ pub fn cargo(
         // 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 && util::use_host_linker(&target) {
+        if self.config.rust_rpath && util::use_host_linker(target) {
             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
@@ -1021,7 +1024,7 @@ pub fn cargo(
         }
 
         if let Some(target_linker) = self.linker(target, can_use_lld) {
-            let target = crate::envify(&target);
+            let target = crate::envify(&target.triple);
             cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker);
         }
         if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
@@ -1139,6 +1142,7 @@ pub fn cargo(
 
             if self.config.deny_warnings {
                 lint_flags.push("-Dwarnings");
+                rustdocflags.arg("-Dwarnings");
             }
 
             // FIXME(#58633) hide "unused attribute" errors in incremental
@@ -1156,6 +1160,8 @@ pub fn cargo(
             // are always ignored in dependencies. Eventually this should be
             // fixed via better support from Cargo.
             cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" "));
+
+            rustdocflags.arg("-Winvalid_codeblock_attributes");
         }
 
         if let Mode::Rustc | Mode::Codegen = mode {
@@ -1192,21 +1198,23 @@ pub fn cargo(
                 }
             };
             let cc = ccacheify(&self.cc(target));
-            cargo.env(format!("CC_{}", target), &cc);
+            cargo.env(format!("CC_{}", target.triple), &cc);
 
             let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
-            cargo.env(format!("CFLAGS_{}", target), cflags.clone());
+            cargo.env(format!("CFLAGS_{}", target.triple), cflags.clone());
 
             if let Some(ar) = self.ar(target) {
                 let ranlib = format!("{} s", ar.display());
-                cargo.env(format!("AR_{}", target), ar).env(format!("RANLIB_{}", target), ranlib);
+                cargo
+                    .env(format!("AR_{}", target.triple), ar)
+                    .env(format!("RANLIB_{}", target.triple), ranlib);
             }
 
             if let Ok(cxx) = self.cxx(target) {
                 let cxx = ccacheify(&cxx);
                 cargo
-                    .env(format!("CXX_{}", target), &cxx)
-                    .env(format!("CXXFLAGS_{}", target), cflags);
+                    .env(format!("CXX_{}", target.triple), &cxx)
+                    .env(format!("CXXFLAGS_{}", target.triple), cflags);
             }
         }
 
@@ -1240,7 +1248,7 @@ pub fn cargo(
         // Environment variables *required* throughout the build
         //
         // FIXME: should update code to not require this env var
-        cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
+        cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);
 
         // Set this for all builds to make sure doc builds also get it.
         cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
@@ -1396,7 +1404,7 @@ pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
 struct Rustflags(String);
 
 impl Rustflags {
-    fn new(target: &str) -> Rustflags {
+    fn new(target: TargetSelection) -> Rustflags {
         let mut ret = Rustflags(String::new());
 
         // Inherit `RUSTFLAGS` by default ...
@@ -1404,7 +1412,7 @@ fn new(target: &str) -> Rustflags {
 
         // ... and also handle target-specific env RUSTFLAGS if they're
         // configured.
-        let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(target));
+        let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(&target.triple));
         ret.env(&target_specific);
 
         ret
index 1e75e67af0c9e17f847e5e63255ad1d41e2d8feb..69a54bec33b678ebbb8a062888100ea5f763f555 100644 (file)
@@ -1,5 +1,5 @@
 use super::*;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 use std::thread;
 
 use pretty_assertions::assert_eq;
@@ -17,16 +17,16 @@ fn configure(host: &[&str], target: &[&str]) -> Config {
         .join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
     t!(fs::create_dir_all(&dir));
     config.out = dir;
-    config.build = INTERNER.intern_str("A");
+    config.build = TargetSelection::from_user("A");
     config.hosts = vec![config.build]
         .into_iter()
-        .chain(host.iter().map(|s| INTERNER.intern_str(s)))
+        .chain(host.iter().map(|s| TargetSelection::from_user(s)))
         .collect::<Vec<_>>();
     config.targets = config
         .hosts
         .clone()
         .into_iter()
-        .chain(target.iter().map(|s| INTERNER.intern_str(s)))
+        .chain(target.iter().map(|s| TargetSelection::from_user(s)))
         .collect::<Vec<_>>();
     config
 }
@@ -41,7 +41,7 @@ fn dist_baseline() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
+    let a = TargetSelection::from_user("A");
 
     assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
     assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
@@ -67,8 +67,8 @@ fn dist_with_targets() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -98,8 +98,8 @@ fn dist_with_hosts() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -128,8 +128,8 @@ fn dist_with_hosts() {
 
 #[test]
 fn dist_only_cross_host() {
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
     let mut build = Build::new(configure(&["B"], &[]));
     build.config.docs = false;
     build.config.extended = true;
@@ -156,9 +156,9 @@ fn dist_with_targets_and_hosts() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
-    let c = INTERNER.intern_str("C");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -194,9 +194,9 @@ fn dist_with_target_flag() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
-    let c = INTERNER.intern_str("C");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -224,8 +224,8 @@ fn dist_with_same_targets_and_hosts() {
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
-    let a = INTERNER.intern_str("A");
-    let b = INTERNER.intern_str("B");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
 
     assert_eq!(
         first(builder.cache.all::<dist::Docs>()),
@@ -277,9 +277,9 @@ fn build_default() {
     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");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<compile::Std>()),
@@ -318,9 +318,9 @@ fn build_with_target_flag() {
     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");
+    let a = TargetSelection::from_user("A");
+    let b = TargetSelection::from_user("B");
+    let c = TargetSelection::from_user("C");
 
     assert_eq!(
         first(builder.cache.all::<compile::Std>()),
@@ -374,7 +374,7 @@ fn test_with_no_doc_stage0() {
     let build = Build::new(config);
     let mut builder = Builder::new(&build);
 
-    let host = INTERNER.intern_str("A");
+    let host = TargetSelection::from_user("A");
 
     builder
         .run_step_descriptions(&[StepDescription::from::<test::Crate>()], &["src/libstd".into()]);
@@ -428,7 +428,7 @@ fn doc_default() {
     let build = Build::new(config);
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
-    let a = INTERNER.intern_str("A");
+    let a = TargetSelection::from_user("A");
 
     // error_index_generator uses stage 1 to share rustdoc artifacts with the
     // rustdoc tool.
@@ -466,7 +466,7 @@ fn test_docs() {
     let build = Build::new(config);
     let mut builder = Builder::new(&build);
     builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
-    let a = INTERNER.intern_str("A");
+    let a = TargetSelection::from_user("A");
 
     // error_index_generator uses stage 1 to share rustdoc artifacts with the
     // rustdoc tool.
index ab16ca3732c1fc93a81d4ed8ac20855052155c5f..7ff00d85dd2f24a0ea0d9bc8552e4d6960aadc11 100644 (file)
 
 use build_helper::output;
 
-use crate::cache::Interned;
-use crate::config::Target;
+use crate::config::{Target, TargetSelection};
 use crate::{Build, GitRepo};
 
 // The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
 // so use some simplified logic here. First we respect the environment variable `AR`, then
 // try to infer the archiver path from the C compiler path.
 // In the future this logic should be replaced by calling into the `cc` crate.
-fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
-    if let Some(ar) = env::var_os(format!("AR_{}", target.replace("-", "_"))) {
+fn cc2ar(cc: &Path, target: TargetSelection) -> Option<PathBuf> {
+    if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace("-", "_"))) {
         Some(PathBuf::from(ar))
     } else if let Some(ar) = env::var_os("AR") {
         Some(PathBuf::from(ar))
@@ -79,8 +78,8 @@ pub fn find(build: &mut Build) {
             .opt_level(2)
             .warnings(false)
             .debug(false)
-            .target(&target)
-            .host(&build.build);
+            .target(&target.triple)
+            .host(&build.build.triple);
         match build.crt_static(target) {
             Some(a) => {
                 cfg.static_crt(a);
@@ -106,10 +105,10 @@ pub fn find(build: &mut Build) {
         let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
             ar
         } else {
-            cc2ar(compiler.path(), &target)
+            cc2ar(compiler.path(), target)
         };
 
-        build.cc.insert(target, compiler);
+        build.cc.insert(target, compiler.clone());
         let cflags = build.cflags(target, GitRepo::Rustc);
 
         // If we use llvm-libunwind, we will need a C++ compiler as well for all targets
@@ -120,8 +119,8 @@ pub fn find(build: &mut Build) {
             .warnings(false)
             .debug(false)
             .cpp(true)
-            .target(&target)
-            .host(&build.build);
+            .target(&target.triple)
+            .host(&build.build.triple);
 
         let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
             cfg.compiler(cxx);
@@ -138,14 +137,14 @@ pub fn find(build: &mut Build) {
             build.cxx.insert(target, compiler);
         }
 
-        build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
-        build.verbose(&format!("CFLAGS_{} = {:?}", &target, cflags));
+        build.verbose(&format!("CC_{} = {:?}", &target.triple, build.cc(target)));
+        build.verbose(&format!("CFLAGS_{} = {:?}", &target.triple, cflags));
         if let Ok(cxx) = build.cxx(target) {
-            build.verbose(&format!("CXX_{} = {:?}", &target, cxx));
-            build.verbose(&format!("CXXFLAGS_{} = {:?}", &target, cflags));
+            build.verbose(&format!("CXX_{} = {:?}", &target.triple, cxx));
+            build.verbose(&format!("CXXFLAGS_{} = {:?}", &target.triple, cflags));
         }
         if let Some(ar) = ar {
-            build.verbose(&format!("AR_{} = {:?}", &target, ar));
+            build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
             build.ar.insert(target, ar);
         }
     }
@@ -154,17 +153,18 @@ pub fn find(build: &mut Build) {
 fn set_compiler(
     cfg: &mut cc::Build,
     compiler: Language,
-    target: Interned<String>,
+    target: TargetSelection,
     config: Option<&Target>,
     build: &Build,
 ) {
-    match &*target {
+    match &*target.triple {
         // When compiling for android we may have the NDK configured in the
         // config.toml in which case we look there. Otherwise the default
         // compiler already takes into account the triple in question.
         t if t.contains("android") => {
             if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
                 let target = target
+                    .triple
                     .replace("armv7neon", "arm")
                     .replace("armv7", "arm")
                     .replace("thumbv7neon", "arm")
index a4115904ac76f16500d5c6fd6eb834a683041ec9..51a9b0e0a52e14a853dd6b6edf32668da86b229b 100644 (file)
@@ -13,7 +13,7 @@
 use crate::Build;
 
 // The version number
-pub const CFG_RELEASE_NUM: &str = "1.46.0";
+pub const CFG_RELEASE_NUM: &str = "1.47.0";
 
 pub struct GitInfo {
     inner: Option<Info>,
index 0d38d2eebe79390fefb2eae22ca674574f0f136f..9f34bb4e6ccd73b159ab78cfd2b7112dae06cf62 100644 (file)
@@ -1,15 +1,15 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
 use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, std_cargo};
+use crate::config::TargetSelection;
 use crate::tool::{prepare_tool_cargo, SourceType};
 use crate::{Compiler, Mode};
 use std::path::PathBuf;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 fn args(kind: Kind) -> Vec<String> {
@@ -71,7 +71,7 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Rustc {
@@ -127,7 +127,7 @@ macro_rules! tool_check_step {
     ($name:ident, $path:expr, $source_type:expr) => {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl Step for $name {
@@ -163,8 +163,8 @@ fn run(self, builder: &Builder<'_>) {
                 println!(
                     "Checking {} artifacts ({} -> {})",
                     stringify!($name).to_lowercase(),
-                    &compiler.host,
-                    target
+                    &compiler.host.triple,
+                    target.triple
                 );
                 run_cargo(
                     builder,
@@ -184,7 +184,7 @@ fn run(self, builder: &Builder<'_>) {
                 fn stamp(
                     builder: &Builder<'_>,
                     compiler: Compiler,
-                    target: Interned<String>,
+                    target: TargetSelection,
                 ) -> PathBuf {
                     builder
                         .cargo_out(compiler, Mode::ToolRustc, target)
@@ -204,12 +204,12 @@ fn stamp(
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
-fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned<String>) -> PathBuf {
+fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
 }
 
 /// Cargo's output path for librustc in a given stage, compiled by a particular
 /// compiler for the specified target.
-fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned<String>) -> PathBuf {
+fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
 }
index b4e58c06fdea902e39a0ad2f5d838632af388be3..f83dfe8e635e3a759b9c3a8e82d6d87e28ab318d 100644 (file)
@@ -23,7 +23,7 @@ pub fn clean(build: &Build, all: bool) {
         rm_rf(&build.out.join("dist"));
 
         for host in &build.hosts {
-            let entries = match build.out.join(host).read_dir() {
+            let entries = match build.out.join(host.triple).read_dir() {
                 Ok(iter) => iter,
                 Err(_) => continue,
             };
index 9b4926f28d4edb320d50b6efc3a1069215113f32..89b070e15e28699e4c9d0e277c66b2c3f35fd255 100644 (file)
@@ -22,6 +22,7 @@
 use crate::builder::Cargo;
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
+use crate::config::TargetSelection;
 use crate::dist;
 use crate::native;
 use crate::tool::SourceType;
@@ -30,7 +31,7 @@
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -129,7 +130,7 @@ fn copy_and_stamp(
 fn copy_third_party_objects(
     builder: &Builder<'_>,
     compiler: &Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Vec<(PathBuf, DependencyType)> {
     let mut target_deps = vec![];
 
@@ -157,15 +158,9 @@ fn copy_third_party_objects(
 fn copy_self_contained_objects(
     builder: &Builder<'_>,
     compiler: &Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Vec<(PathBuf, DependencyType)> {
-    // cfg(bootstrap)
-    // Remove when upgrading bootstrap compiler.
-    let libdir_self_contained = if compiler.stage == 0 {
-        builder.sysroot_libdir(*compiler, target).to_path_buf()
-    } else {
-        builder.sysroot_libdir(*compiler, target).join("self-contained")
-    };
+    let libdir_self_contained = builder.sysroot_libdir(*compiler, target).join("self-contained");
     t!(fs::create_dir_all(&libdir_self_contained));
     let mut target_deps = vec![];
 
@@ -212,7 +207,7 @@ fn copy_self_contained_objects(
 
 /// Configure cargo to compile the standard library, adding appropriate env vars
 /// and such.
-pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, stage: u32, cargo: &mut Cargo) {
+pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) {
     if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
         cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
     }
@@ -307,7 +302,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, stage: u32, ca
 struct StdLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for StdLink {
@@ -343,7 +338,7 @@ fn run(self, builder: &Builder<'_>) {
 fn copy_sanitizers(
     builder: &Builder<'_>,
     compiler: &Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Vec<PathBuf> {
     let runtimes: Vec<native::SanitizerRuntime> = builder.ensure(native::Sanitizers { target });
 
@@ -378,7 +373,7 @@ fn copy_sanitizers(
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct StartupObjects {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for StartupObjects {
@@ -425,7 +420,7 @@ fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
                         .arg("--cfg")
                         .arg("bootstrap")
                         .arg("--target")
-                        .arg(target)
+                        .arg(target.rustc_target_arg())
                         .arg("--emit=obj")
                         .arg("-o")
                         .arg(dst_file)
@@ -444,7 +439,7 @@ fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -524,7 +519,7 @@ fn run(self, builder: &Builder<'_>) {
     }
 }
 
-pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
+pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
     cargo
         .arg("--features")
         .arg(builder.rustc_features())
@@ -533,7 +528,7 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<St
     rustc_cargo_env(builder, cargo, target);
 }
 
-pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
+pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
     // Set some configuration variables picked up by build scripts and
     // the compiler alike
     cargo
@@ -614,7 +609,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interne
 struct RustcLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustcLink {
@@ -644,11 +639,7 @@ fn run(self, builder: &Builder<'_>) {
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
-pub fn libstd_stamp(
-    builder: &Builder<'_>,
-    compiler: Compiler,
-    target: Interned<String>,
-) -> PathBuf {
+pub fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
     builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp")
 }
 
@@ -657,7 +648,7 @@ pub fn libstd_stamp(
 pub fn librustc_stamp(
     builder: &Builder<'_>,
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> PathBuf {
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp")
 }
@@ -665,7 +656,7 @@ pub fn librustc_stamp(
 pub fn compiler_file(
     builder: &Builder<'_>,
     compiler: &Path,
-    target: Interned<String>,
+    target: TargetSelection,
     file: &str,
 ) -> PathBuf {
     let mut cmd = Command::new(compiler);
@@ -696,9 +687,9 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
     fn run(self, builder: &Builder<'_>) -> Interned<PathBuf> {
         let compiler = self.compiler;
         let sysroot = if compiler.stage == 0 {
-            builder.out.join(&compiler.host).join("stage0-sysroot")
+            builder.out.join(&compiler.host.triple).join("stage0-sysroot")
         } else {
-            builder.out.join(&compiler.host).join(format!("stage{}", compiler.stage))
+            builder.out.join(&compiler.host.triple).join(format!("stage{}", compiler.stage))
         };
         let _ = fs::remove_dir_all(&sysroot);
         t!(fs::create_dir_all(&sysroot));
@@ -812,8 +803,8 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
 
         let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
         if let Some(lld_install) = lld_install {
-            let src_exe = exe("lld", &target_compiler.host);
-            let dst_exe = exe("rust-lld", &target_compiler.host);
+            let src_exe = exe("lld", target_compiler.host);
+            let dst_exe = exe("rust-lld", target_compiler.host);
             // we prepend this bin directory to the user PATH when linking Rust binaries. To
             // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
             let dst = libdir.parent().unwrap().join("bin");
@@ -828,7 +819,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
 
         // Link the compiler binary itself into place
         let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host);
-        let rustc = out_dir.join(exe("rustc_binary", &*host));
+        let rustc = out_dir.join(exe("rustc_binary", host));
         let bindir = sysroot.join("bin");
         t!(fs::create_dir_all(&bindir));
         let compiler = builder.rustc(target_compiler);
index ff545a6ddcf47902ef580d2622107eceba396f3b..d71f31704209eb1b895956fe5acd46f37589509f 100644 (file)
@@ -7,6 +7,7 @@
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::ffi::OsString;
+use std::fmt;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process;
@@ -39,7 +40,7 @@ pub struct Config {
     pub docs: bool,
     pub locked_deps: bool,
     pub vendor: bool,
-    pub target_config: HashMap<Interned<String>, Target>,
+    pub target_config: HashMap<TargetSelection, Target>,
     pub full_bootstrap: bool,
     pub extended: bool,
     pub tools: Option<HashSet<String>>,
@@ -112,9 +113,9 @@ pub struct Config {
     pub rust_thin_lto_import_instr_limit: Option<u32>,
     pub rust_remap_debuginfo: bool,
 
-    pub build: Interned<String>,
-    pub hosts: Vec<Interned<String>>,
-    pub targets: Vec<Interned<String>>,
+    pub build: TargetSelection,
+    pub hosts: Vec<TargetSelection>,
+    pub targets: Vec<TargetSelection>,
     pub local_rebuild: bool,
     pub jemalloc: bool,
     pub control_flow_guard: bool,
@@ -158,6 +159,67 @@ pub struct Config {
     pub out: PathBuf,
 }
 
+#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct TargetSelection {
+    pub triple: Interned<String>,
+    file: Option<Interned<String>>,
+}
+
+impl TargetSelection {
+    pub fn from_user(selection: &str) -> Self {
+        let path = Path::new(selection);
+
+        let (triple, file) = if path.exists() {
+            let triple = path
+                .file_stem()
+                .expect("Target specification file has no file stem")
+                .to_str()
+                .expect("Target specification file stem is not UTF-8");
+
+            (triple, Some(selection))
+        } else {
+            (selection, None)
+        };
+
+        let triple = INTERNER.intern_str(triple);
+        let file = file.map(|f| INTERNER.intern_str(f));
+
+        Self { triple, file }
+    }
+
+    pub fn rustc_target_arg(&self) -> &str {
+        self.file.as_ref().unwrap_or(&self.triple)
+    }
+
+    pub fn contains(&self, needle: &str) -> bool {
+        self.triple.contains(needle)
+    }
+
+    pub fn starts_with(&self, needle: &str) -> bool {
+        self.triple.starts_with(needle)
+    }
+
+    pub fn ends_with(&self, needle: &str) -> bool {
+        self.triple.ends_with(needle)
+    }
+}
+
+impl fmt::Display for TargetSelection {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.triple)?;
+        if let Some(file) = self.file {
+            write!(f, "({})", file)?;
+        }
+        Ok(())
+    }
+}
+
+impl PartialEq<&str> for TargetSelection {
+    fn eq(&self, other: &&str) -> bool {
+        self.triple == *other
+    }
+}
+
 /// Per-target configuration stored in the global configuration structure.
 #[derive(Default)]
 pub struct Target {
@@ -403,7 +465,7 @@ pub fn default_opts() -> Config {
         config.missing_tools = false;
 
         // set by bootstrap.py
-        config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set"));
+        config.build = TargetSelection::from_user(&env::var("BUILD").expect("'BUILD' to be set"));
         config.src = Config::path_from_python("SRC");
         config.out = Config::path_from_python("BUILD_DIR");
 
@@ -464,14 +526,16 @@ pub fn parse(args: &[String]) -> Config {
         let build = toml.build.clone().unwrap_or_default();
         // set by bootstrap.py
         config.hosts.push(config.build.clone());
-        for host in build.host.iter() {
-            let host = INTERNER.intern_str(host);
+        for host in build.host.iter().map(|h| TargetSelection::from_user(h)) {
             if !config.hosts.contains(&host) {
                 config.hosts.push(host);
             }
         }
-        for target in
-            config.hosts.iter().cloned().chain(build.target.iter().map(|s| INTERNER.intern_str(s)))
+        for target in config
+            .hosts
+            .iter()
+            .copied()
+            .chain(build.target.iter().map(|h| TargetSelection::from_user(h)))
         {
             if !config.targets.contains(&target) {
                 config.targets.push(target);
@@ -637,7 +701,7 @@ pub fn parse(args: &[String]) -> Config {
                 target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from);
                 target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from);
 
-                config.target_config.insert(INTERNER.intern_string(triple.clone()), target);
+                config.target_config.insert(TargetSelection::from_user(triple), target);
             }
         }
 
index 5d2fcba7feabaaf16662bf7154ffcb13907bf2b5..af30747a9592e6dcaf4eccaa226ba34f0c1d06cb 100644 (file)
@@ -20,6 +20,7 @@
 use crate::cache::{Interned, INTERNER};
 use crate::channel;
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::tool::{self, Tool};
 use crate::util::{exe, is_dylib, timeit};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
@@ -68,7 +69,7 @@ fn missing_tool(tool_name: &str, skip: bool) {
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Docs {
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for Docs {
@@ -131,7 +132,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustcDocs {
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for RustcDocs {
@@ -210,11 +211,11 @@ fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
 fn make_win_dist(
     rust_root: &Path,
     plat_root: &Path,
-    target_triple: Interned<String>,
+    target: TargetSelection,
     builder: &Builder<'_>,
 ) {
     //Ask gcc where it keeps its stuff
-    let mut cmd = Command::new(builder.cc(target_triple));
+    let mut cmd = Command::new(builder.cc(target));
     cmd.arg("-print-search-dirs");
     let gcc_out = output(&mut cmd);
 
@@ -234,16 +235,16 @@ fn make_win_dist(
         }
     }
 
-    let compiler = if target_triple == "i686-pc-windows-gnu" {
+    let compiler = if target == "i686-pc-windows-gnu" {
         "i686-w64-mingw32-gcc.exe"
-    } else if target_triple == "x86_64-pc-windows-gnu" {
+    } else if target == "x86_64-pc-windows-gnu" {
         "x86_64-w64-mingw32-gcc.exe"
     } else {
         "gcc.exe"
     };
     let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
     let mut rustc_dlls = vec!["libwinpthread-1.dll"];
-    if target_triple.starts_with("i686-") {
+    if target.starts_with("i686-") {
         rustc_dlls.push("libgcc_s_dw2-1.dll");
     } else {
         rustc_dlls.push("libgcc_s_seh-1.dll");
@@ -311,7 +312,7 @@ fn make_win_dist(
     let target_bin_dir = plat_root
         .join("lib")
         .join("rustlib")
-        .join(target_triple)
+        .join(target.triple)
         .join("bin")
         .join("self-contained");
     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
@@ -331,7 +332,7 @@ fn make_win_dist(
     let target_lib_dir = plat_root
         .join("lib")
         .join("rustlib")
-        .join(target_triple)
+        .join(target.triple)
         .join("lib")
         .join("self-contained");
     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
@@ -342,7 +343,7 @@ fn make_win_dist(
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Mingw {
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for Mingw {
@@ -530,11 +531,11 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
 
             // Copy over lld if it's there
             if builder.config.lld_enabled {
-                let exe = exe("rust-lld", &compiler.host);
+                let exe = exe("rust-lld", compiler.host);
                 let src =
                     builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin").join(&exe);
                 // for the rationale about this rename check `compile::copy_lld_to_sysroot`
-                let dst = image.join("lib/rustlib").join(&*host).join("bin").join(&exe);
+                let dst = image.join("lib/rustlib").join(&*host.triple).join("bin").join(&exe);
                 t!(fs::create_dir_all(&dst.parent().unwrap()));
                 builder.copy(&src, &dst);
             }
@@ -592,7 +593,7 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct DebuggerScripts {
     pub sysroot: Interned<PathBuf>,
-    pub host: Interned<String>,
+    pub host: TargetSelection,
 }
 
 impl Step for DebuggerScripts {
@@ -662,8 +663,8 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
 }
 
 /// 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");
+fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) {
+    let dst = image.join("lib/rustlib").join(target.triple).join("lib");
     let self_contained_dst = dst.join("self-contained");
     t!(fs::create_dir_all(&dst));
     t!(fs::create_dir_all(&self_contained_dst));
@@ -679,7 +680,7 @@ fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &P
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Std {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Std {
@@ -718,7 +719,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         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);
+        copy_target_libs(builder, target, &image, &stamp);
 
         let mut cmd = rust_installer(builder);
         cmd.arg("generate")
@@ -747,7 +748,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustcDev {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustcDev {
@@ -787,7 +788,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         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);
+        copy_target_libs(builder, target, &image, &stamp);
 
         let mut cmd = rust_installer(builder);
         cmd.arg("generate")
@@ -818,7 +819,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Analysis {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Analysis {
@@ -861,12 +862,12 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         let src = builder
             .stage_out(compiler, Mode::Std)
-            .join(target)
+            .join(target.triple)
             .join(builder.cargo_dir())
             .join("deps");
 
         let image_src = src.join("save-analysis");
-        let dst = image.join("lib/rustlib").join(target).join("analysis");
+        let dst = image.join("lib/rustlib").join(target.triple).join("analysis");
         t!(fs::create_dir_all(&dst));
         builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
         builder.cp_r(&image_src, &dst);
@@ -1163,7 +1164,7 @@ fn change_drive(s: &str) -> Option<String> {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Cargo {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Cargo {
@@ -1255,7 +1256,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rls {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Rls {
@@ -1345,7 +1346,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustAnalyzer {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustAnalyzer {
@@ -1432,7 +1433,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Clippy {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Clippy {
@@ -1523,7 +1524,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Miri {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Miri {
@@ -1620,7 +1621,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rustfmt {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Rustfmt {
@@ -1714,8 +1715,8 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Extended {
     stage: u32,
-    host: Interned<String>,
-    target: Interned<String>,
+    host: TargetSelection,
+    target: TargetSelection,
 }
 
 impl Step for Extended {
@@ -2255,7 +2256,7 @@ fn filter(contents: &str, marker: &str) -> String {
     }
 }
 
-fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned<String>) {
+fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
     let mut parts = channel::CFG_RELEASE_NUM.split('.');
     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
         .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
@@ -2266,7 +2267,7 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned<String>) {
         .env("CFG_VER_BUILD", "0") // just needed to build
         .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
         .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
-        .env("CFG_BUILD", target)
+        .env("CFG_BUILD", target.triple)
         .env("CFG_CHANNEL", &builder.config.channel);
 
     if target.contains("windows-gnu") {
@@ -2348,7 +2349,7 @@ fn run(self, builder: &Builder<'_>) {
 ///
 /// Note: This function does not yet support Windows, but we also don't support
 ///       linking LLVM tools dynamically on Windows yet.
-fn maybe_install_llvm(builder: &Builder<'_>, target: Interned<String>, dst_libdir: &Path) {
+fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) {
     let src_libdir = builder.llvm_out(target).join("lib");
 
     if target.contains("apple-darwin") {
@@ -2373,13 +2374,13 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: Interned<String>, dst_libdi
 }
 
 /// Maybe add libLLVM.so to the target lib-dir for linking.
-pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
-    let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
+pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
+    let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib");
     maybe_install_llvm(builder, target, &dst_libdir);
 }
 
 /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
-pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
+pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
     let dst_libdir =
         sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
     maybe_install_llvm(builder, target, &dst_libdir);
@@ -2387,7 +2388,7 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned<String
 
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
 pub struct LlvmTools {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for LlvmTools {
@@ -2425,10 +2426,10 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
 
         // Prepare the image directory
         let src_bindir = builder.llvm_out(target).join("bin");
-        let dst_bindir = image.join("lib/rustlib").join(&*target).join("bin");
+        let dst_bindir = image.join("lib/rustlib").join(&*target.triple).join("bin");
         t!(fs::create_dir_all(&dst_bindir));
         for tool in LLVM_TOOLS {
-            let exe = src_bindir.join(exe(tool, &target));
+            let exe = src_bindir.join(exe(tool, target));
             builder.install(&exe, &dst_bindir, 0o755);
         }
 
index 582bc9da0e804d4838da8b343b9f21de04957f9a..b051390fc2671f73b7fe1f134717b5e8a4bc4dec 100644 (file)
@@ -18,7 +18,7 @@
 use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 use crate::tool::{self, prepare_tool_cargo, SourceType, Tool};
 use crate::util::symlink_dir;
 
@@ -27,7 +27,7 @@ macro_rules! book {
         $(
             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
-            target: Interned<String>,
+            target: TargetSelection,
         }
 
         impl Step for $name {
@@ -101,7 +101,7 @@ fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBook {
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for UnstableBook {
@@ -129,7 +129,7 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 struct RustbookSrc {
-    target: Interned<String>,
+    target: TargetSelection,
     name: Interned<String>,
     src: Interned<PathBuf>,
 }
@@ -169,7 +169,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct TheBook {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for TheBook {
@@ -241,7 +241,7 @@ fn run(self, builder: &Builder<'_>) {
 fn invoke_rustdoc(
     builder: &Builder<'_>,
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     markdown: &str,
 ) {
     let out = builder.doc_out(target);
@@ -277,7 +277,7 @@ fn invoke_rustdoc(
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Standalone {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for Standalone {
@@ -386,7 +386,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Std {
     pub stage: u32,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Std {
@@ -415,23 +415,8 @@ fn run(self, builder: &Builder<'_>) {
         let compiler = builder.compiler(stage, builder.config.build);
 
         builder.ensure(compile::Std { compiler, target });
-        let out_dir = builder.stage_out(compiler, Mode::Std).join(target).join("doc");
+        let out_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join("doc");
 
-        // Here what we're doing is creating a *symlink* (directory junction on
-        // Windows) to the final output location. This is not done as an
-        // optimization but rather for correctness. We've got three trees of
-        // documentation, one for std, one for test, and one for rustc. It's then
-        // our job to merge them all together.
-        //
-        // Unfortunately rustbuild doesn't know nearly as well how to merge doc
-        // trees as rustdoc does itself, so instead of actually having three
-        // separate trees we just have rustdoc output to the same location across
-        // all of them.
-        //
-        // This way rustdoc generates output directly into the output, and rustdoc
-        // will also directly handle merging.
-        let my_out = builder.crate_doc_out(target);
-        t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
         t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
 
         let run_cargo_rustdoc_for = |package: &str| {
@@ -439,12 +424,9 @@ fn run(self, builder: &Builder<'_>) {
                 builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc");
             compile::std_cargo(builder, target, compiler.stage, &mut cargo);
 
-            cargo.arg("-p").arg(package);
-            // Create all crate output directories first to make sure rustdoc uses
-            // relative links.
-            // FIXME: Cargo should probably do this itself.
-            t!(fs::create_dir_all(out_dir.join(package)));
             cargo
+                .arg("-p")
+                .arg(package)
                 .arg("--")
                 .arg("--markdown-css")
                 .arg("rust.css")
@@ -462,11 +444,17 @@ fn run(self, builder: &Builder<'_>) {
         // folder structure, that would also build internal crates that we do
         // not want to show in documentation. These crates will later be visited
         // by the rustc step, so internal documentation will show them.
-        let krates = ["alloc", "core", "std", "proc_macro", "test"];
+        //
+        // Note that the order here is important! The crates need to be
+        // processed starting from the leaves, otherwise rustdoc will not
+        // create correct links between crates because rustdoc depends on the
+        // existence of the output directories to know if it should be a local
+        // or remote link.
+        let krates = ["core", "alloc", "std", "proc_macro", "test"];
         for krate in &krates {
             run_cargo_rustdoc_for(krate);
         }
-        builder.cp_r(&my_out, &out);
+        builder.cp_r(&out_dir, &out);
 
         // Look for src/libstd, src/libcore etc in the `x.py doc` arguments and
         // open the corresponding rendered docs.
@@ -487,7 +475,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rustc {
     stage: u32,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for Rustc {
@@ -529,9 +517,12 @@ fn run(self, builder: &Builder<'_>) {
         // Build rustc.
         builder.ensure(compile::Rustc { compiler, target });
 
-        // We do not symlink to the same shared folder that already contains std library
-        // documentation from previous steps as we do not want to include that.
-        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc");
+        // This uses a shared directory so that librustdoc documentation gets
+        // correctly built and merged with the rustc documentation. This is
+        // needed because rustdoc is built in a different directory from
+        // rustc. rustdoc needs to be able to see everything, for example when
+        // merging the search index, or generating local (relative) links.
+        let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
         t!(symlink_dir_force(&builder.config, &out, &out_dir));
 
         // Build cargo command.
@@ -568,7 +559,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rustdoc {
     stage: u32,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for Rustdoc {
@@ -613,7 +604,7 @@ fn run(self, builder: &Builder<'_>) {
         builder.ensure(tool::Rustdoc { compiler });
 
         // Symlink compiler docs to the output directory of rustdoc documentation.
-        let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc");
+        let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc");
         t!(fs::create_dir_all(&out_dir));
         t!(symlink_dir_force(&builder.config, &out, &out_dir));
 
@@ -641,7 +632,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ErrorIndex {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for ErrorIndex {
@@ -681,7 +672,7 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBookGen {
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for UnstableBookGen {
index f477c752933856e0ffd07747f963dcf20fff026c..1055689c81e6a7680d5f4fd1e25c6175e9025ac4 100644 (file)
@@ -10,8 +10,7 @@
 use getopts::Options;
 
 use crate::builder::Builder;
-use crate::cache::{Interned, INTERNER};
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 use crate::{Build, DocTests};
 
 /// Deserialized version of all flags for this compile.
@@ -21,8 +20,8 @@ pub struct Flags {
     pub stage: Option<u32>,
     pub keep_stage: Vec<u32>,
 
-    pub host: Vec<Interned<String>>,
-    pub target: Vec<Interned<String>>,
+    pub host: Vec<TargetSelection>,
+    pub target: Vec<TargetSelection>,
     pub config: Option<PathBuf>,
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
@@ -532,11 +531,11 @@ pub fn parse(args: &[String]) -> Flags {
                 .collect(),
             host: split(&matches.opt_strs("host"))
                 .into_iter()
-                .map(|x| INTERNER.intern_string(x))
+                .map(|x| TargetSelection::from_user(&x))
                 .collect::<Vec<_>>(),
             target: split(&matches.opt_strs("target"))
                 .into_iter()
-                .map(|x| INTERNER.intern_string(x))
+                .map(|x| TargetSelection::from_user(&x))
                 .collect::<Vec<_>>(),
             config: cfg_file,
             jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
index 7026b25d1b98467d821f5fd2981c263bcddb8de3..dcdc681e87dbb010e75ee5c34eee6951bd990da1 100644 (file)
 use crate::Compiler;
 
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 
-pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_docs(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "docs", "rust-docs", stage, Some(host));
 }
 
-pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned<String>) {
+pub fn install_std(builder: &Builder<'_>, stage: u32, target: TargetSelection) {
     install_sh(builder, "std", "rust-std", stage, Some(target));
 }
 
-pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "cargo", "cargo", stage, Some(host));
 }
 
-pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_rls(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rls", "rls", stage, Some(host));
 }
-pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+
+pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host));
 }
-pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+
+pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "clippy", "clippy", stage, Some(host));
 }
-pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_miri(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "miri", "miri", stage, Some(host));
 }
 
-pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rustfmt", "rustfmt", stage, Some(host));
 }
 
-pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
 }
 
 pub fn install_src(builder: &Builder<'_>, stage: u32) {
     install_sh(builder, "src", "rust-src", stage, None);
 }
-pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned<String>) {
+pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: TargetSelection) {
     install_sh(builder, "rustc", "rustc", stage, Some(host));
 }
 
@@ -62,7 +63,7 @@ fn install_sh(
     package: &str,
     name: &str,
     stage: u32,
-    host: Option<Interned<String>>,
+    host: Option<TargetSelection>,
 ) {
     builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));
 
@@ -150,7 +151,7 @@ macro_rules! install {
             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl $name {
@@ -159,11 +160,6 @@ fn should_build(config: &Config) -> bool {
                 config.extended && config.tools.as_ref()
                     .map_or(true, |t| t.contains($path))
             }
-
-            #[allow(dead_code)]
-            fn should_install(builder: &Builder<'_>) -> bool {
-                builder.config.tools.as_ref().map_or(false, |t| t.contains($path))
-            }
         }
 
         impl Step for $name {
@@ -210,8 +206,7 @@ fn run($sel, $builder: &Builder<'_>) {
         install_cargo(builder, self.compiler.stage, self.target);
     };
     Rls, "rls", Self::should_build(_config), only_hosts: true, {
-        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() ||
-            Self::should_install(builder) {
+        if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() {
             install_rls(builder, self.compiler.stage, self.target);
         } else {
             builder.info(
@@ -221,27 +216,14 @@ fn run($sel, $builder: &Builder<'_>) {
     };
     RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
         builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target });
-        if Self::should_install(builder) {
-            install_rust_analyzer(builder, self.compiler.stage, self.target);
-        } else {
-            builder.info(
-                &format!("skipping Install rust-analyzer stage{} ({})", self.compiler.stage, self.target),
-            );
-        }
+        install_rust_analyzer(builder, self.compiler.stage, self.target);
     };
     Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
         builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target });
-        if Self::should_install(builder) {
-            install_clippy(builder, self.compiler.stage, self.target);
-        } else {
-            builder.info(
-                &format!("skipping Install clippy stage{} ({})", self.compiler.stage, self.target),
-            );
-        }
+        install_clippy(builder, self.compiler.stage, self.target);
     };
     Miri, "miri", Self::should_build(_config), only_hosts: true, {
-        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() ||
-            Self::should_install(builder) {
+        if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() {
             install_miri(builder, self.compiler.stage, self.target);
         } else {
             builder.info(
@@ -253,7 +235,7 @@ fn run($sel, $builder: &Builder<'_>) {
         if builder.ensure(dist::Rustfmt {
             compiler: self.compiler,
             target: self.target
-        }).is_some() || Self::should_install(builder) {
+        }).is_some() {
             install_rustfmt(builder, self.compiler.stage, self.target);
         } else {
             builder.info(
index 783a64c3581f96a43b6b106bcebff0bdce9ec3ec..77820ef87e3b470399217ffcbcb9c33128bcfe76 100644 (file)
 use build_helper::{mtime, output, run, run_suppressed, t, try_run, try_run_suppressed};
 use filetime::FileTime;
 
+use crate::config::TargetSelection;
 use crate::util::{exe, libdir, CiEnv};
 
 mod builder;
@@ -187,7 +188,7 @@ pub unsafe fn setup(_build: &mut crate::Build) {}
 #[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)]
 pub struct Compiler {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
@@ -236,9 +237,9 @@ pub struct Build {
     verbosity: usize,
 
     // Targets for which to build
-    build: Interned<String>,
-    hosts: Vec<Interned<String>>,
-    targets: Vec<Interned<String>>,
+    build: TargetSelection,
+    hosts: Vec<TargetSelection>,
+    targets: Vec<TargetSelection>,
 
     // Stage 0 (downloaded) compiler, lld and cargo or their local rust equivalents
     initial_rustc: PathBuf,
@@ -248,10 +249,10 @@ pub struct Build {
 
     // Runtime state filled in later on
     // C/C++ compilers and archiver for all targets
-    cc: HashMap<Interned<String>, cc::Tool>,
-    cxx: HashMap<Interned<String>, cc::Tool>,
-    ar: HashMap<Interned<String>, PathBuf>,
-    ranlib: HashMap<Interned<String>, PathBuf>,
+    cc: HashMap<TargetSelection, cc::Tool>,
+    cxx: HashMap<TargetSelection, cc::Tool>,
+    ar: HashMap<TargetSelection, PathBuf>,
+    ranlib: HashMap<TargetSelection, PathBuf>,
     // Miscellaneous
     crates: HashMap<Interned<String>, Crate>,
     is_sudo: bool,
@@ -259,7 +260,7 @@ pub struct Build {
     delayed_failures: RefCell<Vec<String>>,
     prerelease_version: Cell<Option<u32>>,
     tool_artifacts:
-        RefCell<HashMap<Interned<String>, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
+        RefCell<HashMap<TargetSelection, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
 }
 
 #[derive(Debug)]
@@ -365,7 +366,7 @@ pub fn new(config: Config) -> Build {
             output(
                 Command::new(&config.initial_rustc)
                     .arg("--target")
-                    .arg(config.build)
+                    .arg(config.build.rustc_target_arg())
                     .arg("--print")
                     .arg("target-libdir"),
             )
@@ -453,7 +454,7 @@ pub fn new(config: Config) -> Build {
     }
 
     pub fn build_triple(&self) -> &[Interned<String>] {
-        unsafe { slice::from_raw_parts(&self.build, 1) }
+        slice::from_ref(&self.build.triple)
     }
 
     /// Executes the entire build, as configured by the flags and configuration.
@@ -558,7 +559,10 @@ fn cargo_dir(&self) -> &'static str {
     }
 
     fn tools_dir(&self, compiler: Compiler) -> PathBuf {
-        let out = self.out.join(&*compiler.host).join(format!("stage{}-tools-bin", compiler.stage));
+        let out = self
+            .out
+            .join(&*compiler.host.triple)
+            .join(format!("stage{}-tools-bin", compiler.stage));
         t!(fs::create_dir_all(&out));
         out
     }
@@ -575,54 +579,47 @@ fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf {
             Mode::ToolBootstrap => "-bootstrap-tools",
             Mode::ToolStd | Mode::ToolRustc => "-tools",
         };
-        self.out.join(&*compiler.host).join(format!("stage{}{}", compiler.stage, suffix))
+        self.out.join(&*compiler.host.triple).join(format!("stage{}{}", compiler.stage, suffix))
     }
 
     /// Returns the root output directory for all Cargo output in a given stage,
     /// running a particular compiler, whether or not we're building the
     /// standard library, and targeting the specified architecture.
-    fn cargo_out(&self, compiler: Compiler, mode: Mode, target: Interned<String>) -> PathBuf {
-        self.stage_out(compiler, mode).join(&*target).join(self.cargo_dir())
+    fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf {
+        self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir())
     }
 
     /// Root output directory for LLVM compiled for `target`
     ///
     /// Note that if LLVM is configured externally then the directory returned
     /// will likely be empty.
-    fn llvm_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("llvm")
+    fn llvm_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("llvm")
     }
 
-    fn lld_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("lld")
+    fn lld_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("lld")
     }
 
     /// Output directory for all documentation for a target
-    fn doc_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("doc")
+    fn doc_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("doc")
     }
 
     /// Output directory for all documentation for a target
-    fn compiler_doc_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("compiler-doc")
+    fn compiler_doc_out(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("compiler-doc")
     }
 
     /// Output directory for some generated md crate documentation for a target (temporary)
-    fn md_doc_out(&self, target: Interned<String>) -> Interned<PathBuf> {
-        INTERNER.intern_path(self.out.join(&*target).join("md-doc"))
-    }
-
-    /// Output directory for all crate documentation for a target (temporary)
-    ///
-    /// The artifacts here are then copied into `doc_out` above.
-    fn crate_doc_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("crate-docs")
+    fn md_doc_out(&self, target: TargetSelection) -> Interned<PathBuf> {
+        INTERNER.intern_path(self.out.join(&*target.triple).join("md-doc"))
     }
 
     /// Returns `true` if no custom `llvm-config` is set for the specified target.
     ///
     /// If no custom `llvm-config` was specified then Rust's llvm will be used.
-    fn is_rust_llvm(&self, target: Interned<String>) -> bool {
+    fn is_rust_llvm(&self, target: TargetSelection) -> bool {
         match self.config.target_config.get(&target) {
             Some(ref c) => c.llvm_config.is_none(),
             None => true,
@@ -630,13 +627,13 @@ fn is_rust_llvm(&self, target: Interned<String>) -> bool {
     }
 
     /// Returns the path to `FileCheck` binary for the specified target
-    fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
+    fn llvm_filecheck(&self, target: TargetSelection) -> PathBuf {
         let target_config = self.config.target_config.get(&target);
         if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) {
             s.to_path_buf()
         } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
             let llvm_bindir = output(Command::new(s).arg("--bindir"));
-            let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target));
+            let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target));
             if filecheck.exists() {
                 filecheck
             } else {
@@ -644,7 +641,7 @@ fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
                 // llvm subdirectory of the libdir.
                 let llvm_libdir = output(Command::new(s).arg("--libdir"));
                 let lib_filecheck =
-                    Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", &*target));
+                    Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target));
                 if lib_filecheck.exists() {
                     lib_filecheck
                 } else {
@@ -669,18 +666,18 @@ fn llvm_filecheck(&self, target: Interned<String>) -> PathBuf {
             } else {
                 base
             };
-            base.join("bin").join(exe("FileCheck", &*target))
+            base.join("bin").join(exe("FileCheck", target))
         }
     }
 
     /// Directory for libraries built from C/C++ code and shared between stages.
-    fn native_dir(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("native")
+    fn native_dir(&self, target: TargetSelection) -> PathBuf {
+        self.out.join(&*target.triple).join("native")
     }
 
     /// Root output directory for rust_test_helpers library compiled for
     /// `target`
-    fn test_helpers_out(&self, target: Interned<String>) -> PathBuf {
+    fn test_helpers_out(&self, target: TargetSelection) -> PathBuf {
         self.native_dir(target).join("rust-test-helpers")
     }
 
@@ -693,7 +690,7 @@ fn add_rust_test_threads(&self, cmd: &mut Command) {
 
     /// Returns the libdir of the snapshot compiler.
     fn rustc_snapshot_libdir(&self) -> PathBuf {
-        self.rustc_snapshot_sysroot().join(libdir(&self.config.build))
+        self.rustc_snapshot_sysroot().join(libdir(self.config.build))
     }
 
     /// Returns the sysroot of the snapshot compiler.
@@ -791,13 +788,13 @@ fn debuginfo_map_to(&self, which: GitRepo) -> Option<String> {
     }
 
     /// Returns the path to the C compiler for the target specified.
-    fn cc(&self, target: Interned<String>) -> &Path {
+    fn cc(&self, target: TargetSelection) -> &Path {
         self.cc[&target].path()
     }
 
     /// Returns a list of flags to pass to the C compiler for the target
     /// specified.
-    fn cflags(&self, target: Interned<String>, which: GitRepo) -> Vec<String> {
+    fn cflags(&self, target: TargetSelection, which: GitRepo) -> Vec<String> {
         // Filter out -O and /O (the optimization flags) that we picked up from
         // cc-rs because the build scripts will determine that for themselves.
         let mut base = self.cc[&target]
@@ -818,7 +815,7 @@ fn cflags(&self, target: Interned<String>, which: GitRepo) -> Vec<String> {
         // Work around an apparently bad MinGW / GCC optimization,
         // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html
         // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936
-        if &*target == "i686-pc-windows-gnu" {
+        if &*target.triple == "i686-pc-windows-gnu" {
             base.push("-fno-omit-frame-pointer".into());
         }
 
@@ -836,17 +833,17 @@ fn cflags(&self, target: Interned<String>, which: GitRepo) -> Vec<String> {
     }
 
     /// Returns the path to the `ar` archive utility for the target specified.
-    fn ar(&self, target: Interned<String>) -> Option<&Path> {
+    fn ar(&self, target: TargetSelection) -> Option<&Path> {
         self.ar.get(&target).map(|p| &**p)
     }
 
     /// Returns the path to the `ranlib` utility for the target specified.
-    fn ranlib(&self, target: Interned<String>) -> Option<&Path> {
+    fn ranlib(&self, target: TargetSelection) -> Option<&Path> {
         self.ranlib.get(&target).map(|p| &**p)
     }
 
     /// Returns the path to the C++ compiler for the target specified.
-    fn cxx(&self, target: Interned<String>) -> Result<&Path, String> {
+    fn cxx(&self, target: TargetSelection) -> Result<&Path, String> {
         match self.cxx.get(&target) {
             Some(p) => Ok(p.path()),
             None => {
@@ -856,12 +853,12 @@ fn cxx(&self, target: Interned<String>) -> Result<&Path, String> {
     }
 
     /// Returns the path to the linker for the given target if it needs to be overridden.
-    fn linker(&self, target: Interned<String>, can_use_lld: bool) -> Option<&Path> {
+    fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> {
         if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref())
         {
             Some(linker)
         } else if target != self.config.build
-            && util::use_host_linker(&target)
+            && util::use_host_linker(target)
             && !target.contains("msvc")
         {
             Some(self.cc(target))
@@ -873,7 +870,7 @@ fn linker(&self, target: Interned<String>, can_use_lld: bool) -> Option<&Path> {
     }
 
     /// Returns if this target should statically link the C runtime, if specified
-    fn crt_static(&self, target: Interned<String>) -> Option<bool> {
+    fn crt_static(&self, target: TargetSelection) -> Option<bool> {
         if target.contains("pc-windows-msvc") {
             Some(true)
         } else {
@@ -882,7 +879,7 @@ fn crt_static(&self, target: Interned<String>) -> Option<bool> {
     }
 
     /// Returns the "musl root" for this `target`, if defined
-    fn musl_root(&self, target: Interned<String>) -> Option<&Path> {
+    fn musl_root(&self, target: TargetSelection) -> Option<&Path> {
         self.config
             .target_config
             .get(&target)
@@ -892,7 +889,7 @@ fn musl_root(&self, target: Interned<String>) -> Option<&Path> {
     }
 
     /// Returns the "musl libdir" for this `target`.
-    fn musl_libdir(&self, target: Interned<String>) -> Option<PathBuf> {
+    fn musl_libdir(&self, target: TargetSelection) -> Option<PathBuf> {
         let t = self.config.target_config.get(&target)?;
         if let libdir @ Some(_) = &t.musl_libdir {
             return libdir.clone();
@@ -901,18 +898,18 @@ fn musl_libdir(&self, target: Interned<String>) -> Option<PathBuf> {
     }
 
     /// Returns the sysroot for the wasi target, if defined
-    fn wasi_root(&self, target: Interned<String>) -> Option<&Path> {
+    fn wasi_root(&self, target: TargetSelection) -> Option<&Path> {
         self.config.target_config.get(&target).and_then(|t| t.wasi_root.as_ref()).map(|p| &**p)
     }
 
     /// Returns `true` if this is a no-std `target`, if defined
-    fn no_std(&self, target: Interned<String>) -> Option<bool> {
+    fn no_std(&self, target: TargetSelection) -> Option<bool> {
         self.config.target_config.get(&target).map(|t| t.no_std)
     }
 
     /// Returns `true` if the target will be tested using the `remote-test-client`
     /// and `remote-test-server` binaries.
-    fn remote_tested(&self, target: Interned<String>) -> bool {
+    fn remote_tested(&self, target: TargetSelection) -> bool {
         self.qemu_rootfs(target).is_some()
             || target.contains("android")
             || env::var_os("TEST_DEVICE_ADDR").is_some()
@@ -923,7 +920,7 @@ fn remote_tested(&self, target: Interned<String>) -> bool {
     ///
     /// If `Some` is returned then that means that tests for this target are
     /// emulated with QEMU and binaries will need to be shipped to the emulator.
-    fn qemu_rootfs(&self, target: Interned<String>) -> Option<&Path> {
+    fn qemu_rootfs(&self, target: TargetSelection) -> Option<&Path> {
         self.config.target_config.get(&target).and_then(|t| t.qemu_rootfs.as_ref()).map(|p| &**p)
     }
 
@@ -955,7 +952,7 @@ fn extended_error_dir(&self) -> PathBuf {
     ///
     /// When all of these conditions are met the build will lift artifacts from
     /// the previous stage forward.
-    fn force_use_stage1(&self, compiler: Compiler, target: Interned<String>) -> bool {
+    fn force_use_stage1(&self, compiler: Compiler, target: TargetSelection) -> bool {
         !self.config.full_bootstrap
             && compiler.stage >= 2
             && (self.hosts.iter().any(|h| *h == target) || target == self.build)
@@ -1065,7 +1062,7 @@ fn llvm_tools_vers(&self) -> String {
         self.rust_version()
     }
 
-    fn llvm_link_tools_dynamically(&self, target: Interned<String>) -> bool {
+    fn llvm_link_tools_dynamically(&self, target: TargetSelection) -> bool {
         target.contains("linux-gnu") || target.contains("apple-darwin")
     }
 
index e8ec575ea37466379f6ab1e75ccc3134f5c22ddd..48b2cc24d4cd8bfb22b62e84dab700b320e07046 100644 (file)
@@ -19,8 +19,8 @@
 use build_helper::{output, t};
 
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
 use crate::channel;
+use crate::config::TargetSelection;
 use crate::util::{self, exe};
 use crate::GitRepo;
 use build_helper::up_to_date;
@@ -41,7 +41,7 @@ pub struct Meta {
 // if not).
 pub fn prebuilt_llvm_config(
     builder: &Builder<'_>,
-    target: Interned<String>,
+    target: TargetSelection,
 ) -> Result<PathBuf, Meta> {
     // If we're using a custom LLVM bail out here, but we can only use a
     // custom LLVM for the build triple.
@@ -54,13 +54,14 @@ pub fn prebuilt_llvm_config(
 
     let root = "src/llvm-project/llvm";
     let out_dir = builder.llvm_out(target);
+
     let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build);
     if !builder.config.build.contains("msvc") || builder.config.ninja {
         llvm_config_ret_dir.push("build");
     }
     llvm_config_ret_dir.push("bin");
 
-    let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", &*builder.config.build));
+    let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", builder.config.build));
 
     let stamp = out_dir.join("llvm-finished-building");
     let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());
@@ -93,7 +94,7 @@ pub fn prebuilt_llvm_config(
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Llvm {
@@ -112,6 +113,15 @@ fn make_run(run: RunConfig<'_>) {
     /// Compile LLVM for `target`.
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let target = self.target;
+        let target_native = if self.target.starts_with("riscv") {
+            // RISC-V target triples in Rust is not named the same as C compiler target triples.
+            // This converts Rust RISC-V target triples to C compiler triples.
+            let idx = target.triple.find('-').unwrap();
+
+            format!("riscv{}{}", &target.triple[5..7], &target.triple[idx..])
+        } else {
+            target.to_string()
+        };
 
         let Meta { stamp, build_llvm_config, out_dir, root } =
             match prebuilt_llvm_config(builder, target) {
@@ -165,8 +175,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .define("LLVM_ENABLE_BINDINGS", "OFF")
             .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
             .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
-            .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
-            .define("LLVM_DEFAULT_TARGET_TRIPLE", target);
+            .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
+            .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
 
         if !target.contains("netbsd") {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
@@ -213,6 +223,17 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             }
         }
 
+        if target.starts_with("riscv") {
+            // In RISC-V, using C++ atomics require linking to `libatomic` but the LLVM build
+            // system check cannot detect this. Therefore it is set manually here.
+            if !builder.config.llvm_tools_enabled {
+                cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic");
+            } else {
+                cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic -static-libstdc++");
+            }
+            cfg.define("CMAKE_SHARED_LINKER_FLAGS", "-latomic");
+        }
+
         if target.contains("msvc") {
             cfg.define("LLVM_USE_CRT_DEBUG", "MT");
             cfg.define("LLVM_USE_CRT_RELEASE", "MT");
@@ -339,7 +360,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
 
 fn configure_cmake(
     builder: &Builder<'_>,
-    target: Interned<String>,
+    target: TargetSelection,
     cfg: &mut cmake::Config,
     use_compiler_launcher: bool,
 ) {
@@ -347,10 +368,15 @@ fn configure_cmake(
     // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
     cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY");
 
+    // Do not allow the user's value of DESTDIR to influence where
+    // LLVM will install itself. LLVM must always be installed in our
+    // own build directories.
+    cfg.env("DESTDIR", "");
+
     if builder.config.ninja {
         cfg.generator("Ninja");
     }
-    cfg.target(&target).host(&builder.config.build);
+    cfg.target(&target.triple).host(&builder.config.build.triple);
 
     let sanitize_cc = |cc: &Path| {
         if target.contains("msvc") {
@@ -380,7 +406,7 @@ fn configure_cmake(
         cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc))
             .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc));
         cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap())
-            .env("SCCACHE_TARGET", target)
+            .env("SCCACHE_TARGET", target.triple)
             .env("SCCACHE_CC", &cc)
             .env("SCCACHE_CXX", &cxx);
 
@@ -480,7 +506,7 @@ fn configure_cmake(
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Lld {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Lld {
@@ -553,8 +579,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         // brittle and will break over time. If anyone knows better how to
         // cross-compile LLD it would be much appreciated to fix this!
         if target != builder.config.build {
-            cfg.env("LLVM_CONFIG_SHIM_REPLACE", &builder.config.build)
-                .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target)
+            cfg.env("LLVM_CONFIG_SHIM_REPLACE", &builder.config.build.triple)
+                .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target.triple)
                 .define(
                     "LLVM_TABLEGEN_EXE",
                     llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION),
@@ -574,7 +600,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct TestHelpers {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for TestHelpers {
@@ -621,8 +647,8 @@ fn run(self, builder: &Builder<'_>) {
 
         cfg.cargo_metadata(false)
             .out_dir(&dst)
-            .target(&target)
-            .host(&builder.config.build)
+            .target(&target.triple)
+            .host(&builder.config.build.triple)
             .opt_level(0)
             .warnings(false)
             .debug(false)
@@ -633,7 +659,7 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Sanitizers {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Sanitizers {
@@ -684,7 +710,7 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
 
         let mut cfg = cmake::Config::new(&compiler_rt_dir);
         cfg.profile("Release");
-        cfg.define("CMAKE_C_COMPILER_TARGET", self.target);
+        cfg.define("CMAKE_C_COMPILER_TARGET", self.target.triple);
         cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF");
         cfg.define("COMPILER_RT_BUILD_CRT", "OFF");
         cfg.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF");
@@ -727,7 +753,7 @@ pub struct SanitizerRuntime {
 /// Returns sanitizers available on a given target.
 fn supported_sanitizers(
     out_dir: &Path,
-    target: Interned<String>,
+    target: TargetSelection,
     channel: &str,
 ) -> Vec<SanitizerRuntime> {
     let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
@@ -753,7 +779,7 @@ fn supported_sanitizers(
             .collect()
     };
 
-    match &*target {
+    match &*target.triple {
         "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
         "aarch64-unknown-linux-gnu" => {
             common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
index 3301d41cfeefa9f5c3571eaeae8914c7c7c500ab..f89bef50de982374352a826c163a0b3d70a27542 100644 (file)
@@ -183,7 +183,11 @@ pub fn check(build: &mut Build) {
             panic!("the iOS target is only supported on macOS");
         }
 
-        build.config.target_config.entry(target.clone()).or_insert(Target::from_triple(target));
+        build
+            .config
+            .target_config
+            .entry(target.clone())
+            .or_insert(Target::from_triple(&target.triple));
 
         if target.contains("-none-") || target.contains("nvptx") {
             if build.no_std(*target) == Some(false) {
index 1916d96bed71dba0632b9881504bebd2c8a59725..b76d80aa509a5c6d353c3f48df176177b714d62c 100644 (file)
@@ -16,6 +16,7 @@
 use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::dist;
 use crate::flags::Subcommand;
 use crate::native;
@@ -93,7 +94,7 @@ fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Linkcheck {
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Linkcheck {
@@ -115,7 +116,7 @@ fn run(self, builder: &Builder<'_>) {
         let _time = util::timeit(&builder);
         try_run(
             builder,
-            builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host).join("doc")),
+            builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")),
         );
     }
 
@@ -132,7 +133,7 @@ fn make_run(run: RunConfig<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Cargotest {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Cargotest {
@@ -177,7 +178,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Cargo {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Cargo {
@@ -230,7 +231,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rls {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Rls {
@@ -281,7 +282,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustfmt {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Rustfmt {
@@ -338,7 +339,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Miri {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Miri {
@@ -464,7 +465,7 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CompiletestTest {
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for CompiletestTest {
@@ -501,7 +502,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Clippy {
     stage: u32,
-    host: Interned<String>,
+    host: TargetSelection,
 }
 
 impl Step for Clippy {
@@ -542,8 +543,10 @@ fn run(self, builder: &Builder<'_>) {
         cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
         cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
         let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
-        let target_libs =
-            builder.stage_out(compiler, Mode::ToolRustc).join(&self.host).join(builder.cargo_dir());
+        let target_libs = builder
+            .stage_out(compiler, Mode::ToolRustc)
+            .join(&self.host.triple)
+            .join(builder.cargo_dir());
         cargo.env("HOST_LIBS", host_libs);
         cargo.env("TARGET_LIBS", target_libs);
         // clippy tests need to find the driver
@@ -607,7 +610,7 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocJSStd {
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RustdocJSStd {
@@ -646,8 +649,8 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocJSNotStd {
-    pub host: Interned<String>,
-    pub target: Interned<String>,
+    pub host: TargetSelection,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -683,8 +686,8 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocUi {
-    pub host: Interned<String>,
-    pub target: Interned<String>,
+    pub host: TargetSelection,
+    pub target: TargetSelection,
     pub compiler: Compiler,
 }
 
@@ -785,8 +788,8 @@ fn make_run(run: RunConfig<'_>) {
     }
 }
 
-fn testdir(builder: &Builder<'_>, host: Interned<String>) -> PathBuf {
-    builder.out.join(host).join("test")
+fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
+    builder.out.join(host.triple).join("test")
 }
 
 macro_rules! default_test {
@@ -855,7 +858,7 @@ macro_rules! test_definitions {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl Step for $name {
@@ -943,7 +946,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 struct Compiletest {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     mode: &'static str,
     suite: &'static str,
     path: &'static str,
@@ -1019,12 +1022,16 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
         }
 
+        if mode == "run-make" && suite.ends_with("fulldeps") {
+            cmd.arg("--rust-demangler-path").arg(builder.tool_exe(Tool::RustDemangler));
+        }
+
         cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite));
         cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
         cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
         cmd.arg("--mode").arg(mode);
-        cmd.arg("--target").arg(target);
-        cmd.arg("--host").arg(&*compiler.host);
+        cmd.arg("--target").arg(target.rustc_target_arg());
+        cmd.arg("--host").arg(&*compiler.host.triple);
         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
 
         if builder.config.cmd.bless() {
@@ -1543,7 +1550,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateLibrustc {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     test_kind: TestKind,
     krate: Interned<String>,
 }
@@ -1589,7 +1596,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateNotDefault {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     test_kind: TestKind,
     krate: &'static str,
 }
@@ -1638,7 +1645,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Crate {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
     pub mode: Mode,
     pub test_kind: TestKind,
     pub krate: Interned<String>,
@@ -1750,17 +1757,17 @@ fn run(self, builder: &Builder<'_>) {
 
         if target.contains("emscripten") {
             cargo.env(
-                format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
+                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
                 builder.config.nodejs.as_ref().expect("nodejs not configured"),
             );
         } else if target.starts_with("wasm32") {
             let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
             let runner =
                 format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
-            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
+            cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
         } else if builder.remote_tested(target) {
             cargo.env(
-                format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
+                format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
                 format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
             );
         }
@@ -1776,7 +1783,7 @@ fn run(self, builder: &Builder<'_>) {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CrateRustdoc {
-    host: Interned<String>,
+    host: TargetSelection,
     test_kind: TestKind,
 }
 
@@ -1883,7 +1890,7 @@ fn run(self, builder: &Builder<'_>) {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct RemoteCopyLibs {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
 }
 
 impl Step for RemoteCopyLibs {
@@ -1911,7 +1918,7 @@ fn run(self, builder: &Builder<'_>) {
         // Spawn the emulator and wait for it to come online
         let tool = builder.tool_exe(Tool::RemoteTestClient);
         let mut cmd = Command::new(&tool);
-        cmd.arg("spawn-emulator").arg(target).arg(&server).arg(builder.out.join("tmp"));
+        cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp"));
         if let Some(rootfs) = builder.qemu_rootfs(target) {
             cmd.arg(rootfs);
         }
@@ -1966,7 +1973,9 @@ fn run(self, builder: &Builder<'_>) {
                 .current_dir(&dir),
         );
         builder.run(
-            Command::new(build_helper::make(&builder.config.build)).arg("check").current_dir(&dir),
+            Command::new(build_helper::make(&builder.config.build.triple))
+                .arg("check")
+                .current_dir(&dir),
         );
 
         // Now make sure that rust-src has all of libstd's dependencies
index 450b534d5dfdbe378ab8d2b26ab975b14fb36193..fe3f1e78029d7679aa9983b1ee5e334a61b76c79 100644 (file)
@@ -7,10 +7,10 @@
 use build_helper::t;
 
 use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
-use crate::cache::Interned;
 use crate::channel;
 use crate::channel::GitInfo;
 use crate::compile;
+use crate::config::TargetSelection;
 use crate::toolstate::ToolState;
 use crate::util::{add_dylib_path, exe};
 use crate::Compiler;
@@ -25,7 +25,7 @@ pub enum SourceType {
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 struct ToolBuild {
     compiler: Compiler,
-    target: Interned<String>,
+    target: TargetSelection,
     tool: &'static str,
     path: &'static str,
     mode: Mode,
@@ -111,7 +111,7 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
                             .and_then(|p| p.file_name())
                             .and_then(|p| p.to_str())
                             .unwrap();
-                        if maybe_target != &*target {
+                        if maybe_target != &*target.triple {
                             continue;
                         }
                     }
@@ -208,8 +208,8 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             }
         } else {
             let cargo_out =
-                builder.cargo_out(compiler, self.mode, target).join(exe(tool, &compiler.host));
-            let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host));
+                builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host));
+            let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host));
             builder.copy(&cargo_out, &bin);
             Some(bin)
         }
@@ -220,7 +220,7 @@ pub fn prepare_tool_cargo(
     builder: &Builder<'_>,
     compiler: Compiler,
     mode: Mode,
-    target: Interned<String>,
+    target: TargetSelection,
     command: &'static str,
     path: &'static str,
     source_type: SourceType,
@@ -303,7 +303,7 @@ pub fn tool_exe(&self, tool: Tool) -> PathBuf {
             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
         }
 
         impl Step for $name {
@@ -361,6 +361,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
     Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true;
     BuildManifest, "src/tools/build-manifest", "build-manifest";
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
+    RustDemangler, "src/tools/rust-demangler", "rust-demangler";
     RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
     RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
     ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
@@ -416,7 +417,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RemoteTestServer {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for RemoteTestServer {
@@ -476,7 +477,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             if !target_compiler.is_snapshot(builder) {
                 panic!("rustdoc in stage 0 must be snapshot rustdoc");
             }
-            return builder.initial_rustc.with_file_name(exe("rustdoc", &target_compiler.host));
+            return builder.initial_rustc.with_file_name(exe("rustdoc", target_compiler.host));
         }
         let target = target_compiler.host;
         // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
@@ -514,14 +515,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         // rustdoc a different name.
         let tool_rustdoc = builder
             .cargo_out(build_compiler, Mode::ToolRustc, target)
-            .join(exe("rustdoc_tool_binary", &target_compiler.host));
+            .join(exe("rustdoc_tool_binary", target_compiler.host));
 
         // don't create a stage0-sysroot/bin directory.
         if target_compiler.stage > 0 {
             let sysroot = builder.sysroot(target_compiler);
             let bindir = sysroot.join("bin");
             t!(fs::create_dir_all(&bindir));
-            let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host));
+            let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host));
             let _ = fs::remove_file(&bin_rustdoc);
             builder.copy(&tool_rustdoc, &bin_rustdoc);
             bin_rustdoc
@@ -534,7 +535,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Cargo {
     pub compiler: Compiler,
-    pub target: Interned<String>,
+    pub target: TargetSelection,
 }
 
 impl Step for Cargo {
@@ -583,7 +584,7 @@ macro_rules! tool_extended {
             #[derive(Debug, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
             pub compiler: Compiler,
-            pub target: Interned<String>,
+            pub target: TargetSelection,
             pub extra_features: Vec<String>,
         }
 
index 2bc6f1939d97b5cc53b420e95e20f37710b27fd3..a307ef39d03a8daba772d99b75f62e9958f30131 100644 (file)
 use build_helper::t;
 
 use crate::builder::Builder;
-use crate::cache::Interned;
-use crate::config::Config;
+use crate::config::{Config, TargetSelection};
 
 /// Returns the `name` as the filename of a static library for `target`.
-pub fn staticlib(name: &str, target: &str) -> String {
+pub fn staticlib(name: &str, target: TargetSelection) -> String {
     if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) }
 }
 
 /// Given an executable called `name`, return the filename for the
 /// executable for a particular target.
-pub fn exe(name: &str, target: &str) -> String {
+pub fn exe(name: &str, target: TargetSelection) -> String {
     if target.contains("windows") { format!("{}.exe", name) } else { name.to_string() }
 }
 
@@ -35,7 +34,7 @@ pub fn is_dylib(name: &str) -> bool {
 
 /// Returns the corresponding relative library directory that the compiler's
 /// dylibs will be found in.
-pub fn libdir(target: &str) -> &'static str {
+pub fn libdir(target: TargetSelection) -> &'static str {
     if target.contains("windows") { "bin" } else { "lib" }
 }
 
@@ -294,7 +293,7 @@ pub fn forcing_clang_based_tests() -> bool {
     }
 }
 
-pub fn use_host_linker(target: &Interned<String>) -> bool {
+pub fn use_host_linker(target: TargetSelection) -> bool {
     // FIXME: this information should be gotten by checking the linker flavor
     // of the rustc target
     !(target.contains("emscripten")
index 3de5a19f851645e2c2e1468c9296cf38f3b26b46..1786baa0278b9896df976494b3051a9eedfc972f 100644 (file)
@@ -53,8 +53,10 @@ jobs:
       dist-powerpc-linux: {}
       dist-powerpc64-linux: {}
       dist-powerpc64le-linux: {}
+      dist-riscv64-linux: {}
       dist-s390x-linux: {}
       dist-x86_64-freebsd: {}
+      dist-x86_64-illumos: {}
       dist-x86_64-musl: {}
       dist-x86_64-netbsd: {}
       i686-gnu: {}
index 7e79cc88513695f137a4936e9d6390fc15e17360..ff28f4f603c9dcc97fe4bbdb0ba6378e3080b8db 100644 (file)
@@ -16,6 +16,11 @@ for example:
 
 Images will output artifacts in an `obj` dir at the root of a repository.
 
+To match conditions in rusts CI, also set the environment variable `DEPLOY=1`, e.g.:
+```
+DEPLOY=1 ./src/ci/docker/run.sh x86_64-gnu
+```
+
 **NOTE**: Re-using the same `obj` dir with different docker images with
 the same target triple (e.g. `dist-x86_64-linux` and `dist-various-1`)
 may result in strange linker errors, due shared library versions differing between platforms.
@@ -85,27 +90,44 @@ how to generate them, and how the existing ones were generated.
 
 ### Generating a `.config` file
 
+**NOTE:** Existing Dockerfiles can also be a good guide for the process and order
+of script execution.
+
 If you have a `linux-cross` image lying around you can use that and skip the
 next two steps.
 
-- First we spin up a container and copy `build_toolchain_root.sh` into it. All
+- First we spin up a container and copy all scripts into it. All
   these steps are outside the container:
 
 ```
-# Note: We use ubuntu:15.10 because that's the "base" of linux-cross Docker
-# image
-$ docker run -it ubuntu:15.10 bash
+# Note: We use ubuntu:16.04 because that's the "base" of linux-cross Docker
+# image, or simply run ./src/ci/docker/run.sh once, which will download the correct
+# one and you can check it out with `docker images`
+$ docker run -it ubuntu:16.04 bash
+# in another terminal:
 $ docker ps
 CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
-cfbec05ed730        ubuntu:15.10        "bash"              16 seconds ago      Up 15 seconds                           drunk_murdock
-$ docker cp build_toolchain_root.sh drunk_murdock:/
+cfbec05ed730        ubuntu:16.04        "bash"              16 seconds ago      Up 15 seconds                           drunk_murdock
+$ docker cp src/ci/docker/scripts drunk_murdock:/tmp/
 ```
 
 - Then inside the container we build crosstool-ng by simply calling the bash
   script we copied in the previous step:
 
 ```
-$ bash build_toolchain_root.sh
+$ cd /tmp/scripts
+# Download packages necessary for building
+$ bash ./cross-apt-packages.sh
+# Download and build crosstool-ng
+$ bash ./crosstool-ng.sh
+```
+
+- In case you want to adjust or start from an existing config, copy that
+  to the container. `crosstool-ng` will automatically load `./.config` if
+  present. Otherwise one can use the TUI to load any config-file.
+
+```
+$ docker cp arm-linux-gnueabi.config drunk_murdock:/tmp/.config
 ```
 
 - Now, inside the container run the following command to configure the
@@ -113,6 +135,7 @@ $ bash build_toolchain_root.sh
   section and come back.
 
 ```
+$ cd /tmp/
 $ ct-ng menuconfig
 ```
 
@@ -120,7 +143,7 @@ $ ct-ng menuconfig
   meaningful name. This is done outside the container.
 
 ```
-$ docker drunk_murdock:/.config arm-linux-gnueabi.config
+$ docker cp drunk_murdock:/tmp/.config arm-linux-gnueabi.config
 ```
 
 - Now you can shutdown the container or repeat the two last steps to generate a
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
new file mode 100644 (file)
index 0000000..dff7c47
--- /dev/null
@@ -0,0 +1,31 @@
+FROM ubuntu:18.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+COPY host-x86_64/dist-riscv64-linux/crosstool-ng.sh /scripts/
+RUN sh /scripts/crosstool-ng.sh
+
+COPY scripts/rustbuild-setup.sh /scripts/
+RUN sh /scripts/rustbuild-setup.sh
+USER rustbuild
+WORKDIR /tmp
+
+COPY host-x86_64/dist-riscv64-linux/build-toolchains.sh host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config /tmp/
+RUN ./build-toolchains.sh
+
+USER root
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV PATH=$PATH:/x-tools/riscv64-unknown-linux-gnu/bin
+
+ENV CC_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-gcc \
+    AR_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-ar \
+    CXX_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-g++
+
+ENV HOSTS=riscv64gc-unknown-linux-gnu
+
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV SCRIPT python3 ../x.py dist --target $HOSTS --host $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/build-toolchains.sh b/src/ci/docker/host-x86_64/dist-riscv64-linux/build-toolchains.sh
new file mode 100755 (executable)
index 0000000..6a7c022
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  $@ &> /tmp/build.log
+  rm /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir build
+cd build
+cp ../riscv64-unknown-linux-gnu.config .config
+hide_output ct-ng build
+cd ..
+rm -rf build
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh b/src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh
new file mode 100644 (file)
index 0000000..fb067a7
--- /dev/null
@@ -0,0 +1,12 @@
+set -ex
+
+# Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz
+url="https://ci-mirrors.rust-lang.org/rustc/crosstool-ng-1.24.0.tar.gz"
+curl -Lf $url | tar xzf -
+cd crosstool-ng-crosstool-ng-1.24.0
+./bootstrap
+./configure --prefix=/usr/local
+make -j$(nproc)
+make install
+cd ..
+rm -rf crosstool-ng-crosstool-ng-1.24.0
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config
new file mode 100644 (file)
index 0000000..dbb4be5
--- /dev/null
@@ -0,0 +1,906 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
+CT_MODULES=y
+
+#
+# Paths and misc options
+#
+
+#
+# crosstool-NG behavior
+#
+# CT_OBSOLETE is not set
+CT_EXPERIMENTAL=y
+# CT_ALLOW_BUILD_AS_ROOT is not set
+# CT_DEBUG_CT is not set
+
+#
+# Paths
+#
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
+CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
+CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
+CT_RM_RF_PREFIX_DIR=y
+CT_REMOVE_DOCS=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
+CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
+# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
+
+#
+# Downloading
+#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
+# CT_FORBID_DOWNLOAD is not set
+# CT_FORCE_DOWNLOAD is not set
+CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
+# CT_ONLY_DOWNLOAD is not set
+# CT_USE_MIRROR is not set
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
+
+#
+# Extracting
+#
+# CT_FORCE_EXTRACT is not set
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
+# CT_ONLY_EXTRACT is not set
+CT_PATCH_BUNDLED=y
+# CT_PATCH_LOCAL is not set
+# CT_PATCH_BUNDLED_LOCAL is not set
+# CT_PATCH_LOCAL_BUNDLED is not set
+# CT_PATCH_NONE is not set
+CT_PATCH_ORDER="bundled"
+
+#
+# Build behavior
+#
+CT_PARALLEL_JOBS=0
+CT_LOAD=""
+CT_USE_PIPES=y
+CT_EXTRA_CFLAGS_FOR_BUILD=""
+CT_EXTRA_LDFLAGS_FOR_BUILD=""
+CT_EXTRA_CFLAGS_FOR_HOST=""
+CT_EXTRA_LDFLAGS_FOR_HOST=""
+# CT_CONFIG_SHELL_SH is not set
+# CT_CONFIG_SHELL_ASH is not set
+CT_CONFIG_SHELL_BASH=y
+# CT_CONFIG_SHELL_CUSTOM is not set
+CT_CONFIG_SHELL="${bash}"
+
+#
+# Logging
+#
+# CT_LOG_ERROR is not set
+# CT_LOG_WARN is not set
+# CT_LOG_INFO is not set
+# CT_LOG_EXTRA is not set
+CT_LOG_ALL=y
+# CT_LOG_DEBUG is not set
+CT_LOG_LEVEL_MAX="ALL"
+# CT_LOG_SEE_TOOLS_WARN is not set
+CT_LOG_TO_FILE=y
+CT_LOG_FILE_COMPRESS=y
+
+#
+# Target options
+#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MICROBLAZE is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_MOXIE is not set
+# CT_ARCH_MSP430 is not set
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+CT_ARCH_RISCV=y
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
+CT_ARCH="riscv"
+CT_ARCH_CHOICE_KSYM="RISCV"
+CT_ARCH_TUNE=""
+CT_ARCH_RISCV_SHOW=y
+
+#
+# Options for riscv
+#
+CT_ARCH_RISCV_PKG_KSYM=""
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
+CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
+
+#
+# Generic target options
+#
+# CT_MULTILIB is not set
+# CT_DEMULTILIB is not set
+CT_ARCH_SUPPORTS_BOTH_MMU=y
+CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
+
+#
+# Target optimisations
+#
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_ABI=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_ARCH="rv64gc"
+CT_ARCH_ABI=""
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
+
+#
+# Toolchain options
+#
+
+#
+# General toolchain options
+#
+CT_FORCE_SYSROOT=y
+CT_USE_SYSROOT=y
+CT_SYSROOT_NAME="sysroot"
+CT_SYSROOT_DIR_PREFIX=""
+CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
+# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
+CT_TOOLCHAIN_PKGVERSION=""
+CT_TOOLCHAIN_BUGURL=""
+
+#
+# Tuple completion and aliasing
+#
+CT_TARGET_VENDOR="unknown"
+CT_TARGET_ALIAS_SED_EXPR=""
+CT_TARGET_ALIAS=""
+
+#
+# Toolchain type
+#
+# CT_NATIVE is not set
+CT_CROSS=y
+# CT_CROSS_NATIVE is not set
+# CT_CANADIAN is not set
+CT_TOOLCHAIN_TYPE="cross"
+
+#
+# Build system
+#
+CT_BUILD=""
+CT_BUILD_PREFIX=""
+CT_BUILD_SUFFIX=""
+
+#
+# Misc options
+#
+# CT_TOOLCHAIN_ENABLE_NLS is not set
+
+#
+# Operating System
+#
+CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
+CT_KERNEL="linux"
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+# CT_LINUX_SRC_DEVEL is not set
+# CT_LINUX_SRC_CUSTOM is not set
+CT_LINUX_PATCH_GLOBAL=y
+# CT_LINUX_PATCH_BUNDLED is not set
+# CT_LINUX_PATCH_LOCAL is not set
+# CT_LINUX_PATCH_BUNDLED_LOCAL is not set
+# CT_LINUX_PATCH_LOCAL_BUNDLED is not set
+# CT_LINUX_PATCH_NONE is not set
+CT_LINUX_PATCH_ORDER="global"
+CT_LINUX_V_4_20=y
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+# CT_LINUX_V_3_2 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.20.8"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_later_than_4_8=y
+CT_LINUX_4_8_or_later=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
+CT_LINUX_REQUIRE_3_2_or_later=y
+CT_KERNEL_LINUX_VERBOSITY_0=y
+# CT_KERNEL_LINUX_VERBOSITY_1 is not set
+# CT_KERNEL_LINUX_VERBOSITY_2 is not set
+CT_KERNEL_LINUX_VERBOSE_LEVEL=0
+CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
+
+#
+# Binary utilities
+#
+CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
+CT_BINUTILS="binutils"
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+# CT_BINUTILS_SRC_DEVEL is not set
+# CT_BINUTILS_SRC_CUSTOM is not set
+CT_BINUTILS_PATCH_GLOBAL=y
+# CT_BINUTILS_PATCH_BUNDLED is not set
+# CT_BINUTILS_PATCH_LOCAL is not set
+# CT_BINUTILS_PATCH_BUNDLED_LOCAL is not set
+# CT_BINUTILS_PATCH_LOCAL_BUNDLED is not set
+# CT_BINUTILS_PATCH_NONE is not set
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_REQUIRE_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
+
+#
+# GNU binutils
+#
+CT_BINUTILS_HAS_HASH_STYLE=y
+CT_BINUTILS_HAS_GOLD=y
+CT_BINUTILS_HAS_PLUGINS=y
+CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
+CT_BINUTILS_LINKER_LD=y
+CT_BINUTILS_LINKERS_LIST="ld"
+CT_BINUTILS_LINKER_DEFAULT="bfd"
+# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
+CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
+# CT_BINUTILS_FOR_TARGET is not set
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
+
+#
+# C-library
+#
+CT_LIBC_GLIBC=y
+# CT_LIBC_MUSL is not set
+# CT_LIBC_UCLIBC is not set
+CT_LIBC="glibc"
+CT_LIBC_CHOICE_KSYM="GLIBC"
+CT_THREADS="nptl"
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+# CT_GLIBC_SRC_DEVEL is not set
+# CT_GLIBC_SRC_CUSTOM is not set
+CT_GLIBC_PATCH_GLOBAL=y
+# CT_GLIBC_PATCH_BUNDLED is not set
+# CT_GLIBC_PATCH_LOCAL is not set
+# CT_GLIBC_PATCH_BUNDLED_LOCAL is not set
+# CT_GLIBC_PATCH_LOCAL_BUNDLED is not set
+# CT_GLIBC_PATCH_NONE is not set
+CT_GLIBC_PATCH_ORDER="global"
+CT_GLIBC_V_2_29=y
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.29"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_later=y
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_REQUIRE_2_29_or_later=y
+CT_GLIBC_later_than_2_27=y
+CT_GLIBC_2_27_or_later=y
+CT_GLIBC_later_than_2_26=y
+CT_GLIBC_2_26_or_later=y
+CT_GLIBC_later_than_2_25=y
+CT_GLIBC_2_25_or_later=y
+CT_GLIBC_later_than_2_24=y
+CT_GLIBC_2_24_or_later=y
+CT_GLIBC_later_than_2_23=y
+CT_GLIBC_2_23_or_later=y
+CT_GLIBC_later_than_2_20=y
+CT_GLIBC_2_20_or_later=y
+CT_GLIBC_later_than_2_17=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_BUILD_SSP=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_NO_SPARC_V8=y
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_ENABLE_FORTIFIED_BUILD is not set
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+CT_GLIBC_KERNEL_VERSION_NONE=y
+# CT_GLIBC_KERNEL_VERSION_AS_HEADERS is not set
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL=""
+CT_GLIBC_SSP_DEFAULT=y
+# CT_GLIBC_SSP_NO is not set
+# CT_GLIBC_SSP_YES is not set
+# CT_GLIBC_SSP_ALL is not set
+# CT_GLIBC_SSP_STRONG is not set
+# CT_GLIBC_ENABLE_WERROR is not set
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
+CT_LIBC_SUPPORT_THREADS_ANY=y
+CT_LIBC_SUPPORT_THREADS_NATIVE=y
+
+#
+# Common C library options
+#
+CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
+CT_LIBC_XLDD=y
+
+#
+# C compiler
+#
+CT_CC_CORE_PASSES_NEEDED=y
+CT_CC_CORE_PASS_1_NEEDED=y
+CT_CC_CORE_PASS_2_NEEDED=y
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+# CT_GCC_USE_LINARO is not set
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+# CT_GCC_SRC_DEVEL is not set
+# CT_GCC_SRC_CUSTOM is not set
+CT_GCC_PATCH_GLOBAL=y
+# CT_GCC_PATCH_BUNDLED is not set
+# CT_GCC_PATCH_LOCAL is not set
+# CT_GCC_PATCH_BUNDLED_LOCAL is not set
+# CT_GCC_PATCH_LOCAL_BUNDLED is not set
+# CT_GCC_PATCH_NONE is not set
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_REQUIRE_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_REQUIRE_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_REQUIRE_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
+CT_CC_GCC_ENABLE_CXX_FLAGS=""
+CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_STATIC_LIBSTDCXX=y
+# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
+
+#
+# Optimisation features
+#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
+
+#
+# Settings for libraries running on target
+#
+CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y
+# CT_CC_GCC_LIBMUDFLAP is not set
+# CT_CC_GCC_LIBGOMP is not set
+# CT_CC_GCC_LIBSSP is not set
+# CT_CC_GCC_LIBQUADMATH is not set
+# CT_CC_GCC_LIBSANITIZER is not set
+
+#
+# Misc. obscure options.
+#
+CT_CC_CXA_ATEXIT=y
+# CT_CC_GCC_DISABLE_PCH is not set
+CT_CC_GCC_SJLJ_EXCEPTIONS=m
+CT_CC_GCC_LDBL_128=m
+# CT_CC_GCC_BUILD_ID is not set
+CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y
+# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set
+# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set
+# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set
+CT_CC_GCC_LNK_HASH_STYLE=""
+CT_CC_GCC_DEC_FLOAT_AUTO=y
+# CT_CC_GCC_DEC_FLOAT_BID is not set
+# CT_CC_GCC_DEC_FLOAT_DPD is not set
+# CT_CC_GCC_DEC_FLOATS_NO is not set
+CT_ALL_CC_CHOICES="GCC"
+
+#
+# Additional supported languages:
+#
+CT_CC_LANG_CXX=y
+# CT_CC_LANG_FORTRAN is not set
+# CT_CC_LANG_ADA is not set
+# CT_CC_LANG_OBJC is not set
+# CT_CC_LANG_OBJCXX is not set
+# CT_CC_LANG_GOLANG is not set
+CT_CC_LANG_OTHERS=""
+
+#
+# Debug facilities
+#
+# CT_DEBUG_DUMA is not set
+CT_DEBUG_GDB=y
+CT_DEBUG_GDB_PKG_KSYM="GDB"
+CT_GDB_DIR_NAME="gdb"
+CT_GDB_USE_GNU=y
+CT_GDB_USE="GDB"
+CT_GDB_PKG_NAME="gdb"
+CT_GDB_SRC_RELEASE=y
+# CT_GDB_SRC_DEVEL is not set
+# CT_GDB_SRC_CUSTOM is not set
+CT_GDB_PATCH_GLOBAL=y
+# CT_GDB_PATCH_BUNDLED is not set
+# CT_GDB_PATCH_LOCAL is not set
+# CT_GDB_PATCH_BUNDLED_LOCAL is not set
+# CT_GDB_PATCH_LOCAL_BUNDLED is not set
+# CT_GDB_PATCH_NONE is not set
+CT_GDB_PATCH_ORDER="global"
+CT_GDB_V_8_2=y
+# CT_GDB_V_8_1 is not set
+# CT_GDB_V_8_0 is not set
+# CT_GDB_NO_VERSIONS is not set
+CT_GDB_VERSION="8.2.1"
+CT_GDB_MIRRORS="$(CT_Mirrors GNU gdb) $(CT_Mirrors sourceware gdb/releases)"
+CT_GDB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GDB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GDB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GDB_SIGNATURE_FORMAT=""
+CT_GDB_later_than_8_0=y
+CT_GDB_8_0_or_later=y
+CT_GDB_REQUIRE_8_0_or_later=y
+CT_GDB_later_than_7_12=y
+CT_GDB_7_12_or_later=y
+CT_GDB_later_than_7_2=y
+CT_GDB_7_2_or_later=y
+CT_GDB_later_than_7_0=y
+CT_GDB_7_0_or_later=y
+CT_GDB_CROSS=y
+# CT_GDB_CROSS_STATIC is not set
+# CT_GDB_CROSS_SIM is not set
+# CT_GDB_CROSS_PYTHON is not set
+CT_GDB_CROSS_EXTRA_CONFIG_ARRAY=""
+# CT_GDB_NATIVE is not set
+# CT_GDB_GDBSERVER is not set
+CT_GDB_HAS_PKGVERSION_BUGURL=y
+CT_GDB_HAS_PYTHON=y
+CT_GDB_INSTALL_GDBINIT=y
+CT_GDB_HAS_IPA_LIB=y
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
+
+#
+# Companion libraries
+#
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+CT_COMP_LIBS_EXPAT=y
+CT_COMP_LIBS_EXPAT_PKG_KSYM="EXPAT"
+CT_EXPAT_DIR_NAME="expat"
+CT_EXPAT_PKG_NAME="expat"
+CT_EXPAT_SRC_RELEASE=y
+# CT_EXPAT_SRC_DEVEL is not set
+# CT_EXPAT_SRC_CUSTOM is not set
+CT_EXPAT_PATCH_GLOBAL=y
+# CT_EXPAT_PATCH_BUNDLED is not set
+# CT_EXPAT_PATCH_LOCAL is not set
+# CT_EXPAT_PATCH_BUNDLED_LOCAL is not set
+# CT_EXPAT_PATCH_LOCAL_BUNDLED is not set
+# CT_EXPAT_PATCH_NONE is not set
+CT_EXPAT_PATCH_ORDER="global"
+CT_EXPAT_V_2_2=y
+# CT_EXPAT_NO_VERSIONS is not set
+CT_EXPAT_VERSION="2.2.6"
+CT_EXPAT_MIRRORS="http://downloads.sourceforge.net/project/expat/expat/${CT_EXPAT_VERSION}"
+CT_EXPAT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_EXPAT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_EXPAT_ARCHIVE_FORMATS=".tar.bz2"
+CT_EXPAT_SIGNATURE_FORMAT=""
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+# CT_GETTEXT_SRC_DEVEL is not set
+# CT_GETTEXT_SRC_CUSTOM is not set
+CT_GETTEXT_PATCH_GLOBAL=y
+# CT_GETTEXT_PATCH_BUNDLED is not set
+# CT_GETTEXT_PATCH_LOCAL is not set
+# CT_GETTEXT_PATCH_BUNDLED_LOCAL is not set
+# CT_GETTEXT_PATCH_LOCAL_BUNDLED is not set
+# CT_GETTEXT_PATCH_NONE is not set
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+# CT_GMP_SRC_DEVEL is not set
+# CT_GMP_SRC_CUSTOM is not set
+CT_GMP_PATCH_GLOBAL=y
+# CT_GMP_PATCH_BUNDLED is not set
+# CT_GMP_PATCH_LOCAL is not set
+# CT_GMP_PATCH_BUNDLED_LOCAL is not set
+# CT_GMP_PATCH_LOCAL_BUNDLED is not set
+# CT_GMP_PATCH_NONE is not set
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+# CT_ISL_SRC_DEVEL is not set
+# CT_ISL_SRC_CUSTOM is not set
+CT_ISL_PATCH_GLOBAL=y
+# CT_ISL_PATCH_BUNDLED is not set
+# CT_ISL_PATCH_LOCAL is not set
+# CT_ISL_PATCH_BUNDLED_LOCAL is not set
+# CT_ISL_PATCH_LOCAL_BUNDLED is not set
+# CT_ISL_PATCH_NONE is not set
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+# CT_LIBICONV_SRC_DEVEL is not set
+# CT_LIBICONV_SRC_CUSTOM is not set
+CT_LIBICONV_PATCH_GLOBAL=y
+# CT_LIBICONV_PATCH_BUNDLED is not set
+# CT_LIBICONV_PATCH_LOCAL is not set
+# CT_LIBICONV_PATCH_BUNDLED_LOCAL is not set
+# CT_LIBICONV_PATCH_LOCAL_BUNDLED is not set
+# CT_LIBICONV_PATCH_NONE is not set
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+# CT_MPC_SRC_DEVEL is not set
+# CT_MPC_SRC_CUSTOM is not set
+CT_MPC_PATCH_GLOBAL=y
+# CT_MPC_PATCH_BUNDLED is not set
+# CT_MPC_PATCH_LOCAL is not set
+# CT_MPC_PATCH_BUNDLED_LOCAL is not set
+# CT_MPC_PATCH_LOCAL_BUNDLED is not set
+# CT_MPC_PATCH_NONE is not set
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+# CT_MPFR_SRC_DEVEL is not set
+# CT_MPFR_SRC_CUSTOM is not set
+CT_MPFR_PATCH_GLOBAL=y
+# CT_MPFR_PATCH_BUNDLED is not set
+# CT_MPFR_PATCH_LOCAL is not set
+# CT_MPFR_PATCH_BUNDLED_LOCAL is not set
+# CT_MPFR_PATCH_LOCAL_BUNDLED is not set
+# CT_MPFR_PATCH_NONE is not set
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+# CT_NCURSES_SRC_DEVEL is not set
+# CT_NCURSES_SRC_CUSTOM is not set
+CT_NCURSES_PATCH_GLOBAL=y
+# CT_NCURSES_PATCH_BUNDLED is not set
+# CT_NCURSES_PATCH_LOCAL is not set
+# CT_NCURSES_PATCH_BUNDLED_LOCAL is not set
+# CT_NCURSES_PATCH_LOCAL_BUNDLED is not set
+# CT_NCURSES_PATCH_NONE is not set
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+# CT_NCURSES_NEW_ABI is not set
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+# CT_ZLIB_SRC_DEVEL is not set
+# CT_ZLIB_SRC_CUSTOM is not set
+CT_ZLIB_PATCH_GLOBAL=y
+# CT_ZLIB_PATCH_BUNDLED is not set
+# CT_ZLIB_PATCH_LOCAL is not set
+# CT_ZLIB_PATCH_BUNDLED_LOCAL is not set
+# CT_ZLIB_PATCH_LOCAL_BUNDLED is not set
+# CT_ZLIB_PATCH_NONE is not set
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
+CT_LIBICONV_NEEDED=y
+CT_GETTEXT_NEEDED=y
+CT_GMP_NEEDED=y
+CT_MPFR_NEEDED=y
+CT_ISL_NEEDED=y
+CT_MPC_NEEDED=y
+CT_EXPAT_NEEDED=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
+CT_LIBICONV=y
+CT_GETTEXT=y
+CT_GMP=y
+CT_MPFR=y
+CT_ISL=y
+CT_MPC=y
+CT_EXPAT=y
+CT_NCURSES=y
+CT_ZLIB=y
+
+#
+# Companion tools
+#
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
+
+#
+# Test suite
+#
+# CT_TEST_SUITE_GCC is not set
index 87bab78f796c072b9b1c2e2f90474f426e7b4745..ac228cfe01d800cb777297c58631957487e42d3d 100644 (file)
@@ -47,18 +47,6 @@ RUN add-apt-repository ppa:team-gcc-arm-embedded/ppa && \
     apt-get update && \
     apt-get install -y --no-install-recommends gcc-arm-embedded
 
-COPY scripts/rustbuild-setup.sh host-x86_64/dist-various-1/build-riscv-toolchain.sh host-x86_64/dist-various-1/riscv64-unknown-linux-gnu.config host-x86_64/dist-various-1/crosstool-ng.sh /build/
-RUN ./crosstool-ng.sh
-
-# Crosstool-ng will refuse to build as root
-RUN sh ./rustbuild-setup.sh
-USER rustbuild
-
-RUN ./build-riscv-toolchain.sh
-
-USER root
-ENV PATH=/x-tools/riscv64-unknown-linux-gnu/bin:$PATH
-
 COPY host-x86_64/dist-various-1/build-rumprun.sh /build
 RUN ./build-rumprun.sh
 
@@ -158,7 +146,6 @@ ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf
 ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf
-ENV TARGETS=$TARGETS,riscv64gc-unknown-linux-gnu
 ENV TARGETS=$TARGETS,armebv7r-none-eabi
 ENV TARGETS=$TARGETS,armebv7r-none-eabihf
 ENV TARGETS=$TARGETS,armv7r-none-eabi
@@ -186,9 +173,6 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
     CFLAGS_aarch64_unknown_none_softfloat=-mstrict-align -march=armv8-a+nofp+nosimd \
     CC_aarch64_unknown_none=aarch64-none-elf-gcc \
     CFLAGS_aarch64_unknown_none=-mstrict-align -march=armv8-a+fp+simd \
-    CC_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-gcc \
-    AR_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-ar \
-    CXX_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-g++ \
     CC_riscv32i_unknown_none_elf=false \
     CC_riscv32imc_unknown_none_elf=false \
     CC_riscv32imac_unknown_none_elf=false \
diff --git a/src/ci/docker/host-x86_64/dist-various-1/build-riscv-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-1/build-riscv-toolchain.sh
deleted file mode 100755 (executable)
index 9cb5700..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-
-hide_output() {
-  set +x
-  on_err="
-echo ERROR: An error was encountered with the build.
-cat /tmp/build.log
-exit 1
-"
-  trap "$on_err" ERR
-  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
-  PING_LOOP_PID=$!
-  $@ &> /tmp/build.log
-  rm /tmp/build.log
-  trap - ERR
-  kill $PING_LOOP_PID
-  set -x
-}
-
-mkdir -p /tmp/build-riscv
-cp riscv64-unknown-linux-gnu.config /tmp/build-riscv/.config
-cd /tmp/build-riscv
-hide_output ct-ng build
-cd ..
-rm -rf build-riscv
diff --git a/src/ci/docker/host-x86_64/dist-various-1/crosstool-ng.sh b/src/ci/docker/host-x86_64/dist-various-1/crosstool-ng.sh
deleted file mode 100755 (executable)
index b01fdd0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-set -ex
-
-# Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz
-url="https://ci-mirrors.rust-lang.org/rustc/crosstool-ng-1.24.0.tar.gz"
-curl -Lf $url | tar xzf -
-cd crosstool-ng-crosstool-ng-1.24.0
-./bootstrap
-./configure --prefix=/usr/local
-make -j$(nproc)
-make install
-cd ..
-rm -rf crosstool-ng-crosstool-ng-1.24.0
diff --git a/src/ci/docker/host-x86_64/dist-various-1/riscv64-unknown-linux-gnu.config b/src/ci/docker/host-x86_64/dist-various-1/riscv64-unknown-linux-gnu.config
deleted file mode 100644 (file)
index dd06065..0000000
+++ /dev/null
@@ -1,908 +0,0 @@
-#
-# Automatically generated file; DO NOT EDIT.
-# crosstool-NG  Configuration
-#
-CT_CONFIGURE_has_static_link=y
-CT_CONFIGURE_has_cxx11=y
-CT_CONFIGURE_has_wget=y
-CT_CONFIGURE_has_curl=y
-CT_CONFIGURE_has_make_3_81_or_newer=y
-CT_CONFIGURE_has_make_4_0_or_newer=y
-CT_CONFIGURE_has_libtool_2_4_or_newer=y
-CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
-CT_CONFIGURE_has_autoconf_2_65_or_newer=y
-CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
-CT_CONFIGURE_has_automake_1_15_or_newer=y
-CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
-CT_CONFIGURE_has_python_3_4_or_newer=y
-CT_CONFIGURE_has_bison_2_7_or_newer=y
-CT_CONFIGURE_has_python=y
-CT_CONFIGURE_has_dtc=y
-CT_CONFIGURE_has_svn=y
-CT_CONFIGURE_has_git=y
-CT_CONFIGURE_has_md5sum=y
-CT_CONFIGURE_has_sha1sum=y
-CT_CONFIGURE_has_sha256sum=y
-CT_CONFIGURE_has_sha512sum=y
-CT_CONFIGURE_has_install_with_strip_program=y
-CT_CONFIG_VERSION_CURRENT="3"
-CT_CONFIG_VERSION="3"
-CT_MODULES=y
-
-#
-# Paths and misc options
-#
-
-#
-# crosstool-NG behavior
-#
-# CT_OBSOLETE is not set
-CT_EXPERIMENTAL=y
-# CT_ALLOW_BUILD_AS_ROOT is not set
-# CT_DEBUG_CT is not set
-
-#
-# Paths
-#
-CT_LOCAL_TARBALLS_DIR="${HOME}/src"
-CT_SAVE_TARBALLS=y
-# CT_TARBALLS_BUILDROOT_LAYOUT is not set
-CT_WORK_DIR="${CT_TOP_DIR}/.build"
-CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
-CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_RM_RF_PREFIX_DIR=y
-CT_REMOVE_DOCS=y
-CT_INSTALL_LICENSES=y
-CT_PREFIX_DIR_RO=y
-CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
-# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
-
-#
-# Downloading
-#
-CT_DOWNLOAD_AGENT_WGET=y
-# CT_DOWNLOAD_AGENT_CURL is not set
-# CT_DOWNLOAD_AGENT_NONE is not set
-# CT_FORBID_DOWNLOAD is not set
-# CT_FORCE_DOWNLOAD is not set
-CT_CONNECT_TIMEOUT=10
-CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
-# CT_ONLY_DOWNLOAD is not set
-# CT_USE_MIRROR is not set
-CT_VERIFY_DOWNLOAD_DIGEST=y
-CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
-# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
-# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
-# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
-CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
-# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
-
-#
-# Extracting
-#
-# CT_FORCE_EXTRACT is not set
-CT_OVERRIDE_CONFIG_GUESS_SUB=y
-# CT_ONLY_EXTRACT is not set
-CT_PATCH_BUNDLED=y
-# CT_PATCH_LOCAL is not set
-# CT_PATCH_BUNDLED_LOCAL is not set
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled"
-
-#
-# Build behavior
-#
-CT_PARALLEL_JOBS=0
-CT_LOAD=""
-CT_USE_PIPES=y
-CT_EXTRA_CFLAGS_FOR_BUILD=""
-CT_EXTRA_LDFLAGS_FOR_BUILD=""
-CT_EXTRA_CFLAGS_FOR_HOST=""
-CT_EXTRA_LDFLAGS_FOR_HOST=""
-# CT_CONFIG_SHELL_SH is not set
-# CT_CONFIG_SHELL_ASH is not set
-CT_CONFIG_SHELL_BASH=y
-# CT_CONFIG_SHELL_CUSTOM is not set
-CT_CONFIG_SHELL="${bash}"
-
-#
-# Logging
-#
-# CT_LOG_ERROR is not set
-# CT_LOG_WARN is not set
-# CT_LOG_INFO is not set
-# CT_LOG_EXTRA is not set
-CT_LOG_ALL=y
-# CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="ALL"
-# CT_LOG_SEE_TOOLS_WARN is not set
-CT_LOG_TO_FILE=y
-CT_LOG_FILE_COMPRESS=y
-
-#
-# Target options
-#
-# CT_ARCH_ALPHA is not set
-# CT_ARCH_ARC is not set
-# CT_ARCH_ARM is not set
-# CT_ARCH_AVR is not set
-# CT_ARCH_M68K is not set
-# CT_ARCH_MICROBLAZE is not set
-# CT_ARCH_MIPS is not set
-# CT_ARCH_MOXIE is not set
-# CT_ARCH_MSP430 is not set
-# CT_ARCH_NIOS2 is not set
-# CT_ARCH_POWERPC is not set
-CT_ARCH_RISCV=y
-# CT_ARCH_S390 is not set
-# CT_ARCH_SH is not set
-# CT_ARCH_SPARC is not set
-# CT_ARCH_X86 is not set
-# CT_ARCH_XTENSA is not set
-CT_ARCH="riscv"
-CT_ARCH_CHOICE_KSYM="RISCV"
-CT_ARCH_TUNE=""
-CT_ARCH_RISCV_SHOW=y
-
-#
-# Options for riscv
-#
-CT_ARCH_RISCV_PKG_KSYM=""
-CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
-CT_ARCH_SUFFIX=""
-# CT_OMIT_TARGET_VENDOR is not set
-
-#
-# Generic target options
-#
-# CT_MULTILIB is not set
-# CT_DEMULTILIB is not set
-CT_ARCH_SUPPORTS_BOTH_MMU=y
-CT_ARCH_USE_MMU=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_BITNESS=64
-# CT_ARCH_32 is not set
-CT_ARCH_64=y
-
-#
-# Target optimisations
-#
-CT_ARCH_SUPPORTS_WITH_ARCH=y
-CT_ARCH_SUPPORTS_WITH_ABI=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_ARCH="rv64gc"
-CT_ARCH_ABI=""
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-
-#
-# Toolchain options
-#
-
-#
-# General toolchain options
-#
-CT_FORCE_SYSROOT=y
-CT_USE_SYSROOT=y
-CT_SYSROOT_NAME="sysroot"
-CT_SYSROOT_DIR_PREFIX=""
-CT_WANTS_STATIC_LINK=y
-CT_WANTS_STATIC_LINK_CXX=y
-# CT_STATIC_TOOLCHAIN is not set
-CT_SHOW_CT_VERSION=y
-CT_TOOLCHAIN_PKGVERSION=""
-CT_TOOLCHAIN_BUGURL=""
-
-#
-# Tuple completion and aliasing
-#
-CT_TARGET_VENDOR="unknown"
-CT_TARGET_ALIAS_SED_EXPR=""
-CT_TARGET_ALIAS=""
-
-#
-# Toolchain type
-#
-# CT_NATIVE is not set
-CT_CROSS=y
-# CT_CROSS_NATIVE is not set
-# CT_CANADIAN is not set
-CT_TOOLCHAIN_TYPE="cross"
-
-#
-# Build system
-#
-CT_BUILD=""
-CT_BUILD_PREFIX=""
-CT_BUILD_SUFFIX=""
-
-#
-# Misc options
-#
-# CT_TOOLCHAIN_ENABLE_NLS is not set
-
-#
-# Operating System
-#
-CT_KERNEL_SUPPORTS_SHARED_LIBS=y
-# CT_KERNEL_BARE_METAL is not set
-CT_KERNEL_LINUX=y
-CT_KERNEL="linux"
-CT_KERNEL_CHOICE_KSYM="LINUX"
-CT_KERNEL_LINUX_SHOW=y
-
-#
-# Options for linux
-#
-CT_KERNEL_LINUX_PKG_KSYM="LINUX"
-CT_LINUX_DIR_NAME="linux"
-CT_LINUX_PKG_NAME="linux"
-CT_LINUX_SRC_RELEASE=y
-# CT_LINUX_SRC_DEVEL is not set
-# CT_LINUX_SRC_CUSTOM is not set
-CT_LINUX_PATCH_GLOBAL=y
-# CT_LINUX_PATCH_BUNDLED is not set
-# CT_LINUX_PATCH_LOCAL is not set
-# CT_LINUX_PATCH_BUNDLED_LOCAL is not set
-# CT_LINUX_PATCH_LOCAL_BUNDLED is not set
-# CT_LINUX_PATCH_NONE is not set
-CT_LINUX_PATCH_ORDER="global"
-CT_LINUX_V_4_20=y
-# CT_LINUX_V_4_19 is not set
-# CT_LINUX_V_4_18 is not set
-# CT_LINUX_V_4_17 is not set
-# CT_LINUX_V_4_16 is not set
-# CT_LINUX_V_4_15 is not set
-# CT_LINUX_V_4_14 is not set
-# CT_LINUX_V_4_13 is not set
-# CT_LINUX_V_4_12 is not set
-# CT_LINUX_V_4_11 is not set
-# CT_LINUX_V_4_10 is not set
-# CT_LINUX_V_4_9 is not set
-# CT_LINUX_V_4_4 is not set
-# CT_LINUX_V_4_1 is not set
-# CT_LINUX_V_3_16 is not set
-# CT_LINUX_V_3_13 is not set
-# CT_LINUX_V_3_12 is not set
-# CT_LINUX_V_3_10 is not set
-# CT_LINUX_V_3_4 is not set
-# CT_LINUX_V_3_2 is not set
-# CT_LINUX_NO_VERSIONS is not set
-CT_LINUX_VERSION="4.20.8"
-CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
-CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
-CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
-CT_LINUX_later_than_4_8=y
-CT_LINUX_4_8_or_later=y
-CT_LINUX_later_than_3_7=y
-CT_LINUX_3_7_or_later=y
-CT_LINUX_later_than_3_2=y
-CT_LINUX_3_2_or_later=y
-CT_LINUX_REQUIRE_3_2_or_later=y
-CT_KERNEL_LINUX_VERBOSITY_0=y
-# CT_KERNEL_LINUX_VERBOSITY_1 is not set
-# CT_KERNEL_LINUX_VERBOSITY_2 is not set
-CT_KERNEL_LINUX_VERBOSE_LEVEL=0
-CT_KERNEL_LINUX_INSTALL_CHECK=y
-CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# Binary utilities
-#
-CT_ARCH_BINFMT_ELF=y
-CT_BINUTILS_BINUTILS=y
-CT_BINUTILS="binutils"
-CT_BINUTILS_CHOICE_KSYM="BINUTILS"
-CT_BINUTILS_BINUTILS_SHOW=y
-
-#
-# Options for binutils
-#
-CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
-CT_BINUTILS_DIR_NAME="binutils"
-CT_BINUTILS_USE_GNU=y
-CT_BINUTILS_USE="BINUTILS"
-CT_BINUTILS_PKG_NAME="binutils"
-CT_BINUTILS_SRC_RELEASE=y
-# CT_BINUTILS_SRC_DEVEL is not set
-# CT_BINUTILS_SRC_CUSTOM is not set
-CT_BINUTILS_PATCH_GLOBAL=y
-# CT_BINUTILS_PATCH_BUNDLED is not set
-# CT_BINUTILS_PATCH_LOCAL is not set
-# CT_BINUTILS_PATCH_BUNDLED_LOCAL is not set
-# CT_BINUTILS_PATCH_LOCAL_BUNDLED is not set
-# CT_BINUTILS_PATCH_NONE is not set
-CT_BINUTILS_PATCH_ORDER="global"
-CT_BINUTILS_V_2_32=y
-# CT_BINUTILS_V_2_31 is not set
-# CT_BINUTILS_V_2_30 is not set
-# CT_BINUTILS_V_2_29 is not set
-# CT_BINUTILS_V_2_28 is not set
-# CT_BINUTILS_V_2_27 is not set
-# CT_BINUTILS_V_2_26 is not set
-# CT_BINUTILS_NO_VERSIONS is not set
-CT_BINUTILS_VERSION="2.32"
-CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
-CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
-CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
-CT_BINUTILS_later_than_2_30=y
-CT_BINUTILS_2_30_or_later=y
-CT_BINUTILS_later_than_2_27=y
-CT_BINUTILS_2_27_or_later=y
-CT_BINUTILS_later_than_2_25=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_REQUIRE_2_25_or_later=y
-CT_BINUTILS_later_than_2_23=y
-CT_BINUTILS_2_23_or_later=y
-
-#
-# GNU binutils
-#
-CT_BINUTILS_HAS_HASH_STYLE=y
-CT_BINUTILS_HAS_GOLD=y
-CT_BINUTILS_HAS_PLUGINS=y
-CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
-CT_BINUTILS_LINKER_LD=y
-CT_BINUTILS_LINKERS_LIST="ld"
-CT_BINUTILS_LINKER_DEFAULT="bfd"
-# CT_BINUTILS_PLUGINS is not set
-CT_BINUTILS_RELRO=m
-CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
-# CT_BINUTILS_FOR_TARGET is not set
-CT_ALL_BINUTILS_CHOICES="BINUTILS"
-
-#
-# C-library
-#
-CT_LIBC_GLIBC=y
-# CT_LIBC_MUSL is not set
-# CT_LIBC_UCLIBC is not set
-CT_LIBC="glibc"
-CT_LIBC_CHOICE_KSYM="GLIBC"
-CT_THREADS="nptl"
-CT_LIBC_GLIBC_SHOW=y
-
-#
-# Options for glibc
-#
-CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
-CT_GLIBC_DIR_NAME="glibc"
-CT_GLIBC_USE_GNU=y
-CT_GLIBC_USE="GLIBC"
-CT_GLIBC_PKG_NAME="glibc"
-CT_GLIBC_SRC_RELEASE=y
-# CT_GLIBC_SRC_DEVEL is not set
-# CT_GLIBC_SRC_CUSTOM is not set
-CT_GLIBC_PATCH_GLOBAL=y
-# CT_GLIBC_PATCH_BUNDLED is not set
-# CT_GLIBC_PATCH_LOCAL is not set
-# CT_GLIBC_PATCH_BUNDLED_LOCAL is not set
-# CT_GLIBC_PATCH_LOCAL_BUNDLED is not set
-# CT_GLIBC_PATCH_NONE is not set
-CT_GLIBC_PATCH_ORDER="global"
-CT_GLIBC_V_2_29=y
-# CT_GLIBC_NO_VERSIONS is not set
-CT_GLIBC_VERSION="2.29"
-CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
-CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
-CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
-CT_GLIBC_2_29_or_later=y
-CT_GLIBC_2_29_or_older=y
-CT_GLIBC_REQUIRE_2_29_or_later=y
-CT_GLIBC_later_than_2_27=y
-CT_GLIBC_2_27_or_later=y
-CT_GLIBC_later_than_2_26=y
-CT_GLIBC_2_26_or_later=y
-CT_GLIBC_later_than_2_25=y
-CT_GLIBC_2_25_or_later=y
-CT_GLIBC_later_than_2_24=y
-CT_GLIBC_2_24_or_later=y
-CT_GLIBC_later_than_2_23=y
-CT_GLIBC_2_23_or_later=y
-CT_GLIBC_later_than_2_20=y
-CT_GLIBC_2_20_or_later=y
-CT_GLIBC_later_than_2_17=y
-CT_GLIBC_2_17_or_later=y
-CT_GLIBC_later_than_2_14=y
-CT_GLIBC_2_14_or_later=y
-CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
-CT_GLIBC_DEP_BINUTILS=y
-CT_GLIBC_DEP_GCC=y
-CT_GLIBC_DEP_PYTHON=y
-CT_GLIBC_BUILD_SSP=y
-CT_GLIBC_HAS_LIBIDN_ADDON=y
-# CT_GLIBC_USE_LIBIDN_ADDON is not set
-CT_GLIBC_NO_SPARC_V8=y
-CT_GLIBC_HAS_OBSOLETE_RPC=y
-CT_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_GLIBC_CONFIGPARMS=""
-CT_GLIBC_EXTRA_CFLAGS=""
-CT_GLIBC_ENABLE_OBSOLETE_RPC=y
-# CT_GLIBC_ENABLE_FORTIFIED_BUILD is not set
-# CT_GLIBC_DISABLE_VERSIONING is not set
-CT_GLIBC_OLDEST_ABI=""
-CT_GLIBC_FORCE_UNWIND=y
-# CT_GLIBC_LOCALES is not set
-CT_GLIBC_KERNEL_VERSION_NONE=y
-# CT_GLIBC_KERNEL_VERSION_AS_HEADERS is not set
-# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_GLIBC_MIN_KERNEL=""
-CT_GLIBC_SSP_DEFAULT=y
-# CT_GLIBC_SSP_NO is not set
-# CT_GLIBC_SSP_YES is not set
-# CT_GLIBC_SSP_ALL is not set
-# CT_GLIBC_SSP_STRONG is not set
-# CT_GLIBC_ENABLE_WERROR is not set
-CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
-CT_LIBC_SUPPORT_THREADS_ANY=y
-CT_LIBC_SUPPORT_THREADS_NATIVE=y
-
-#
-# Common C library options
-#
-CT_THREADS_NATIVE=y
-# CT_CREATE_LDSO_CONF is not set
-CT_LIBC_XLDD=y
-
-#
-# C compiler
-#
-CT_CC_CORE_PASSES_NEEDED=y
-CT_CC_CORE_PASS_1_NEEDED=y
-CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
-CT_CC_GCC=y
-CT_CC="gcc"
-CT_CC_CHOICE_KSYM="GCC"
-CT_CC_GCC_SHOW=y
-
-#
-# Options for gcc
-#
-CT_CC_GCC_PKG_KSYM="GCC"
-CT_GCC_DIR_NAME="gcc"
-CT_GCC_USE_GNU=y
-# CT_GCC_USE_LINARO is not set
-CT_GCC_USE="GCC"
-CT_GCC_PKG_NAME="gcc"
-CT_GCC_SRC_RELEASE=y
-# CT_GCC_SRC_DEVEL is not set
-# CT_GCC_SRC_CUSTOM is not set
-CT_GCC_PATCH_GLOBAL=y
-# CT_GCC_PATCH_BUNDLED is not set
-# CT_GCC_PATCH_LOCAL is not set
-# CT_GCC_PATCH_BUNDLED_LOCAL is not set
-# CT_GCC_PATCH_LOCAL_BUNDLED is not set
-# CT_GCC_PATCH_NONE is not set
-CT_GCC_PATCH_ORDER="global"
-CT_GCC_V_8=y
-# CT_GCC_V_7 is not set
-# CT_GCC_NO_VERSIONS is not set
-CT_GCC_VERSION="8.3.0"
-CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
-CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
-CT_GCC_SIGNATURE_FORMAT=""
-CT_GCC_later_than_7=y
-CT_GCC_7_or_later=y
-CT_GCC_REQUIRE_7_or_later=y
-CT_GCC_later_than_6=y
-CT_GCC_6_or_later=y
-CT_GCC_later_than_5=y
-CT_GCC_5_or_later=y
-CT_GCC_REQUIRE_5_or_later=y
-CT_GCC_later_than_4_9=y
-CT_GCC_4_9_or_later=y
-CT_GCC_REQUIRE_4_9_or_later=y
-CT_GCC_later_than_4_8=y
-CT_GCC_4_8_or_later=y
-CT_CC_GCC_HAS_LIBMPX=y
-CT_CC_GCC_ENABLE_CXX_FLAGS=""
-CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_STATIC_LIBSTDCXX=y
-# CT_CC_GCC_SYSTEM_ZLIB is not set
-CT_CC_GCC_CONFIG_TLS=m
-
-#
-# Optimisation features
-#
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_USE_LTO=y
-
-#
-# Settings for libraries running on target
-#
-CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y
-# CT_CC_GCC_LIBMUDFLAP is not set
-# CT_CC_GCC_LIBGOMP is not set
-# CT_CC_GCC_LIBSSP is not set
-# CT_CC_GCC_LIBQUADMATH is not set
-# CT_CC_GCC_LIBSANITIZER is not set
-
-#
-# Misc. obscure options.
-#
-CT_CC_CXA_ATEXIT=y
-# CT_CC_GCC_DISABLE_PCH is not set
-CT_CC_GCC_SJLJ_EXCEPTIONS=m
-CT_CC_GCC_LDBL_128=m
-# CT_CC_GCC_BUILD_ID is not set
-CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y
-# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set
-# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set
-# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set
-CT_CC_GCC_LNK_HASH_STYLE=""
-CT_CC_GCC_DEC_FLOAT_AUTO=y
-# CT_CC_GCC_DEC_FLOAT_BID is not set
-# CT_CC_GCC_DEC_FLOAT_DPD is not set
-# CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_ALL_CC_CHOICES="GCC"
-
-#
-# Additional supported languages:
-#
-CT_CC_LANG_CXX=y
-# CT_CC_LANG_FORTRAN is not set
-# CT_CC_LANG_ADA is not set
-# CT_CC_LANG_OBJC is not set
-# CT_CC_LANG_OBJCXX is not set
-# CT_CC_LANG_GOLANG is not set
-CT_CC_LANG_OTHERS=""
-
-#
-# Debug facilities
-#
-# CT_DEBUG_DUMA is not set
-CT_DEBUG_GDB=y
-CT_DEBUG_GDB_PKG_KSYM="GDB"
-CT_GDB_DIR_NAME="gdb"
-CT_GDB_USE_GNU=y
-CT_GDB_USE="GDB"
-CT_GDB_PKG_NAME="gdb"
-CT_GDB_SRC_RELEASE=y
-# CT_GDB_SRC_DEVEL is not set
-# CT_GDB_SRC_CUSTOM is not set
-CT_GDB_PATCH_GLOBAL=y
-# CT_GDB_PATCH_BUNDLED is not set
-# CT_GDB_PATCH_LOCAL is not set
-# CT_GDB_PATCH_BUNDLED_LOCAL is not set
-# CT_GDB_PATCH_LOCAL_BUNDLED is not set
-# CT_GDB_PATCH_NONE is not set
-CT_GDB_PATCH_ORDER="global"
-CT_GDB_V_8_2=y
-# CT_GDB_V_8_1 is not set
-# CT_GDB_V_8_0 is not set
-# CT_GDB_NO_VERSIONS is not set
-CT_GDB_VERSION="8.2.1"
-CT_GDB_MIRRORS="$(CT_Mirrors GNU gdb) $(CT_Mirrors sourceware gdb/releases)"
-CT_GDB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_GDB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_GDB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
-CT_GDB_SIGNATURE_FORMAT=""
-CT_GDB_later_than_8_0=y
-CT_GDB_8_0_or_later=y
-CT_GDB_REQUIRE_8_0_or_later=y
-CT_GDB_later_than_7_12=y
-CT_GDB_7_12_or_later=y
-CT_GDB_later_than_7_2=y
-CT_GDB_7_2_or_later=y
-CT_GDB_later_than_7_0=y
-CT_GDB_7_0_or_later=y
-CT_GDB_CROSS=y
-# CT_GDB_CROSS_STATIC is not set
-# CT_GDB_CROSS_SIM is not set
-# CT_GDB_CROSS_PYTHON is not set
-CT_GDB_CROSS_EXTRA_CONFIG_ARRAY=""
-# CT_GDB_NATIVE is not set
-# CT_GDB_GDBSERVER is not set
-CT_GDB_HAS_PKGVERSION_BUGURL=y
-CT_GDB_HAS_PYTHON=y
-CT_GDB_INSTALL_GDBINIT=y
-CT_GDB_HAS_IPA_LIB=y
-# CT_DEBUG_LTRACE is not set
-# CT_DEBUG_STRACE is not set
-CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
-
-#
-# Companion libraries
-#
-# CT_COMPLIBS_CHECK is not set
-# CT_COMP_LIBS_CLOOG is not set
-CT_COMP_LIBS_EXPAT=y
-CT_COMP_LIBS_EXPAT_PKG_KSYM="EXPAT"
-CT_EXPAT_DIR_NAME="expat"
-CT_EXPAT_PKG_NAME="expat"
-CT_EXPAT_SRC_RELEASE=y
-# CT_EXPAT_SRC_DEVEL is not set
-# CT_EXPAT_SRC_CUSTOM is not set
-CT_EXPAT_PATCH_GLOBAL=y
-# CT_EXPAT_PATCH_BUNDLED is not set
-# CT_EXPAT_PATCH_LOCAL is not set
-# CT_EXPAT_PATCH_BUNDLED_LOCAL is not set
-# CT_EXPAT_PATCH_LOCAL_BUNDLED is not set
-# CT_EXPAT_PATCH_NONE is not set
-CT_EXPAT_PATCH_ORDER="global"
-CT_EXPAT_V_2_2=y
-# CT_EXPAT_NO_VERSIONS is not set
-CT_EXPAT_VERSION="2.2.6"
-CT_EXPAT_MIRRORS="http://downloads.sourceforge.net/project/expat/expat/${CT_EXPAT_VERSION}"
-CT_EXPAT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_EXPAT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_EXPAT_ARCHIVE_FORMATS=".tar.bz2"
-CT_EXPAT_SIGNATURE_FORMAT=""
-CT_COMP_LIBS_GETTEXT=y
-CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
-CT_GETTEXT_DIR_NAME="gettext"
-CT_GETTEXT_PKG_NAME="gettext"
-CT_GETTEXT_SRC_RELEASE=y
-# CT_GETTEXT_SRC_DEVEL is not set
-# CT_GETTEXT_SRC_CUSTOM is not set
-CT_GETTEXT_PATCH_GLOBAL=y
-# CT_GETTEXT_PATCH_BUNDLED is not set
-# CT_GETTEXT_PATCH_LOCAL is not set
-# CT_GETTEXT_PATCH_BUNDLED_LOCAL is not set
-# CT_GETTEXT_PATCH_LOCAL_BUNDLED is not set
-# CT_GETTEXT_PATCH_NONE is not set
-CT_GETTEXT_PATCH_ORDER="global"
-CT_GETTEXT_V_0_19_8_1=y
-# CT_GETTEXT_NO_VERSIONS is not set
-CT_GETTEXT_VERSION="0.19.8.1"
-CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
-CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
-CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
-CT_COMP_LIBS_GMP=y
-CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
-CT_GMP_DIR_NAME="gmp"
-CT_GMP_PKG_NAME="gmp"
-CT_GMP_SRC_RELEASE=y
-# CT_GMP_SRC_DEVEL is not set
-# CT_GMP_SRC_CUSTOM is not set
-CT_GMP_PATCH_GLOBAL=y
-# CT_GMP_PATCH_BUNDLED is not set
-# CT_GMP_PATCH_LOCAL is not set
-# CT_GMP_PATCH_BUNDLED_LOCAL is not set
-# CT_GMP_PATCH_LOCAL_BUNDLED is not set
-# CT_GMP_PATCH_NONE is not set
-CT_GMP_PATCH_ORDER="global"
-CT_GMP_V_6_1=y
-# CT_GMP_NO_VERSIONS is not set
-CT_GMP_VERSION="6.1.2"
-CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
-CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
-CT_GMP_SIGNATURE_FORMAT="packed/.sig"
-CT_GMP_later_than_5_1_0=y
-CT_GMP_5_1_0_or_later=y
-CT_GMP_later_than_5_0_0=y
-CT_GMP_5_0_0_or_later=y
-CT_GMP_REQUIRE_5_0_0_or_later=y
-CT_COMP_LIBS_ISL=y
-CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
-CT_ISL_DIR_NAME="isl"
-CT_ISL_PKG_NAME="isl"
-CT_ISL_SRC_RELEASE=y
-# CT_ISL_SRC_DEVEL is not set
-# CT_ISL_SRC_CUSTOM is not set
-CT_ISL_PATCH_GLOBAL=y
-# CT_ISL_PATCH_BUNDLED is not set
-# CT_ISL_PATCH_LOCAL is not set
-# CT_ISL_PATCH_BUNDLED_LOCAL is not set
-# CT_ISL_PATCH_LOCAL_BUNDLED is not set
-# CT_ISL_PATCH_NONE is not set
-CT_ISL_PATCH_ORDER="global"
-CT_ISL_V_0_20=y
-# CT_ISL_V_0_19 is not set
-# CT_ISL_V_0_18 is not set
-# CT_ISL_V_0_17 is not set
-# CT_ISL_V_0_16 is not set
-# CT_ISL_V_0_15 is not set
-# CT_ISL_NO_VERSIONS is not set
-CT_ISL_VERSION="0.20"
-CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
-CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
-CT_ISL_SIGNATURE_FORMAT=""
-CT_ISL_later_than_0_18=y
-CT_ISL_0_18_or_later=y
-CT_ISL_later_than_0_15=y
-CT_ISL_0_15_or_later=y
-CT_ISL_REQUIRE_0_15_or_later=y
-CT_ISL_later_than_0_14=y
-CT_ISL_0_14_or_later=y
-CT_ISL_REQUIRE_0_14_or_later=y
-CT_ISL_later_than_0_13=y
-CT_ISL_0_13_or_later=y
-CT_ISL_later_than_0_12=y
-CT_ISL_0_12_or_later=y
-CT_ISL_REQUIRE_0_12_or_later=y
-# CT_COMP_LIBS_LIBELF is not set
-CT_COMP_LIBS_LIBICONV=y
-CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
-CT_LIBICONV_DIR_NAME="libiconv"
-CT_LIBICONV_PKG_NAME="libiconv"
-CT_LIBICONV_SRC_RELEASE=y
-# CT_LIBICONV_SRC_DEVEL is not set
-# CT_LIBICONV_SRC_CUSTOM is not set
-CT_LIBICONV_PATCH_GLOBAL=y
-# CT_LIBICONV_PATCH_BUNDLED is not set
-# CT_LIBICONV_PATCH_LOCAL is not set
-# CT_LIBICONV_PATCH_BUNDLED_LOCAL is not set
-# CT_LIBICONV_PATCH_LOCAL_BUNDLED is not set
-# CT_LIBICONV_PATCH_NONE is not set
-CT_LIBICONV_PATCH_ORDER="global"
-CT_LIBICONV_V_1_15=y
-# CT_LIBICONV_NO_VERSIONS is not set
-CT_LIBICONV_VERSION="1.15"
-CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
-CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
-CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
-CT_COMP_LIBS_MPC=y
-CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
-CT_MPC_DIR_NAME="mpc"
-CT_MPC_PKG_NAME="mpc"
-CT_MPC_SRC_RELEASE=y
-# CT_MPC_SRC_DEVEL is not set
-# CT_MPC_SRC_CUSTOM is not set
-CT_MPC_PATCH_GLOBAL=y
-# CT_MPC_PATCH_BUNDLED is not set
-# CT_MPC_PATCH_LOCAL is not set
-# CT_MPC_PATCH_BUNDLED_LOCAL is not set
-# CT_MPC_PATCH_LOCAL_BUNDLED is not set
-# CT_MPC_PATCH_NONE is not set
-CT_MPC_PATCH_ORDER="global"
-CT_MPC_V_1_1=y
-# CT_MPC_V_1_0 is not set
-# CT_MPC_NO_VERSIONS is not set
-CT_MPC_VERSION="1.1.0"
-CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
-CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_MPC_ARCHIVE_FORMATS=".tar.gz"
-CT_MPC_SIGNATURE_FORMAT="packed/.sig"
-CT_MPC_1_1_0_or_later=y
-CT_MPC_1_1_0_or_older=y
-CT_COMP_LIBS_MPFR=y
-CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
-CT_MPFR_DIR_NAME="mpfr"
-CT_MPFR_PKG_NAME="mpfr"
-CT_MPFR_SRC_RELEASE=y
-# CT_MPFR_SRC_DEVEL is not set
-# CT_MPFR_SRC_CUSTOM is not set
-CT_MPFR_PATCH_GLOBAL=y
-# CT_MPFR_PATCH_BUNDLED is not set
-# CT_MPFR_PATCH_LOCAL is not set
-# CT_MPFR_PATCH_BUNDLED_LOCAL is not set
-# CT_MPFR_PATCH_LOCAL_BUNDLED is not set
-# CT_MPFR_PATCH_NONE is not set
-CT_MPFR_PATCH_ORDER="global"
-CT_MPFR_V_4_0=y
-# CT_MPFR_V_3_1 is not set
-# CT_MPFR_NO_VERSIONS is not set
-CT_MPFR_VERSION="4.0.2"
-CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
-CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
-CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
-CT_MPFR_later_than_4_0_0=y
-CT_MPFR_4_0_0_or_later=y
-CT_MPFR_later_than_3_0_0=y
-CT_MPFR_3_0_0_or_later=y
-CT_MPFR_REQUIRE_3_0_0_or_later=y
-CT_COMP_LIBS_NCURSES=y
-CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
-CT_NCURSES_DIR_NAME="ncurses"
-CT_NCURSES_PKG_NAME="ncurses"
-CT_NCURSES_SRC_RELEASE=y
-# CT_NCURSES_SRC_DEVEL is not set
-# CT_NCURSES_SRC_CUSTOM is not set
-CT_NCURSES_PATCH_GLOBAL=y
-# CT_NCURSES_PATCH_BUNDLED is not set
-# CT_NCURSES_PATCH_LOCAL is not set
-# CT_NCURSES_PATCH_BUNDLED_LOCAL is not set
-# CT_NCURSES_PATCH_LOCAL_BUNDLED is not set
-# CT_NCURSES_PATCH_NONE is not set
-CT_NCURSES_PATCH_ORDER="global"
-CT_NCURSES_V_6_1=y
-# CT_NCURSES_V_6_0 is not set
-# CT_NCURSES_NO_VERSIONS is not set
-CT_NCURSES_VERSION="6.1"
-CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
-CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
-CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
-# CT_NCURSES_NEW_ABI is not set
-CT_NCURSES_HOST_CONFIG_ARGS=""
-CT_NCURSES_HOST_DISABLE_DB=y
-CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
-CT_NCURSES_TARGET_CONFIG_ARGS=""
-# CT_NCURSES_TARGET_DISABLE_DB is not set
-CT_NCURSES_TARGET_FALLBACKS=""
-CT_COMP_LIBS_ZLIB=y
-CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
-CT_ZLIB_DIR_NAME="zlib"
-CT_ZLIB_PKG_NAME="zlib"
-CT_ZLIB_SRC_RELEASE=y
-# CT_ZLIB_SRC_DEVEL is not set
-# CT_ZLIB_SRC_CUSTOM is not set
-CT_ZLIB_PATCH_GLOBAL=y
-# CT_ZLIB_PATCH_BUNDLED is not set
-# CT_ZLIB_PATCH_LOCAL is not set
-# CT_ZLIB_PATCH_BUNDLED_LOCAL is not set
-# CT_ZLIB_PATCH_LOCAL_BUNDLED is not set
-# CT_ZLIB_PATCH_NONE is not set
-CT_ZLIB_PATCH_ORDER="global"
-CT_ZLIB_V_1_2_11=y
-# CT_ZLIB_NO_VERSIONS is not set
-CT_ZLIB_VERSION="1.2.11"
-CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
-CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
-CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
-CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
-CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
-CT_LIBICONV_NEEDED=y
-CT_GETTEXT_NEEDED=y
-CT_GMP_NEEDED=y
-CT_MPFR_NEEDED=y
-CT_ISL_NEEDED=y
-CT_MPC_NEEDED=y
-CT_EXPAT_NEEDED=y
-CT_NCURSES_NEEDED=y
-CT_ZLIB_NEEDED=y
-CT_LIBICONV=y
-CT_GETTEXT=y
-CT_GMP=y
-CT_MPFR=y
-CT_ISL=y
-CT_MPC=y
-CT_EXPAT=y
-CT_NCURSES=y
-CT_ZLIB=y
-
-#
-# Companion tools
-#
-# CT_COMP_TOOLS_FOR_HOST is not set
-# CT_COMP_TOOLS_AUTOCONF is not set
-# CT_COMP_TOOLS_AUTOMAKE is not set
-# CT_COMP_TOOLS_BISON is not set
-# CT_COMP_TOOLS_DTC is not set
-# CT_COMP_TOOLS_LIBTOOL is not set
-# CT_COMP_TOOLS_M4 is not set
-# CT_COMP_TOOLS_MAKE is not set
-CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
-
-#
-# Test suite
-#
-# CT_TEST_SUITE_GCC is not set
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-illumos/Dockerfile
new file mode 100644 (file)
index 0000000..2a0f6a3
--- /dev/null
@@ -0,0 +1,33 @@
+FROM ubuntu:18.04
+
+# Enable source repositories, which are disabled by default on Ubuntu >= 18.04
+RUN sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list
+
+COPY scripts/cross-apt-packages.sh /tmp/
+RUN bash /tmp/cross-apt-packages.sh
+
+# Required for cross-build gcc
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+      libgmp-dev \
+      libmpfr-dev \
+      libmpc-dev
+
+COPY scripts/illumos-toolchain.sh /tmp/
+
+RUN bash /tmp/illumos-toolchain.sh x86_64 sysroot
+RUN bash /tmp/illumos-toolchain.sh x86_64 binutils
+RUN bash /tmp/illumos-toolchain.sh x86_64 gcc
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV \
+    AR_x86_64_unknown_illumos=x86_64-illumos-ar \
+    CC_x86_64_unknown_illumos=x86_64-illumos-gcc \
+    CXX_x86_64_unknown_illumos=x86_64-illumos-g++
+
+ENV HOSTS=x86_64-unknown-illumos
+
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index c15b437e6d3157dea376b816c82172a449564a41..436215839f7dd1d94177f4622321cf9f9d8efbd6 100644 (file)
@@ -11,6 +11,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   sudo \
   gdb \
+  zlib1g-dev \
+  lib32z1-dev \
   xz-utils
 
 
index 377f07cef4e46e7444e7a21eea56d742e2eafa56..34a76f39668a727df3abf43ef3bb1e0691df42cb 100644 (file)
@@ -11,6 +11,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   sudo \
   gdb \
+  zlib1g-dev \
+  lib32z1-dev \
   xz-utils
 
 
diff --git a/src/ci/docker/scripts/illumos-toolchain.sh b/src/ci/docker/scripts/illumos-toolchain.sh
new file mode 100644 (file)
index 0000000..8cb5712
--- /dev/null
@@ -0,0 +1,177 @@
+#!/bin/bash
+
+set -o errexit
+set -o pipefail
+set -o xtrace
+
+ARCH="$1"
+PHASE="$2"
+
+JOBS="$(getconf _NPROCESSORS_ONLN)"
+
+case "$ARCH" in
+x86_64)
+        SYSROOT_MACH='i386'
+        ;;
+*)
+        printf 'ERROR: unknown architecture: %s\n' "$ARCH"
+        exit 1
+esac
+
+BUILD_TARGET="$ARCH-sun-solaris2.10"
+
+#
+# The illumos and the Solaris build both use the same GCC-level host triple,
+# though different versions of GCC are used and with different configure
+# options.  To ensure as little accidental cross-pollination as possible, we
+# build the illumos toolchain in a specific directory tree and just symlink the
+# expected tools into /usr/local/bin at the end.  We omit /usr/local/bin from
+# PATH here for similar reasons.
+#
+PREFIX="/opt/illumos/$ARCH"
+export PATH="$PREFIX/bin:/usr/bin:/bin:/usr/sbin:/sbin"
+
+#
+# NOTE: The compiler version selected here is more specific than might appear.
+# GCC 7.X releases do not appear to cross-compile correctly for Solaris
+# targets, at least insofar as they refuse to enable TLS in libstdc++.  When
+# changing the GCC version in future, one must carefully verify that TLS is
+# enabled in all of the static libraries we intend to include in output
+# binaries.
+#
+GCC_VERSION='8.4.0'
+GCC_SUM='e30a6e52d10e1f27ed55104ad233c30bd1e99cfb5ff98ab022dc941edd1b2dd4'
+GCC_BASE="gcc-$GCC_VERSION"
+GCC_TAR="gcc-$GCC_VERSION.tar.xz"
+GCC_URL="https://ftp.gnu.org/gnu/gcc/$GCC_BASE/$GCC_TAR"
+
+SYSROOT_VER='20181213-de6af22ae73b-v1'
+SYSROOT_SUM='ee792d956dfa6967453cebe9286a149143290d296a8ce4b8a91d36bea89f8112'
+SYSROOT_TAR="illumos-sysroot-$SYSROOT_MACH-$SYSROOT_VER.tar.gz"
+SYSROOT_URL='https://github.com/illumos/sysroot/releases/download/'
+SYSROOT_URL+="$SYSROOT_VER/$SYSROOT_TAR"
+SYSROOT_DIR="$PREFIX/sysroot"
+
+BINUTILS_VERSION='2.25.1'
+BINUTILS_SUM='b5b14added7d78a8d1ca70b5cb75fef57ce2197264f4f5835326b0df22ac9f22'
+BINUTILS_BASE="binutils-$BINUTILS_VERSION"
+BINUTILS_TAR="$BINUTILS_BASE.tar.bz2"
+BINUTILS_URL="https://ftp.gnu.org/gnu/binutils/$BINUTILS_TAR"
+
+
+download_file() {
+        local file="$1"
+        local url="$2"
+        local sum="$3"
+
+        while :; do
+                if [[ -f "$file" ]]; then
+                        if ! h="$(sha256sum "$file" | awk '{ print $1 }')"; then
+                                printf 'ERROR: reading hash\n' >&2
+                                exit 1
+                        fi
+
+                        if [[ "$h" == "$sum" ]]; then
+                                return 0
+                        fi
+
+                        printf 'WARNING: hash mismatch: %s != expected %s\n' \
+                            "$h" "$sum" >&2
+                        rm -f "$file"
+                fi
+
+                printf 'Downloading: %s\n' "$url"
+                if ! curl -f -L -o "$file" "$url"; then
+                        rm -f "$file"
+                        sleep 1
+                fi
+        done
+}
+
+
+case "$PHASE" in
+sysroot)
+        download_file "/tmp/$SYSROOT_TAR" "$SYSROOT_URL" "$SYSROOT_SUM"
+        mkdir -p "$SYSROOT_DIR"
+        cd "$SYSROOT_DIR"
+        tar -xzf "/tmp/$SYSROOT_TAR"
+        rm -f "/tmp/$SYSROOT_TAR"
+        ;;
+
+binutils)
+        download_file "/tmp/$BINUTILS_TAR" "$BINUTILS_URL" "$BINUTILS_SUM"
+        mkdir -p /ws/src/binutils
+        cd /ws/src/binutils
+        tar -xjf "/tmp/$BINUTILS_TAR"
+        rm -f "/tmp/$BINUTILS_TAR"
+
+        mkdir -p /ws/build/binutils
+        cd /ws/build/binutils
+        "/ws/src/binutils/$BINUTILS_BASE/configure" \
+            --prefix="$PREFIX" \
+            --target="$BUILD_TARGET" \
+            --program-prefix="$ARCH-illumos-" \
+            --with-sysroot="$SYSROOT_DIR"
+
+        make -j "$JOBS"
+
+        mkdir -p "$PREFIX"
+        make install
+
+        cd /
+        rm -rf /ws/src/binutils /ws/build/binutils
+        ;;
+
+gcc)
+        download_file "/tmp/$GCC_TAR" "$GCC_URL" "$GCC_SUM"
+        mkdir -p /ws/src/gcc
+        cd /ws/src/gcc
+        tar -xJf "/tmp/$GCC_TAR"
+        rm -f "/tmp/$GCC_TAR"
+
+        mkdir -p /ws/build/gcc
+        cd /ws/build/gcc
+        export CFLAGS='-fPIC'
+        export CXXFLAGS='-fPIC'
+        export CXXFLAGS_FOR_TARGET='-fPIC'
+        export CFLAGS_FOR_TARGET='-fPIC'
+        "/ws/src/gcc/$GCC_BASE/configure" \
+            --prefix="$PREFIX" \
+            --target="$BUILD_TARGET" \
+            --program-prefix="$ARCH-illumos-" \
+            --with-sysroot="$SYSROOT_DIR" \
+            --with-gnu-as \
+            --with-gnu-ld \
+            --disable-nls \
+            --disable-libgomp \
+            --disable-libquadmath \
+            --disable-libssp \
+            --disable-libvtv \
+            --disable-libcilkrts \
+            --disable-libada \
+            --disable-libsanitizer \
+            --disable-libquadmath-support \
+            --disable-shared \
+            --enable-tls
+
+        make -j "$JOBS"
+
+        mkdir -p "$PREFIX"
+        make install
+
+        #
+        # Link toolchain commands into /usr/local/bin so that cmake and others
+        # can find them:
+        #
+        (cd "$PREFIX/bin" && ls -U) | grep "^$ARCH-illumos-" |
+            xargs -t -I% ln -s "$PREFIX/bin/%" '/usr/local/bin/'
+
+        cd /
+        rm -rf /ws/src/gcc /ws/build/gcc
+        ;;
+
+*)
+        printf 'ERROR: unknown phase "%s"\n' "$PHASE" >&2
+        exit 100
+        ;;
+esac
diff --git a/src/ci/exec-with-shell.py b/src/ci/exec-with-shell.py
deleted file mode 100755 (executable)
index 26ce69e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-# A simple wrapper that forwards the arguments to bash, unless the
-# CI_OVERRIDE_SHELL environment variable is present: in that case the content
-# of that environment variable is used as the shell path.
-
-import os
-import sys
-import subprocess
-
-try:
-    shell = os.environ["CI_OVERRIDE_SHELL"]
-except KeyError:
-    shell = "bash"
-
-res = subprocess.call([shell] + sys.argv[1:])
-sys.exit(res)
index 502949d5e4c13dc5464b8102833baa2c917e7346..5573d87aa2e55c278399a8f0e0c1b6a12bf11600 100644 (file)
@@ -79,7 +79,6 @@ x--expand-yaml-anchors--remove:
     steps:
       - name: disable git crlf conversion
         run: git config --global core.autocrlf false
-        shell: bash
 
       - name: checkout the source code
         uses: actions/checkout@v1
@@ -231,18 +230,10 @@ on:
 
 defaults:
   run:
-    # While on Linux and macOS builders it just forwards the arguments to the
-    # system bash, this wrapper allows switching from the host's bash.exe to
-    # the one we install along with MSYS2 mid-build on Windows.
-    #
-    # Once the step to install MSYS2 is executed, the CI_OVERRIDE_SHELL
-    # environment variable is set pointing to our MSYS2's bash.exe. From that
-    # moment the host's bash.exe will not be called anymore.
-    #
-    # This is needed because we can't launch our own bash.exe from the host
-    # bash.exe, as that would load two different cygwin1.dll in memory, causing
-    # "cygwin heap mismatch" errors.
-    shell: python src/ci/exec-with-shell.py {0}
+    # On Linux, macOS, and Windows, use the system-provided bash as the default
+    # shell. (This should only make a difference on Windows, where the default
+    # shell is PowerShell.)
+    shell: bash
 
 jobs:
   pr:
@@ -341,6 +332,9 @@ jobs:
           - name: dist-powerpc64le-linux
             <<: *job-linux-xl
 
+          - name: dist-riscv64-linux
+            <<: *job-linux-xl
+
           - name: dist-s390x-linux
             <<: *job-linux-xl
 
@@ -353,6 +347,9 @@ jobs:
           - name: dist-x86_64-freebsd
             <<: *job-linux-xl
 
+          - name: dist-x86_64-illumos
+            <<: *job-linux-xl
+
           - name: dist-x86_64-linux
             <<: *job-linux-xl
 
@@ -614,6 +611,7 @@ jobs:
 
       - name: publish toolstate
         run: src/ci/publish_toolstate.sh
+        shell: bash
         env:
           TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
         <<: *step
index 3a0c965a67710ba45d3e66b5553b50ab83df5c2a..185d361582505224f9a223ca0a1d78ff14b79ae9 100755 (executable)
@@ -12,9 +12,6 @@ if isWindows; then
     mkdir -p "${msys2Path}/home/${USERNAME}"
     ciCommandAddPath "${msys2Path}/usr/bin"
 
-    echo "switching shell to use our own bash"
-    ciCommandSetEnv CI_OVERRIDE_SHELL "${msys2Path}/usr/bin/bash.exe"
-
     # Detect the native Python version installed on the agent. On GitHub
     # Actions, the C:\hostedtoolcache\windows\Python directory contains a
     # subdirectory for each installed Python version.
index eea674f2b84b9193d16322cff968cfb5b285d798..d16c2a9d0342c71f4512a02c4db1a1dab0d5abea 100644 (file)
@@ -150,6 +150,27 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
 [unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
 [issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
 
+### Adding your trait to the "Important Traits" dialog
+
+Rustdoc keeps a list of a few traits that are believed to be "fundamental" to a given type when
+implemented on it. These traits are intended to be the primary interface for their types, and are
+often the only thing available to be documented on their types. For this reason, Rustdoc will track
+when a given type implements one of these traits and call special attention to it when a function
+returns one of these types. This is the "Important Traits" dialog, visible as a circle-i button next
+to the function, which, when clicked, shows the dialog.
+
+In the standard library, the traits that qualify for inclusion are `Iterator`, `io::Read`, and
+`io::Write`. However, rather than being implemented as a hard-coded list, these traits have a
+special marker attribute on them: `#[doc(spotlight)]`. This means that you could apply this
+attribute to your own trait to include it in the "Important Traits" dialog in documentation.
+
+The `#[doc(spotlight)]` attribute currently requires the `#![feature(doc_spotlight)]` feature gate.
+For more information, see [its chapter in the Unstable Book][unstable-spotlight] and [its tracking
+issue][issue-spotlight].
+
+[unstable-spotlight]: ../unstable-book/language-features/doc-spotlight.html
+[issue-spotlight]: https://github.com/rust-lang/rust/issues/45040
+
 ### Exclude certain dependencies from documentation
 
 The standard library uses several dependencies which, in turn, use several types and traits from the
diff --git a/src/doc/unstable-book/src/language-features/doc-spotlight.md b/src/doc/unstable-book/src/language-features/doc-spotlight.md
new file mode 100644 (file)
index 0000000..8117755
--- /dev/null
@@ -0,0 +1,30 @@
+# `doc_spotlight`
+
+The tracking issue for this feature is: [#45040]
+
+The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute,
+to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]`
+attribute to a trait definition will make rustdoc print extra information for functions which return
+a type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and
+`io::Write` traits in the standard library.
+
+You can do this on your own traits, like this:
+
+```
+#![feature(doc_spotlight)]
+
+#[doc(spotlight)]
+pub trait MyTrait {}
+
+pub struct MyStruct;
+impl MyTrait for MyStruct {}
+
+/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`,
+/// without having to write that yourself!
+pub fn my_fn() -> MyStruct { MyStruct }
+```
+
+This feature was originally implemented in PR [#45039].
+
+[#45040]: https://github.com/rust-lang/rust/issues/45040
+[#45039]: https://github.com/rust-lang/rust/pull/45039
index bb9091a66594bda1665309811e38deab38fe4bd4..bf5748739d470422e0d110770812baf6bc9a1bbc 100644 (file)
@@ -151,7 +151,7 @@ fn clone_subtree<'a, K: Clone, V: Clone>(
                     let mut out_tree = BTreeMap { root: Some(node::Root::new_leaf()), length: 0 };
 
                     {
-                        let root = out_tree.root.as_mut().unwrap();
+                        let root = out_tree.root.as_mut().unwrap(); // unwrap succeeds because we just wrapped
                         let mut out_node = match root.as_mut().force() {
                             Leaf(leaf) => leaf,
                             Internal(_) => unreachable!(),
@@ -171,14 +171,10 @@ fn clone_subtree<'a, K: Clone, V: Clone>(
                 }
                 Internal(internal) => {
                     let mut out_tree = clone_subtree(internal.first_edge().descend());
-                    out_tree.ensure_root_is_owned();
 
                     {
-                        // Ideally we'd use the return of ensure_root_is_owned
-                        // instead of re-unwrapping here but unfortunately that
-                        // borrows all of out_tree and we need access to the
-                        // length below.
-                        let mut out_node = out_tree.root.as_mut().unwrap().push_level();
+                        let out_root = BTreeMap::ensure_is_owned(&mut out_tree.root);
+                        let mut out_node = out_root.push_level();
                         let mut in_edge = internal.first_edge();
                         while let Ok(kv) = in_edge.right_kv() {
                             let (k, v) = kv.into_kv();
@@ -212,7 +208,7 @@ fn clone_subtree<'a, K: Clone, V: Clone>(
             // Ord` constraint, which this method lacks.
             BTreeMap { root: None, length: 0 }
         } else {
-            clone_subtree(self.root.as_ref().unwrap().as_ref())
+            clone_subtree(self.root.as_ref().unwrap().as_ref()) // unwrap succeeds because not empty
         }
     }
 }
@@ -243,8 +239,8 @@ fn take(&mut self, key: &Q) -> Option<K> {
     }
 
     fn replace(&mut self, key: K) -> Option<K> {
-        self.ensure_root_is_owned();
-        match search::search_tree::<marker::Mut<'_>, K, (), K>(self.root.as_mut()?.as_mut(), &key) {
+        let root = Self::ensure_is_owned(&mut self.root);
+        match search::search_tree::<marker::Mut<'_>, K, (), K>(root.as_mut(), &key) {
             Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
             GoDown(handle) => {
                 VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData }
@@ -943,7 +939,6 @@ pub fn append(&mut self, other: &mut Self) {
 
         // Second, we build a tree from the sorted sequence in linear time.
         self.from_sorted_iter(iter);
-        self.fix_right_edge();
     }
 
     /// Constructs a double-ended iterator over a sub-range of elements in the map.
@@ -1058,8 +1053,8 @@ pub fn range_mut<T: ?Sized, R>(&mut self, range: R) -> RangeMut<'_, K, V>
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
         // FIXME(@porglezomp) Avoid allocating if we don't insert
-        self.ensure_root_is_owned();
-        match search::search_tree(self.root.as_mut().unwrap().as_mut(), &key) {
+        let root = Self::ensure_is_owned(&mut self.root);
+        match search::search_tree(root.as_mut(), &key) {
             Found(handle) => {
                 Occupied(OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData })
             }
@@ -1070,8 +1065,8 @@ pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
     }
 
     fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
-        self.ensure_root_is_owned();
-        let mut cur_node = self.root.as_mut().unwrap().as_mut().last_leaf_edge().into_node();
+        let root = Self::ensure_is_owned(&mut self.root);
+        let mut cur_node = root.as_mut().last_leaf_edge().into_node();
         // Iterate through all key-value pairs, pushing them into nodes at the right level.
         for (key, value) in iter {
             // Try to push key-value pair into the current leaf node.
@@ -1116,11 +1111,12 @@ fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
 
             self.length += 1;
         }
+        Self::fix_right_edge(root)
     }
 
-    fn fix_right_edge(&mut self) {
+    fn fix_right_edge(root: &mut node::Root<K, V>) {
         // Handle underfull nodes, start from the top.
-        let mut cur_node = self.root.as_mut().unwrap().as_mut();
+        let mut cur_node = root.as_mut();
         while let Internal(internal) = cur_node.force() {
             // Check if right-most child is underfull.
             let mut last_edge = internal.last_edge();
@@ -1179,16 +1175,17 @@ pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
         }
 
         let total_num = self.len();
+        let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty
 
         let mut right = Self::new();
-        let right_root = right.ensure_root_is_owned();
-        for _ in 0..(self.root.as_ref().unwrap().as_ref().height()) {
+        let right_root = Self::ensure_is_owned(&mut right.root);
+        for _ in 0..left_root.height() {
             right_root.push_level();
         }
 
         {
-            let mut left_node = self.root.as_mut().unwrap().as_mut();
-            let mut right_node = right.root.as_mut().unwrap().as_mut();
+            let mut left_node = left_root.as_mut();
+            let mut right_node = right_root.as_mut();
 
             loop {
                 let mut split_edge = match search::search_node(left_node, key) {
@@ -1214,12 +1211,10 @@ pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
             }
         }
 
-        self.fix_right_border();
-        right.fix_left_border();
+        left_root.fix_right_border();
+        right_root.fix_left_border();
 
-        if self.root.as_ref().unwrap().as_ref().height()
-            < right.root.as_ref().unwrap().as_ref().height()
-        {
+        if left_root.height() < right_root.height() {
             self.recalc_length();
             right.length = total_num - self.len();
         } else {
@@ -1301,69 +1296,6 @@ fn dfs<'a, K, V>(node: NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>)
 
         self.length = dfs(self.root.as_ref().unwrap().as_ref());
     }
-
-    /// Removes empty levels on the top.
-    fn fix_top(&mut self) {
-        loop {
-            {
-                let node = self.root.as_ref().unwrap().as_ref();
-                if node.height() == 0 || node.len() > 0 {
-                    break;
-                }
-            }
-            self.root.as_mut().unwrap().pop_level();
-        }
-    }
-
-    fn fix_right_border(&mut self) {
-        self.fix_top();
-
-        {
-            let mut cur_node = self.root.as_mut().unwrap().as_mut();
-
-            while let Internal(node) = cur_node.force() {
-                let mut last_kv = node.last_kv();
-
-                if last_kv.can_merge() {
-                    cur_node = last_kv.merge().descend();
-                } else {
-                    let right_len = last_kv.reborrow().right_edge().descend().len();
-                    // `MINLEN + 1` to avoid readjust if merge happens on the next level.
-                    if right_len < node::MIN_LEN + 1 {
-                        last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len);
-                    }
-                    cur_node = last_kv.right_edge().descend();
-                }
-            }
-        }
-
-        self.fix_top();
-    }
-
-    /// The symmetric clone of `fix_right_border`.
-    fn fix_left_border(&mut self) {
-        self.fix_top();
-
-        {
-            let mut cur_node = self.root.as_mut().unwrap().as_mut();
-
-            while let Internal(node) = cur_node.force() {
-                let mut first_kv = node.first_kv();
-
-                if first_kv.can_merge() {
-                    cur_node = first_kv.merge().descend();
-                } else {
-                    let left_len = first_kv.reborrow().left_edge().descend().len();
-                    if left_len < node::MIN_LEN + 1 {
-                        first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len);
-                    }
-                    cur_node = first_kv.left_edge().descend();
-                }
-            }
-        }
-
-        self.fix_top();
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1697,6 +1629,8 @@ pub struct DrainFilter<'a, K, V, F>
     pred: F,
     inner: DrainFilterInner<'a, K, V>,
 }
+/// Most of the implementation of DrainFilter, independent of the type
+/// of the predicate, thus also serving for BTreeSet::DrainFilter.
 pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> {
     length: &'a mut usize,
     cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
@@ -2319,9 +2253,9 @@ pub fn is_empty(&self) -> bool {
     }
 
     /// If the root node is the empty (non-allocated) root node, allocate our
-    /// own node.
-    fn ensure_root_is_owned(&mut self) -> &mut node::Root<K, V> {
-        self.root.get_or_insert_with(node::Root::new_leaf)
+    /// own node. Is an associated function to avoid borrowing the entire BTreeMap.
+    fn ensure_is_owned(root: &mut Option<node::Root<K, V>>) -> &mut node::Root<K, V> {
+        root.get_or_insert_with(node::Root::new_leaf)
     }
 }
 
@@ -2823,6 +2757,65 @@ fn remove_kv_tracking(
     }
 }
 
+impl<K, V> node::Root<K, V> {
+    /// Removes empty levels on the top, but keep an empty leaf if the entire tree is empty.
+    fn fix_top(&mut self) {
+        while self.height() > 0 && self.as_ref().len() == 0 {
+            self.pop_level();
+        }
+    }
+
+    fn fix_right_border(&mut self) {
+        self.fix_top();
+
+        {
+            let mut cur_node = self.as_mut();
+
+            while let Internal(node) = cur_node.force() {
+                let mut last_kv = node.last_kv();
+
+                if last_kv.can_merge() {
+                    cur_node = last_kv.merge().descend();
+                } else {
+                    let right_len = last_kv.reborrow().right_edge().descend().len();
+                    // `MINLEN + 1` to avoid readjust if merge happens on the next level.
+                    if right_len < node::MIN_LEN + 1 {
+                        last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len);
+                    }
+                    cur_node = last_kv.right_edge().descend();
+                }
+            }
+        }
+
+        self.fix_top();
+    }
+
+    /// The symmetric clone of `fix_right_border`.
+    fn fix_left_border(&mut self) {
+        self.fix_top();
+
+        {
+            let mut cur_node = self.as_mut();
+
+            while let Internal(node) = cur_node.force() {
+                let mut first_kv = node.first_kv();
+
+                if first_kv.can_merge() {
+                    cur_node = first_kv.merge().descend();
+                } else {
+                    let left_len = first_kv.reborrow().left_edge().descend().len();
+                    if left_len < node::MIN_LEN + 1 {
+                        first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len);
+                    }
+                    cur_node = first_kv.left_edge().descend();
+                }
+            }
+        }
+
+        self.fix_top();
+    }
+}
+
 enum UnderflowResult<'a, K, V> {
     AtRoot,
     Merged(Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::Edge>, bool, usize),
index 5478d822438b1ca3afd2f169f7d50422147dbd52..44f0e25bbd79888e770eaf1c98131a63750bbebf 100644 (file)
@@ -161,15 +161,16 @@ pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
 impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
     /// Moves the leaf edge handle to the next leaf edge and returns the key and value
     /// in between, while deallocating any node left behind.
-    /// Unsafe for three reasons:
+    /// Unsafe for two reasons:
     /// - The caller must ensure that the leaf edge is not the last one in the tree
     ///   and is not a handle previously resulting from counterpart `next_back_unchecked`.
-    /// - If the leaf edge is the last edge of a node, that node and possibly ancestors
+    /// - Further use of the updated leaf edge handle is very dangerous. In particular,
+    ///   if the leaf edge is the last edge of a node, that node and possibly ancestors
     ///   will be deallocated, while the reference to those nodes in the surviving ancestor
-    ///   is left dangling; thus further use of the leaf edge handle is dangerous.
-    ///   It is, however, safe to call this method again on the updated handle.
-    ///   if the two preconditions above hold.
-    /// - Using the updated handle may well invalidate the returned references.
+    ///   is left dangling.
+    ///   The only safe way to proceed with the updated handle is to compare it, drop it,
+    ///   call this method again subject to both preconditions listed in the first point,
+    ///   or call counterpart `next_back_unchecked` subject to its preconditions.
     pub unsafe fn next_unchecked(&mut self) -> (K, V) {
         unsafe {
             replace(self, |leaf_edge| {
@@ -183,15 +184,16 @@ pub unsafe fn next_unchecked(&mut self) -> (K, V) {
 
     /// Moves the leaf edge handle to the previous leaf edge and returns the key
     /// and value in between, while deallocating any node left behind.
-    /// Unsafe for three reasons:
+    /// Unsafe for two reasons:
     /// - The caller must ensure that the leaf edge is not the first one in the tree
     ///   and is not a handle previously resulting from counterpart `next_unchecked`.
-    /// - If the lead edge is the first edge of a node, that node and possibly ancestors
+    /// - Further use of the updated leaf edge handle is very dangerous. In particular,
+    ///   if the leaf edge is the first edge of a node, that node and possibly ancestors
     ///   will be deallocated, while the reference to those nodes in the surviving ancestor
-    ///   is left dangling; thus further use of the leaf edge handle is dangerous.
-    ///   It is, however, safe to call this method again on the updated handle.
-    ///   if the two preconditions above hold.
-    /// - Using the updated handle may well invalidate the returned references.
+    ///   is left dangling.
+    ///   The only safe way to proceed with the updated handle is to compare it, drop it,
+    ///   call this method again subject to both preconditions listed in the first point,
+    ///   or call counterpart `next_unchecked` subject to its preconditions.
     pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
         unsafe {
             replace(self, |leaf_edge| {
index a4b6cf12a23bd92671d30db8cdc4eaa8b293aeed..f7bd64608d63cd40205364fa604979009f141b21 100644 (file)
@@ -94,7 +94,8 @@ struct InternalNode<K, V> {
     data: LeafNode<K, V>,
 
     /// The pointers to the children of this node. `len + 1` of these are considered
-    /// initialized and valid.
+    /// initialized and valid. Although during the process of `into_iter` or `drop`,
+    /// some pointers are dangling while others still need to be traversed.
     edges: [MaybeUninit<BoxedNode<K, V>>; 2 * B],
 }
 
@@ -152,6 +153,11 @@ unsafe impl<K: Sync, V: Sync> Sync for Root<K, V> {}
 unsafe impl<K: Send, V: Send> Send for Root<K, V> {}
 
 impl<K, V> Root<K, V> {
+    /// Returns the number of levels below the root.
+    pub fn height(&self) -> usize {
+        self.height
+    }
+
     /// Returns a new owned tree, with its own root node that is initially empty.
     pub fn new_leaf() -> Self {
         Root { node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), height: 0 }
@@ -408,7 +414,7 @@ pub unsafe fn deallocate_and_ascend(
 
 impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
     /// Unsafely asserts to the compiler some static information about whether this
-    /// node is a `Leaf`.
+    /// node is a `Leaf` or an `Internal`.
     unsafe fn cast_unchecked<NewType>(&mut self) -> NodeRef<marker::Mut<'_>, K, V, NewType> {
         NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData }
     }
@@ -515,7 +521,7 @@ fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
 }
 
 impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
-    /// Adds a key/value pair the end of the node.
+    /// Adds a key/value pair to the end of the node.
     pub fn push(&mut self, key: K, val: V) {
         assert!(self.len() < CAPACITY);
 
@@ -602,8 +608,10 @@ pub fn push_front(&mut self, key: K, val: V, edge: Root<K, V>) {
 }
 
 impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
-    /// Removes a key/value pair from the end of this node. If this is an internal node,
-    /// also removes the edge that was to the right of that pair.
+    /// Removes a key/value pair from the end of this node and returns the pair.
+    /// If this is an internal node, also removes the edge that was to the right
+    /// of that pair and returns the orphaned node that this edge owned with its
+    /// parent erased.
     pub fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
         assert!(self.len() > 0);
 
@@ -883,7 +891,7 @@ fn correct_parent_link(mut self) {
     }
 
     /// Unsafely asserts to the compiler some static information about whether the underlying
-    /// node of this handle is a `Leaf`.
+    /// node of this handle is a `Leaf` or an `Internal`.
     unsafe fn cast_unchecked<NewType>(
         &mut self,
     ) -> Handle<NodeRef<marker::Mut<'_>, K, V, NewType>, marker::Edge> {
index d8959966fe5ad38a8f846780af27892a77fba621..530cb0c91b8e314894a198802100ad04873f792d 100644 (file)
@@ -22,7 +22,6 @@
 /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
 /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
 ///
-/// [`BTreeMap`]: struct.BTreeMap.html
 /// [`Ord`]: ../../std/cmp/trait.Ord.html
 /// [`Cell`]: ../../std/cell/struct.Cell.html
 /// [`RefCell`]: ../../std/cell/struct.RefCell.html
@@ -78,8 +77,7 @@ fn clone_from(&mut self, other: &Self) {
 /// This `struct` is created by the [`iter`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`iter`]: struct.BTreeSet.html#method.iter
+/// [`iter`]: BTreeSet::iter
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Iter<'a, T: 'a> {
     iter: Keys<'a, T, ()>,
@@ -97,8 +95,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`into_iter`]: struct.BTreeSet.html#method.into_iter
+/// [`into_iter`]: BTreeSet#method.into_iter
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct IntoIter<T> {
@@ -110,8 +107,7 @@ pub struct IntoIter<T> {
 /// This `struct` is created by the [`range`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`range`]: struct.BTreeSet.html#method.range
+/// [`range`]: BTreeSet::range
 #[derive(Debug)]
 #[stable(feature = "btree_range", since = "1.17.0")]
 pub struct Range<'a, T: 'a> {
@@ -194,8 +190,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`difference`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`difference`]: struct.BTreeSet.html#method.difference
+/// [`difference`]: BTreeSet::difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Difference<'a, T: 'a> {
     inner: DifferenceInner<'a, T>,
@@ -227,8 +222,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`symmetric_difference`] method on
 /// [`BTreeSet`]. See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference
+/// [`symmetric_difference`]: BTreeSet::symmetric_difference
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SymmetricDifference<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
@@ -244,8 +238,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`intersection`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`intersection`]: struct.BTreeSet.html#method.intersection
+/// [`intersection`]: BTreeSet::intersection
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Intersection<'a, T: 'a> {
     inner: IntersectionInner<'a, T>,
@@ -277,8 +270,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// This `struct` is created by the [`union`] method on [`BTreeSet`].
 /// See its documentation for more.
 ///
-/// [`BTreeSet`]: struct.BTreeSet.html
-/// [`union`]: struct.BTreeSet.html#method.union
+/// [`union`]: BTreeSet::union
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Union<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
index 2ec777ac85c6651699620d502a525cbca46b4045..87aee950082e9cac6e217db63c3f4a0e901e2147 100644 (file)
@@ -87,7 +87,6 @@
 #![feature(const_generic_impls_guard)]
 #![feature(const_generics)]
 #![feature(const_in_array_repeat_expressions)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(cow_is_borrowed)]
 #![feature(deque_range)]
 #![feature(dispatch_from_dyn)]
index 0053a54f20346cbc0408011e13ce4a89e5ba67f5..0cf250576f176b402408a96585da795e04edeefc 100644 (file)
@@ -573,7 +573,7 @@ pub fn into_raw(this: Self) -> *const T {
 
     /// Provides a raw pointer to the data.
     ///
-    /// The counts are not affected in way and the `Arc` is not consumed. The pointer is valid for
+    /// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
     /// as long as there are strong counts in the `Arc`.
     ///
     /// # Examples
index 0d1cc99df47c552e24bccd7b7e22bd63b7ddd352..252e04a410548e9ad9f9eb82ade14b6d1ddedd47 100644 (file)
@@ -69,14 +69,13 @@ unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawW
 
     // Wake by value, moving the Arc into the Wake::wake function
     unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
-        let waker: Arc<W> = unsafe { Arc::from_raw(waker as *const W) };
+        let waker = unsafe { Arc::from_raw(waker as *const W) };
         <W as Wake>::wake(waker);
     }
 
     // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
     unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
-        let waker: ManuallyDrop<Arc<W>> =
-            unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
+        let waker = unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
         <W as Wake>::wake_by_ref(&waker);
     }
 
index 8ff1ced53b071840f45edad5e3c3184804fb90c2..94f7ff5c1f7fe7864f6bf1fd0399ae7d8b568eef 100644 (file)
@@ -18,8 +18,9 @@
 //! [`TryFrom<T>`][`TryFrom`] rather than [`Into<U>`][`Into`] or [`TryInto<U>`][`TryInto`],
 //! as [`From`] and [`TryFrom`] provide greater flexibility and offer
 //! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a
-//! blanket implementation in the standard library. Only implement [`Into`] or [`TryInto`]
-//! when a conversion to a type outside the current crate is required.
+//! blanket implementation in the standard library. When targeting a version prior to Rust 1.41, it
+//! may be necessary to implement [`Into`] or [`TryInto`] directly when converting to a type
+//! outside the current crate.
 //!
 //! # Generic Implementations
 //!
@@ -298,8 +299,10 @@ pub trait Into<T>: Sized {
 /// because implementing `From` automatically provides one with an implementation of [`Into`]
 /// thanks to the blanket implementation in the standard library.
 ///
-/// Only implement [`Into`] if a conversion to a type outside the current crate is required.
-/// `From` cannot do these type of conversions because of Rust's orphaning rules.
+/// Only implement [`Into`] when targeting a version prior to Rust 1.41 and converting to a type
+/// outside the current crate.
+/// `From` was not able to do these types of conversions in earlier versions because of Rust's
+/// orphaning rules.
 /// See [`Into`] for more details.
 ///
 /// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function.
index 9c5dbb5e6f3567fd567be94c44d00038e638d58b..638e83c3b939da6d1996d73cf28fb337c353a242 100644 (file)
@@ -324,7 +324,7 @@ impl<'a> Arguments<'a> {
     #[doc(hidden)]
     #[inline]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
-    pub fn new_v1(pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
+    pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
         Arguments { pieces, fmt: None, args }
     }
 
@@ -338,7 +338,7 @@ pub fn new_v1(pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a
     #[inline]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
     pub fn new_v1_formatted(
-        pieces: &'a [&'a str],
+        pieces: &'a [&'static str],
         args: &'a [ArgumentV1<'a>],
         fmt: &'a [rt::v1::Argument],
     ) -> Arguments<'a> {
@@ -399,7 +399,7 @@ pub fn estimated_capacity(&self) -> usize {
 #[derive(Copy, Clone)]
 pub struct Arguments<'a> {
     // Format string pieces to print.
-    pieces: &'a [&'a str],
+    pieces: &'a [&'static str],
 
     // Placeholder specs, or `None` if all specs are default (as in "{}{}").
     fmt: Option<&'a [rt::v1::Argument]>,
@@ -409,6 +409,47 @@ pub struct Arguments<'a> {
     args: &'a [ArgumentV1<'a>],
 }
 
+impl<'a> Arguments<'a> {
+    /// Get the formatted string, if it has no arguments to be formatted.
+    ///
+    /// This can be used to avoid allocations in the most trivial case.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(fmt_as_str)]
+    ///
+    /// use core::fmt::Arguments;
+    ///
+    /// fn write_str(_: &str) { /* ... */ }
+    ///
+    /// fn write_fmt(args: &Arguments) {
+    ///     if let Some(s) = args.as_str() {
+    ///         write_str(s)
+    ///     } else {
+    ///         write_str(&args.to_string());
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// ```rust
+    /// #![feature(fmt_as_str)]
+    ///
+    /// assert_eq!(format_args!("hello").as_str(), Some("hello"));
+    /// assert_eq!(format_args!("").as_str(), Some(""));
+    /// assert_eq!(format_args!("{}", 1).as_str(), None);
+    /// ```
+    #[unstable(feature = "fmt_as_str", issue = "74442")]
+    #[inline]
+    pub fn as_str(&self) -> Option<&'static str> {
+        match (self.pieces, self.args) {
+            ([], []) => Some(""),
+            ([s], []) => Some(s),
+            _ => None,
+        }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Debug for Arguments<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
index abf461338d80a95137e6c1e8f2715ccfdd8e27a4..733ebdc0e97f236e3c88120c51431696e0df9aca 100644 (file)
@@ -24,6 +24,7 @@
 /// `.await` the value.
 ///
 /// [`Waker`]: ../task/struct.Waker.html
+#[doc(spotlight)]
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[lang = "future_trait"]
index 9ebcde79b633d3ea0492f5c90991a1d803e15e0f..3116815f5d655a03461d6cfbc19f19a056aa78ec 100644 (file)
@@ -45,7 +45,8 @@
 /// ```
 #[inline]
 #[stable(feature = "unreachable", since = "1.27.0")]
-pub unsafe fn unreachable_unchecked() -> ! {
+#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
+pub const unsafe fn unreachable_unchecked() -> ! {
     // SAFETY: the safety contract for `intrinsics::unreachable` must
     // be upheld by the caller.
     unsafe { intrinsics::unreachable() }
index 540a8cfb290b36deb3741e69a5635f46f6399bc9..049f51fb1035a3d2a3ea4496135eff651a85fa51 100644 (file)
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html).
+    #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
     pub fn unreachable() -> !;
 
     /// Informs the optimizer that a condition is always true.
     ///
     /// // use `u32::from_ne_bytes` instead
     /// let num = u32::from_ne_bytes(raw_bytes);
-    /// // or use `u32::from_le_bytes` or `u32::from_ge_bytes` to specify the endianness
+    /// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness
     /// let num = u32::from_le_bytes(raw_bytes);
     /// assert_eq!(num, 0x12345678);
     /// let num = u32::from_be_bytes(raw_bytes);
     /// The to-be-stabilized version of this intrinsic is
     /// [`std::mem::variant_count`](../../std/mem/fn.variant_count.html)
     #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
-    #[cfg(not(bootstrap))]
     pub fn variant_count<T>() -> usize;
 
     /// Rust's "try catch" construct which invokes the function pointer `try_fn`
     /// generation.
     #[cfg(not(bootstrap))]
     #[lang = "count_code_region"]
-    pub fn count_code_region(index: u32, start_byte_pos: u32, end_byte_pos: u32);
+    pub fn count_code_region(
+        function_source_hash: u64,
+        index: u32,
+        start_byte_pos: u32,
+        end_byte_pos: u32,
+    );
 
     /// Internal marker for code coverage expressions, injected into the MIR when the
     /// "instrument-coverage" option is enabled. This intrinsic is not converted into a
     /// This marker identifies a code region and two other counters or counter expressions
     /// whose sum is the number of times the code region was executed.
     #[cfg(not(bootstrap))]
+    #[lang = "coverage_counter_add"]
     pub fn coverage_counter_add(
         index: u32,
         left_index: u32,
@@ -1981,6 +1987,7 @@ pub fn coverage_counter_add(
     /// whose difference is the number of times the code region was executed.
     /// (See `coverage_counter_add` for more information.)
     #[cfg(not(bootstrap))]
+    #[lang = "coverage_counter_subtract"]
     pub fn coverage_counter_subtract(
         index: u32,
         left_index: u32,
@@ -1992,17 +1999,14 @@ pub fn coverage_counter_subtract(
     /// This marker identifies a code region to be added to the "coverage map" to indicate source
     /// code that can never be reached.
     /// (See `coverage_counter_add` for more information.)
-    #[cfg(not(bootstrap))]
     pub fn coverage_unreachable(start_byte_pos: u32, end_byte_pos: u32);
 
     /// See documentation of `<*const T>::guaranteed_eq` for details.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
-    #[cfg(not(bootstrap))]
     pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
 
     /// See documentation of `<*const T>::guaranteed_ne` for details.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
-    #[cfg(not(bootstrap))]
     pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
 }
 
index 080b70c6368b286bf80f5636300001df18c2b4d0..9b528cdbe30c4203c12aff07e1f66638b71b746b 100644 (file)
 //! ```
 //!
 //! An iterator has a method, [`next`], which when called, returns an
-//! [`Option`]`<Item>`. [`next`] will return `Some(Item)` as long as there
+//! [`Option`]`<Item>`. [`next`] will return [`Some(Item)`] as long as there
 //! are elements, and once they've all been exhausted, will return `None` to
 //! indicate that iteration is finished. Individual iterators may choose to
 //! resume iteration, and so calling [`next`] again may or may not eventually
-//! start returning `Some(Item)` again at some point (for example, see [`TryIter`]).
+//! start returning [`Some(Item)`] again at some point (for example, see [`TryIter`]).
 //!
 //! [`Iterator`]'s full definition includes a number of other methods as well,
 //! but they are default methods, built on top of [`next`], and so you get
@@ -53,9 +53,9 @@
 //! more complex forms of processing. See the [Adapters](#adapters) section
 //! below for more details.
 //!
+//! [`Some(Item)`]: Some
 //! [`Iterator`]: trait.Iterator.html
 //! [`next`]: trait.Iterator.html#tymethod.next
-//! [`Option`]: ../../std/option/enum.Option.html
 //! [`TryIter`]: ../../std/sync/mpsc/struct.TryIter.html
 //!
 //! # The three forms of iteration
@@ -72,9 +72,9 @@
 //! # Implementing Iterator
 //!
 //! Creating an iterator of your own involves two steps: creating a `struct` to
-//! hold the iterator's state, and then `impl`ementing [`Iterator`] for that
-//! `struct`. This is why there are so many `struct`s in this module: there is
-//! one for each iterator and iterator adapter.
+//! hold the iterator's state, and then implementing [`Iterator`] for that `struct`.
+//! This is why there are so many `struct`s in this module: there is one for
+//! each iterator and iterator adapter.
 //!
 //! Let's make an iterator named `Counter` which counts from `1` to `5`:
 //!
index 55f30794af6522045fd9d51998a73c838373b0ed..494c75174ff831733c7bc312645229c4e1ea5541 100644 (file)
@@ -9,9 +9,9 @@
 /// [`FromIterator`] this trait should rarely be called directly and instead
 /// interacted with through [`Iterator::sum`].
 ///
-/// [`sum`]: ../../std/iter/trait.Sum.html#tymethod.sum
-/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html
-/// [`Iterator::sum`]: ../../std/iter/trait.Iterator.html#method.sum
+/// [`sum`]: #tymethod.sum
+/// [`FromIterator`]: crate::iter::FromIterator
+/// [`Iterator::sum`]: crate::iter::Iterator::sum
 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
 pub trait Sum<A = Self>: Sized {
     /// Method which takes an iterator and generates `Self` from the elements by
@@ -28,9 +28,9 @@ pub trait Sum<A = Self>: Sized {
 /// [`FromIterator`] this trait should rarely be called directly and instead
 /// interacted with through [`Iterator::product`].
 ///
-/// [`product`]: ../../std/iter/trait.Product.html#tymethod.product
-/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html
-/// [`Iterator::product`]: ../../std/iter/trait.Iterator.html#method.product
+/// [`product`]: #tymethod.product
+/// [`FromIterator`]: crate::iter::FromIterator
+/// [`Iterator::product`]: crate::iter::Iterator::product
 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
 pub trait Product<A = Self>: Sized {
     /// Method which takes an iterator and generates `Self` from the elements by
index f6329c6c593ed778a52f9b20b5df28a0a2b54ed3..851a1e49a493b6d2d464ce5d07f43db52d5f934b 100644 (file)
@@ -106,8 +106,7 @@ pub trait DoubleEndedIterator: Iterator {
     /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
     /// iterator.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth
+    /// [`nth`]: crate::iter::Iterator::nth
     ///
     /// # Examples
     ///
@@ -274,8 +273,7 @@ fn rfold<B, F>(mut self, init: B, mut f: F) -> B
     /// argument is a double reference. You can see this effect in the
     /// examples below, with `&&x`.
     ///
-    /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`Some(element)`]: Some
     ///
     /// # Examples
     ///
index ce4be973140e58fa8a182daad5acbc350e339f38..b8faeb488e72d3cf776f324498c170d1cc6f319d 100644 (file)
@@ -92,6 +92,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
     label = "`{Self}` is not an iterator",
     message = "`{Self}` is not an iterator"
 )]
+#[doc(spotlight)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub trait Iterator {
     /// The type of the elements being iterated over.
@@ -105,8 +106,7 @@ pub trait Iterator {
     /// again may or may not eventually start returning [`Some(Item)`] again at some
     /// point.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`Some(Item)`]: ../../std/option/enum.Option.html#variant.Some
+    /// [`Some(Item)`]: Some
     ///
     /// # Examples
     ///
@@ -159,9 +159,7 @@ pub trait Iterator {
     /// The default implementation returns `(0, `[`None`]`)` which is correct for any
     /// iterator.
     ///
-    /// [`usize`]: ../../std/primitive.usize.html
-    /// [`Option`]: ../../std/option/enum.Option.html
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`usize`]: type@usize
     ///
     /// # Examples
     ///
@@ -213,8 +211,6 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     /// called at least once even if the iterator does not have any elements.
     ///
     /// [`next`]: #tymethod.next
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
     ///
     /// # Overflow Behavior
     ///
@@ -228,7 +224,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     /// This function might panic if the iterator has more than [`usize::MAX`]
     /// elements.
     ///
-    /// [`usize::MAX`]: ../../std/usize/constant.MAX.html
+    /// [`usize::MAX`]: crate::usize::MAX
     ///
     /// # Examples
     ///
@@ -262,8 +258,6 @@ fn add1<T>(count: usize, _: T) -> usize {
     /// doing so, it keeps track of the current element. After [`None`] is
     /// returned, `last()` will then return the last element it saw.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -302,8 +296,6 @@ fn some<T>(_: Option<T>, x: T) -> Option<T> {
     /// `nth()` will return [`None`] if `n` is greater than or equal to the length of the
     /// iterator.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -536,9 +528,8 @@ fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter>
     /// assert_eq!((2, 'o'), zipper[2]);
     /// ```
     ///
-    /// [`enumerate`]: trait.Iterator.html#method.enumerate
-    /// [`next`]: ../../std/iter/trait.Iterator.html#tymethod.next
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`enumerate`]: #method.enumerate
+    /// [`next`]: #tymethod.next
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
@@ -567,7 +558,7 @@ fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
     /// more idiomatic to use [`for`] than `map()`.
     ///
     /// [`for`]: ../../book/ch03-05-control-flow.html#looping-through-a-collection-with-for
-    /// [`FnMut`]: ../../std/ops/trait.FnMut.html
+    /// [`FnMut`]: crate::ops::FnMut
     ///
     /// # Examples
     ///
@@ -755,12 +746,11 @@ fn filter<P>(self, predicate: P) -> Filter<Self, P>
     /// Basic usage:
     ///
     /// ```
-    /// let a = ["1", "lol", "3", "NaN", "5"];
+    /// let a = ["1", "two", "NaN", "four", "5"];
     ///
     /// let mut iter = a.iter().filter_map(|s| s.parse().ok());
     ///
     /// assert_eq!(iter.next(), Some(1));
-    /// assert_eq!(iter.next(), Some(3));
     /// assert_eq!(iter.next(), Some(5));
     /// assert_eq!(iter.next(), None);
     /// ```
@@ -768,17 +758,14 @@ fn filter<P>(self, predicate: P) -> Filter<Self, P>
     /// Here's the same example, but with [`filter`] and [`map`]:
     ///
     /// ```
-    /// let a = ["1", "lol", "3", "NaN", "5"];
+    /// let a = ["1", "two", "NaN", "four", "5"];
     /// let mut iter = a.iter().map(|s| s.parse()).filter(|s| s.is_ok()).map(|s| s.unwrap());
     /// assert_eq!(iter.next(), Some(1));
-    /// assert_eq!(iter.next(), Some(3));
     /// assert_eq!(iter.next(), Some(5));
     /// assert_eq!(iter.next(), None);
     /// ```
     ///
-    /// [`Option<T>`]: ../../std/option/enum.Option.html
-    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`Option<T>`]: Option
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
@@ -811,8 +798,8 @@ fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
     /// The returned iterator might panic if the to-be-returned index would
     /// overflow a [`usize`].
     ///
-    /// [`usize::MAX`]: ../../std/usize/constant.MAX.html
-    /// [`usize`]: ../../std/primitive.usize.html
+    /// [`usize`]: type@usize
+    /// [`usize::MAX`]: crate::usize::MAX
     /// [`zip`]: #method.zip
     ///
     /// # Examples
@@ -848,8 +835,8 @@ fn enumerate(self) -> Enumerate<Self>
     /// anything other than fetching the next value) of the [`next`] method
     /// will occur.
     ///
-    /// [`peek`]: struct.Peekable.html#method.peek
-    /// [`next`]: ../../std/iter/trait.Iterator.html#tymethod.next
+    /// [`peek`]: crate::iter::Peekable::peek
+    /// [`next`]: #tymethod.next
     ///
     /// # Examples
     ///
@@ -1115,8 +1102,6 @@ fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
     /// It is also not specified what this iterator returns after the first` None` is returned.
     /// If you need fused iterator, use [`fuse`].
     ///
-    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
     /// [`fuse`]: #method.fuse
     #[inline]
     #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
@@ -1215,8 +1200,6 @@ fn take(self, n: usize) -> Take<Self>
     /// iterator and the return value from the closure, an [`Option`], is
     /// yielded by the iterator.
     ///
-    /// [`Option`]: ../../std/option/enum.Option.html
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -1365,8 +1348,7 @@ fn flatten(self) -> Flatten<Self>
     /// [`Some(T)`] again. `fuse()` adapts an iterator, ensuring that after a
     /// [`None`] is given, it will always return [`None`] forever.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`Some(T)`]: ../../std/option/enum.Option.html#variant.Some
+    /// [`Some(T)`]: Some
     ///
     /// # Examples
     ///
@@ -1657,10 +1639,9 @@ fn by_ref(&mut self) -> &mut Self
     /// assert_eq!(Ok(vec![1, 3]), result);
     /// ```
     ///
-    /// [`iter`]: ../../std/iter/trait.Iterator.html#tymethod.next
+    /// [`iter`]: #tymethod.next
     /// [`String`]: ../../std/string/struct.String.html
-    /// [`char`]: ../../std/primitive.char.html
-    /// [`Result`]: ../../std/result/enum.Result.html
+    /// [`char`]: type@char
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"]
@@ -2183,8 +2164,7 @@ fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(),
     /// argument is a double reference. You can see this effect in the
     /// examples below, with `&&x`.
     ///
-    /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`Some(element)`]: Some
     ///
     /// # Examples
     ///
@@ -2330,9 +2310,8 @@ fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result<T, R::E
     /// This function might panic if the iterator has more than `usize::MAX`
     /// non-matching elements.
     ///
-    /// [`Some(index)`]: ../../std/option/enum.Option.html#variant.Some
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    /// [`usize::MAX`]: ../../std/usize/constant.MAX.html
+    /// [`Some(index)`]: Some
+    /// [`usize::MAX`]: crate::usize::MAX
     ///
     /// # Examples
     ///
@@ -2393,8 +2372,7 @@ fn check<T>(
     /// `rposition()` is short-circuiting; in other words, it will stop
     /// processing as soon as it finds a `true`.
     ///
-    /// [`Some(index)`]: ../../std/option/enum.Option.html#variant.Some
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`Some(index)`]: Some
     ///
     /// # Examples
     ///
@@ -2448,8 +2426,6 @@ fn check<T>(
     /// If several elements are equally maximum, the last element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -2476,8 +2452,6 @@ fn max(self) -> Option<Self::Item>
     /// If several elements are equally minimum, the first element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -2505,8 +2479,6 @@ fn min(self) -> Option<Self::Item>
     /// If several elements are equally maximum, the last element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2540,8 +2512,6 @@ fn compare<T, B: Ord>((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering {
     /// If several elements are equally maximum, the last element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2569,8 +2539,6 @@ fn fold<T>(mut compare: impl FnMut(&T, &T) -> Ordering) -> impl FnMut(T, T) -> T
     /// If several elements are equally minimum, the first element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2604,8 +2572,6 @@ fn compare<T, B: Ord>((x_p, _): &(B, T), (y_p, _): &(B, T)) -> Ordering {
     /// If several elements are equally minimum, the first element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2746,7 +2712,7 @@ fn copied<'a, T: 'a>(self) -> Copied<Self>
     /// This is useful when you have an iterator over `&T`, but you need an
     /// iterator over `T`.
     ///
-    /// [`clone`]: ../../std/clone/trait.Clone.html#tymethod.clone
+    /// [`clone`]: crate::clone::Clone::clone
     ///
     /// # Examples
     ///
@@ -2778,8 +2744,6 @@ fn cloned<'a, T: 'a>(self) -> Cloned<Self>
     /// from the beginning. After iterating again, it will start at the
     /// beginning again. And again. And again. Forever.
     ///
-    /// [`None`]: ../../std/option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -3232,7 +3196,7 @@ fn is_sorted(self) -> bool
     /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b)));
     /// ```
     ///
-    /// [`is_sorted`]: trait.Iterator.html#method.is_sorted
+    /// [`is_sorted`]: #method.is_sorted
     #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
     fn is_sorted_by<F>(mut self, mut compare: F) -> bool
     where
@@ -3261,7 +3225,7 @@ fn is_sorted_by<F>(mut self, mut compare: F) -> bool
     /// the elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see
     /// its documentation for more information.
     ///
-    /// [`is_sorted`]: trait.Iterator.html#method.is_sorted
+    /// [`is_sorted`]: #method.is_sorted
     ///
     /// # Examples
     ///
index a9ba3908c38982a1e4014e0bf6efb09e4c068456..3c893c039923ead483300501fbf4d8046b60f2e3 100644 (file)
@@ -9,9 +9,8 @@
 /// on the iterator. If the iterator is already fused, the additional [`Fuse`]
 /// wrapper will be a no-op with no performance penalty.
 ///
-/// [`None`]: ../../std/option/enum.Option.html#variant.None
-/// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse
-/// [`Fuse`]: ../../std/iter/struct.Fuse.html
+/// [`Iterator::fuse`]: crate::iter::Iterator::fuse
+/// [`Fuse`]: crate::iter::Fuse
 #[stable(feature = "fused", since = "1.26.0")]
 #[rustc_unsafe_specialization_marker]
 pub trait FusedIterator: Iterator {}
@@ -35,9 +34,8 @@ impl<I: FusedIterator + ?Sized> FusedIterator for &mut I {}
 /// This trait must only be implemented when the contract is upheld.
 /// Consumers of this trait must inspect [`.size_hint`]’s upper bound.
 ///
-/// [`None`]: ../../std/option/enum.Option.html#variant.None
-/// [`usize::MAX`]: ../../std/usize/constant.MAX.html
-/// [`.size_hint`]: ../../std/iter/trait.Iterator.html#method.size_hint
+/// [`usize::MAX`]: crate::usize::MAX
+/// [`.size_hint`]: crate::iter::Iterator::size_hint
 #[unstable(feature = "trusted_len", issue = "37572")]
 #[rustc_unsafe_specialization_marker]
 pub unsafe trait TrustedLen: Iterator {}
diff --git a/src/libcore/lazy.rs b/src/libcore/lazy.rs
new file mode 100644 (file)
index 0000000..5cf7217
--- /dev/null
@@ -0,0 +1,379 @@
+//! Lazy values and one-time initialization of static data.
+
+use crate::cell::{Cell, UnsafeCell};
+use crate::fmt;
+use crate::mem;
+use crate::ops::Deref;
+
+/// A cell which can be written to only once.
+///
+/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value.
+/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::lazy::OnceCell;
+///
+/// let cell = OnceCell::new();
+/// assert!(cell.get().is_none());
+///
+/// let value: &String = cell.get_or_init(|| {
+///     "Hello, World!".to_string()
+/// });
+/// assert_eq!(value, "Hello, World!");
+/// assert!(cell.get().is_some());
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct OnceCell<T> {
+    // Invariant: written to at most once.
+    inner: UnsafeCell<Option<T>>,
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> Default for OnceCell<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.get() {
+            Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
+            None => f.write_str("OnceCell(Uninit)"),
+        }
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Clone> Clone for OnceCell<T> {
+    fn clone(&self) -> OnceCell<T> {
+        let res = OnceCell::new();
+        if let Some(value) = self.get() {
+            match res.set(value.clone()) {
+                Ok(()) => (),
+                Err(_) => unreachable!(),
+            }
+        }
+        res
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: PartialEq> PartialEq for OnceCell<T> {
+    fn eq(&self, other: &Self) -> bool {
+        self.get() == other.get()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Eq> Eq for OnceCell<T> {}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> From<T> for OnceCell<T> {
+    fn from(value: T) -> Self {
+        OnceCell { inner: UnsafeCell::new(Some(value)) }
+    }
+}
+
+impl<T> OnceCell<T> {
+    /// Creates a new empty cell.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new() -> OnceCell<T> {
+        OnceCell { inner: UnsafeCell::new(None) }
+    }
+
+    /// Gets the reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get(&self) -> Option<&T> {
+        // Safety: Safe due to `inner`'s invariant
+        unsafe { &*self.inner.get() }.as_ref()
+    }
+
+    /// Gets the mutable reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_mut(&mut self) -> Option<&mut T> {
+        // Safety: Safe because we have unique access
+        unsafe { &mut *self.inner.get() }.as_mut()
+    }
+
+    /// Sets the contents of the cell to `value`.
+    ///
+    /// # Errors
+    ///
+    /// This method returns `Ok(())` if the cell was empty and `Err(value)` if
+    /// it was full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell = OnceCell::new();
+    /// assert!(cell.get().is_none());
+    ///
+    /// assert_eq!(cell.set(92), Ok(()));
+    /// assert_eq!(cell.set(62), Err(62));
+    ///
+    /// assert!(cell.get().is_some());
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn set(&self, value: T) -> Result<(), T> {
+        // Safety: Safe because we cannot have overlapping mutable borrows
+        let slot = unsafe { &*self.inner.get() };
+        if slot.is_some() {
+            return Err(value);
+        }
+
+        // Safety: This is the only place where we set the slot, no races
+        // due to reentrancy/concurrency are possible, and we've
+        // checked that slot is currently `None`, so this write
+        // maintains the `inner`'s invariant.
+        let slot = unsafe { &mut *self.inner.get() };
+        *slot = Some(value);
+        Ok(())
+    }
+
+    /// Gets the contents of the cell, initializing it with `f`
+    /// if the cell was empty.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. Doing
+    /// so results in a panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell = OnceCell::new();
+    /// let value = cell.get_or_init(|| 92);
+    /// assert_eq!(value, &92);
+    /// let value = cell.get_or_init(|| unreachable!());
+    /// assert_eq!(value, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_init<F>(&self, f: F) -> &T
+    where
+        F: FnOnce() -> T,
+    {
+        match self.get_or_try_init(|| Ok::<T, !>(f())) {
+            Ok(val) => val,
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if
+    /// the cell was empty. If the cell was empty and `f` failed, an
+    /// error is returned.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. Doing
+    /// so results in a panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell = OnceCell::new();
+    /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+    /// assert!(cell.get().is_none());
+    /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
+    ///     Ok(92)
+    /// });
+    /// assert_eq!(value, Ok(&92));
+    /// assert_eq!(cell.get(), Some(&92))
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        if let Some(val) = self.get() {
+            return Ok(val);
+        }
+        let val = f()?;
+        // Note that *some* forms of reentrant initialization might lead to
+        // UB (see `reentrant_init` test). I believe that just removing this
+        // `assert`, while keeping `set/get` would be sound, but it seems
+        // better to panic, rather than to silently use an old value.
+        assert!(self.set(val).is_ok(), "reentrant init");
+        Ok(self.get().unwrap())
+    }
+
+    /// Consumes the cell, returning the wrapped value.
+    ///
+    /// Returns `None` if the cell was empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let cell: OnceCell<String> = OnceCell::new();
+    /// assert_eq!(cell.into_inner(), None);
+    ///
+    /// let cell = OnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn into_inner(self) -> Option<T> {
+        // Because `into_inner` takes `self` by value, the compiler statically verifies
+        // that it is not currently borrowed. So it is safe to move out `Option<T>`.
+        self.inner.into_inner()
+    }
+
+    /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
+    ///
+    /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
+    ///
+    /// Safety is guaranteed by requiring a mutable reference.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::OnceCell;
+    ///
+    /// let mut cell: OnceCell<String> = OnceCell::new();
+    /// assert_eq!(cell.take(), None);
+    ///
+    /// let mut cell = OnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.take(), Some("hello".to_string()));
+    /// assert_eq!(cell.get(), None);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn take(&mut self) -> Option<T> {
+        mem::take(self).into_inner()
+    }
+}
+
+/// A value which is initialized on the first access.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::lazy::Lazy;
+///
+/// let lazy: Lazy<i32> = Lazy::new(|| {
+///     println!("initializing");
+///     92
+/// });
+/// println!("ready");
+/// println!("{}", *lazy);
+/// println!("{}", *lazy);
+///
+/// // Prints:
+/// //   ready
+/// //   initializing
+/// //   92
+/// //   92
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct Lazy<T, F = fn() -> T> {
+    cell: OnceCell<T>,
+    init: Cell<Option<F>>,
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
+    }
+}
+
+impl<T, F> Lazy<T, F> {
+    /// Creates a new lazy value with the given initializing function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// # fn main() {
+    /// use std::lazy::Lazy;
+    ///
+    /// let hello = "Hello, World!".to_string();
+    ///
+    /// let lazy = Lazy::new(|| hello.to_uppercase());
+    ///
+    /// assert_eq!(&*lazy, "HELLO, WORLD!");
+    /// # }
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new(init: F) -> Lazy<T, F> {
+        Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) }
+    }
+}
+
+impl<T, F: FnOnce() -> T> Lazy<T, F> {
+    /// Forces the evaluation of this lazy value and returns a reference to
+    /// the result.
+    ///
+    /// This is equivalent to the `Deref` impl, but is explicit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::Lazy;
+    ///
+    /// let lazy = Lazy::new(|| 92);
+    ///
+    /// assert_eq!(Lazy::force(&lazy), &92);
+    /// assert_eq!(&*lazy, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn force(this: &Lazy<T, F>) -> &T {
+        this.cell.get_or_init(|| match this.init.take() {
+            Some(f) => f(),
+            None => panic!("`Lazy` instance has previously been poisoned"),
+        })
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        Lazy::force(self)
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Default> Default for Lazy<T> {
+    /// Creates a new lazy value using `Default` as the initializing function.
+    fn default() -> Lazy<T> {
+        Lazy::new(T::default)
+    }
+}
index 820c0a49e7f0318aaf4b1ef35464ad496982653a..2e443064706d239117b7890ee3f74ff07daaa3bd 100644 (file)
@@ -73,8 +73,6 @@
 #![feature(const_ascii_ctype_on_intrinsics)]
 #![feature(const_alloc_layout)]
 #![feature(const_discriminant)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
-#![cfg_attr(bootstrap, feature(const_loop))]
 #![feature(const_checked_int_methods)]
 #![feature(const_euclidean_int_methods)]
 #![feature(const_overflowing_int_methods)]
 #![feature(const_panic)]
 #![feature(const_fn_union)]
 #![feature(const_generics)]
+#![feature(const_option)]
 #![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
-#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
+#![feature(const_raw_ptr_comparison)]
 #![feature(const_result)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_slice_ptr_len)]
 #![feature(const_type_name)]
 #![feature(const_likely)]
+#![feature(const_unreachable_unchecked)]
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
+#![cfg_attr(not(bootstrap), feature(doc_spotlight))]
+#![feature(duration_consts_2)]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intrinsics)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![feature(transparent_unions)]
 #![feature(unboxed_closures)]
 #![feature(unsized_locals)]
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
-#![cfg_attr(not(bootstrap), feature(variant_count))]
+#![feature(variant_count)]
 #![feature(doc_alias)]
 #![feature(mmx_target_feature)]
 #![feature(tbm_target_feature)]
 #![feature(rtm_target_feature)]
 #![feature(f16c_target_feature)]
 #![feature(hexagon_target_feature)]
-#![cfg_attr(not(bootstrap), feature(const_fn_transmute))]
+#![feature(const_fn_transmute)]
 #![feature(abi_unadjusted)]
 #![feature(adx_target_feature)]
 #![feature(maybe_uninit_slice)]
 #![feature(associated_type_bounds)]
 #![feature(const_type_id)]
 #![feature(const_caller_location)]
+#![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
 #![feature(unsafe_block_in_unsafe_fn)]
+#![deny(intra_doc_link_resolution_failure)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 #[prelude_import]
 pub mod ffi;
 #[cfg(not(test))] // See #65860
 pub mod iter;
+#[unstable(feature = "once_cell", issue = "74465")]
+pub mod lazy;
 pub mod option;
 pub mod panic;
 pub mod panicking;
 )]
 // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
 // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
-#[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
+#[allow(clashing_extern_declarations)]
 #[unstable(feature = "stdsimd", issue = "48556")]
 mod core_arch;
 
index 17f7349bac23380f4d0477244eecfdc8e3008d9f..4ac366ab16408eb3de7c8d60359a9cd5fb8dbd05 100644 (file)
@@ -6,9 +6,12 @@ macro_rules! panic {
     () => (
         $crate::panic!("explicit panic")
     );
-    ($msg:expr) => (
+    ($msg:literal) => (
         $crate::panicking::panic($msg)
     );
+    ($msg:expr) => (
+        $crate::panic!("{}", $crate::convert::identity::<&str>($msg))
+    );
     ($msg:expr,) => (
         $crate::panic!($msg)
     );
index fdcfae8530a3b8034189209a40f699d484a53088..56dddee7b7799f00fd01a608f11b20a74f4f22f9 100644 (file)
@@ -84,11 +84,8 @@ impl<T: ?Sized> !Send for *mut T {}
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "sized"]
 #[rustc_on_unimplemented(
-    on(parent_trait = "std::path::Path", label = "borrow the `Path` instead"),
     message = "the size for values of type `{Self}` cannot be known at compilation time",
-    label = "doesn't have a size known at compile-time",
-    note = "to learn more, visit <https://doc.rust-lang.org/book/\
-            ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>"
+    label = "doesn't have a size known at compile-time"
 )]
 #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
 #[rustc_specialization_trait]
@@ -696,6 +693,7 @@ unsafe impl<T: Send + ?Sized> Send for &mut T {}
 pub trait DiscriminantKind {
     /// The type of the discriminant, which must satisfy the trait
     /// bounds required by `mem::Discriminant`.
+    #[cfg_attr(not(bootstrap), lang = "discriminant_type")]
     type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin;
 }
 
index 98d2027268b1a2fd6df1289ed36b8e2e1fea1b1c..d62de7617a00df5de0e4161462237247644e6a36 100644 (file)
@@ -1037,7 +1037,6 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
 /// assert_eq!(mem::variant_count::<Result<!, !>>(), 2);
 /// ```
 #[inline(always)]
-#[cfg(not(bootstrap))]
 #[unstable(feature = "variant_count", issue = "73662")]
 #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
 pub const fn variant_count<T>() -> usize {
index f4a1afd436adb7608a9e08695f0c839dccc86fac..7392a678b0549277cb1efa95fbde7f52fd80455a 100644 (file)
@@ -21,14 +21,6 @@ macro_rules! try_opt {
     };
 }
 
-#[cfg(bootstrap)]
-macro_rules! unlikely {
-    ($e: expr) => {
-        $e
-    };
-}
-
-#[cfg(not(bootstrap))]
 #[allow_internal_unstable(const_likely)]
 macro_rules! unlikely {
     ($e: expr) => {
@@ -1600,7 +1592,6 @@ pub const fn wrapping_shr(self, rhs: u32) -> Self {
             #[stable(feature = "no_panic_abs", since = "1.13.0")]
             #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[allow(unused_attributes)]
-            #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
             #[inline]
             pub const fn wrapping_abs(self) -> Self {
                  if self.is_negative() {
@@ -1889,7 +1880,6 @@ pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
             #[stable(feature = "wrapping", since = "1.7.0")]
             #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[allow(unused_attributes)]
-            #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
             pub const fn overflowing_neg(self) -> (Self, bool) {
                 if unlikely!(self == Self::MIN) {
                     (Self::MIN, true)
@@ -2182,7 +2172,6 @@ pub const fn rem_euclid(self, rhs: Self) -> Self {
             #[stable(feature = "rust1", since = "1.0.0")]
             #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[allow(unused_attributes)]
-            #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
             #[inline]
             #[rustc_inherit_overflow_checks]
             pub const fn abs(self) -> Self {
index 2cdfee87a3546ab97637817a25f5c35744bc6959..22a738d0bc1c0515c71e484aa7878d64a070052c 100644 (file)
@@ -224,7 +224,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
 #[must_use = "closures are lazy and do nothing unless called"]
 pub trait FnOnce<Args> {
     /// The returned type after the call operator is used.
-    #[cfg_attr(not(bootstrap), lang = "fn_once_output")]
+    #[lang = "fn_once_output"]
     #[stable(feature = "fn_once_output", since = "1.12.0")]
     type Output;
 
index 7aca6af3de6f3641f5daefcf0b0b9b3b422c3e55..5932f8e5856a74c7aafb67e98a95f2ec0e8118fb 100644 (file)
@@ -179,8 +179,9 @@ impl<T> Option<T> {
     /// [`Some`]: #variant.Some
     #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"]
     #[inline]
+    #[rustc_const_unstable(feature = "const_option", issue = "67441")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_some(&self) -> bool {
+    pub const fn is_some(&self) -> bool {
         matches!(*self, Some(_))
     }
 
@@ -200,8 +201,9 @@ pub fn is_some(&self) -> bool {
     #[must_use = "if you intended to assert that this doesn't have a value, consider \
                   `.and_then(|| panic!(\"`Option` had a value when expected `None`\"))` instead"]
     #[inline]
+    #[rustc_const_unstable(feature = "const_option", issue = "67441")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_none(&self) -> bool {
+    pub const fn is_none(&self) -> bool {
         !self.is_some()
     }
 
@@ -259,8 +261,9 @@ pub fn contains<U>(&self, x: &U) -> bool
     /// println!("still can print text: {:?}", text);
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_option", issue = "67441")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn as_ref(&self) -> Option<&T> {
+    pub const fn as_ref(&self) -> Option<&T> {
         match *self {
             Some(ref x) => Some(x),
             None => None,
@@ -580,8 +583,9 @@ pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
     /// assert_eq!(x.iter().next(), None);
     /// ```
     #[inline]
+    #[rustc_const_unstable(feature = "const_option", issue = "67441")]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn iter(&self) -> Iter<'_, T> {
+    pub const fn iter(&self) -> Iter<'_, T> {
         Iter { inner: Item { opt: self.as_ref() } }
     }
 
@@ -1681,6 +1685,7 @@ fn from_iter<I: IntoIterator<Item = Option<A>>>(iter: I) -> Option<V> {
 /// to allow `x?` (where `x` is an `Option<T>`) to be converted into your error type, you can
 /// implement `impl From<NoneError>` for `YourErrorType`. In that case, `x?` within a function that
 /// returns `Result<_, YourErrorType>` will translate a `None` value into an `Err` result.
+#[rustc_diagnostic_item = "none_error"]
 #[unstable(feature = "try_trait", issue = "42327")]
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
 pub struct NoneError;
index 766c69a5f94206ae7944ae635c5f17fbe954c219..15fd638bef8ad738375efc715e8aabd0db7d3df0 100644 (file)
@@ -36,7 +36,7 @@
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
 #[track_caller]
 #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
-pub fn panic(expr: &str) -> ! {
+pub fn panic(expr: &'static str) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
     }
index d1d7a71523822a12c2679917a2f355f064857783..896ad740e1e692424a695f23fc0ca04576d326a8 100644 (file)
@@ -2,6 +2,7 @@
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::intrinsics;
 use crate::mem;
+use crate::slice::SliceIndex;
 
 #[lang = "const_ptr"]
 impl<T: ?Sized> *const T {
@@ -323,7 +324,6 @@ pub const fn wrapping_offset(self, count: isize) -> *const T
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    #[cfg(not(bootstrap))]
     pub const fn guaranteed_eq(self, other: *const T) -> bool
     where
         T: Sized,
@@ -355,7 +355,6 @@ pub const fn guaranteed_eq(self, other: *const T) -> bool
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    #[cfg(not(bootstrap))]
     pub const fn guaranteed_ne(self, other: *const T) -> bool
     where
         T: Sized,
@@ -826,6 +825,55 @@ pub const fn len(self) -> usize {
         // Only `std` can make this guarantee.
         unsafe { Repr { rust: self }.raw }.len
     }
+
+    /// Returns a raw pointer to the slice's buffer.
+    ///
+    /// This is equivalent to casting `self` to `*const T`, but more type-safe.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    /// use std::ptr;
+    ///
+    /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3);
+    /// assert_eq!(slice.as_ptr(), 0 as *const i8);
+    /// ```
+    #[inline]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+    pub const fn as_ptr(self) -> *const T {
+        self as *const T
+    }
+
+    /// Returns a raw pointer to an element or subslice, without doing bounds
+    /// checking.
+    ///
+    /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+    /// is *[undefined behavior]* even if the resulting pointer is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// let x = &[1, 2, 4] as *const [i32];
+    ///
+    /// unsafe {
+    ///     assert_eq!(x.get_unchecked(1), x.as_ptr().add(1));
+    /// }
+    /// ```
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[inline]
+    pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
+    where
+        I: SliceIndex<[T]>,
+    {
+        // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+        unsafe { index.get_unchecked(self) }
+    }
 }
 
 // Equality for pointers
index 7d4b6339b511f2b2e2ea331e156319b09af88da1..96856e7512cabdcf5cad84e732ad9de4f30c543c 100644 (file)
@@ -1,6 +1,7 @@
 use super::*;
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::intrinsics;
+use crate::slice::SliceIndex;
 
 #[lang = "mut_ptr"]
 impl<T: ?Sized> *mut T {
@@ -304,7 +305,6 @@ pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    #[cfg(not(bootstrap))]
     pub const fn guaranteed_eq(self, other: *mut T) -> bool
     where
         T: Sized,
@@ -336,7 +336,6 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     #[inline]
-    #[cfg(not(bootstrap))]
     pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
     where
         T: Sized,
@@ -1014,7 +1013,6 @@ impl<T> *mut [T] {
     ///
     /// ```rust
     /// #![feature(slice_ptr_len)]
-    ///
     /// use std::ptr;
     ///
     /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
@@ -1028,6 +1026,55 @@ pub const fn len(self) -> usize {
         // Only `std` can make this guarantee.
         unsafe { Repr { rust_mut: self }.raw }.len
     }
+
+    /// Returns a raw pointer to the slice's buffer.
+    ///
+    /// This is equivalent to casting `self` to `*mut T`, but more type-safe.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    /// use std::ptr;
+    ///
+    /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3);
+    /// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8);
+    /// ```
+    #[inline]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+    pub const fn as_mut_ptr(self) -> *mut T {
+        self as *mut T
+    }
+
+    /// Returns a raw pointer to an element or subslice, without doing bounds
+    /// checking.
+    ///
+    /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+    /// is *[undefined behavior]* even if the resulting pointer is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// let x = &mut [1, 2, 4] as *mut [i32];
+    ///
+    /// unsafe {
+    ///     assert_eq!(x.get_unchecked_mut(1), x.as_mut_ptr().add(1));
+    /// }
+    /// ```
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[inline]
+    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
+    where
+        I: SliceIndex<[T]>,
+    {
+        // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+        unsafe { index.get_unchecked_mut(self) }
+    }
 }
 
 // Equality for pointers
index c2d31bfb6a4ee717f01d547f2ca5133aa72a9e87..b362a49d604e7ffd2a3ccdecee89c4f33c17f440 100644 (file)
@@ -6,6 +6,7 @@
 use crate::mem;
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
 use crate::ptr::Unique;
+use crate::slice::SliceIndex;
 
 /// `*mut T` but non-zero and covariant.
 ///
@@ -192,7 +193,6 @@ pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
     ///
     /// ```rust
     /// #![feature(slice_ptr_len, nonnull_slice_from_raw_parts)]
-    ///
     /// use std::ptr::NonNull;
     ///
     /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
@@ -204,6 +204,57 @@ pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
     pub const fn len(self) -> usize {
         self.as_ptr().len()
     }
+
+    /// Returns a non-null pointer to the slice's buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+    /// use std::ptr::NonNull;
+    ///
+    /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
+    /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap());
+    /// ```
+    #[inline]
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+    pub const fn as_non_null_ptr(self) -> NonNull<T> {
+        // SAFETY: We know `self` is non-null.
+        unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
+    }
+
+    /// Returns a raw pointer to an element or subslice, without doing bounds
+    /// checking.
+    ///
+    /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+    /// is *[undefined behavior]* even if the resulting pointer is not used.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+    /// use std::ptr::NonNull;
+    ///
+    /// let x = &mut [1, 2, 4];
+    /// let x = NonNull::slice_from_raw_parts(NonNull::new(x.as_mut_ptr()).unwrap(), x.len());
+    ///
+    /// unsafe {
+    ///     assert_eq!(x.get_unchecked_mut(1).as_ptr(), x.as_non_null_ptr().as_ptr().add(1));
+    /// }
+    /// ```
+    #[unstable(feature = "slice_ptr_get", issue = "74265")]
+    #[inline]
+    pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
+    where
+        I: SliceIndex<[T]>,
+    {
+        // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+        // As a consequence, the resulting pointer cannot be NULL.
+        unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
+    }
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
index bed8495993f438f81354070f61738873e368b781..20b2c3d3c965a8eb2c4cbc7d5de1e2891492cd1b 100644 (file)
@@ -310,8 +310,10 @@ pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
     where
         I: SliceIndex<Self>,
     {
-        // SAFETY: the caller must uphold the safety requirements for `get_unchecked`.
-        unsafe { index.get_unchecked(self) }
+        // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &*index.get_unchecked(self) }
     }
 
     /// Returns a mutable reference to an element or subslice, without doing
@@ -342,8 +344,10 @@ pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
     where
         I: SliceIndex<Self>,
     {
-        // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`.
-        unsafe { index.get_unchecked_mut(self) }
+        // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &mut *index.get_unchecked_mut(self) }
     }
 
     /// Returns a raw pointer to the slice's buffer.
@@ -3010,6 +3014,9 @@ impl Sealed for ops::RangeToInclusive<usize> {}
 }
 
 /// A helper trait used for indexing operations.
+///
+/// Implementations of this trait have to promise that if the argument
+/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
 #[stable(feature = "slice_get_slice", since = "1.28.0")]
 #[rustc_on_unimplemented(
     on(T = "str", label = "string indices are ranges of `usize`",),
@@ -3021,7 +3028,7 @@ impl Sealed for ops::RangeToInclusive<usize> {}
     message = "the type `{T}` cannot be indexed by `{Self}`",
     label = "slice indices are of type `usize` or ranges of `usize`"
 )]
-pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
+pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
     /// The output type returned by methods.
     #[stable(feature = "slice_get_slice", since = "1.28.0")]
     type Output: ?Sized;
@@ -3038,21 +3045,21 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
 
     /// Returns a shared reference to the output at this location, without
     /// performing any bounds checking.
-    /// Calling this method with an out-of-bounds index is *[undefined behavior]*
-    /// even if the resulting reference is not used.
+    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+    /// is *[undefined behavior]* even if the resulting reference is not used.
     ///
     /// [undefined behavior]: ../../reference/behavior-considered-undefined.html
     #[unstable(feature = "slice_index_methods", issue = "none")]
-    unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;
+    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
 
     /// Returns a mutable reference to the output at this location, without
     /// performing any bounds checking.
-    /// Calling this method with an out-of-bounds index is *[undefined behavior]*
-    /// even if the resulting reference is not used.
+    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+    /// is *[undefined behavior]* even if the resulting reference is not used.
     ///
     /// [undefined behavior]: ../../reference/behavior-considered-undefined.html
     #[unstable(feature = "slice_index_methods", issue = "none")]
-    unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output;
+    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
 
     /// Returns a shared reference to the output at this location, panicking
     /// if out of bounds.
@@ -3068,33 +3075,32 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for usize {
+unsafe impl<T> SliceIndex<[T]> for usize {
     type Output = T;
 
     #[inline]
     fn get(self, slice: &[T]) -> Option<&T> {
-        if self < slice.len() { unsafe { Some(self.get_unchecked(slice)) } } else { None }
+        if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
     }
 
     #[inline]
     fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
-        if self < slice.len() { unsafe { Some(self.get_unchecked_mut(slice)) } } else { None }
+        if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &T {
-        // SAFETY: `slice` cannot be longer than `isize::MAX` and
-        // the caller guarantees that `self` is in bounds of `slice`
-        // so `self` cannot overflow an `isize`, so the call to `add` is safe.
-        // The obtained pointer comes from a reference which is guaranteed
-        // to be valid.
-        unsafe { &*slice.as_ptr().add(self) }
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+        // SAFETY: the caller guarantees that `slice` is not dangling, so it
+        // cannot be longer than `isize::MAX`. They also guarantee that
+        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+        // so the call to `add` is safe.
+        unsafe { slice.as_ptr().add(self) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut T {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
         // SAFETY: see comments for `get_unchecked` above.
-        unsafe { &mut *slice.as_mut_ptr().add(self) }
+        unsafe { slice.as_mut_ptr().add(self) }
     }
 
     #[inline]
@@ -3111,7 +3117,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut T {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::Range<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
     type Output = [T];
 
     #[inline]
@@ -3119,7 +3125,7 @@ fn get(self, slice: &[T]) -> Option<&[T]> {
         if self.start > self.end || self.end > slice.len() {
             None
         } else {
-            unsafe { Some(self.get_unchecked(slice)) }
+            unsafe { Some(&*self.get_unchecked(slice)) }
         }
     }
 
@@ -3128,24 +3134,25 @@ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
         if self.start > self.end || self.end > slice.len() {
             None
         } else {
-            unsafe { Some(self.get_unchecked_mut(slice)) }
+            unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
         }
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
-        // SAFETY: `slice` cannot be longer than `isize::MAX` and
-        // the caller guarantees that `self` is in bounds of `slice`
-        // so `self` cannot overflow an `isize`, so the call to `add` is safe.
-        // Also, since the caller guarantees that `self` is in bounds of `slice`,
-        // `from_raw_parts` will give a subslice of `slice` which is always safe.
-        unsafe { from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+        // SAFETY: the caller guarantees that `slice` is not dangling, so it
+        // cannot be longer than `isize::MAX`. They also guarantee that
+        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+        // so the call to `add` is safe.
+        unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: see comments for `get_unchecked` above.
-        unsafe { from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) }
+        unsafe {
+            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
+        }
     }
 
     #[inline]
@@ -3155,7 +3162,7 @@ fn index(self, slice: &[T]) -> &[T] {
         } else if self.end > slice.len() {
             slice_index_len_fail(self.end, slice.len());
         }
-        unsafe { self.get_unchecked(slice) }
+        unsafe { &*self.get_unchecked(slice) }
     }
 
     #[inline]
@@ -3165,12 +3172,12 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
         } else if self.end > slice.len() {
             slice_index_len_fail(self.end, slice.len());
         }
-        unsafe { self.get_unchecked_mut(slice) }
+        unsafe { &mut *self.get_unchecked_mut(slice) }
     }
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
     type Output = [T];
 
     #[inline]
@@ -3184,13 +3191,13 @@ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (0..self.end).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (0..self.end).get_unchecked_mut(slice) }
     }
@@ -3207,7 +3214,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
     type Output = [T];
 
     #[inline]
@@ -3221,13 +3228,13 @@ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (self.start..slice.len()).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (self.start..slice.len()).get_unchecked_mut(slice) }
     }
@@ -3244,7 +3251,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-impl<T> SliceIndex<[T]> for ops::RangeFull {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
     type Output = [T];
 
     #[inline]
@@ -3258,12 +3265,12 @@ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         slice
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         slice
     }
 
@@ -3279,7 +3286,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -3297,13 +3304,13 @@ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
     }
@@ -3326,7 +3333,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
 }
 
 #[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
     type Output = [T];
 
     #[inline]
@@ -3340,13 +3347,13 @@ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
     }
 
     #[inline]
-    unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
+    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
         unsafe { (0..=self.end).get_unchecked(slice) }
     }
 
     #[inline]
-    unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] {
+    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
         // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
         unsafe { (0..=self.end).get_unchecked_mut(slice) }
     }
@@ -6088,7 +6095,7 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
 ///
 /// Behavior is undefined if any of the following conditions are violated:
 ///
-/// * `data` must be [valid] for writes for `len * mem::size_of::<T>()` many bytes,
+/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::<T>()` many bytes,
 ///   and it must be properly aligned. This means in particular:
 ///
 ///     * The entire memory range of this slice must be contained within a single allocated object!
@@ -6226,14 +6233,8 @@ impl<A> SlicePartialEq<A> for [A]
             return false;
         }
 
-        #[cfg(bootstrap)]
-        if self.as_ptr() == other.as_ptr() {
-            return true;
-        }
-
         // While performance would suffer if `guaranteed_eq` just returned `false`
         // for all arguments, correctness and return value of this function are not affected.
-        #[cfg(not(bootstrap))]
         if self.as_ptr().guaranteed_eq(other.as_ptr()) {
             return true;
         }
@@ -6252,14 +6253,8 @@ fn equal(&self, other: &[A]) -> bool {
             return false;
         }
 
-        #[cfg(bootstrap)]
-        if self.as_ptr() == other.as_ptr() {
-            return true;
-        }
-
         // While performance would suffer if `guaranteed_eq` just returned `false`
         // for all arguments, correctness and return value of this function are not affected.
-        #[cfg(not(bootstrap))]
         if self.as_ptr().guaranteed_eq(other.as_ptr()) {
             return true;
         }
index 003ed7df36e2a44d07943c718542e9c25e29eedf..faf58cafbb70b626d582c91b31822a316800d807 100644 (file)
@@ -31,9 +31,8 @@
 /// `FromStr`'s [`from_str`] method is often used implicitly, through
 /// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples.
 ///
-/// [`from_str`]: #tymethod.from_str
-/// [`str`]: ../../std/primitive.str.html
-/// [`parse`]: ../../std/primitive.str.html#method.parse
+/// [`from_str`]: FromStr::from_str
+/// [`parse`]: str::parse
 ///
 /// `FromStr` does not have a lifetime parameter, and so you can only parse types
 /// that do not contain a lifetime parameter themselves. In other words, you can
@@ -143,7 +142,7 @@ fn from_str(s: &str) -> Result<bool, ParseBoolError> {
 
 /// An error returned when parsing a `bool` using [`from_str`] fails
 ///
-/// [`from_str`]: ../../std/primitive.bool.html#method.from_str
+/// [`from_str`]: FromStr::from_str
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct ParseBoolError {
@@ -266,8 +265,7 @@ pub fn error_len(&self) -> Option<usize> {
 /// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid
 /// UTF-8, and then does the conversion.
 ///
-/// [`&str`]: ../../std/primitive.str.html
-/// [`u8`]: ../../std/primitive.u8.html
+/// [`&str`]: str
 /// [byteslice]: ../../std/primitive.slice.html
 ///
 /// If you are sure that the byte slice is valid UTF-8, and you don't want to
@@ -398,7 +396,7 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
 /// it are valid UTF-8. If this constraint is violated, undefined behavior
 /// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8.
 ///
-/// [`&str`]: ../../std/primitive.str.html
+/// [`&str`]: str
 ///
 /// # Examples
 ///
@@ -429,9 +427,7 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
 /// Converts a slice of bytes to a string slice without checking
 /// that the string contains valid UTF-8; mutable version.
 ///
-/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
-///
-/// [fromutf8]: fn.from_utf8_unchecked.html
+/// See the immutable version, [`from_utf8_unchecked()`] for more information.
 ///
 /// # Examples
 ///
@@ -476,13 +472,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// An iterator over the [`char`]s of a string slice.
 ///
-/// [`char`]: ../../std/primitive.char.html
 ///
 /// This struct is created by the [`chars`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`chars`]: ../../std/primitive.str.html#method.chars
-/// [`str`]: ../../std/primitive.str.html
+/// [`chars`]: str::chars
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Chars<'a> {
@@ -676,13 +670,10 @@ pub fn as_str(&self) -> &'a str {
 
 /// An iterator over the [`char`]s of a string slice, and their positions.
 ///
-/// [`char`]: ../../std/primitive.char.html
-///
 /// This struct is created by the [`char_indices`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`char_indices`]: ../../std/primitive.str.html#method.char_indices
-/// [`str`]: ../../std/primitive.str.html
+/// [`char_indices`]: str::char_indices
 #[derive(Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct CharIndices<'a> {
@@ -756,8 +747,7 @@ pub fn as_str(&self) -> &'a str {
 /// This struct is created by the [`bytes`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`bytes`]: ../../std/primitive.str.html#method.bytes
-/// [`str`]: ../../std/primitive.str.html
+/// [`bytes`]: str::bytes
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone, Debug)]
 pub struct Bytes<'a>(Copied<slice::Iter<'a, u8>>);
@@ -1249,12 +1239,12 @@ fn next_back_inclusive(&mut self) -> Option<&'a str>
     forward:
         /// Created with the method [`split`].
         ///
-        /// [`split`]: ../../std/primitive.str.html#method.split
+        /// [`split`]: str::split
         struct Split;
     reverse:
         /// Created with the method [`rsplit`].
         ///
-        /// [`rsplit`]: ../../std/primitive.str.html#method.rsplit
+        /// [`rsplit`]: str::rsplit
         struct RSplit;
     stability:
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -1267,12 +1257,12 @@ fn next_back_inclusive(&mut self) -> Option<&'a str>
     forward:
         /// Created with the method [`split_terminator`].
         ///
-        /// [`split_terminator`]: ../../std/primitive.str.html#method.split_terminator
+        /// [`split_terminator`]: str::split_terminator
         struct SplitTerminator;
     reverse:
         /// Created with the method [`rsplit_terminator`].
         ///
-        /// [`rsplit_terminator`]: ../../std/primitive.str.html#method.rsplit_terminator
+        /// [`rsplit_terminator`]: str::rsplit_terminator
         struct RSplitTerminator;
     stability:
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -1343,12 +1333,12 @@ fn next_back(&mut self) -> Option<&'a str>
     forward:
         /// Created with the method [`splitn`].
         ///
-        /// [`splitn`]: ../../std/primitive.str.html#method.splitn
+        /// [`splitn`]: str::splitn
         struct SplitN;
     reverse:
         /// Created with the method [`rsplitn`].
         ///
-        /// [`rsplitn`]: ../../std/primitive.str.html#method.rsplitn
+        /// [`rsplitn`]: str::rsplitn
         struct RSplitN;
     stability:
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -1398,12 +1388,12 @@ fn next_back(&mut self) -> Option<(usize, &'a str)>
     forward:
         /// Created with the method [`match_indices`].
         ///
-        /// [`match_indices`]: ../../std/primitive.str.html#method.match_indices
+        /// [`match_indices`]: str::match_indices
         struct MatchIndices;
     reverse:
         /// Created with the method [`rmatch_indices`].
         ///
-        /// [`rmatch_indices`]: ../../std/primitive.str.html#method.rmatch_indices
+        /// [`rmatch_indices`]: str::rmatch_indices
         struct RMatchIndices;
     stability:
         #[stable(feature = "str_match_indices", since = "1.5.0")]
@@ -1455,12 +1445,12 @@ fn next_back(&mut self) -> Option<&'a str>
     forward:
         /// Created with the method [`matches`].
         ///
-        /// [`matches`]: ../../std/primitive.str.html#method.matches
+        /// [`matches`]: str::matches
         struct Matches;
     reverse:
         /// Created with the method [`rmatches`].
         ///
-        /// [`rmatches`]: ../../std/primitive.str.html#method.rmatches
+        /// [`rmatches`]: str::rmatches
         struct RMatches;
     stability:
         #[stable(feature = "str_matches", since = "1.2.0")]
@@ -1474,8 +1464,7 @@ fn next_back(&mut self) -> Option<&'a str>
 /// This struct is created with the [`lines`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`lines`]: ../../std/primitive.str.html#method.lines
-/// [`str`]: ../../std/primitive.str.html
+/// [`lines`]: str::lines
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone, Debug)]
 pub struct Lines<'a>(Map<SplitTerminator<'a, char>, LinesAnyMap>);
@@ -1513,7 +1502,7 @@ impl FusedIterator for Lines<'_> {}
 
 /// Created with the method [`lines_any`].
 ///
-/// [`lines_any`]: ../../std/primitive.str.html#method.lines_any
+/// [`lines_any`]: str::lines_any
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
 #[derive(Clone, Debug)]
@@ -1731,7 +1720,8 @@ pub fn utf8_char_width(b: u8) -> usize {
 mod traits {
     use crate::cmp::Ordering;
     use crate::ops;
-    use crate::slice::{self, SliceIndex};
+    use crate::ptr;
+    use crate::slice::SliceIndex;
 
     /// Implements ordering of strings.
     ///
@@ -1822,7 +1812,7 @@ fn str_index_overflow_fail() -> ! {
     ///
     /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::RangeFull {
+    unsafe impl SliceIndex<str> for ops::RangeFull {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -1833,11 +1823,11 @@ fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
             Some(slice)
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
             slice
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
             slice
         }
         #[inline]
@@ -1886,7 +1876,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
     /// // &s[3 .. 100];
     /// ```
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::Range<usize> {
+    unsafe impl SliceIndex<str> for ops::Range<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -1894,8 +1884,10 @@ fn get(self, slice: &str) -> Option<&Self::Output> {
                 && slice.is_char_boundary(self.start)
                 && slice.is_char_boundary(self.end)
             {
-                // SAFETY: just checked that `start` and `end` are on a char boundary.
-                Some(unsafe { self.get_unchecked(slice) })
+                // SAFETY: just checked that `start` and `end` are on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                // We also checked char boundaries, so this is valid UTF-8.
+                Some(unsafe { &*self.get_unchecked(slice) })
             } else {
                 None
             }
@@ -1907,34 +1899,28 @@ fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
                 && slice.is_char_boundary(self.end)
             {
                 // SAFETY: just checked that `start` and `end` are on a char boundary.
-                Some(unsafe { self.get_unchecked_mut(slice) })
+                // We know the pointer is unique because we got it from `slice`.
+                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
             } else {
                 None
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+            let slice = slice as *const [u8];
             // SAFETY: the caller guarantees that `self` is in bounds of `slice`
             // which satisfies all the conditions for `add`.
             let ptr = unsafe { slice.as_ptr().add(self.start) };
             let len = self.end - self.start;
-            // SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
-            // we can safely construct a subslice with `from_raw_parts` and use it
-            // since we return a shared thus immutable reference.
-            // The call to `from_utf8_unchecked` is safe since the data comes from
-            // a `str` which is guaranteed to be valid utf8, since the caller
-            // must guarantee that `self.start` and `self.end` are char boundaries.
-            unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
+            ptr::slice_from_raw_parts(ptr, len) as *const str
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+            let slice = slice as *mut [u8];
             // SAFETY: see comments for `get_unchecked`.
             let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
             let len = self.end - self.start;
-            // SAFETY: mostly identical to the comments for `get_unchecked`, except that we
-            // can return a mutable reference since the caller passed a mutable reference
-            // and is thus guaranteed to have exclusive write access to `slice`.
-            unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
+            ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1949,8 +1935,9 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
                 && slice.is_char_boundary(self.start)
                 && slice.is_char_boundary(self.end)
             {
-                // SAFETY: just checked that `start` and `end` are on a char boundary.
-                unsafe { self.get_unchecked_mut(slice) }
+                // SAFETY: just checked that `start` and `end` are on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                unsafe { &mut *self.get_unchecked_mut(slice) }
             } else {
                 super::slice_error_fail(slice, self.start, self.end)
             }
@@ -1973,13 +1960,14 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
     /// Panics if `end` does not point to the starting byte offset of a
     /// character (as defined by `is_char_boundary`), or if `end > len`.
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::RangeTo<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
             if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary.
-                Some(unsafe { self.get_unchecked(slice) })
+                // SAFETY: just checked that `end` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &*self.get_unchecked(slice) })
             } else {
                 None
             }
@@ -1987,30 +1975,24 @@ fn get(self, slice: &str) -> Option<&Self::Output> {
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
             if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary.
-                Some(unsafe { self.get_unchecked_mut(slice) })
+                // SAFETY: just checked that `end` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
             } else {
                 None
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+            let slice = slice as *const [u8];
             let ptr = slice.as_ptr();
-            // SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
-            // we can safely construct a subslice with `from_raw_parts` and use it
-            // since we return a shared thus immutable reference.
-            // The call to `from_utf8_unchecked` is safe since the data comes from
-            // a `str` which is guaranteed to be valid utf8, since the caller
-            // must guarantee that `self.end` is a char boundary.
-            unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) }
+            ptr::slice_from_raw_parts(ptr, self.end) as *const str
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+            let slice = slice as *mut [u8];
             let ptr = slice.as_mut_ptr();
-            // SAFETY: mostly identical to `get_unchecked`, except that we can safely
-            // return a mutable reference since the caller passed a mutable reference
-            // and is thus guaranteed to have exclusive write access to `slice`.
-            unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) }
+            ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -2020,8 +2002,9 @@ fn index(self, slice: &str) -> &Self::Output {
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
             if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary.
-                unsafe { self.get_unchecked_mut(slice) }
+                // SAFETY: just checked that `end` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                unsafe { &mut *self.get_unchecked_mut(slice) }
             } else {
                 super::slice_error_fail(slice, 0, self.end)
             }
@@ -2045,13 +2028,14 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
     /// Panics if `begin` does not point to the starting byte offset of
     /// a character (as defined by `is_char_boundary`), or if `begin >= len`.
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    impl SliceIndex<str> for ops::RangeFrom<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
             if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary.
-                Some(unsafe { self.get_unchecked(slice) })
+                // SAFETY: just checked that `start` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &*self.get_unchecked(slice) })
             } else {
                 None
             }
@@ -2059,35 +2043,29 @@ fn get(self, slice: &str) -> Option<&Self::Output> {
         #[inline]
         fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
             if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary.
-                Some(unsafe { self.get_unchecked_mut(slice) })
+                // SAFETY: just checked that `start` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
             } else {
                 None
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+            let slice = slice as *const [u8];
             // SAFETY: the caller guarantees that `self` is in bounds of `slice`
             // which satisfies all the conditions for `add`.
             let ptr = unsafe { slice.as_ptr().add(self.start) };
             let len = slice.len() - self.start;
-            // SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
-            // we can safely construct a subslice with `from_raw_parts` and use it
-            // since we return a shared thus immutable reference.
-            // The call to `from_utf8_unchecked` is safe since the data comes from
-            // a `str` which is guaranteed to be valid utf8, since the caller
-            // must guarantee that `self.start` is a char boundary.
-            unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
+            ptr::slice_from_raw_parts(ptr, len) as *const str
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+            let slice = slice as *mut [u8];
             // SAFETY: identical to `get_unchecked`.
             let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
             let len = slice.len() - self.start;
-            // SAFETY: mostly identical to `get_unchecked`, except that we can safely
-            // return a mutable reference since the caller passed a mutable reference
-            // and is thus guaranteed to have exclusive write access to `slice`.
-            unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
+            ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -2097,8 +2075,9 @@ fn index(self, slice: &str) -> &Self::Output {
         #[inline]
         fn index_mut(self, slice: &mut str) -> &mut Self::Output {
             if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary.
-                unsafe { self.get_unchecked_mut(slice) }
+                // SAFETY: just checked that `start` is on a char boundary,
+                // and we are passing in a safe reference, so the return value will also be one.
+                unsafe { &mut *self.get_unchecked_mut(slice) }
             } else {
                 super::slice_error_fail(slice, self.start, slice.len())
             }
@@ -2122,7 +2101,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
     /// to the ending byte offset of a character (`end + 1` is either a starting
     /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
     #[stable(feature = "inclusive_range", since = "1.26.0")]
-    impl SliceIndex<str> for ops::RangeInclusive<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -2141,12 +2120,12 @@ fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
             }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
             unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
             unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
         }
@@ -2181,7 +2160,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
     /// (`end + 1` is either a starting byte offset as defined by
     /// `is_char_boundary`, or equal to `len`), or if `end >= len`.
     #[stable(feature = "inclusive_range", since = "1.26.0")]
-    impl SliceIndex<str> for ops::RangeToInclusive<usize> {
+    unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
         type Output = str;
         #[inline]
         fn get(self, slice: &str) -> Option<&Self::Output> {
@@ -2192,12 +2171,12 @@ fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
             if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) }
         }
         #[inline]
-        unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
+        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
             unsafe { (..self.end + 1).get_unchecked(slice) }
         }
         #[inline]
-        unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
+        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
             // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
             unsafe { (..self.end + 1).get_unchecked_mut(slice) }
         }
@@ -2357,9 +2336,7 @@ pub fn is_char_boundary(&self, index: usize) -> bool {
     }
 
     /// Converts a string slice to a byte slice. To convert the byte slice back
-    /// into a string slice, use the [`str::from_utf8`] function.
-    ///
-    /// [`str::from_utf8`]: ./str/fn.from_utf8.html
+    /// into a string slice, use the [`from_utf8`] function.
     ///
     /// # Examples
     ///
@@ -2384,11 +2361,14 @@ union Slices<'a> {
         unsafe { Slices { str: self }.slice }
     }
 
-    /// Converts a mutable string slice to a mutable byte slice. To convert the
-    /// mutable byte slice back into a mutable string slice, use the
-    /// [`str::from_utf8_mut`] function.
+    /// Converts a mutable string slice to a mutable byte slice.
+    ///
+    /// # Safety
     ///
-    /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html
+    /// The caller must ensure that the content of the slice is valid UTF-8
+    /// before the borrow ends and the underlying `str` is used.
+    ///
+    /// Use of a `str` whose contents are not valid UTF-8 is undefined behavior.
     ///
     /// # Examples
     ///
@@ -2436,8 +2416,7 @@ pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
     /// The caller must ensure that the returned pointer is never written to.
     /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`].
     ///
-    /// [`u8`]: primitive.u8.html
-    /// [`as_mut_ptr`]: #method.as_mut_ptr
+    /// [`as_mut_ptr`]: str::as_mut_ptr
     ///
     /// # Examples
     ///
@@ -2462,8 +2441,6 @@ pub const fn as_ptr(&self) -> *const u8 {
     ///
     /// It is your responsibility to make sure that the string slice only gets
     /// modified in a way that it remains valid UTF-8.
-    ///
-    /// [`u8`]: primitive.u8.html
     #[stable(feature = "str_as_mut_ptr", since = "1.36.0")]
     #[inline]
     pub fn as_mut_ptr(&mut self) -> *mut u8 {
@@ -2475,8 +2452,6 @@ pub fn as_mut_ptr(&mut self) -> *mut u8 {
     /// This is the non-panicking alternative to indexing the `str`. Returns
     /// [`None`] whenever equivalent indexing operation would panic.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2502,8 +2477,6 @@ pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
     /// This is the non-panicking alternative to indexing the `str`. Returns
     /// [`None`] whenever equivalent indexing operation would panic.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    ///
     /// # Examples
     ///
     /// ```
@@ -2560,8 +2533,10 @@ pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
-        unsafe { i.get_unchecked(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &*i.get_unchecked(self) }
     }
 
     /// Returns a mutable, unchecked subslice of `str`.
@@ -2593,8 +2568,10 @@ pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
-        unsafe { i.get_unchecked_mut(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &mut *i.get_unchecked_mut(self) }
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2603,8 +2580,7 @@ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::
     /// This is generally not recommended, use with caution! For a safe
     /// alternative see [`str`] and [`Index`].
     ///
-    /// [`str`]: primitive.str.html
-    /// [`Index`]: ops/trait.Index.html
+    /// [`Index`]: crate::ops::Index
     ///
     /// This new slice goes from `begin` to `end`, including `begin` but
     /// excluding `end`.
@@ -2612,7 +2588,7 @@ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::
     /// To get a mutable string slice instead, see the
     /// [`slice_mut_unchecked`] method.
     ///
-    /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked
+    /// [`slice_mut_unchecked`]: str::slice_mut_unchecked
     ///
     /// # Safety
     ///
@@ -2644,8 +2620,10 @@ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::
     #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
     #[inline]
     pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
-        unsafe { (begin..end).get_unchecked(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &*(begin..end).get_unchecked(self) }
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2653,8 +2631,7 @@ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
     /// This is generally not recommended, use with caution! For a safe
     /// alternative see [`str`] and [`IndexMut`].
     ///
-    /// [`str`]: primitive.str.html
-    /// [`IndexMut`]: ops/trait.IndexMut.html
+    /// [`IndexMut`]: crate::ops::IndexMut
     ///
     /// This new slice goes from `begin` to `end`, including `begin` but
     /// excluding `end`.
@@ -2662,7 +2639,7 @@ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
     /// To get an immutable string slice instead, see the
     /// [`slice_unchecked`] method.
     ///
-    /// [`slice_unchecked`]: #method.slice_unchecked
+    /// [`slice_unchecked`]: str::slice_unchecked
     ///
     /// # Safety
     ///
@@ -2676,8 +2653,10 @@ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
     #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")]
     #[inline]
     pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
-        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
-        unsafe { (begin..end).get_unchecked_mut(self) }
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
+        // the slice is dereferencable because `self` is a safe reference.
+        // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
+        unsafe { &mut *(begin..end).get_unchecked_mut(self) }
     }
 
     /// Divide one string slice into two at an index.
@@ -2691,7 +2670,7 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
     /// To get mutable string slices instead, see the [`split_at_mut`]
     /// method.
     ///
-    /// [`split_at_mut`]: #method.split_at_mut
+    /// [`split_at_mut`]: str::split_at_mut
     ///
     /// # Panics
     ///
@@ -2732,7 +2711,7 @@ pub fn split_at(&self, mid: usize) -> (&str, &str) {
     ///
     /// To get immutable string slices instead, see the [`split_at`] method.
     ///
-    /// [`split_at`]: #method.split_at
+    /// [`split_at`]: str::split_at
     ///
     /// # Panics
     ///
@@ -2912,7 +2891,7 @@ pub fn bytes(&self) -> Bytes<'_> {
     /// Core Property `White_Space`. If you only want to split on ASCII whitespace
     /// instead, use [`split_ascii_whitespace`].
     ///
-    /// [`split_ascii_whitespace`]: #method.split_ascii_whitespace
+    /// [`split_ascii_whitespace`]: str::split_ascii_whitespace
     ///
     /// # Examples
     ///
@@ -2953,7 +2932,7 @@ pub fn split_whitespace(&self) -> SplitWhitespace<'_> {
     ///
     /// To split by Unicode `Whitespace` instead, use [`split_whitespace`].
     ///
-    /// [`split_whitespace`]: #method.split_whitespace
+    /// [`split_whitespace`]: str::split_whitespace
     ///
     /// # Examples
     ///
@@ -3067,8 +3046,7 @@ pub fn encode_utf16(&self) -> EncodeUtf16<'_> {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3094,8 +3072,7 @@ pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3120,8 +3097,7 @@ pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3149,20 +3125,18 @@ pub fn ends_with<'a, P>(&'a self, pat: P) -> bool
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
     /// Simple patterns:
     ///
     /// ```
-    /// let s = "Löwe 老虎 Léopard";
+    /// let s = "Löwe 老虎 Léopard Gepardi";
     ///
     /// assert_eq!(s.find('L'), Some(0));
     /// assert_eq!(s.find('é'), Some(14));
-    /// assert_eq!(s.find("Léopard"), Some(13));
+    /// assert_eq!(s.find("pard"), Some(17));
     /// ```
     ///
     /// More complex patterns using point-free style and closures:
@@ -3190,27 +3164,26 @@ pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
         pat.into_searcher(self).next_match().map(|(i, _)| i)
     }
 
-    /// Returns the byte index of the last character of this string slice that
-    /// matches the pattern.
+    /// Returns the byte index for the first character of the rightmost match of the pattern in
+    /// this string slice.
     ///
     /// Returns [`None`] if the pattern doesn't match.
     ///
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`None`]: option/enum.Option.html#variant.None
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
     /// Simple patterns:
     ///
     /// ```
-    /// let s = "Löwe 老虎 Léopard";
+    /// let s = "Löwe 老虎 Léopard Gepardi";
     ///
     /// assert_eq!(s.rfind('L'), Some(13));
     /// assert_eq!(s.rfind('é'), Some(14));
+    /// assert_eq!(s.rfind("pard"), Some(24));
     /// ```
     ///
     /// More complex patterns with closures:
@@ -3245,8 +3218,7 @@ pub fn rfind<'a, P>(&'a self, pat: P) -> Option<usize>
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3254,12 +3226,10 @@ pub fn rfind<'a, P>(&'a self, pat: P) -> Option<usize>
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rsplit`] method can be used.
     ///
-    /// [`rsplit`]: #method.rsplit
+    /// [`rsplit`]: str::rsplit
     ///
     /// # Examples
     ///
@@ -3346,7 +3316,7 @@ pub fn rfind<'a, P>(&'a self, pat: P) -> Option<usize>
     ///
     /// Use [`split_whitespace`] for this behavior.
     ///
-    /// [`split_whitespace`]: #method.split_whitespace
+    /// [`split_whitespace`]: str::split_whitespace
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
@@ -3367,8 +3337,7 @@ pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -3407,8 +3376,7 @@ pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3416,11 +3384,9 @@ pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'
     /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
     /// search yields the same elements.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// For iterating from the front, the [`split`] method can be used.
     ///
-    /// [`split`]: #method.split
+    /// [`split`]: str::split
     ///
     /// # Examples
     ///
@@ -3461,13 +3427,12 @@ pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P>
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// Equivalent to [`split`], except that the trailing substring
     /// is skipped if empty.
     ///
-    /// [`split`]: #method.split
+    /// [`split`]: str::split
     ///
     /// This method can be used for string data that is _terminated_,
     /// rather than _separated_ by a pattern.
@@ -3478,12 +3443,10 @@ pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P>
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rsplit_terminator`] method can be used.
     ///
-    /// [`rsplit_terminator`]: #method.rsplit_terminator
+    /// [`rsplit_terminator`]: str::rsplit_terminator
     ///
     /// # Examples
     ///
@@ -3508,13 +3471,12 @@ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// Equivalent to [`split`], except that the trailing substring is
     /// skipped if empty.
     ///
-    /// [`split`]: #method.split
+    /// [`split`]: str::split
     ///
     /// This method can be used for string data that is _terminated_,
     /// rather than _separated_ by a pattern.
@@ -3528,7 +3490,7 @@ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator
     /// For iterating from the front, the [`split_terminator`] method can be
     /// used.
     ///
-    /// [`split_terminator`]: #method.split_terminator
+    /// [`split_terminator`]: str::split_terminator
     ///
     /// # Examples
     ///
@@ -3557,8 +3519,7 @@ pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P>
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3568,7 +3529,7 @@ pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P>
     /// If the pattern allows a reverse search, the [`rsplitn`] method can be
     /// used.
     ///
-    /// [`rsplitn`]: #method.rsplitn
+    /// [`rsplitn`]: str::rsplitn
     ///
     /// # Examples
     ///
@@ -3610,8 +3571,7 @@ pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3620,7 +3580,7 @@ pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
     ///
     /// For splitting from the front, the [`splitn`] method can be used.
     ///
-    /// [`splitn`]: #method.splitn
+    /// [`splitn`]: str::splitn
     ///
     /// # Examples
     ///
@@ -3658,8 +3618,7 @@ pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3667,12 +3626,10 @@ pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rmatches`] method can be used.
     ///
-    /// [`rmatches`]: #method.rmatches
+    /// [`rmatches`]: str::matches
     ///
     /// # Examples
     ///
@@ -3697,8 +3654,7 @@ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3706,11 +3662,9 @@ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
     /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
     /// search yields the same elements.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// For iterating from the front, the [`matches`] method can be used.
     ///
-    /// [`matches`]: #method.matches
+    /// [`matches`]: str::matches
     ///
     /// # Examples
     ///
@@ -3741,8 +3695,7 @@ pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P>
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3750,12 +3703,10 @@ pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P>
     /// allows a reverse search and forward/reverse search yields the same
     /// elements. This is true for, e.g., [`char`], but not for `&str`.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// If the pattern allows a reverse search but its results might differ
     /// from a forward search, the [`rmatch_indices`] method can be used.
     ///
-    /// [`rmatch_indices`]: #method.rmatch_indices
+    /// [`rmatch_indices`]: str::match_indices
     ///
     /// # Examples
     ///
@@ -3786,8 +3737,7 @@ pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Iterator behavior
     ///
@@ -3795,11 +3745,9 @@ pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P
     /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
     /// search yields the same elements.
     ///
-    /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
-    ///
     /// For iterating from the front, the [`match_indices`] method can be used.
     ///
-    /// [`match_indices`]: #method.match_indices
+    /// [`match_indices`]: str::match_indices
     ///
     /// # Examples
     ///
@@ -4007,8 +3955,7 @@ pub fn trim_right(&self) -> &str {
     /// The [pattern] can be a [`char`], a slice of [`char`]s, or a function
     /// or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -4055,8 +4002,7 @@ pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4100,8 +4046,7 @@ pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -4128,8 +4073,7 @@ pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str>
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Examples
     ///
@@ -4155,8 +4099,7 @@ pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str>
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4204,8 +4147,7 @@ pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4241,8 +4183,7 @@ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
     /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
     /// function or closure that determines if a character matches.
     ///
-    /// [`char`]: primitive.char.html
-    /// [pattern]: str/pattern/index.html
+    /// [pattern]: self::pattern
     ///
     /// # Text directionality
     ///
@@ -4290,15 +4231,14 @@ pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str
     /// you're trying to parse into.
     ///
     /// `parse` can parse any type that implements the [`FromStr`] trait.
-    ///
-    /// [`FromStr`]: str/trait.FromStr.html
+
     ///
     /// # Errors
     ///
     /// Will return [`Err`] if it's not possible to parse this string slice into
     /// the desired type.
     ///
-    /// [`Err`]: str/trait.FromStr.html#associatedtype.Err
+    /// [`Err`]: FromStr::Err
     ///
     /// # Examples
     ///
@@ -4426,8 +4366,6 @@ pub fn make_ascii_lowercase(&mut self) {
     /// Note: only extended grapheme codepoints that begin the string will be
     /// escaped.
     ///
-    /// [`char::escape_debug`]: ../std/primitive.char.html#method.escape_debug
-    ///
     /// # Examples
     ///
     /// As an iterator:
@@ -4472,8 +4410,6 @@ pub fn escape_debug(&self) -> EscapeDebug<'_> {
 
     /// Return an iterator that escapes each char in `self` with [`char::escape_default`].
     ///
-    /// [`char::escape_default`]: ../std/primitive.char.html#method.escape_default
-    ///
     /// # Examples
     ///
     /// As an iterator:
@@ -4510,8 +4446,6 @@ pub fn escape_default(&self) -> EscapeDefault<'_> {
 
     /// Return an iterator that escapes each char in `self` with [`char::escape_unicode`].
     ///
-    /// [`char::escape_unicode`]: ../std/primitive.char.html#method.escape_unicode
-    ///
     /// # Examples
     ///
     /// As an iterator:
@@ -4594,8 +4528,7 @@ fn default() -> Self {
 /// This struct is created by the [`split_whitespace`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace
-/// [`str`]: ../../std/primitive.str.html
+/// [`split_whitespace`]: str::split_whitespace
 #[stable(feature = "split_whitespace", since = "1.1.0")]
 #[derive(Clone, Debug)]
 pub struct SplitWhitespace<'a> {
@@ -4608,8 +4541,7 @@ pub struct SplitWhitespace<'a> {
 /// This struct is created by the [`split_ascii_whitespace`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`split_ascii_whitespace`]: ../../std/primitive.str.html#method.split_ascii_whitespace
-/// [`str`]: ../../std/primitive.str.html
+/// [`split_ascii_whitespace`]: str::split_ascii_whitespace
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct SplitAsciiWhitespace<'a> {
@@ -4624,8 +4556,7 @@ pub struct SplitAsciiWhitespace<'a> {
 /// This struct is created by the [`split_inclusive`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`split_inclusive`]: ../../std/primitive.str.html#method.split_inclusive
-/// [`str`]: ../../std/primitive.str.html
+/// [`split_inclusive`]: str::split_inclusive
 #[unstable(feature = "split_inclusive", issue = "72360")]
 pub struct SplitInclusive<'a, P: Pattern<'a>>(SplitInternal<'a, P>);
 
@@ -4759,13 +4690,10 @@ impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
 
 /// An iterator of [`u16`] over the string encoded as UTF-16.
 ///
-/// [`u16`]: ../../std/primitive.u16.html
-///
 /// This struct is created by the [`encode_utf16`] method on [`str`].
 /// See its documentation for more.
 ///
-/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16
-/// [`str`]: ../../std/primitive.str.html
+/// [`encode_utf16`]: str::encode_utf16
 #[derive(Clone)]
 #[stable(feature = "encode_utf16", since = "1.8.0")]
 pub struct EncodeUtf16<'a> {
@@ -4816,8 +4744,6 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 impl FusedIterator for EncodeUtf16<'_> {}
 
 /// The return type of [`str::escape_debug`].
-///
-/// [`str::escape_debug`]: ../../std/primitive.str.html#method.escape_debug
 #[stable(feature = "str_escape", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct EscapeDebug<'a> {
@@ -4828,8 +4754,6 @@ pub struct EscapeDebug<'a> {
 }
 
 /// The return type of [`str::escape_default`].
-///
-/// [`str::escape_default`]: ../../std/primitive.str.html#method.escape_default
 #[stable(feature = "str_escape", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct EscapeDefault<'a> {
@@ -4837,8 +4761,6 @@ pub struct EscapeDefault<'a> {
 }
 
 /// The return type of [`str::escape_unicode`].
-///
-/// [`str::escape_unicode`]: ../../std/primitive.str.html#method.escape_unicode
 #[stable(feature = "str_escape", since = "1.34.0")]
 #[derive(Clone, Debug)]
 pub struct EscapeUnicode<'a> {
index 27760749c1d4b63ddca3afbf14d25da6d2c5ef3e..3d6f4f5971a62db2a88b3657a26008ade27732c4 100644 (file)
@@ -9,3 +9,7 @@
 mod wake;
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
+
+mod ready;
+#[unstable(feature = "ready_macro", issue = "70922")]
+pub use ready::ready;
diff --git a/src/libcore/task/ready.rs b/src/libcore/task/ready.rs
new file mode 100644 (file)
index 0000000..d4e733e
--- /dev/null
@@ -0,0 +1,60 @@
+/// Extracts the successful type of a `Poll<T>`.
+///
+/// This macro bakes in propagation of `Pending` signals by returning early.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(future_readiness_fns)]
+/// #![feature(ready_macro)]
+///
+/// use core::task::{ready, Context, Poll};
+/// use core::future::{self, Future};
+/// use core::pin::Pin;
+///
+/// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
+///     let mut fut = future::ready(42);
+///     let fut = Pin::new(&mut fut);
+///
+///     let num = ready!(fut.poll(cx));
+///     # drop(num);
+///     // ... use num
+///
+///     Poll::Ready(())
+/// }
+/// ```
+///
+/// The `ready!` call expands to:
+///
+/// ```
+/// # #![feature(future_readiness_fns)]
+/// # #![feature(ready_macro)]
+/// #
+/// # use core::task::{Context, Poll};
+/// # use core::future::{self, Future};
+/// # use core::pin::Pin;
+/// #
+/// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
+///     # let mut fut = future::ready(42);
+///     # let fut = Pin::new(&mut fut);
+///     #
+/// let num = match fut.poll(cx) {
+///     Poll::Ready(t) => t,
+///     Poll::Pending => return Poll::Pending,
+/// };
+///     # drop(num);
+///     # // ... use num
+///     #
+///     # Poll::Ready(())
+/// # }
+/// ```
+#[unstable(feature = "ready_macro", issue = "70922")]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro ready($e:expr) {
+    match $e {
+        $crate::task::Poll::Ready(t) => t,
+        $crate::task::Poll::Pending => {
+            return $crate::task::Poll::Pending;
+        }
+    }
+}
diff --git a/src/libcore/tests/lazy.rs b/src/libcore/tests/lazy.rs
new file mode 100644 (file)
index 0000000..1c0bddb
--- /dev/null
@@ -0,0 +1,124 @@
+use core::{
+    cell::Cell,
+    lazy::{Lazy, OnceCell},
+    sync::atomic::{AtomicUsize, Ordering::SeqCst},
+};
+
+#[test]
+fn once_cell() {
+    let c = OnceCell::new();
+    assert!(c.get().is_none());
+    c.get_or_init(|| 92);
+    assert_eq!(c.get(), Some(&92));
+
+    c.get_or_init(|| panic!("Kabom!"));
+    assert_eq!(c.get(), Some(&92));
+}
+
+#[test]
+fn once_cell_get_mut() {
+    let mut c = OnceCell::new();
+    assert!(c.get_mut().is_none());
+    c.set(90).unwrap();
+    *c.get_mut().unwrap() += 2;
+    assert_eq!(c.get_mut(), Some(&mut 92));
+}
+
+#[test]
+fn once_cell_drop() {
+    static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
+    struct Dropper;
+    impl Drop for Dropper {
+        fn drop(&mut self) {
+            DROP_CNT.fetch_add(1, SeqCst);
+        }
+    }
+
+    let x = OnceCell::new();
+    x.get_or_init(|| Dropper);
+    assert_eq!(DROP_CNT.load(SeqCst), 0);
+    drop(x);
+    assert_eq!(DROP_CNT.load(SeqCst), 1);
+}
+
+#[test]
+fn unsync_once_cell_drop_empty() {
+    let x = OnceCell::<&'static str>::new();
+    drop(x);
+}
+
+#[test]
+fn clone() {
+    let s = OnceCell::new();
+    let c = s.clone();
+    assert!(c.get().is_none());
+
+    s.set("hello").unwrap();
+    let c = s.clone();
+    assert_eq!(c.get().map(|c| *c), Some("hello"));
+}
+
+#[test]
+fn from_impl() {
+    assert_eq!(OnceCell::from("value").get(), Some(&"value"));
+    assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
+}
+
+#[test]
+fn partialeq_impl() {
+    assert!(OnceCell::from("value") == OnceCell::from("value"));
+    assert!(OnceCell::from("foo") != OnceCell::from("bar"));
+
+    assert!(OnceCell::<&'static str>::new() == OnceCell::new());
+    assert!(OnceCell::<&'static str>::new() != OnceCell::from("value"));
+}
+
+#[test]
+fn into_inner() {
+    let cell: OnceCell<&'static str> = OnceCell::new();
+    assert_eq!(cell.into_inner(), None);
+    let cell = OnceCell::new();
+    cell.set("hello").unwrap();
+    assert_eq!(cell.into_inner(), Some("hello"));
+}
+
+#[test]
+fn lazy_new() {
+    let called = Cell::new(0);
+    let x = Lazy::new(|| {
+        called.set(called.get() + 1);
+        92
+    });
+
+    assert_eq!(called.get(), 0);
+
+    let y = *x - 30;
+    assert_eq!(y, 62);
+    assert_eq!(called.get(), 1);
+
+    let y = *x - 30;
+    assert_eq!(y, 62);
+    assert_eq!(called.get(), 1);
+}
+
+#[test]
+fn aliasing_in_get() {
+    let x = OnceCell::new();
+    x.set(42).unwrap();
+    let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
+    let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>`   |
+    println!("{}", at_x); // <------- up until here ---------------------------+
+}
+
+#[test]
+#[should_panic(expected = "reentrant init")]
+fn reentrant_init() {
+    let x: OnceCell<Box<i32>> = OnceCell::new();
+    let dangling_ref: Cell<Option<&i32>> = Cell::new(None);
+    x.get_or_init(|| {
+        let r = x.get_or_init(|| Box::new(92));
+        dangling_ref.set(Some(r));
+        Box::new(62)
+    });
+    eprintln!("use after free: {:?}", dangling_ref.get().unwrap());
+}
index 090ce471745668b2802bae1fb055fde69d81a9e6..47ed6db6c677b17428d423aa2cd40379df8e3645 100644 (file)
@@ -43,6 +43,7 @@
 #![feature(option_unwrap_none)]
 #![feature(peekable_next_if)]
 #![feature(partition_point)]
+#![feature(once_cell)]
 #![feature(unsafe_block_in_unsafe_fn)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
@@ -62,6 +63,7 @@
 mod hash;
 mod intrinsics;
 mod iter;
+mod lazy;
 mod manually_drop;
 mod mem;
 mod nonzero;
index 3b6dafeee25404b151a80d898cc5866545e0114a..acaedbd135e7c3c7d7cdeef7a807a475096af0a0 100644 (file)
@@ -130,10 +130,12 @@ impl Duration {
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
-    #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
-    pub fn new(secs: u64, nanos: u32) -> Duration {
-        let secs =
-            secs.checked_add((nanos / NANOS_PER_SEC) as u64).expect("overflow in Duration::new");
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn new(secs: u64, nanos: u32) -> Duration {
+        let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
+            Some(secs) => secs,
+            None => panic!("overflow in Duration::new"),
+        };
         let nanos = nanos % NANOS_PER_SEC;
         Duration { secs, nanos }
     }
@@ -433,7 +435,8 @@ pub const fn as_nanos(&self) -> u128 {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
             let mut nanos = self.nanos + rhs.nanos;
             if nanos >= NANOS_PER_SEC {
@@ -468,7 +471,8 @@ pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
             let nanos = if self.nanos >= rhs.nanos {
                 self.nanos - rhs.nanos
@@ -504,19 +508,19 @@ pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
         // Multiply nanoseconds as u64, because it cannot overflow that way.
         let total_nanos = self.nanos as u64 * rhs as u64;
         let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
         let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
-        if let Some(secs) =
-            self.secs.checked_mul(rhs as u64).and_then(|s| s.checked_add(extra_secs))
-        {
-            debug_assert!(nanos < NANOS_PER_SEC);
-            Some(Duration { secs, nanos })
-        } else {
-            None
+        if let Some(s) = self.secs.checked_mul(rhs as u64) {
+            if let Some(secs) = s.checked_add(extra_secs) {
+                debug_assert!(nanos < NANOS_PER_SEC);
+                return Some(Duration { secs, nanos });
+            }
         }
+        None
     }
 
     /// Checked `Duration` division. Computes `self / other`, returning [`None`]
@@ -537,7 +541,8 @@ pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
     /// ```
     #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
-    pub fn checked_div(self, rhs: u32) -> Option<Duration> {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
         if rhs != 0 {
             let secs = self.secs / (rhs as u64);
             let carry = self.secs - secs * (rhs as u64);
@@ -563,7 +568,8 @@ pub fn checked_div(self, rhs: u32) -> Option<Duration> {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn as_secs_f64(&self) -> f64 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn as_secs_f64(&self) -> f64 {
         (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
     }
 
@@ -580,7 +586,8 @@ pub fn as_secs_f64(&self) -> f64 {
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[inline]
-    pub fn as_secs_f32(&self) -> f32 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn as_secs_f32(&self) -> f32 {
         (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
     }
 
@@ -747,7 +754,8 @@ pub fn div_f32(self, rhs: f32) -> Duration {
     /// ```
     #[unstable(feature = "div_duration", issue = "63139")]
     #[inline]
-    pub fn div_duration_f64(self, rhs: Duration) -> f64 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn div_duration_f64(self, rhs: Duration) -> f64 {
         self.as_secs_f64() / rhs.as_secs_f64()
     }
 
@@ -764,7 +772,8 @@ pub fn div_duration_f64(self, rhs: Duration) -> f64 {
     /// ```
     #[unstable(feature = "div_duration", issue = "63139")]
     #[inline]
-    pub fn div_duration_f32(self, rhs: Duration) -> f32 {
+    #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+    pub const fn div_duration_f32(self, rhs: Duration) -> f32 {
         self.as_secs_f32() / rhs.as_secs_f32()
     }
 }
index 2bee0b716c750f4836068ea38b85e74cceb09b7d..dc385022440e04da18fa35401831f8cbf94fdf1a 100644 (file)
@@ -11,6 +11,7 @@ bench = false
 doc = false
 
 [dependencies]
+cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 core = { path = "../libcore" }
 libc = { version = "0.2", default-features = false }
 compiler_builtins = "0.1.0"
index 27056d5f934fdc1c4f503ab294ba7803dbab2d17..cf52091f609edc90498e9e75bd5dd2954d485d1c 100644 (file)
@@ -21,7 +21,7 @@
 use core::any::Any;
 
 #[rustc_std_internal_symbol]
-#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
+#[allow(improper_ctypes_definitions)]
 pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
     unreachable!()
 }
 pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
     abort();
 
-    #[cfg(any(unix, target_os = "cloudabi"))]
-    unsafe fn abort() -> ! {
-        libc::abort();
-    }
-
-    #[cfg(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten"))))]
-    unsafe fn abort() -> ! {
-        core::intrinsics::abort();
-    }
-
-    #[cfg(any(target_os = "hermit", all(target_vendor = "fortanix", target_env = "sgx")))]
-    unsafe fn abort() -> ! {
-        // call std::sys::abort_internal
-        extern "C" {
-            pub fn __rust_abort() -> !;
+    cfg_if::cfg_if! {
+        if #[cfg(any(unix, target_os = "cloudabi"))] {
+            unsafe fn abort() -> ! {
+                libc::abort();
+            }
+        } else if #[cfg(any(target_os = "hermit",
+                            all(target_vendor = "fortanix", target_env = "sgx")
+        ))] {
+            unsafe fn abort() -> ! {
+                // call std::sys::abort_internal
+                extern "C" {
+                    pub fn __rust_abort() -> !;
+                }
+                __rust_abort();
+            }
+        } else {
+            unsafe fn abort() -> ! {
+                core::intrinsics::abort();
+            }
         }
-        __rust_abort();
     }
 }
 
index f361354da2ac2ff59081a778e10b4fcfb67edec6..72eab0763d8bcdf3e24122c64cc8e3e5bc2091cf 100644 (file)
     if #[cfg(target_os = "emscripten")] {
         #[path = "emcc.rs"]
         mod real_imp;
-    } else if #[cfg(target_arch = "wasm32")] {
-        #[path = "dummy.rs"]
-        mod real_imp;
     } else if #[cfg(target_os = "hermit")] {
         #[path = "hermit.rs"]
         mod real_imp;
     } else if #[cfg(target_env = "msvc")] {
         #[path = "seh.rs"]
         mod real_imp;
-    } else {
+    } else if #[cfg(any(
+        all(target_family = "windows", target_env = "gnu"),
+        target_os = "cloudabi",
+        target_family = "unix",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+    ))] {
         // Rust runtime's startup objects depend on these symbols, so make them public.
         #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
         pub use real_imp::eh_frame_registry::*;
         #[path = "gcc.rs"]
         mod real_imp;
+    } else {
+        // Targets that don't support unwinding.
+        // - arch=wasm32
+        // - os=none ("bare metal" targets)
+        // - os=uefi
+        // - nvptx64-nvidia-cuda
+        // - avr-unknown-unknown
+        // - mipsel-sony-psp
+        #[path = "dummy.rs"]
+        mod real_imp;
     }
 }
 
@@ -81,7 +93,7 @@
 mod dwarf;
 
 #[rustc_std_internal_symbol]
-#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
+#[allow(improper_ctypes_definitions)]
 pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
     Box::into_raw(imp::cleanup(payload))
 }
index 2d5bd7e872bd5923856cbb0dbfbf256f899ea4c3..f960bdecc579f642f0c1489e0eb94ae4eb8703c8 100644 (file)
@@ -26,6 +26,7 @@
 #![feature(in_band_lifetimes)]
 #![feature(negative_impls)]
 #![feature(optin_builtin_traits)]
+#![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
 #![recursion_limit = "256"]
index fbeeb47c23e9dfd40d88ee85d16e8a4c7808d9cf..7c67f029f382db1b4107fc73092759e9885ae413 100644 (file)
@@ -9,7 +9,7 @@ pub enum AllocatorKind {
 }
 
 impl AllocatorKind {
-    pub fn fn_name(&self, base: &str) -> String {
+    pub fn fn_name(&self, base: Symbol) -> String {
         match *self {
             AllocatorKind::Global => format!("__rg_{}", base),
             AllocatorKind::Default => format!("__rdl_{}", base),
@@ -26,29 +26,29 @@ pub enum AllocatorTy {
 }
 
 pub struct AllocatorMethod {
-    pub name: &'static str,
+    pub name: Symbol,
     pub inputs: &'static [AllocatorTy],
     pub output: AllocatorTy,
 }
 
 pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
     AllocatorMethod {
-        name: "alloc",
+        name: sym::alloc,
         inputs: &[AllocatorTy::Layout],
         output: AllocatorTy::ResultPtr,
     },
     AllocatorMethod {
-        name: "dealloc",
+        name: sym::dealloc,
         inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
         output: AllocatorTy::Unit,
     },
     AllocatorMethod {
-        name: "realloc",
+        name: sym::realloc,
         inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize],
         output: AllocatorTy::ResultPtr,
     },
     AllocatorMethod {
-        name: "alloc_zeroed",
+        name: sym::alloc_zeroed,
         inputs: &[AllocatorTy::Layout],
         output: AllocatorTy::ResultPtr,
     },
@@ -70,7 +70,7 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
         }
     }
 
-    let name = Symbol::intern(&AllocatorKind::Global.fn_name("alloc"));
+    let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
     let mut f = Finder { name, spans: Vec::new() };
     visit::walk_crate(&mut f, krate);
     f.spans
index c32ed1ea48c976ca3516ac147f5a01bdd3d24c19..ca68db0b9f6474c70f7d81839c2601d21129a288 100644 (file)
@@ -7,10 +7,9 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)] // For the `transmute` in `P::new`
 #![feature(const_panic)]
-#![cfg_attr(not(bootstrap), feature(const_fn_transmute))]
+#![feature(const_fn_transmute)]
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
 #![feature(nll)]
index 9874754fcd2f7e4b3ce325d03c9fd1cd9031af4e..39921b20226065f74edfa6c541cb6181f07678fb 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::ast;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, CharPos, FileName, Pos};
+use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol};
 
 use log::debug;
 
@@ -52,7 +52,8 @@ pub fn is_doc_comment(s: &str) -> bool {
         || s.starts_with("/*!")
 }
 
-pub fn doc_comment_style(comment: &str) -> ast::AttrStyle {
+pub fn doc_comment_style(comment: Symbol) -> ast::AttrStyle {
+    let comment = &comment.as_str();
     assert!(is_doc_comment(comment));
     if comment.starts_with("//!") || comment.starts_with("/*!") {
         ast::AttrStyle::Inner
@@ -61,7 +62,9 @@ pub fn doc_comment_style(comment: &str) -> ast::AttrStyle {
     }
 }
 
-pub fn strip_doc_comment_decoration(comment: &str) -> String {
+pub fn strip_doc_comment_decoration(comment: Symbol) -> String {
+    let comment = &comment.as_str();
+
     /// remove whitespace-only lines from the start/end of lines
     fn vertical_trim(lines: Vec<String>) -> Vec<String> {
         let mut i = 0;
index f9cd69fb50d7472c9b3044c9c5f2fc3be279cdb2..f08011fe4f862d213e22596d302492dc3de20a43 100644 (file)
@@ -1,47 +1,58 @@
 use super::*;
+use crate::with_default_session_globals;
 
 #[test]
 fn test_block_doc_comment_1() {
-    let comment = "/**\n * Test \n **  Test\n *   Test\n*/";
-    let stripped = strip_doc_comment_decoration(comment);
-    assert_eq!(stripped, " Test \n*  Test\n   Test");
+    with_default_session_globals(|| {
+        let comment = "/**\n * Test \n **  Test\n *   Test\n*/";
+        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+        assert_eq!(stripped, " Test \n*  Test\n   Test");
+    })
 }
 
 #[test]
 fn test_block_doc_comment_2() {
-    let comment = "/**\n * Test\n *  Test\n*/";
-    let stripped = strip_doc_comment_decoration(comment);
-    assert_eq!(stripped, " Test\n  Test");
+    with_default_session_globals(|| {
+        let comment = "/**\n * Test\n *  Test\n*/";
+        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+        assert_eq!(stripped, " Test\n  Test");
+    })
 }
 
 #[test]
 fn test_block_doc_comment_3() {
-    let comment = "/**\n let a: *i32;\n *a = 5;\n*/";
-    let stripped = strip_doc_comment_decoration(comment);
-    assert_eq!(stripped, " let a: *i32;\n *a = 5;");
+    with_default_session_globals(|| {
+        let comment = "/**\n let a: *i32;\n *a = 5;\n*/";
+        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+        assert_eq!(stripped, " let a: *i32;\n *a = 5;");
+    })
 }
 
 #[test]
 fn test_block_doc_comment_4() {
-    let comment = "/*******************\n test\n *********************/";
-    let stripped = strip_doc_comment_decoration(comment);
-    assert_eq!(stripped, " test");
+    with_default_session_globals(|| {
+        let comment = "/*******************\n test\n *********************/";
+        let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+        assert_eq!(stripped, " test");
+    })
 }
 
 #[test]
 fn test_line_doc_comment() {
-    let stripped = strip_doc_comment_decoration("/// test");
-    assert_eq!(stripped, " test");
-    let stripped = strip_doc_comment_decoration("///! test");
-    assert_eq!(stripped, " test");
-    let stripped = strip_doc_comment_decoration("// test");
-    assert_eq!(stripped, " test");
-    let stripped = strip_doc_comment_decoration("// test");
-    assert_eq!(stripped, " test");
-    let stripped = strip_doc_comment_decoration("///test");
-    assert_eq!(stripped, "test");
-    let stripped = strip_doc_comment_decoration("///!test");
-    assert_eq!(stripped, "test");
-    let stripped = strip_doc_comment_decoration("//test");
-    assert_eq!(stripped, "test");
+    with_default_session_globals(|| {
+        let stripped = strip_doc_comment_decoration(Symbol::intern("/// test"));
+        assert_eq!(stripped, " test");
+        let stripped = strip_doc_comment_decoration(Symbol::intern("///! test"));
+        assert_eq!(stripped, " test");
+        let stripped = strip_doc_comment_decoration(Symbol::intern("// test"));
+        assert_eq!(stripped, " test");
+        let stripped = strip_doc_comment_decoration(Symbol::intern("// test"));
+        assert_eq!(stripped, " test");
+        let stripped = strip_doc_comment_decoration(Symbol::intern("///test"));
+        assert_eq!(stripped, "test");
+        let stripped = strip_doc_comment_decoration(Symbol::intern("///!test"));
+        assert_eq!(stripped, "test");
+        let stripped = strip_doc_comment_decoration(Symbol::intern("//test"));
+        assert_eq!(stripped, "test");
+    })
 }
index cce86fed9891c14fe3b4e5c8e44d556338df3271..d4e0e3ba051c95c214f2561ce94757583d6a3787 100644 (file)
@@ -47,12 +47,13 @@ pub fn lev_distance(a: &str, b: &str) -> usize {
 /// a lower(upper)case letters mismatch.
 pub fn find_best_match_for_name<'a, T>(
     iter_names: T,
-    lookup: &str,
+    lookup: Symbol,
     dist: Option<usize>,
 ) -> Option<Symbol>
 where
     T: Iterator<Item = &'a Symbol>,
 {
+    let lookup = &lookup.as_str();
     let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
     let name_vec: Vec<&Symbol> = iter_names.collect();
 
index e9b6c9759b64409db1808f9965bfb8022c5adc48..94d56a3d7b4ae23944a9df7606147616b1752c10 100644 (file)
@@ -25,31 +25,34 @@ fn test_find_best_match_for_name() {
     with_default_session_globals(|| {
         let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")];
         assert_eq!(
-            find_best_match_for_name(input.iter(), "aaaa", None),
+            find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None),
             Some(Symbol::intern("aaab"))
         );
 
-        assert_eq!(find_best_match_for_name(input.iter(), "1111111111", None), None);
+        assert_eq!(
+            find_best_match_for_name(input.iter(), Symbol::intern("1111111111"), None),
+            None
+        );
 
         let input = vec![Symbol::intern("aAAA")];
         assert_eq!(
-            find_best_match_for_name(input.iter(), "AAAA", None),
+            find_best_match_for_name(input.iter(), Symbol::intern("AAAA"), None),
             Some(Symbol::intern("aAAA"))
         );
 
         let input = vec![Symbol::intern("AAAA")];
         // Returns None because `lev_distance > max_dist / 3`
-        assert_eq!(find_best_match_for_name(input.iter(), "aaaa", None), None);
+        assert_eq!(find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None), None);
 
         let input = vec![Symbol::intern("AAAA")];
         assert_eq!(
-            find_best_match_for_name(input.iter(), "aaaa", Some(4)),
+            find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), Some(4)),
             Some(Symbol::intern("AAAA"))
         );
 
         let input = vec![Symbol::intern("a_longer_variable_name")];
         assert_eq!(
-            find_best_match_for_name(input.iter(), "a_variable_longer_name", None),
+            find_best_match_for_name(input.iter(), Symbol::intern("a_variable_longer_name"), None),
             Some(Symbol::intern("a_longer_variable_name"))
         );
     })
index 90a3a5ec64e0e56ba973720bc30932a8e9ffd267..201972fcf264bd505b6e5f61b187f1e4e0be9541 100644 (file)
@@ -526,7 +526,7 @@ pub(super) fn make_async_expr(
             Ident::with_dummy_span(sym::_task_context),
             hir::BindingAnnotation::Mutable,
         );
-        let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, span };
+        let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, ty_span: span, span };
         let params = arena_vec![self; param];
 
         let body_id = self.lower_body(move |this| {
index 00665c4cafb6b4d24d23c180cddeecaa52cd0414..dd5e658102facacbe5688df07b9427c7961a5c03 100644 (file)
@@ -972,6 +972,7 @@ fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> {
             attrs: self.lower_attrs(&param.attrs),
             hir_id: self.lower_node_id(param.id),
             pat: self.lower_pat(&param.pat),
+            ty_span: param.ty.span,
             span: param.span,
         }
     }
@@ -1098,6 +1099,7 @@ fn lower_maybe_async_body(
                     attrs: parameter.attrs,
                     hir_id: parameter.hir_id,
                     pat: new_parameter_pat,
+                    ty_span: parameter.ty_span,
                     span: parameter.span,
                 };
 
index a7b0c9cf81be6706d053ed6a90d6f8a9ddf8e3d4..b424c8afb34717121efaf16fbbe025e3c33bb6c5 100644 (file)
@@ -253,6 +253,7 @@ macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
                     include => external_doc
                     cfg => doc_cfg
                     masked => doc_masked
+                    spotlight => doc_spotlight
                     alias => doc_alias
                     keyword => doc_keyword
                 );
index 2d803262f79e1cf2ffeeb523035f1e59ed395942..b0edb1ca41d207df4bb9cc15ace04de4fc254e0e 100644 (file)
@@ -450,9 +450,20 @@ fn maybe_print_comment(&mut self, pos: BytePos) {
     fn print_comment(&mut self, cmnt: &comments::Comment) {
         match cmnt.style {
             comments::Mixed => {
-                assert_eq!(cmnt.lines.len(), 1);
                 self.zerobreak();
-                self.word(cmnt.lines[0].clone());
+                if let Some((last, lines)) = cmnt.lines.split_last() {
+                    self.ibox(0);
+
+                    for line in lines {
+                        self.word(line.clone());
+                        self.hardbreak()
+                    }
+
+                    self.word(last.clone());
+                    self.space();
+
+                    self.end();
+                }
                 self.zerobreak()
             }
             comments::Isolated => {
@@ -522,6 +533,10 @@ fn print_string(&mut self, st: &str, style: ast::StrStyle) {
         self.word(st)
     }
 
+    fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
+        self.print_string(&sym.as_str(), style);
+    }
+
     fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
     }
@@ -2050,7 +2065,7 @@ enum AsmArg<'a> {
                         let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r
                         {
                             InlineAsmRegOrRegClass::Reg(r) => {
-                                s.print_string(&r.as_str(), ast::StrStyle::Cooked)
+                                s.print_symbol(*r, ast::StrStyle::Cooked)
                             }
                             InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
                         };
@@ -2144,7 +2159,7 @@ enum AsmArg<'a> {
             ast::ExprKind::LlvmInlineAsm(ref a) => {
                 self.s.word("llvm_asm!");
                 self.popen();
-                self.print_string(&a.asm.as_str(), a.asm_str_style);
+                self.print_symbol(a.asm, a.asm_str_style);
                 self.word_space(":");
 
                 self.commasep(Inconsistent, &a.outputs, |s, out| {
@@ -2164,7 +2179,7 @@ enum AsmArg<'a> {
                 self.word_space(":");
 
                 self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
-                    s.print_string(&co.as_str(), ast::StrStyle::Cooked);
+                    s.print_symbol(co, ast::StrStyle::Cooked);
                     s.popen();
                     s.print_expr(o);
                     s.pclose();
@@ -2172,8 +2187,8 @@ enum AsmArg<'a> {
                 self.s.space();
                 self.word_space(":");
 
-                self.commasep(Inconsistent, &a.clobbers, |s, co| {
-                    s.print_string(&co.as_str(), ast::StrStyle::Cooked);
+                self.commasep(Inconsistent, &a.clobbers, |s, &co| {
+                    s.print_symbol(co, ast::StrStyle::Cooked);
                 });
 
                 let mut options = vec![];
index af09779d072c313d608ea781676bb6e97699dae4..0606fac2fe748f17aa13ee7e078ab363f146ecb6 100644 (file)
@@ -1041,10 +1041,10 @@ pub fn find_transparency(
                 break;
             } else if let Some(value) = attr.value_str() {
                 transparency = Some((
-                    match &*value.as_str() {
-                        "transparent" => Transparency::Transparent,
-                        "semitransparent" => Transparency::SemiTransparent,
-                        "opaque" => Transparency::Opaque,
+                    match value {
+                        sym::transparent => Transparency::Transparent,
+                        sym::semitransparent => Transparency::SemiTransparent,
+                        sym::opaque => Transparency::Opaque,
                         _ => {
                             error = Some(TransparencyError::UnknownTransparency(value, attr.span));
                             continue;
index a1c818caff3bf02dd1c8e1f600ba2dd3fa37090c..cef0da60a61c8c642693d930fc9079d9d9089e88 100644 (file)
@@ -16,9 +16,9 @@ pub fn expand_deriving_copy(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, marker::Copy),
+        path: path_std!(marker::Copy),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: true,
         methods: Vec::new(),
index 5dbf3825ce6930139a38e0163f274682350f39f2..b307ee26c91d518e513cc31379a77f69698e2573 100644 (file)
@@ -56,7 +56,7 @@ pub fn expand_deriving_clone(
                 }
             }
             ItemKind::Union(..) => {
-                bounds = vec![Literal(path_std!(cx, marker::Copy))];
+                bounds = vec![Literal(path_std!(marker::Copy))];
                 is_shallow = true;
                 substructure = combine_substructure(Box::new(|c, s, sub| {
                     cs_clone_shallow("Clone", c, s, sub, true)
@@ -78,14 +78,14 @@ pub fn expand_deriving_clone(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, clone::Clone),
+        path: path_std!(clone::Clone),
         additional_bounds: bounds,
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: true,
         methods: vec![MethodDef {
-            name: "clone",
-            generics: LifetimeBounds::empty(),
+            name: sym::clone,
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
             args: Vec::new(),
             ret_ty: Self_,
index b3b15b897828a6adfa9846f2d8ecbae6edc6d6a3..d1b799cd6a112d841614ccba3f1d9731f70b76ef 100644 (file)
@@ -22,14 +22,14 @@ pub fn expand_deriving_eq(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, cmp::Eq),
+        path: path_std!(cmp::Eq),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: true,
         methods: vec![MethodDef {
-            name: "assert_receiver_is_total_eq",
-            generics: LifetimeBounds::empty(),
+            name: sym::assert_receiver_is_total_eq,
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
             args: vec![],
             ret_ty: nil_ty(),
@@ -43,13 +43,7 @@ pub fn expand_deriving_eq(
         associated_types: Vec::new(),
     };
 
-    super::inject_impl_of_structural_trait(
-        cx,
-        span,
-        item,
-        path_std!(cx, marker::StructuralEq),
-        push,
-    );
+    super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);
 
     trait_def.expand_ext(cx, mitem, item, push, true)
 }
index 030d2c837428ba915bb3710eba7513ea86b0b511..3bf3860d32307d52c3f53d07fccf571f58ddf346 100644 (file)
@@ -20,17 +20,17 @@ pub fn expand_deriving_ord(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, cmp::Ord),
+        path: path_std!(cmp::Ord),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
-            name: "cmp",
-            generics: LifetimeBounds::empty(),
+            name: sym::cmp,
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
-            args: vec![(borrowed_self(), "other")],
-            ret_ty: Literal(path_std!(cx, cmp::Ordering)),
+            args: vec![(borrowed_self(), sym::other)],
+            ret_ty: Literal(path_std!(cmp::Ordering)),
             attributes: attrs,
             is_unsafe: false,
             unify_fieldless_variants: true,
index d3f1a9c15f49e7595065401cdbc506eb7a0d7d5c..d8edd641acd52dd945f038f942d2ce7ed61877d6 100644 (file)
@@ -69,9 +69,9 @@ macro_rules! md {
             let attrs = vec![cx.attribute(inline)];
             MethodDef {
                 name: $name,
-                generics: LifetimeBounds::empty(),
+                generics: Bounds::empty(),
                 explicit_self: borrowed_explicit_self(),
-                args: vec![(borrowed_self(), "other")],
+                args: vec![(borrowed_self(), sym::other)],
                 ret_ty: Literal(path_local!(bool)),
                 attributes: attrs,
                 is_unsafe: false,
@@ -85,24 +85,24 @@ macro_rules! md {
         cx,
         span,
         item,
-        path_std!(cx, marker::StructuralPartialEq),
+        path_std!(marker::StructuralPartialEq),
         push,
     );
 
     // avoid defining `ne` if we can
     // c-like enums, enums without any fields and structs without fields
     // can safely define only `eq`.
-    let mut methods = vec![md!("eq", cs_eq)];
+    let mut methods = vec![md!(sym::eq, cs_eq)];
     if !is_type_without_fields(item) {
-        methods.push(md!("ne", cs_ne));
+        methods.push(md!(sym::ne, cs_ne));
     }
 
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, cmp::PartialEq),
+        path: path_std!(cmp::PartialEq),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods,
index f29f91e82312befde7d93c190d569e1caa421b26..39a747c856839455077a808c190eb83224299072 100644 (file)
@@ -23,9 +23,9 @@ macro_rules! md {
             let attrs = vec![cx.attribute(inline)];
             MethodDef {
                 name: $name,
-                generics: LifetimeBounds::empty(),
+                generics: Bounds::empty(),
                 explicit_self: borrowed_explicit_self(),
-                args: vec![(borrowed_self(), "other")],
+                args: vec![(borrowed_self(), sym::other)],
                 ret_ty: Literal(path_local!(bool)),
                 attributes: attrs,
                 is_unsafe: false,
@@ -37,9 +37,9 @@ macro_rules! md {
         }};
     }
 
-    let ordering_ty = Literal(path_std!(cx, cmp::Ordering));
+    let ordering_ty = Literal(path_std!(cmp::Ordering));
     let ret_ty = Literal(Path::new_(
-        pathvec_std!(cx, option::Option),
+        pathvec_std!(option::Option),
         None,
         vec![Box::new(ordering_ty)],
         PathKind::Std,
@@ -49,10 +49,10 @@ macro_rules! md {
     let attrs = vec![cx.attribute(inline)];
 
     let partial_cmp_def = MethodDef {
-        name: "partial_cmp",
-        generics: LifetimeBounds::empty(),
+        name: sym::partial_cmp,
+        generics: Bounds::empty(),
         explicit_self: borrowed_explicit_self(),
-        args: vec![(borrowed_self(), "other")],
+        args: vec![(borrowed_self(), sym::other)],
         ret_ty,
         attributes: attrs,
         is_unsafe: false,
@@ -70,19 +70,19 @@ macro_rules! md {
     } else {
         vec![
             partial_cmp_def,
-            md!("lt", true, false),
-            md!("le", true, true),
-            md!("gt", false, false),
-            md!("ge", false, true),
+            md!(sym::lt, true, false),
+            md!(sym::le, true, true),
+            md!(sym::gt, false, false),
+            md!(sym::ge, false, true),
         ]
     };
 
     let trait_def = TraitDef {
         span,
         attributes: vec![],
-        path: path_std!(cx, cmp::PartialOrd),
+        path: path_std!(cmp::PartialOrd),
         additional_bounds: vec![],
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods,
@@ -108,14 +108,14 @@ pub fn some_ordering_collapsed(
 ) -> P<ast::Expr> {
     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 {
-        PartialCmpOp => "partial_cmp",
-        LtOp => "lt",
-        LeOp => "le",
-        GtOp => "gt",
-        GeOp => "ge",
+    let op_sym = match op {
+        PartialCmpOp => sym::partial_cmp,
+        LtOp => sym::lt,
+        LeOp => sym::le,
+        GtOp => sym::gt,
+        GeOp => sym::ge,
     };
-    cx.expr_method_call(span, lft, cx.ident_of(op_str, span), vec![rgt])
+    cx.expr_method_call(span, lft, Ident::new(op_sym, span), vec![rgt])
 }
 
 pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
index 99c2b6f8a4eac38dfba90b50d999f303c342fd80..76e21bc43c52d84ec614ded321737770031e515d 100644 (file)
@@ -18,22 +18,22 @@ pub fn expand_deriving_debug(
 ) {
     // &mut ::std::fmt::Formatter
     let fmtr =
-        Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));
+        Ptr(Box::new(Literal(path_std!(fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));
 
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, fmt::Debug),
+        path: path_std!(fmt::Debug),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
-            name: "fmt",
-            generics: LifetimeBounds::empty(),
+            name: sym::fmt,
+            generics: Bounds::empty(),
             explicit_self: borrowed_explicit_self(),
-            args: vec![(fmtr, "f")],
-            ret_ty: Literal(path_std!(cx, fmt::Result)),
+            args: vec![(fmtr, sym::f)],
+            ret_ty: Literal(path_std!(fmt::Result)),
             attributes: Vec::new(),
             is_unsafe: false,
             unify_fieldless_variants: false,
@@ -62,7 +62,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
     let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
-    let builder = cx.ident_of("debug_trait_builder", span);
+    let builder = Ident::new(sym::debug_trait_builder, span);
     let builder_expr = cx.expr_ident(span, builder);
 
     let fmt = substr.nonself_args[0].clone();
@@ -71,7 +71,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     match vdata {
         ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
             // tuple struct/"normal" variant
-            let expr = cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]);
+            let expr =
+                cx.expr_method_call(span, fmt, Ident::new(sym::debug_tuple, span), vec![name]);
             stmts.push(cx.stmt_let(span, true, builder, expr));
 
             for field in fields {
@@ -94,7 +95,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, cx.ident_of("debug_struct", span), vec![name]);
+                cx.expr_method_call(span, fmt, Ident::new(sym::debug_struct, span), vec![name]);
             stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
 
             for field in fields {
@@ -117,7 +118,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         }
     }
 
-    let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]);
+    let expr = cx.expr_method_call(span, builder_expr, Ident::new(sym::finish, span), vec![]);
 
     stmts.push(cx.stmt_expr(expr));
     let block = cx.block(span, stmts);
index 64a810bdcf687a1fe7caf09ebb6970f1c885ac01..ce8c2dfe4d5a099ebc5890ab5b4ea9e40db82a4f 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_ast::ast::{Expr, MetaItem, Mutability};
 use rustc_ast::ptr::P;
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 
 pub fn expand_deriving_rustc_decodable(
@@ -18,38 +18,37 @@ pub fn expand_deriving_rustc_decodable(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let krate = "rustc_serialize";
-    let typaram = "__D";
+    let krate = sym::rustc_serialize;
+    let typaram = sym::__D;
 
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: Path::new_(vec![krate, "Decodable"], None, vec![], PathKind::Global),
+        path: Path::new_(vec![krate, sym::Decodable], None, vec![], PathKind::Global),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
-            name: "decode",
-            generics: LifetimeBounds {
-                lifetimes: Vec::new(),
+            name: sym::decode,
+            generics: Bounds {
                 bounds: vec![(
                     typaram,
-                    vec![Path::new_(vec![krate, "Decoder"], None, vec![], PathKind::Global)],
+                    vec![Path::new_(vec![krate, sym::Decoder], None, vec![], PathKind::Global)],
                 )],
             },
             explicit_self: None,
             args: vec![(
                 Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
-                "d",
+                sym::d,
             )],
             ret_ty: Literal(Path::new_(
-                pathvec_std!(cx, result::Result),
+                pathvec_std!(result::Result),
                 None,
                 vec![
                     Box::new(Self_),
                     Box::new(Literal(Path::new_(
-                        vec![typaram, "Error"],
+                        vec![typaram, sym::Error],
                         None,
                         vec![],
                         PathKind::Local,
@@ -74,17 +73,17 @@ fn decodable_substructure(
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
-    krate: &str,
+    krate: Symbol,
 ) -> P<Expr> {
     let decoder = substr.nonself_args[0].clone();
     let recurse = vec![
-        cx.ident_of(krate, trait_span),
-        cx.ident_of("Decodable", trait_span),
-        cx.ident_of("decode", trait_span),
+        Ident::new(krate, trait_span),
+        Ident::new(sym::Decodable, trait_span),
+        Ident::new(sym::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", trait_span);
+    let blkarg = Ident::new(sym::_d, trait_span);
     let blkdecoder = cx.expr_ident(trait_span, blkarg);
 
     match *substr.fields {
@@ -93,7 +92,7 @@ fn decodable_substructure(
                 Unnamed(ref fields, _) => fields.len(),
                 Named(ref fields) => fields.len(),
             };
-            let read_struct_field = cx.ident_of("read_struct_field", trait_span);
+            let read_struct_field = Ident::new(sym::read_struct_field, trait_span);
 
             let path = cx.path_ident(trait_span, substr.type_ident);
             let result =
@@ -116,7 +115,7 @@ fn decodable_substructure(
             cx.expr_method_call(
                 trait_span,
                 decoder,
-                cx.ident_of("read_struct", trait_span),
+                Ident::new(sym::read_struct, trait_span),
                 vec![
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.expr_usize(trait_span, nfields),
@@ -125,11 +124,11 @@ fn decodable_substructure(
             )
         }
         StaticEnum(_, ref fields) => {
-            let variant = cx.ident_of("i", trait_span);
+            let variant = Ident::new(sym::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", trait_span);
+            let rvariant_arg = Ident::new(sym::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));
@@ -164,13 +163,13 @@ fn decodable_substructure(
             let result = cx.expr_method_call(
                 trait_span,
                 blkdecoder,
-                cx.ident_of("read_enum_variant", trait_span),
+                Ident::new(sym::read_enum_variant, trait_span),
                 vec![variant_vec, lambda],
             );
             cx.expr_method_call(
                 trait_span,
                 decoder,
-                cx.ident_of("read_enum", trait_span),
+                Ident::new(sym::read_enum, trait_span),
                 vec![
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.lambda1(trait_span, result, blkarg),
index 27d5263320041221b3ac3d18c340db64b0849eac..8ca1be1efb635f7685382e853d35e7e57e34d55f 100644 (file)
@@ -1,6 +1,5 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
-use crate::deriving::path_std;
 
 use rustc_ast::ast::{Expr, MetaItem};
 use rustc_ast::ptr::P;
@@ -21,14 +20,14 @@ pub fn expand_deriving_default(
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: path_std!(cx, default::Default),
+        path: Path::new(vec![kw::Default, sym::Default]),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
-            name: "default",
-            generics: LifetimeBounds::empty(),
+            name: kw::Default,
+            generics: Bounds::empty(),
             explicit_self: None,
             args: Vec::new(),
             ret_ty: Self_,
index 54926ec3fd502aeb44cf1ebbeb2c697e5073e4aa..7a880357a594740939a7fd55bfe129668047d994 100644 (file)
@@ -92,7 +92,7 @@
 use rustc_ast::ast::{Expr, ExprKind, MetaItem, Mutability};
 use rustc_ast::ptr::P;
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 
 pub fn expand_deriving_rustc_encodable(
@@ -102,38 +102,42 @@ pub fn expand_deriving_rustc_encodable(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let krate = "rustc_serialize";
-    let typaram = "__S";
+    let krate = sym::rustc_serialize;
+    let typaram = sym::__S;
 
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
-        path: Path::new_(vec![krate, "Encodable"], None, vec![], PathKind::Global),
+        path: Path::new_(vec![krate, sym::Encodable], None, vec![], PathKind::Global),
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
-            name: "encode",
-            generics: LifetimeBounds {
-                lifetimes: Vec::new(),
+            name: sym::encode,
+            generics: Bounds {
                 bounds: vec![(
                     typaram,
-                    vec![Path::new_(vec![krate, "Encoder"], None, vec![], PathKind::Global)],
+                    vec![Path::new_(vec![krate, sym::Encoder], None, vec![], PathKind::Global)],
                 )],
             },
             explicit_self: borrowed_explicit_self(),
             args: vec![(
                 Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mut)),
-                "s",
+                // FIXME: we could use `sym::s` here, but making `s` a static
+                // symbol changes the symbol index ordering in a way that makes
+                // ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
+                // fail. The linting code should be fixed so that its output
+                // does not depend on the symbol index ordering.
+                Symbol::intern("s"),
             )],
             ret_ty: Literal(Path::new_(
-                pathvec_std!(cx, result::Result),
+                pathvec_std!(result::Result),
                 None,
                 vec![
                     Box::new(Tuple(Vec::new())),
                     Box::new(Literal(Path::new_(
-                        vec![typaram, "Error"],
+                        vec![typaram, sym::Error],
                         None,
                         vec![],
                         PathKind::Local,
@@ -158,24 +162,24 @@ fn encodable_substructure(
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
-    krate: &'static str,
+    krate: Symbol,
 ) -> P<Expr> {
     let encoder = substr.nonself_args[0].clone();
     // throw an underscore in front to suppress unused variable warnings
-    let blkarg = cx.ident_of("_e", trait_span);
+    let blkarg = Ident::new(sym::_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, trait_span),
-            cx.ident_of("Encodable", trait_span),
-            cx.ident_of("encode", trait_span),
+            Ident::new(krate, trait_span),
+            Ident::new(sym::Encodable, trait_span),
+            Ident::new(sym::encode, trait_span),
         ],
     ));
 
     match *substr.fields {
         Struct(_, ref fields) => {
-            let emit_struct_field = cx.ident_of("emit_struct_field", trait_span);
+            let emit_struct_field = Ident::new(sym::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 {
@@ -215,7 +219,7 @@ fn encodable_substructure(
             cx.expr_method_call(
                 trait_span,
                 encoder,
-                cx.ident_of("emit_struct", trait_span),
+                Ident::new(sym::emit_struct, trait_span),
                 vec![
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.expr_usize(trait_span, fields.len()),
@@ -231,7 +235,7 @@ fn encodable_substructure(
             // 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", trait_span);
+            let emit_variant_arg = Ident::new(sym::emit_enum_variant_arg, trait_span);
             let mut stmts = Vec::new();
             if !fields.is_empty() {
                 let last = fields.len() - 1;
@@ -264,7 +268,7 @@ fn encodable_substructure(
             let call = cx.expr_method_call(
                 trait_span,
                 blkencoder,
-                cx.ident_of("emit_enum_variant", trait_span),
+                Ident::new(sym::emit_enum_variant, trait_span),
                 vec![
                     name,
                     cx.expr_usize(trait_span, idx),
@@ -276,7 +280,7 @@ fn encodable_substructure(
             let ret = cx.expr_method_call(
                 trait_span,
                 encoder,
-                cx.ident_of("emit_enum", trait_span),
+                Ident::new(sym::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)]))
index a9567f20d6925ea0dd1f6a4a2fa2ed9887942304..c43d1cf1888c494a012873b554e5c6b1a004a9c4 100644 (file)
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 
-use ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
+use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty};
 
 use crate::deriving;
 
@@ -204,14 +204,14 @@ pub struct TraitDef<'a> {
     pub attributes: Vec<ast::Attribute>,
 
     /// Path of the trait, including any type parameters
-    pub path: Path<'a>,
+    pub path: Path,
 
     /// Additional bounds required of any type parameters of the type,
     /// other than the current trait
-    pub additional_bounds: Vec<Ty<'a>>,
+    pub additional_bounds: Vec<Ty>,
 
     /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder`
-    pub generics: LifetimeBounds<'a>,
+    pub generics: Bounds,
 
     /// Is it an `unsafe` trait?
     pub is_unsafe: bool,
@@ -221,14 +221,14 @@ pub struct TraitDef<'a> {
 
     pub methods: Vec<MethodDef<'a>>,
 
-    pub associated_types: Vec<(Ident, Ty<'a>)>,
+    pub associated_types: Vec<(Ident, Ty)>,
 }
 
 pub struct MethodDef<'a> {
     /// name of the method
-    pub name: &'a str,
+    pub name: Symbol,
     /// List of generics, e.g., `R: rand::Rng`
-    pub generics: LifetimeBounds<'a>,
+    pub generics: Bounds,
 
     /// Whether there is a self argument (outer Option) i.e., whether
     /// this is a static function, and whether it is a pointer (inner
@@ -236,10 +236,10 @@ pub struct MethodDef<'a> {
     pub explicit_self: Option<Option<PtrTy>>,
 
     /// Arguments other than the self argument
-    pub args: Vec<(Ty<'a>, &'a str)>,
+    pub args: Vec<(Ty, Symbol)>,
 
     /// Returns type
-    pub ret_ty: Ty<'a>,
+    pub ret_ty: Ty,
 
     pub attributes: Vec<ast::Attribute>,
 
@@ -681,7 +681,7 @@ fn create_derived_impl(
         let opt_trait_ref = Some(trait_ref);
         let unused_qual = {
             let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
-                Symbol::intern("unused_qualifications"),
+                sym::unused_qualifications,
                 self.span,
             ));
             let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]);
@@ -818,7 +818,7 @@ fn call_substructure_method(
     ) -> P<Expr> {
         let substructure = Substructure {
             type_ident,
-            method_ident: cx.ident_of(self.name, trait_.span),
+            method_ident: Ident::new(self.name, trait_.span),
             self_args,
             nonself_args,
             fields,
@@ -865,7 +865,7 @@ fn split_self_nonself_args(
 
         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, trait_.span);
+            let ident = Ident::new(*name, trait_.span);
             arg_tys.push((ident, ast_ty));
 
             let arg_expr = cx.expr_ident(trait_.span, ident);
@@ -913,7 +913,7 @@ fn create_method(
 
         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
 
-        let method_ident = cx.ident_of(self.name, trait_.span);
+        let method_ident = Ident::new(self.name, trait_.span);
         let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
         let body_block = cx.block_expr(body);
 
@@ -1170,8 +1170,10 @@ fn build_enum_match_tuple<'b>(
             )
             .collect::<Vec<String>>();
 
-        let self_arg_idents =
-            self_arg_names.iter().map(|name| cx.ident_of(name, sp)).collect::<Vec<Ident>>();
+        let self_arg_idents = self_arg_names
+            .iter()
+            .map(|name| Ident::from_str_and_span(name, sp))
+            .collect::<Vec<Ident>>();
 
         // The `vi_idents` will be bound, solely in the catch-all, to
         // a series of let statements mapping each self_arg to an int
@@ -1180,7 +1182,7 @@ fn build_enum_match_tuple<'b>(
             .iter()
             .map(|name| {
                 let vi_suffix = format!("{}_vi", &name[..]);
-                cx.ident_of(&vi_suffix[..], trait_.span)
+                Ident::from_str_and_span(&vi_suffix, trait_.span)
             })
             .collect::<Vec<Ident>>();
 
@@ -1315,7 +1317,7 @@ fn build_enum_match_tuple<'b>(
                 // Since we know that all the arguments will match if we reach
                 // the match expression we add the unreachable intrinsics as the
                 // result of the catch all which should help llvm in optimizing it
-                Some(deriving::call_intrinsic(cx, sp, "unreachable", vec![]))
+                Some(deriving::call_intrinsic(cx, sp, sym::unreachable, vec![]))
             }
             _ => None,
         };
@@ -1363,7 +1365,7 @@ fn build_enum_match_tuple<'b>(
             for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
                 let self_addr = cx.expr_addr_of(sp, self_arg.clone());
                 let variant_value =
-                    deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]);
+                    deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]);
                 let let_stmt = cx.stmt_let(sp, false, ident, variant_value);
                 index_let_stmts.push(let_stmt);
 
@@ -1464,7 +1466,7 @@ fn build_enum_match_tuple<'b>(
             // derive Debug on such a type could here generate code
             // that needs the feature gate enabled.)
 
-            deriving::call_intrinsic(cx, sp, "unreachable", vec![])
+            deriving::call_intrinsic(cx, sp, sym::unreachable, vec![])
         } else {
             // Final wrinkle: the self_args are expressions that deref
             // down to desired places, but we cannot actually deref
@@ -1568,7 +1570,7 @@ fn create_struct_pattern(
         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), self.span);
+            let ident = Ident::from_str_and_span(&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 { val } else { cx.expr_deref(sp, val) };
index 609feb6f259d6a9647de777421155b398b347340..51314dbcffc06e5d50358f6f846632f16a53d499 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_ast::ptr::P;
 use rustc_expand::base::ExtCtxt;
 use rustc_span::source_map::{respan, DUMMY_SP};
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 
 /// The types of pointers
@@ -24,10 +24,10 @@ pub enum PtrTy {
 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
 /// for type parameters and a lifetime.
 #[derive(Clone)]
-pub struct Path<'a> {
-    path: Vec<&'a str>,
+pub struct Path {
+    path: Vec<Symbol>,
     lifetime: Option<Ident>,
-    params: Vec<Box<Ty<'a>>>,
+    params: Vec<Box<Ty>>,
     kind: PathKind,
 }
 
@@ -38,19 +38,19 @@ pub enum PathKind {
     Std,
 }
 
-impl<'a> Path<'a> {
-    pub fn new(path: Vec<&str>) -> Path<'_> {
+impl Path {
+    pub fn new(path: Vec<Symbol>) -> Path {
         Path::new_(path, None, Vec::new(), PathKind::Std)
     }
-    pub fn new_local(path: &str) -> Path<'_> {
+    pub fn new_local(path: Symbol) -> Path {
         Path::new_(vec![path], None, Vec::new(), PathKind::Local)
     }
-    pub fn new_<'r>(
-        path: Vec<&'r str>,
+    pub fn new_(
+        path: Vec<Symbol>,
         lifetime: Option<Ident>,
-        params: Vec<Box<Ty<'r>>>,
+        params: Vec<Box<Ty>>,
         kind: PathKind,
-    ) -> Path<'r> {
+    ) -> Path {
         Path { path, lifetime, params, kind }
     }
 
@@ -70,7 +70,7 @@ pub fn to_path(
         self_ty: Ident,
         self_generics: &Generics,
     ) -> ast::Path {
-        let mut idents = self.path.iter().map(|s| cx.ident_of(*s, span)).collect();
+        let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
         let lt = mk_lifetimes(cx, span, &self.lifetime);
         let tys: Vec<P<ast::Ty>> =
             self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
@@ -94,21 +94,21 @@ pub fn to_path(
 
 /// A type. Supports pointers, Self, and literals.
 #[derive(Clone)]
-pub enum Ty<'a> {
+pub enum Ty {
     Self_,
     /// &/Box/ Ty
-    Ptr(Box<Ty<'a>>, PtrTy),
+    Ptr(Box<Ty>, PtrTy),
     /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
     /// parameter, and things like `i32`
-    Literal(Path<'a>),
+    Literal(Path),
     /// includes unit
-    Tuple(Vec<Ty<'a>>),
+    Tuple(Vec<Ty>),
 }
 
 pub fn borrowed_ptrty() -> PtrTy {
     Borrowed(None, ast::Mutability::Not)
 }
-pub fn borrowed(ty: Box<Ty<'_>>) -> Ty<'_> {
+pub fn borrowed(ty: Box<Ty>) -> Ty {
     Ptr(ty, borrowed_ptrty())
 }
 
@@ -116,11 +116,11 @@ pub fn borrowed_explicit_self() -> Option<Option<PtrTy>> {
     Some(Some(borrowed_ptrty()))
 }
 
-pub fn borrowed_self<'r>() -> Ty<'r> {
+pub fn borrowed_self() -> Ty {
     borrowed(Box::new(Self_))
 }
 
-pub fn nil_ty<'r>() -> Ty<'r> {
+pub fn nil_ty() -> Ty {
     Tuple(Vec::new())
 }
 
@@ -132,7 +132,7 @@ fn mk_lifetimes(cx: &ExtCtxt<'_>, span: Span, lt: &Option<Ident>) -> Vec<ast::Li
     mk_lifetime(cx, span, lt).into_iter().collect()
 }
 
-impl<'a> Ty<'a> {
+impl Ty {
     pub fn to_ty(
         &self,
         cx: &ExtCtxt<'_>,
@@ -199,9 +199,9 @@ pub fn to_path(
 fn mk_ty_param(
     cx: &ExtCtxt<'_>,
     span: Span,
-    name: &str,
+    name: Symbol,
     attrs: &[ast::Attribute],
-    bounds: &[Path<'_>],
+    bounds: &[Path],
     self_ident: Ident,
     self_generics: &Generics,
 ) -> ast::GenericParam {
@@ -212,7 +212,7 @@ fn mk_ty_param(
             cx.trait_bound(path)
         })
         .collect();
-    cx.typaram(span, cx.ident_of(name, span), attrs.to_owned(), bounds, None)
+    cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
 }
 
 fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
@@ -223,16 +223,15 @@ fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
     }
 }
 
-/// Lifetimes and bounds on type parameters
+/// Bounds on type parameters.
 #[derive(Clone)]
-pub struct LifetimeBounds<'a> {
-    pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
-    pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
+pub struct Bounds {
+    pub bounds: Vec<(Symbol, Vec<Path>)>,
 }
 
-impl<'a> LifetimeBounds<'a> {
-    pub fn empty() -> LifetimeBounds<'a> {
-        LifetimeBounds { lifetimes: Vec::new(), bounds: Vec::new() }
+impl Bounds {
+    pub fn empty() -> Bounds {
+        Bounds { bounds: Vec::new() }
     }
     pub fn to_generics(
         &self,
@@ -242,18 +241,12 @@ pub fn to_generics(
         self_generics: &Generics,
     ) -> Generics {
         let generic_params = self
-            .lifetimes
+            .bounds
             .iter()
-            .map(|&(lt, ref bounds)| {
-                let bounds = bounds
-                    .iter()
-                    .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b))));
-                cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect())
-            })
-            .chain(self.bounds.iter().map(|t| {
+            .map(|t| {
                 let (name, ref bounds) = *t;
                 mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
-            }))
+            })
             .collect();
 
         mk_generics(generic_params, span)
index 8776e7ef507903c73a3126c17ca427f3cce5c4f7..d7195188085f01fc3df926a2c77b92e42329fd44 100644 (file)
@@ -15,9 +15,9 @@ pub fn expand_deriving_hash(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std);
+    let path = Path::new_(pathvec_std!(hash::Hash), None, vec![], PathKind::Std);
 
-    let typaram = "__H";
+    let typaram = sym::__H;
 
     let arg = Path::new_local(typaram);
     let hash_trait_def = TraitDef {
@@ -25,17 +25,14 @@ pub fn expand_deriving_hash(
         attributes: Vec::new(),
         path,
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
         methods: vec![MethodDef {
-            name: "hash",
-            generics: LifetimeBounds {
-                lifetimes: Vec::new(),
-                bounds: vec![(typaram, vec![path_std!(cx, hash::Hasher)])],
-            },
+            name: sym::hash,
+            generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] },
             explicit_self: borrowed_explicit_self(),
-            args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), "state")],
+            args: vec![(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mut)), sym::state)],
             ret_ty: nil_ty(),
             attributes: vec![],
             is_unsafe: false,
@@ -73,7 +70,7 @@ fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructu
             let variant_value = deriving::call_intrinsic(
                 cx,
                 trait_span,
-                "discriminant_value",
+                sym::discriminant_value,
                 vec![cx.expr_self(trait_span)],
             );
 
index dc21be3b296aa16db1a128158501efbda5637dd4..33c0edde98f0ba91854e82dcffe64aa32090c9b0 100644 (file)
@@ -7,11 +7,11 @@
 use rustc_span::Span;
 
 macro path_local($x:ident) {
-    generic::ty::Path::new_local(stringify!($x))
+    generic::ty::Path::new_local(sym::$x)
 }
 
-macro pathvec_std($cx:expr, $($rest:ident)::+) {{
-    vec![ $( stringify!($rest) ),+ ]
+macro pathvec_std($($rest:ident)::+) {{
+    vec![ $( sym::$rest ),+ ]
 }}
 
 macro path_std($($x:tt)*) {
@@ -62,11 +62,11 @@ fn expand(
 fn call_intrinsic(
     cx: &ExtCtxt<'_>,
     span: Span,
-    intrinsic: &str,
+    intrinsic: Symbol,
     args: Vec<P<ast::Expr>>,
 ) -> P<ast::Expr> {
     let span = cx.with_def_site_ctxt(span);
-    let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
+    let path = cx.std_path(&[sym::intrinsics, intrinsic]);
     let call = cx.expr_call_global(span, path, args);
 
     cx.expr_block(P(ast::Block {
@@ -84,7 +84,7 @@ fn inject_impl_of_structural_trait(
     cx: &mut ExtCtxt<'_>,
     span: Span,
     item: &Annotatable,
-    structural_path: generic::ty::Path<'_>,
+    structural_path: generic::ty::Path,
     push: &mut dyn FnMut(Annotatable),
 ) {
     let item = match *item {
index 2becbe2f6758a8b0264f0e152054982cc853de07..55eab24b8a5105def8d34e6bfc591bd39c721bff 100644 (file)
@@ -578,31 +578,31 @@ fn build_index_map(&mut self) {
         self.count_args_index_offset = sofar;
     }
 
-    fn rtpath(ecx: &ExtCtxt<'_>, s: &str) -> Vec<Ident> {
-        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
+    fn rtpath(ecx: &ExtCtxt<'_>, s: Symbol) -> Vec<Ident> {
+        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
     }
 
     fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
         let sp = self.macsp;
         let count = |c, arg| {
-            let mut path = Context::rtpath(self.ecx, "Count");
-            path.push(self.ecx.ident_of(c, sp));
+            let mut path = Context::rtpath(self.ecx, sym::Count);
+            path.push(Ident::new(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)),
             }
         };
         match c {
-            parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))),
+            parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
             parse::CountIsParam(i) => {
                 // This needs mapping too, as `i` is referring to a macro
                 // argument. If `i` is not found in `count_positions` then
                 // the error had already been emitted elsewhere.
                 let i = self.count_positions.get(&i).cloned().unwrap_or(0)
                     + self.count_args_index_offset;
-                count("Param", Some(self.ecx.expr_usize(sp, i)))
+                count(sym::Param, Some(self.ecx.expr_usize(sp, i)))
             }
-            parse::CountImplied => count("Implied", None),
+            parse::CountImplied => count(sym::Implied, None),
             // should never be the case, names are already resolved
             parse::CountIsName(_) => panic!("should never happen"),
         }
@@ -690,40 +690,40 @@ fn build_piece(
                 // Build the format
                 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, sp));
+                    let mut p = Context::rtpath(self.ecx, sym::Alignment);
+                    p.push(Ident::new(name, sp));
                     self.ecx.path_global(sp, p)
                 };
                 let align = match arg.format.align {
-                    parse::AlignLeft => align("Left"),
-                    parse::AlignRight => align("Right"),
-                    parse::AlignCenter => align("Center"),
-                    parse::AlignUnknown => align("Unknown"),
+                    parse::AlignLeft => align(sym::Left),
+                    parse::AlignRight => align(sym::Right),
+                    parse::AlignCenter => align(sym::Center),
+                    parse::AlignUnknown => align(sym::Unknown),
                 };
                 let align = self.ecx.expr_path(align);
                 let flags = self.ecx.expr_u32(sp, arg.format.flags);
                 let prec = self.build_count(arg.format.precision);
                 let width = self.build_count(arg.format.width);
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "FormatSpec"));
+                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::FormatSpec));
                 let fmt = self.ecx.expr_struct(
                     sp,
                     path,
                     vec![
-                        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),
+                        self.ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
+                        self.ecx.field_imm(sp, Ident::new(sym::align, sp), align),
+                        self.ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
+                        self.ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
+                        self.ecx.field_imm(sp, Ident::new(sym::width, sp), width),
                     ],
                 );
 
-                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, "Argument"));
+                let path = self.ecx.path_global(sp, Context::rtpath(self.ecx, sym::Argument));
                 Some(self.ecx.expr_struct(
                     sp,
                     path,
                     vec![
-                        self.ecx.field_imm(sp, self.ecx.ident_of("position", sp), pos),
-                        self.ecx.field_imm(sp, self.ecx.ident_of("format", sp), fmt),
+                        self.ecx.field_imm(sp, Ident::new(sym::position, sp), pos),
+                        self.ecx.field_imm(sp, Ident::new(sym::format, sp), fmt),
                     ],
                 ))
             }
@@ -740,7 +740,7 @@ fn into_expr(self) -> P<ast::Expr> {
         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), self.macsp))
+            .map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
             .collect();
 
         // First, build up the static array which will become our precompiled
index feda17c1812cb2a5baa280b2912cb3822dccc878..89446a1aa96f9a79346ef5421910b41154890f61 100644 (file)
@@ -58,7 +58,7 @@ fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt {
         let mut abi_args = Vec::new();
         let mut i = 0;
         let mut mk = || {
-            let name = self.cx.ident_of(&format!("arg{}", i), self.span);
+            let name = Ident::from_str_and_span(&format!("arg{}", i), self.span);
             i += 1;
             name
         };
@@ -72,19 +72,15 @@ fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt {
         let kind = ItemKind::Fn(ast::Defaultness::Final, sig, Generics::default(), block);
         let item = self.cx.item(
             self.span,
-            self.cx.ident_of(&self.kind.fn_name(method.name), self.span),
+            Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
             self.attrs(),
             kind,
         );
         self.cx.stmt_item(self.span, item)
     }
 
-    fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> {
-        let method = self.cx.std_path(&[
-            Symbol::intern("alloc"),
-            Symbol::intern("GlobalAlloc"),
-            Symbol::intern(method),
-        ]);
+    fn call_allocator(&self, method: Symbol, mut args: Vec<P<Expr>>) -> P<Expr> {
+        let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]);
         let method = self.cx.expr_path(self.cx.path(self.span, method));
         let allocator = self.cx.path_ident(self.span, self.global);
         let allocator = self.cx.expr_path(allocator);
@@ -115,11 +111,8 @@ fn arg_ty(
                 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"),
-                    Symbol::intern("Layout"),
-                    Symbol::intern("from_size_align_unchecked"),
-                ]);
+                let layout_new =
+                    self.cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
                 let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new));
                 let size = self.cx.expr_ident(self.span, size);
                 let align = self.cx.expr_ident(self.span, align);
index 7cc9c1f76631e1b80290bd9659489af32dc5c433..f044ce41e879ee8ff3782550c620f334beddcd9e 100644 (file)
@@ -384,12 +384,12 @@ fn mk_decls(
     let proc_macro = Ident::new(sym::proc_macro, span);
     let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None));
 
-    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 bridge = Ident::new(sym::bridge, span);
+    let client = Ident::new(sym::client, span);
+    let proc_macro_ty = Ident::new(sym::ProcMacro, span);
+    let custom_derive = Ident::new(sym::custom_derive, span);
+    let attr = Ident::new(sym::attr, span);
+    let bang = Ident::new(sym::bang, span);
 
     let krate_ref = RefCell::new(ast_krate);
 
@@ -447,7 +447,7 @@ fn mk_decls(
     let decls_static = cx
         .item_static(
             span,
-            cx.ident_of("_DECLS", span),
+            Ident::new(sym::_DECLS, span),
             cx.ty_rptr(
                 span,
                 cx.ty(
index d62f34bab1a31e41685071989d2a4160de90b709..460f947a792af5975b7627f6e7f003ec7b81d021 100644 (file)
@@ -108,22 +108,38 @@ pub fn expand_test_or_bench(
     let test_id = Ident::new(sym::test, attr_sp);
 
     // creates test::$name
-    let test_path = |name| cx.path(sp, vec![test_id, cx.ident_of(name, sp)]);
+    let test_path = |name| cx.path(sp, vec![test_id, Ident::from_str_and_span(name, sp)]);
 
     // creates test::ShouldPanic::$name
-    let should_panic_path =
-        |name| cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic", sp), cx.ident_of(name, sp)]);
+    let should_panic_path = |name| {
+        cx.path(
+            sp,
+            vec![
+                test_id,
+                Ident::from_str_and_span("ShouldPanic", sp),
+                Ident::from_str_and_span(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)]);
+    let test_type_path = |name| {
+        cx.path(
+            sp,
+            vec![
+                test_id,
+                Ident::from_str_and_span("TestType", sp),
+                Ident::from_str_and_span(name, sp),
+            ],
+        )
+    };
 
     // creates $name: $expr
-    let field = |name, expr| cx.field_imm(sp, cx.ident_of(name, sp), expr);
+    let field = |name, expr| cx.field_imm(sp, Ident::from_str_and_span(name, sp), expr);
 
     let test_fn = if is_bench {
         // A simple ident for a lambda
-        let b = cx.ident_of("b", attr_sp);
+        let b = Ident::from_str_and_span("b", attr_sp);
 
         cx.expr_call(
             sp,
index da8bf2b8b5169990a2c989684ea5090b936793fc..98c5c6936d779d07199d701029e647d529e8700f 100644 (file)
@@ -164,10 +164,8 @@ impl MutVisitor for EntryPointCleaner {
             EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => 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 dc_nested =
+                        attr::mk_nested_word_item(Ident::new(sym::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);
                     let attrs = attrs
@@ -272,7 +270,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
     let mut test_runner = cx
         .test_runner
         .clone()
-        .unwrap_or(ecx.path(sp, vec![test_id, ecx.ident_of(runner_name, sp)]));
+        .unwrap_or(ecx.path(sp, vec![test_id, Ident::from_str_and_span(runner_name, sp)]));
 
     test_runner.span = sp;
 
index 89b548a9c5ab23a36300b97ac13e7d19141755d9..227a87ff8199495c2b8a9549c2bd44a1b827c777 100644 (file)
@@ -133,6 +133,9 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
         return;
     }
 
+    // FIXME(richkadel): Make sure probestack plays nice with `-Z instrument-coverage`
+    // or disable it if not, similar to above early exits.
+
     // Flag our internal `__rust_probestack` function as the stack probe symbol.
     // This is defined in the `compiler-builtins` crate for each architecture.
     llvm::AddFunctionAttrStringValue(
index d5e0d7d36ee7a010e2d257c42f5ca7e9ecbee62b..b19199b9cfabd5bc80beb7dbc6fc167f3af7e0df 100644 (file)
@@ -144,17 +144,18 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm
                 }
             }
 
+            // Finalize code coverage by injecting the coverage map. Note, the coverage map will
+            // also be added to the `llvm.used` variable, created next.
+            if cx.sess().opts.debugging_opts.instrument_coverage {
+                cx.coverageinfo_finalize();
+            }
+
             // Create the llvm.used variable
             // This variable has type [N x i8*] and is stored in the llvm.metadata section
             if !cx.used_statics().borrow().is_empty() {
                 cx.create_used_variable()
             }
 
-            // Finalize code coverage by injecting the coverage map
-            if cx.sess().opts.debugging_opts.instrument_coverage {
-                cx.coverageinfo_finalize();
-            }
-
             // Finalize debuginfo
             if cx.sess().opts.debuginfo != DebugInfo::None {
                 cx.debuginfo_finalize();
index 89b70dce52c661c8c571f0929d306f846378c3bd..d58aad340a1dcbc57044edd5f0b473098b84cfbd 100644 (file)
@@ -658,7 +658,7 @@ fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Val
         // `nontrapping-fptoint` target feature is activated. We'll use those if
         // they are available.
         if self.sess().target.target.arch == "wasm32"
-            && self.sess().target_features.contains(&sym::nontrapping_fptoint)
+            && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
         {
             let src_ty = self.cx.val_ty(val);
             let float_width = self.cx.float_width(src_ty);
@@ -683,7 +683,7 @@ fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Val
         // `nontrapping-fptoint` target feature is activated. We'll use those if
         // they are available.
         if self.sess().target.target.arch == "wasm32"
-            && self.sess().target_features.contains(&sym::nontrapping_fptoint)
+            && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
         {
             let src_ty = self.cx.val_ty(val);
             let float_width = self.cx.float_width(src_ty);
@@ -1060,7 +1060,7 @@ fn instrprof_increment(
             fn_name, hash, num_counters, index
         );
 
-        let llfn = unsafe { llvm::LLVMRustGetInstrprofIncrementIntrinsic(self.cx().llmod) };
+        let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
         let args = &[fn_name, hash, num_counters, index];
         let args = self.check_call("call", llfn, args);
 
index 6ad75cff3ddb6be9af1c8cced0c99c0f50930e60..7b341651adf3dec5d0de0ef748257b44047b3cd9 100644 (file)
@@ -35,7 +35,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
         return llfn;
     }
 
-    let sym = tcx.symbol_name(instance).name.as_str();
+    let sym = tcx.symbol_name(instance).name;
     debug!("get_fn({:?}: {:?}) => {}", instance, instance.monomorphic_ty(cx.tcx()), sym);
 
     let fn_abi = FnAbi::of_instance(cx, instance, &[]);
index 9d9b53fc4a87c5adcead1140055b56d1a6676881..c954415f19f346c080508c8df49bc1aa29f83ed7 100644 (file)
@@ -18,7 +18,7 @@
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
 
@@ -107,11 +107,10 @@ fn check_and_apply_linkage(
     cx: &CodegenCx<'ll, 'tcx>,
     attrs: &CodegenFnAttrs,
     ty: Ty<'tcx>,
-    sym: Symbol,
+    sym: &str,
     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);
 
@@ -215,14 +214,13 @@ impl CodegenCx<'ll, 'tcx> {
             // FIXME: refactor this to work without accessing the HIR
             let (g, attrs) = match self.tcx.hir().get(id) {
                 Node::Item(&hir::Item { attrs, span, kind: hir::ItemKind::Static(..), .. }) => {
-                    let sym_str = sym.as_str();
-                    if let Some(g) = self.get_declared_value(&sym_str) {
+                    if let Some(g) = self.get_declared_value(sym) {
                         if self.val_ty(g) != self.type_ptr_to(llty) {
                             span_bug!(span, "Conflicting types for static");
                         }
                     }
 
-                    let g = self.declare_global(&sym_str, llty);
+                    let g = self.declare_global(sym, llty);
 
                     if !self.tcx.is_reachable_non_generic(def_id) {
                         unsafe {
@@ -495,10 +493,14 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             }
 
             if attrs.flags.contains(CodegenFnAttrFlags::USED) {
-                // This static will be stored in the llvm.used variable which is an array of i8*
-                let cast = llvm::LLVMConstPointerCast(g, self.type_i8p());
-                self.used_statics.borrow_mut().push(cast);
+                self.add_used_global(g);
             }
         }
     }
+
+    /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
+    fn add_used_global(&self, global: &'ll Value) {
+        let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
+        self.used_statics.borrow_mut().push(cast);
+    }
 }
diff --git a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs
new file mode 100644 (file)
index 0000000..7f48b1d
--- /dev/null
@@ -0,0 +1,274 @@
+use crate::llvm;
+
+use crate::common::CodegenCx;
+use crate::coverageinfo;
+
+use log::debug;
+use rustc_codegen_ssa::coverageinfo::map::*;
+use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, MiscMethods};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_llvm::RustString;
+use rustc_middle::ty::Instance;
+use rustc_middle::{bug, mir};
+
+use std::collections::BTreeMap;
+use std::ffi::CString;
+use std::path::PathBuf;
+
+// FIXME(richkadel): Complete all variations of generating and exporting the coverage map to LLVM.
+// The current implementation is an initial foundation with basic capabilities (Counters, but not
+// CounterExpressions, etc.).
+
+/// Generates and exports the Coverage Map.
+///
+/// This Coverage Map complies with Coverage Mapping Format version 3 (zero-based encoded as 2),
+/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format)
+/// and published in Rust's current (July 2020) fork of LLVM. This version is supported by the
+/// LLVM coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM.
+///
+/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
+/// version 3. Clang's implementation of Coverage Map generation was referenced when implementing
+/// this Rust version, and though the format documentation is very explicit and detailed, some
+/// undocumented details in Clang's implementation (that may or may not be important) were also
+/// replicated for Rust's Coverage Map.
+pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
+    let mut coverage_writer = CoverageMappingWriter::new(cx);
+
+    let function_coverage_map = cx.coverage_context().take_function_coverage_map();
+
+    // Encode coverage mappings and generate function records
+    let mut function_records = Vec::<&'ll llvm::Value>::new();
+    let coverage_mappings_buffer = llvm::build_byte_buffer(|coverage_mappings_buffer| {
+        for (instance, function_coverage) in function_coverage_map.into_iter() {
+            if let Some(function_record) = coverage_writer.write_function_mappings_and_record(
+                instance,
+                function_coverage,
+                coverage_mappings_buffer,
+            ) {
+                function_records.push(function_record);
+            }
+        }
+    });
+
+    // Encode all filenames covered in this module, ordered by `file_id`
+    let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
+        coverageinfo::write_filenames_section_to_buffer(
+            &coverage_writer.filenames,
+            filenames_buffer,
+        );
+    });
+
+    if coverage_mappings_buffer.len() > 0 {
+        // Generate the LLVM IR representation of the coverage map and store it in a well-known
+        // global constant.
+        coverage_writer.write_coverage_map(
+            function_records,
+            filenames_buffer,
+            coverage_mappings_buffer,
+        );
+    }
+}
+
+struct CoverageMappingWriter<'a, 'll, 'tcx> {
+    cx: &'a CodegenCx<'ll, 'tcx>,
+    filenames: Vec<CString>,
+    filename_to_index: FxHashMap<CString, u32>,
+}
+
+impl<'a, 'll, 'tcx> CoverageMappingWriter<'a, 'll, 'tcx> {
+    fn new(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
+        Self { cx, filenames: Vec::new(), filename_to_index: FxHashMap::<CString, u32>::default() }
+    }
+
+    /// For the given function, get the coverage region data, stream it to the given buffer, and
+    /// then generate and return a new function record.
+    fn write_function_mappings_and_record(
+        &mut self,
+        instance: Instance<'tcx>,
+        mut function_coverage: FunctionCoverage,
+        coverage_mappings_buffer: &RustString,
+    ) -> Option<&'ll llvm::Value> {
+        let cx = self.cx;
+        let coverageinfo: &mir::CoverageInfo = cx.tcx.coverageinfo(instance.def_id());
+        debug!(
+            "Generate coverage map for: {:?}, num_counters: {}, num_expressions: {}",
+            instance, coverageinfo.num_counters, coverageinfo.num_expressions
+        );
+        debug_assert!(coverageinfo.num_counters > 0);
+
+        let regions_in_file_order = function_coverage.regions_in_file_order(cx.sess().source_map());
+        if regions_in_file_order.len() == 0 {
+            return None;
+        }
+
+        // Stream the coverage mapping regions for the function (`instance`) to the buffer, and
+        // compute the data byte size used.
+        let old_len = coverage_mappings_buffer.len();
+        self.regions_to_mappings(regions_in_file_order, coverage_mappings_buffer);
+        let mapping_data_size = coverage_mappings_buffer.len() - old_len;
+        debug_assert!(mapping_data_size > 0);
+
+        let mangled_function_name = cx.tcx.symbol_name(instance).to_string();
+        let name_ref = coverageinfo::compute_hash(&mangled_function_name);
+        let function_source_hash = function_coverage.source_hash();
+
+        // Generate and return the function record
+        let name_ref_val = cx.const_u64(name_ref);
+        let mapping_data_size_val = cx.const_u32(mapping_data_size as u32);
+        let func_hash_val = cx.const_u64(function_source_hash);
+        Some(cx.const_struct(
+            &[name_ref_val, mapping_data_size_val, func_hash_val],
+            /*packed=*/ true,
+        ))
+    }
+
+    /// For each coverage region, extract its coverage data from the earlier coverage analysis.
+    /// Use LLVM APIs to convert the data into buffered bytes compliant with the LLVM Coverage
+    /// Mapping format.
+    fn regions_to_mappings(
+        &mut self,
+        regions_in_file_order: BTreeMap<PathBuf, BTreeMap<CoverageLoc, (usize, CoverageKind)>>,
+        coverage_mappings_buffer: &RustString,
+    ) {
+        let mut virtual_file_mapping = Vec::new();
+        let mut mapping_regions = coverageinfo::SmallVectorCounterMappingRegion::new();
+        let mut expressions = coverageinfo::SmallVectorCounterExpression::new();
+
+        for (file_id, (file_path, file_coverage_regions)) in
+            regions_in_file_order.into_iter().enumerate()
+        {
+            let file_id = file_id as u32;
+            let filename = CString::new(file_path.to_string_lossy().to_string())
+                .expect("null error converting filename to C string");
+            debug!("  file_id: {} = '{:?}'", file_id, filename);
+            let filenames_index = match self.filename_to_index.get(&filename) {
+                Some(index) => *index,
+                None => {
+                    let index = self.filenames.len() as u32;
+                    self.filenames.push(filename.clone());
+                    self.filename_to_index.insert(filename, index);
+                    index
+                }
+            };
+            virtual_file_mapping.push(filenames_index);
+
+            let mut mapping_indexes = vec![0 as u32; file_coverage_regions.len()];
+            for (mapping_index, (region_id, _)) in file_coverage_regions.values().enumerate() {
+                mapping_indexes[*region_id] = mapping_index as u32;
+            }
+
+            for (region_loc, (region_id, region_kind)) in file_coverage_regions.into_iter() {
+                let mapping_index = mapping_indexes[region_id];
+                match region_kind {
+                    CoverageKind::Counter => {
+                        debug!(
+                            "  Counter {}, file_id: {}, region_loc: {}",
+                            mapping_index, file_id, region_loc
+                        );
+                        mapping_regions.push_from(
+                            mapping_index,
+                            file_id,
+                            region_loc.start_line,
+                            region_loc.start_col,
+                            region_loc.end_line,
+                            region_loc.end_col,
+                        );
+                    }
+                    CoverageKind::CounterExpression(lhs, op, rhs) => {
+                        debug!(
+                            "  CounterExpression {} = {} {:?} {}, file_id: {}, region_loc: {:?}",
+                            mapping_index, lhs, op, rhs, file_id, region_loc,
+                        );
+                        mapping_regions.push_from(
+                            mapping_index,
+                            file_id,
+                            region_loc.start_line,
+                            region_loc.start_col,
+                            region_loc.end_line,
+                            region_loc.end_col,
+                        );
+                        expressions.push_from(op, lhs, rhs);
+                    }
+                    CoverageKind::Unreachable => {
+                        debug!(
+                            "  Unreachable region, file_id: {}, region_loc: {:?}",
+                            file_id, region_loc,
+                        );
+                        bug!("Unreachable region not expected and not yet handled!")
+                        // FIXME(richkadel): implement and call
+                        //   mapping_regions.push_from(...) for unreachable regions
+                    }
+                }
+            }
+        }
+
+        // Encode and append the current function's coverage mapping data
+        coverageinfo::write_mapping_to_buffer(
+            virtual_file_mapping,
+            expressions,
+            mapping_regions,
+            coverage_mappings_buffer,
+        );
+    }
+
+    fn write_coverage_map(
+        self,
+        function_records: Vec<&'ll llvm::Value>,
+        filenames_buffer: Vec<u8>,
+        mut coverage_mappings_buffer: Vec<u8>,
+    ) {
+        let cx = self.cx;
+
+        // Concatenate the encoded filenames and encoded coverage mappings, and add additional zero
+        // bytes as-needed to ensure 8-byte alignment.
+        let mut coverage_size = coverage_mappings_buffer.len();
+        let filenames_size = filenames_buffer.len();
+        let remaining_bytes =
+            (filenames_size + coverage_size) % coverageinfo::COVMAP_VAR_ALIGN_BYTES;
+        if remaining_bytes > 0 {
+            let pad = coverageinfo::COVMAP_VAR_ALIGN_BYTES - remaining_bytes;
+            coverage_mappings_buffer.append(&mut [0].repeat(pad));
+            coverage_size += pad;
+        }
+        let filenames_and_coverage_mappings = [filenames_buffer, coverage_mappings_buffer].concat();
+        let filenames_and_coverage_mappings_val =
+            cx.const_bytes(&filenames_and_coverage_mappings[..]);
+
+        debug!(
+            "cov map: n_records = {}, filenames_size = {}, coverage_size = {}, 0-based version = {}",
+            function_records.len(),
+            filenames_size,
+            coverage_size,
+            coverageinfo::mapping_version()
+        );
+
+        // Create the coverage data header
+        let n_records_val = cx.const_u32(function_records.len() as u32);
+        let filenames_size_val = cx.const_u32(filenames_size as u32);
+        let coverage_size_val = cx.const_u32(coverage_size as u32);
+        let version_val = cx.const_u32(coverageinfo::mapping_version());
+        let cov_data_header_val = cx.const_struct(
+            &[n_records_val, filenames_size_val, coverage_size_val, version_val],
+            /*packed=*/ false,
+        );
+
+        // Create the function records array
+        let name_ref_from_u64 = cx.type_i64();
+        let mapping_data_size_from_u32 = cx.type_i32();
+        let func_hash_from_u64 = cx.type_i64();
+        let function_record_ty = cx.type_struct(
+            &[name_ref_from_u64, mapping_data_size_from_u32, func_hash_from_u64],
+            /*packed=*/ true,
+        );
+        let function_records_val = cx.const_array(function_record_ty, &function_records[..]);
+
+        // Create the complete LLVM coverage data value to add to the LLVM IR
+        let cov_data_val = cx.const_struct(
+            &[cov_data_header_val, function_records_val, filenames_and_coverage_mappings_val],
+            /*packed=*/ false,
+        );
+
+        // Save the coverage data value to LLVM IR
+        coverageinfo::save_map_to_mod(cx, cov_data_val);
+    }
+}
index ff9f8f7aeaa544ec591697a2528c5383edc037bd..76894bcd6c1b1c4a63c8b1bcc8c0ef859a629b58 100644 (file)
@@ -1,67 +1,44 @@
+use crate::llvm;
+
 use crate::builder::Builder;
 use crate::common::CodegenCx;
+
+use libc::c_uint;
 use log::debug;
 use rustc_codegen_ssa::coverageinfo::map::*;
-use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
+use rustc_codegen_ssa::traits::{
+    BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
+};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_llvm::RustString;
 use rustc_middle::ty::Instance;
 
 use std::cell::RefCell;
+use std::ffi::CString;
+
+pub mod mapgen;
+
+const COVMAP_VAR_ALIGN_BYTES: usize = 8;
 
 /// A context object for maintaining all state needed by the coverageinfo module.
 pub struct CrateCoverageContext<'tcx> {
     // Coverage region data for each instrumented function identified by DefId.
-    pub(crate) coverage_regions: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageRegions>>,
+    pub(crate) function_coverage_map: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverage>>,
 }
 
 impl<'tcx> CrateCoverageContext<'tcx> {
     pub fn new() -> Self {
-        Self { coverage_regions: Default::default() }
+        Self { function_coverage_map: Default::default() }
     }
-}
 
-/// Generates and exports the Coverage Map.
-// FIXME(richkadel): Actually generate and export the coverage map to LLVM.
-// The current implementation is actually just debug messages to show the data is available.
-pub fn finalize(cx: &CodegenCx<'_, '_>) {
-    let coverage_regions = &*cx.coverage_context().coverage_regions.borrow();
-    for instance in coverage_regions.keys() {
-        let coverageinfo = cx.tcx.coverageinfo(instance.def_id());
-        debug_assert!(coverageinfo.num_counters > 0);
-        debug!(
-            "Generate coverage map for: {:?}, hash: {}, num_counters: {}",
-            instance, coverageinfo.hash, coverageinfo.num_counters
-        );
-        let function_coverage_regions = &coverage_regions[instance];
-        for (index, region) in function_coverage_regions.indexed_regions() {
-            match region.kind {
-                CoverageKind::Counter => debug!(
-                    "  Counter {}, for {}..{}",
-                    index, region.coverage_span.start_byte_pos, region.coverage_span.end_byte_pos
-                ),
-                CoverageKind::CounterExpression(lhs, op, rhs) => debug!(
-                    "  CounterExpression {} = {} {:?} {}, for {}..{}",
-                    index,
-                    lhs,
-                    op,
-                    rhs,
-                    region.coverage_span.start_byte_pos,
-                    region.coverage_span.end_byte_pos
-                ),
-            }
-        }
-        for unreachable in function_coverage_regions.unreachable_regions() {
-            debug!(
-                "  Unreachable code region: {}..{}",
-                unreachable.start_byte_pos, unreachable.end_byte_pos
-            );
-        }
+    pub fn take_function_coverage_map(&self) -> FxHashMap<Instance<'tcx>, FunctionCoverage> {
+        self.function_coverage_map.replace(FxHashMap::default())
     }
 }
 
 impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> {
     fn coverageinfo_finalize(&self) {
-        finalize(self)
+        mapgen::finalize(self)
     }
 }
 
@@ -69,20 +46,22 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn add_counter_region(
         &mut self,
         instance: Instance<'tcx>,
+        function_source_hash: u64,
         index: u32,
         start_byte_pos: u32,
         end_byte_pos: u32,
     ) {
         debug!(
-            "adding counter to coverage map: instance={:?}, index={}, byte range {}..{}",
-            instance, index, start_byte_pos, end_byte_pos,
-        );
-        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
-        coverage_regions.entry(instance).or_default().add_counter(
-            index,
-            start_byte_pos,
-            end_byte_pos,
+            "adding counter to coverage_regions: instance={:?}, function_source_hash={}, index={}, byte range {}..{}",
+            instance, function_source_hash, index, start_byte_pos, end_byte_pos,
         );
+        let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
+        coverage_regions
+            .entry(instance)
+            .or_insert_with(|| {
+                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))
+            })
+            .add_counter(function_source_hash, index, start_byte_pos, end_byte_pos);
     }
 
     fn add_counter_expression_region(
@@ -96,18 +75,16 @@ fn add_counter_expression_region(
         end_byte_pos: u32,
     ) {
         debug!(
-            "adding counter expression to coverage map: instance={:?}, index={}, {} {:?} {}, byte range {}..{}",
+            "adding counter expression to coverage_regions: instance={:?}, index={}, {} {:?} {}, byte range {}..{}",
             instance, index, lhs, op, rhs, start_byte_pos, end_byte_pos,
         );
-        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
-        coverage_regions.entry(instance).or_default().add_counter_expression(
-            index,
-            lhs,
-            op,
-            rhs,
-            start_byte_pos,
-            end_byte_pos,
-        );
+        let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
+        coverage_regions
+            .entry(instance)
+            .or_insert_with(|| {
+                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))
+            })
+            .add_counter_expression(index, lhs, op, rhs, start_byte_pos, end_byte_pos);
     }
 
     fn add_unreachable_region(
@@ -117,10 +94,175 @@ fn add_unreachable_region(
         end_byte_pos: u32,
     ) {
         debug!(
-            "adding unreachable code to coverage map: instance={:?}, byte range {}..{}",
+            "adding unreachable code to coverage_regions: instance={:?}, byte range {}..{}",
             instance, start_byte_pos, end_byte_pos,
         );
-        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
-        coverage_regions.entry(instance).or_default().add_unreachable(start_byte_pos, end_byte_pos);
+        let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
+        coverage_regions
+            .entry(instance)
+            .or_insert_with(|| {
+                FunctionCoverage::with_coverageinfo(self.tcx.coverageinfo(instance.def_id()))
+            })
+            .add_unreachable(start_byte_pos, end_byte_pos);
+    }
+}
+
+/// This struct wraps an opaque reference to the C++ template instantiation of
+/// `llvm::SmallVector<coverage::CounterExpression>`. Each `coverage::CounterExpression` object is
+/// constructed from primative-typed arguments, and pushed to the `SmallVector`, in the C++
+/// implementation of `LLVMRustCoverageSmallVectorCounterExpressionAdd()` (see
+/// `src/rustllvm/CoverageMappingWrapper.cpp`).
+pub struct SmallVectorCounterExpression<'a> {
+    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterExpression<'a>,
+}
+
+impl SmallVectorCounterExpression<'a> {
+    pub fn new() -> Self {
+        SmallVectorCounterExpression {
+            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterExpressionCreate() },
+        }
+    }
+
+    pub fn as_ptr(&self) -> *const llvm::coverageinfo::SmallVectorCounterExpression<'a> {
+        self.raw
+    }
+
+    pub fn push_from(
+        &mut self,
+        kind: rustc_codegen_ssa::coverageinfo::CounterOp,
+        left_index: u32,
+        right_index: u32,
+    ) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterExpressionAdd(
+                &mut *(self.raw as *mut _),
+                kind,
+                left_index,
+                right_index,
+            )
+        }
+    }
+}
+
+impl Drop for SmallVectorCounterExpression<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterExpressionDispose(&mut *(self.raw as *mut _));
+        }
+    }
+}
+
+/// This struct wraps an opaque reference to the C++ template instantiation of
+/// `llvm::SmallVector<coverage::CounterMappingRegion>`. Each `coverage::CounterMappingRegion`
+/// object is constructed from primative-typed arguments, and pushed to the `SmallVector`, in the
+/// C++ implementation of `LLVMRustCoverageSmallVectorCounterMappingRegionAdd()` (see
+/// `src/rustllvm/CoverageMappingWrapper.cpp`).
+pub struct SmallVectorCounterMappingRegion<'a> {
+    pub raw: &'a mut llvm::coverageinfo::SmallVectorCounterMappingRegion<'a>,
+}
+
+impl SmallVectorCounterMappingRegion<'a> {
+    pub fn new() -> Self {
+        SmallVectorCounterMappingRegion {
+            raw: unsafe { llvm::LLVMRustCoverageSmallVectorCounterMappingRegionCreate() },
+        }
+    }
+
+    pub fn as_ptr(&self) -> *const llvm::coverageinfo::SmallVectorCounterMappingRegion<'a> {
+        self.raw
+    }
+
+    pub fn push_from(
+        &mut self,
+        index: u32,
+        file_id: u32,
+        line_start: u32,
+        column_start: u32,
+        line_end: u32,
+        column_end: u32,
+    ) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterMappingRegionAdd(
+                &mut *(self.raw as *mut _),
+                index,
+                file_id,
+                line_start,
+                column_start,
+                line_end,
+                column_end,
+            )
+        }
+    }
+}
+
+impl Drop for SmallVectorCounterMappingRegion<'a> {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustCoverageSmallVectorCounterMappingRegionDispose(
+                &mut *(self.raw as *mut _),
+            );
+        }
+    }
+}
+
+pub(crate) fn write_filenames_section_to_buffer(filenames: &Vec<CString>, buffer: &RustString) {
+    let c_str_vec = filenames.iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
+    unsafe {
+        llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
+            c_str_vec.as_ptr(),
+            c_str_vec.len(),
+            buffer,
+        );
+    }
+}
+
+pub(crate) fn write_mapping_to_buffer(
+    virtual_file_mapping: Vec<u32>,
+    expressions: SmallVectorCounterExpression<'_>,
+    mapping_regions: SmallVectorCounterMappingRegion<'_>,
+    buffer: &RustString,
+) {
+    unsafe {
+        llvm::LLVMRustCoverageWriteMappingToBuffer(
+            virtual_file_mapping.as_ptr(),
+            virtual_file_mapping.len() as c_uint,
+            expressions.as_ptr(),
+            mapping_regions.as_ptr(),
+            buffer,
+        );
     }
 }
+
+pub(crate) fn compute_hash(name: &str) -> u64 {
+    let name = CString::new(name).expect("null error converting hashable name to C string");
+    unsafe { llvm::LLVMRustCoverageComputeHash(name.as_ptr()) }
+}
+
+pub(crate) fn mapping_version() -> u32 {
+    unsafe { llvm::LLVMRustCoverageMappingVersion() }
+}
+
+pub(crate) fn save_map_to_mod<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    cov_data_val: &'ll llvm::Value,
+) {
+    let covmap_var_name = llvm::build_string(|s| unsafe {
+        llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
+    })
+    .expect("Rust Coverage Mapping var name failed UTF-8 conversion");
+    debug!("covmap var name: {:?}", covmap_var_name);
+
+    let covmap_section_name = llvm::build_string(|s| unsafe {
+        llvm::LLVMRustCoverageWriteSectionNameToString(cx.llmod, s);
+    })
+    .expect("Rust Coverage section name failed UTF-8 conversion");
+    debug!("covmap section name: {:?}", covmap_section_name);
+
+    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(cov_data_val), &covmap_var_name);
+    llvm::set_initializer(llglobal, cov_data_val);
+    llvm::set_global_constant(llglobal, true);
+    llvm::set_linkage(llglobal, llvm::Linkage::InternalLinkage);
+    llvm::set_section(llglobal, &covmap_section_name);
+    llvm::set_alignment(llglobal, COVMAP_VAR_ALIGN_BYTES);
+    cx.add_used_global(llglobal);
+}
index f2e042cf86aa5aa7822540772f170f42864ea6cd..ef9d42968ae2e0a1ae27a2fe6c92f9ffbea48405 100644 (file)
@@ -2468,8 +2468,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
     let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx);
     let type_metadata = type_metadata(cx, variable_type, span);
     let var_name = tcx.item_name(def_id).as_str();
-    let linkage_name: &str =
-        &mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name.as_str();
+    let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
     // When empty, linkage_name field is omitted,
     // which is what we want for no_mangle statics
     let linkage_name = if var_name == linkage_name { "" } else { linkage_name };
index b5434298805f3cb35b3537064a1c2025755b621c..44993d7602fe6e89ca9f16c0dce53391b527a88d 100644 (file)
@@ -267,7 +267,7 @@ fn create_function_debug_context(
         let substs = instance.substs.truncate_to(self.tcx(), generics);
         let template_parameters = get_template_parameters(self, &generics, substs, &mut name);
 
-        let linkage_name: &str = &mangled_name_of_instance(self, instance).name.as_str();
+        let linkage_name = &mangled_name_of_instance(self, instance).name;
         // Omit the linkage_name if it is the same as subprogram name.
         let linkage_name = if &name == linkage_name { "" } else { linkage_name };
 
index 475dea239a765ee07be1e1f0c75684edacbf7689..d1a55335c44e7e62705feae9fe23b6f0906f37f6 100644 (file)
@@ -12,7 +12,7 @@
 pub fn mangled_name_of_instance<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
     instance: Instance<'tcx>,
-) -> ty::SymbolName {
+) -> ty::SymbolName<'tcx> {
     let tcx = cx.tcx;
     tcx.symbol_name(instance)
 }
index de90ac0bac1d333941cc52854096efa470e36f11..63ec8031483fed508f50f03fa06d6d29284f627a 100644 (file)
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, span_bug};
-use rustc_span::Span;
+use rustc_span::{sym, symbol::kw, Span, Symbol};
 use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive};
 use rustc_target::spec::PanicStrategy;
 
 use std::cmp::Ordering;
 use std::iter;
 
-fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
+fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Value> {
     let llvm_name = match name {
-        "sqrtf32" => "llvm.sqrt.f32",
-        "sqrtf64" => "llvm.sqrt.f64",
-        "powif32" => "llvm.powi.f32",
-        "powif64" => "llvm.powi.f64",
-        "sinf32" => "llvm.sin.f32",
-        "sinf64" => "llvm.sin.f64",
-        "cosf32" => "llvm.cos.f32",
-        "cosf64" => "llvm.cos.f64",
-        "powf32" => "llvm.pow.f32",
-        "powf64" => "llvm.pow.f64",
-        "expf32" => "llvm.exp.f32",
-        "expf64" => "llvm.exp.f64",
-        "exp2f32" => "llvm.exp2.f32",
-        "exp2f64" => "llvm.exp2.f64",
-        "logf32" => "llvm.log.f32",
-        "logf64" => "llvm.log.f64",
-        "log10f32" => "llvm.log10.f32",
-        "log10f64" => "llvm.log10.f64",
-        "log2f32" => "llvm.log2.f32",
-        "log2f64" => "llvm.log2.f64",
-        "fmaf32" => "llvm.fma.f32",
-        "fmaf64" => "llvm.fma.f64",
-        "fabsf32" => "llvm.fabs.f32",
-        "fabsf64" => "llvm.fabs.f64",
-        "minnumf32" => "llvm.minnum.f32",
-        "minnumf64" => "llvm.minnum.f64",
-        "maxnumf32" => "llvm.maxnum.f32",
-        "maxnumf64" => "llvm.maxnum.f64",
-        "copysignf32" => "llvm.copysign.f32",
-        "copysignf64" => "llvm.copysign.f64",
-        "floorf32" => "llvm.floor.f32",
-        "floorf64" => "llvm.floor.f64",
-        "ceilf32" => "llvm.ceil.f32",
-        "ceilf64" => "llvm.ceil.f64",
-        "truncf32" => "llvm.trunc.f32",
-        "truncf64" => "llvm.trunc.f64",
-        "rintf32" => "llvm.rint.f32",
-        "rintf64" => "llvm.rint.f64",
-        "nearbyintf32" => "llvm.nearbyint.f32",
-        "nearbyintf64" => "llvm.nearbyint.f64",
-        "roundf32" => "llvm.round.f32",
-        "roundf64" => "llvm.round.f64",
-        "assume" => "llvm.assume",
-        "abort" => "llvm.trap",
+        sym::sqrtf32 => "llvm.sqrt.f32",
+        sym::sqrtf64 => "llvm.sqrt.f64",
+        sym::powif32 => "llvm.powi.f32",
+        sym::powif64 => "llvm.powi.f64",
+        sym::sinf32 => "llvm.sin.f32",
+        sym::sinf64 => "llvm.sin.f64",
+        sym::cosf32 => "llvm.cos.f32",
+        sym::cosf64 => "llvm.cos.f64",
+        sym::powf32 => "llvm.pow.f32",
+        sym::powf64 => "llvm.pow.f64",
+        sym::expf32 => "llvm.exp.f32",
+        sym::expf64 => "llvm.exp.f64",
+        sym::exp2f32 => "llvm.exp2.f32",
+        sym::exp2f64 => "llvm.exp2.f64",
+        sym::logf32 => "llvm.log.f32",
+        sym::logf64 => "llvm.log.f64",
+        sym::log10f32 => "llvm.log10.f32",
+        sym::log10f64 => "llvm.log10.f64",
+        sym::log2f32 => "llvm.log2.f32",
+        sym::log2f64 => "llvm.log2.f64",
+        sym::fmaf32 => "llvm.fma.f32",
+        sym::fmaf64 => "llvm.fma.f64",
+        sym::fabsf32 => "llvm.fabs.f32",
+        sym::fabsf64 => "llvm.fabs.f64",
+        sym::minnumf32 => "llvm.minnum.f32",
+        sym::minnumf64 => "llvm.minnum.f64",
+        sym::maxnumf32 => "llvm.maxnum.f32",
+        sym::maxnumf64 => "llvm.maxnum.f64",
+        sym::copysignf32 => "llvm.copysign.f32",
+        sym::copysignf64 => "llvm.copysign.f64",
+        sym::floorf32 => "llvm.floor.f32",
+        sym::floorf64 => "llvm.floor.f64",
+        sym::ceilf32 => "llvm.ceil.f32",
+        sym::ceilf64 => "llvm.ceil.f64",
+        sym::truncf32 => "llvm.trunc.f32",
+        sym::truncf64 => "llvm.trunc.f64",
+        sym::rintf32 => "llvm.rint.f32",
+        sym::rintf64 => "llvm.rint.f64",
+        sym::nearbyintf32 => "llvm.nearbyint.f32",
+        sym::nearbyintf64 => "llvm.nearbyint.f64",
+        sym::roundf32 => "llvm.round.f32",
+        sym::roundf64 => "llvm.round.f64",
+        sym::assume => "llvm.assume",
+        sym::abort => "llvm.trap",
         _ => return None,
     };
     Some(cx.get_intrinsic(&llvm_name))
@@ -86,49 +86,68 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu
 impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn is_codegen_intrinsic(
         &mut self,
-        intrinsic: &str,
+        intrinsic: Symbol,
         args: &Vec<Operand<'tcx>>,
         caller_instance: ty::Instance<'tcx>,
     ) -> bool {
-        match intrinsic {
-            "count_code_region" => {
-                use coverage::count_code_region_args::*;
-                self.add_counter_region(
-                    caller_instance,
-                    op_to_u32(&args[COUNTER_INDEX]),
-                    op_to_u32(&args[START_BYTE_POS]),
-                    op_to_u32(&args[END_BYTE_POS]),
-                );
-                true // Also inject the counter increment in the backend
-            }
-            "coverage_counter_add" | "coverage_counter_subtract" => {
-                use coverage::coverage_counter_expression_args::*;
-                self.add_counter_expression_region(
-                    caller_instance,
-                    op_to_u32(&args[COUNTER_EXPRESSION_INDEX]),
-                    op_to_u32(&args[LEFT_INDEX]),
-                    if intrinsic == "coverage_counter_add" {
-                        CounterOp::Add
-                    } else {
-                        CounterOp::Subtract
-                    },
-                    op_to_u32(&args[RIGHT_INDEX]),
-                    op_to_u32(&args[START_BYTE_POS]),
-                    op_to_u32(&args[END_BYTE_POS]),
-                );
-                false // Does not inject backend code
-            }
-            "coverage_unreachable" => {
-                use coverage::coverage_unreachable_args::*;
-                self.add_unreachable_region(
-                    caller_instance,
-                    op_to_u32(&args[START_BYTE_POS]),
-                    op_to_u32(&args[END_BYTE_POS]),
-                );
-                false // Does not inject backend code
+        if self.tcx.sess.opts.debugging_opts.instrument_coverage {
+            // Add the coverage information from the MIR to the Codegen context. Some coverage
+            // intrinsics are used only to pass along the coverage information (returns `false`
+            // for `is_codegen_intrinsic()`), but `count_code_region` is also converted into an
+            // LLVM intrinsic to increment a coverage counter.
+            match intrinsic {
+                sym::count_code_region => {
+                    use coverage::count_code_region_args::*;
+                    self.add_counter_region(
+                        caller_instance,
+                        op_to_u64(&args[FUNCTION_SOURCE_HASH]),
+                        op_to_u32(&args[COUNTER_INDEX]),
+                        op_to_u32(&args[START_BYTE_POS]),
+                        op_to_u32(&args[END_BYTE_POS]),
+                    );
+                    return true; // Also inject the counter increment in the backend
+                }
+                sym::coverage_counter_add | sym::coverage_counter_subtract => {
+                    use coverage::coverage_counter_expression_args::*;
+                    self.add_counter_expression_region(
+                        caller_instance,
+                        op_to_u32(&args[COUNTER_EXPRESSION_INDEX]),
+                        op_to_u32(&args[LEFT_INDEX]),
+                        if intrinsic == sym::coverage_counter_add {
+                            CounterOp::Add
+                        } else {
+                            CounterOp::Subtract
+                        },
+                        op_to_u32(&args[RIGHT_INDEX]),
+                        op_to_u32(&args[START_BYTE_POS]),
+                        op_to_u32(&args[END_BYTE_POS]),
+                    );
+                    return false; // Does not inject backend code
+                }
+                sym::coverage_unreachable => {
+                    use coverage::coverage_unreachable_args::*;
+                    self.add_unreachable_region(
+                        caller_instance,
+                        op_to_u32(&args[START_BYTE_POS]),
+                        op_to_u32(&args[END_BYTE_POS]),
+                    );
+                    return false; // Does not inject backend code
+                }
+                _ => {}
+            }
+        } else {
+            // NOT self.tcx.sess.opts.debugging_opts.instrument_coverage
+            if intrinsic == sym::count_code_region {
+                // An external crate may have been pre-compiled with coverage instrumentation, and
+                // some references from the current crate to the external crate might carry along
+                // the call terminators to coverage intrinsics, like `count_code_region` (for
+                // example, when instantiating a generic function). If the current crate has
+                // `instrument_coverage` disabled, the `count_code_region` call terminators should
+                // be ignored.
+                return false; // Do not inject coverage counters inlined from external crates
             }
-            _ => true, // Unhandled intrinsics should be passed to `codegen_intrinsic_call()`
         }
+        true // Unhandled intrinsics should be passed to `codegen_intrinsic_call()`
     }
 
     fn codegen_intrinsic_call(
@@ -152,7 +171,8 @@ fn codegen_intrinsic_call(
         let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
-        let name = &*tcx.item_name(def_id).as_str();
+        let name = tcx.item_name(def_id);
+        let name_str = &*name.as_str();
 
         let llret_ty = self.layout_of(ret_ty).llvm_type(self);
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
@@ -164,18 +184,18 @@ fn codegen_intrinsic_call(
                 &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                 None,
             ),
-            "unreachable" => {
+            sym::unreachable => {
                 return;
             }
-            "likely" => {
+            sym::likely => {
                 let expect = self.get_intrinsic(&("llvm.expect.i1"));
                 self.call(expect, &[args[0].immediate(), self.const_bool(true)], None)
             }
-            "unlikely" => {
+            sym::unlikely => {
                 let expect = self.get_intrinsic(&("llvm.expect.i1"));
                 self.call(expect, &[args[0].immediate(), self.const_bool(false)], None)
             }
-            "try" => {
+            kw::Try => {
                 try_intrinsic(
                     self,
                     args[0].immediate(),
@@ -185,34 +205,35 @@ fn codegen_intrinsic_call(
                 );
                 return;
             }
-            "breakpoint" => {
+            sym::breakpoint => {
                 let llfn = self.get_intrinsic(&("llvm.debugtrap"));
                 self.call(llfn, &[], None)
             }
-            "count_code_region" => {
+            sym::count_code_region => {
                 // FIXME(richkadel): The current implementation assumes the MIR for the given
                 // caller_instance represents a single function. Validate and/or correct if inlining
                 // and/or monomorphization invalidates these assumptions.
                 let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
                 let mangled_fn = tcx.symbol_name(caller_instance);
-                let (mangled_fn_name, _len_val) = self.const_str(mangled_fn.name);
-                let hash = self.const_u64(coverageinfo.hash);
+                let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name));
                 let num_counters = self.const_u32(coverageinfo.num_counters);
                 use coverage::count_code_region_args::*;
+                let hash = args[FUNCTION_SOURCE_HASH].immediate();
                 let index = args[COUNTER_INDEX].immediate();
                 debug!(
-                    "count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
+                    "translating Rust intrinsic `count_code_region()` to LLVM intrinsic: \
+                    instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
                     mangled_fn.name, hash, num_counters, index,
                 );
                 self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
             }
-            "va_start" => self.va_start(args[0].immediate()),
-            "va_end" => self.va_end(args[0].immediate()),
-            "va_copy" => {
+            sym::va_start => self.va_start(args[0].immediate()),
+            sym::va_end => self.va_end(args[0].immediate()),
+            sym::va_copy => {
                 let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy"));
                 self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None)
             }
-            "va_arg" => {
+            sym::va_arg => {
                 match fn_abi.ret.layout.abi {
                     abi::Abi::Scalar(ref scalar) => {
                         match scalar.value {
@@ -238,7 +259,7 @@ fn codegen_intrinsic_call(
                     _ => bug!("the va_arg intrinsic does not work with non-scalar types"),
                 }
             }
-            "size_of_val" => {
+            sym::size_of_val => {
                 let tp_ty = substs.type_at(0);
                 if let OperandValue::Pair(_, meta) = args[0].val {
                     let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta));
@@ -247,7 +268,7 @@ fn codegen_intrinsic_call(
                     self.const_usize(self.size_of(tp_ty).bytes())
                 }
             }
-            "min_align_of_val" => {
+            sym::min_align_of_val => {
                 let tp_ty = substs.type_at(0);
                 if let OperandValue::Pair(_, meta) = args[0].val {
                     let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta));
@@ -256,8 +277,13 @@ fn codegen_intrinsic_call(
                     self.const_usize(self.align_of(tp_ty).bytes())
                 }
             }
-            "size_of" | "pref_align_of" | "min_align_of" | "needs_drop" | "type_id"
-            | "type_name" | "variant_count" => {
+            sym::size_of
+            | sym::pref_align_of
+            | sym::min_align_of
+            | sym::needs_drop
+            | sym::type_id
+            | sym::type_name
+            | sym::variant_count => {
                 let value = self
                     .tcx
                     .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
@@ -265,21 +291,21 @@ fn codegen_intrinsic_call(
                 OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self)
             }
             // Effectively no-op
-            "forget" => {
+            sym::forget => {
                 return;
             }
-            "offset" => {
+            sym::offset => {
                 let ptr = args[0].immediate();
                 let offset = args[1].immediate();
                 self.inbounds_gep(ptr, &[offset])
             }
-            "arith_offset" => {
+            sym::arith_offset => {
                 let ptr = args[0].immediate();
                 let offset = args[1].immediate();
                 self.gep(ptr, &[offset])
             }
 
-            "copy_nonoverlapping" => {
+            sym::copy_nonoverlapping => {
                 copy_intrinsic(
                     self,
                     false,
@@ -291,7 +317,7 @@ fn codegen_intrinsic_call(
                 );
                 return;
             }
-            "copy" => {
+            sym::copy => {
                 copy_intrinsic(
                     self,
                     true,
@@ -303,7 +329,7 @@ fn codegen_intrinsic_call(
                 );
                 return;
             }
-            "write_bytes" => {
+            sym::write_bytes => {
                 memset_intrinsic(
                     self,
                     false,
@@ -315,7 +341,7 @@ fn codegen_intrinsic_call(
                 return;
             }
 
-            "volatile_copy_nonoverlapping_memory" => {
+            sym::volatile_copy_nonoverlapping_memory => {
                 copy_intrinsic(
                     self,
                     false,
@@ -327,7 +353,7 @@ fn codegen_intrinsic_call(
                 );
                 return;
             }
-            "volatile_copy_memory" => {
+            sym::volatile_copy_memory => {
                 copy_intrinsic(
                     self,
                     true,
@@ -339,7 +365,7 @@ fn codegen_intrinsic_call(
                 );
                 return;
             }
-            "volatile_set_memory" => {
+            sym::volatile_set_memory => {
                 memset_intrinsic(
                     self,
                     true,
@@ -350,14 +376,14 @@ fn codegen_intrinsic_call(
                 );
                 return;
             }
-            "volatile_load" | "unaligned_volatile_load" => {
+            sym::volatile_load | sym::unaligned_volatile_load => {
                 let tp_ty = substs.type_at(0);
                 let mut ptr = args[0].immediate();
                 if let PassMode::Cast(ty) = fn_abi.ret.mode {
                     ptr = self.pointercast(ptr, self.type_ptr_to(ty.llvm_type(self)));
                 }
                 let load = self.volatile_load(ptr);
-                let align = if name == "unaligned_volatile_load" {
+                let align = if name == sym::unaligned_volatile_load {
                     1
                 } else {
                     self.align_of(tp_ty).bytes() as u32
@@ -367,26 +393,26 @@ fn codegen_intrinsic_call(
                 }
                 to_immediate(self, load, self.layout_of(tp_ty))
             }
-            "volatile_store" => {
+            sym::volatile_store => {
                 let dst = args[0].deref(self.cx());
                 args[1].val.volatile_store(self, dst);
                 return;
             }
-            "unaligned_volatile_store" => {
+            sym::unaligned_volatile_store => {
                 let dst = args[0].deref(self.cx());
                 args[1].val.unaligned_volatile_store(self, dst);
                 return;
             }
-            "prefetch_read_data"
-            | "prefetch_write_data"
-            | "prefetch_read_instruction"
-            | "prefetch_write_instruction" => {
+            sym::prefetch_read_data
+            | sym::prefetch_write_data
+            | sym::prefetch_read_instruction
+            | sym::prefetch_write_instruction => {
                 let expect = self.get_intrinsic(&("llvm.prefetch"));
                 let (rw, cache_type) = match name {
-                    "prefetch_read_data" => (0, 1),
-                    "prefetch_write_data" => (1, 1),
-                    "prefetch_read_instruction" => (0, 0),
-                    "prefetch_write_instruction" => (1, 0),
+                    sym::prefetch_read_data => (0, 1),
+                    sym::prefetch_write_data => (1, 1),
+                    sym::prefetch_read_instruction => (0, 0),
+                    sym::prefetch_write_instruction => (1, 0),
                     _ => bug!(),
                 };
                 self.call(
@@ -400,32 +426,51 @@ fn codegen_intrinsic_call(
                     None,
                 )
             }
-            "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap"
-            | "bitreverse" | "add_with_overflow" | "sub_with_overflow" | "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" => {
+            sym::ctlz
+            | sym::ctlz_nonzero
+            | sym::cttz
+            | sym::cttz_nonzero
+            | sym::ctpop
+            | sym::bswap
+            | sym::bitreverse
+            | sym::add_with_overflow
+            | sym::sub_with_overflow
+            | sym::mul_with_overflow
+            | sym::wrapping_add
+            | sym::wrapping_sub
+            | sym::wrapping_mul
+            | sym::unchecked_div
+            | sym::unchecked_rem
+            | sym::unchecked_shl
+            | sym::unchecked_shr
+            | sym::unchecked_add
+            | sym::unchecked_sub
+            | sym::unchecked_mul
+            | sym::exact_div
+            | sym::rotate_left
+            | sym::rotate_right
+            | sym::saturating_add
+            | sym::saturating_sub => {
                 let ty = arg_tys[0];
                 match int_type_width_signed(ty, self) {
                     Some((width, signed)) => match name {
-                        "ctlz" | "cttz" => {
+                        sym::ctlz | sym::cttz => {
                             let y = self.const_bool(false);
                             let llfn = self.get_intrinsic(&format!("llvm.{}.i{}", name, width));
                             self.call(llfn, &[args[0].immediate(), y], None)
                         }
-                        "ctlz_nonzero" | "cttz_nonzero" => {
+                        sym::ctlz_nonzero | sym::cttz_nonzero => {
                             let y = self.const_bool(true);
-                            let llvm_name = &format!("llvm.{}.i{}", &name[..4], width);
+                            let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width);
                             let llfn = self.get_intrinsic(llvm_name);
                             self.call(llfn, &[args[0].immediate(), y], None)
                         }
-                        "ctpop" => self.call(
+                        sym::ctpop => self.call(
                             self.get_intrinsic(&format!("llvm.ctpop.i{}", width)),
                             &[args[0].immediate()],
                             None,
                         ),
-                        "bswap" => {
+                        sym::bswap => {
                             if width == 8 {
                                 args[0].immediate() // byte swap a u8/i8 is just a no-op
                             } else {
@@ -436,16 +481,18 @@ fn codegen_intrinsic_call(
                                 )
                             }
                         }
-                        "bitreverse" => self.call(
+                        sym::bitreverse => self.call(
                             self.get_intrinsic(&format!("llvm.bitreverse.i{}", width)),
                             &[args[0].immediate()],
                             None,
                         ),
-                        "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
+                        sym::add_with_overflow
+                        | sym::sub_with_overflow
+                        | sym::mul_with_overflow => {
                             let intrinsic = format!(
                                 "llvm.{}{}.with.overflow.i{}",
                                 if signed { 's' } else { 'u' },
-                                &name[..3],
+                                &name_str[..3],
                                 width
                             );
                             let llfn = self.get_intrinsic(&intrinsic);
@@ -464,61 +511,61 @@ fn codegen_intrinsic_call(
 
                             return;
                         }
-                        "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" => {
+                        sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()),
+                        sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()),
+                        sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()),
+                        sym::exact_div => {
                             if signed {
                                 self.exactsdiv(args[0].immediate(), args[1].immediate())
                             } else {
                                 self.exactudiv(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        "unchecked_div" => {
+                        sym::unchecked_div => {
                             if signed {
                                 self.sdiv(args[0].immediate(), args[1].immediate())
                             } else {
                                 self.udiv(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        "unchecked_rem" => {
+                        sym::unchecked_rem => {
                             if signed {
                                 self.srem(args[0].immediate(), args[1].immediate())
                             } else {
                                 self.urem(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        "unchecked_shl" => self.shl(args[0].immediate(), args[1].immediate()),
-                        "unchecked_shr" => {
+                        sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()),
+                        sym::unchecked_shr => {
                             if signed {
                                 self.ashr(args[0].immediate(), args[1].immediate())
                             } else {
                                 self.lshr(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        "unchecked_add" => {
+                        sym::unchecked_add => {
                             if signed {
                                 self.unchecked_sadd(args[0].immediate(), args[1].immediate())
                             } else {
                                 self.unchecked_uadd(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        "unchecked_sub" => {
+                        sym::unchecked_sub => {
                             if signed {
                                 self.unchecked_ssub(args[0].immediate(), args[1].immediate())
                             } else {
                                 self.unchecked_usub(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        "unchecked_mul" => {
+                        sym::unchecked_mul => {
                             if signed {
                                 self.unchecked_smul(args[0].immediate(), args[1].immediate())
                             } else {
                                 self.unchecked_umul(args[0].immediate(), args[1].immediate())
                             }
                         }
-                        "rotate_left" | "rotate_right" => {
-                            let is_left = name == "rotate_left";
+                        sym::rotate_left | sym::rotate_right => {
+                            let is_left = name == sym::rotate_left;
                             let val = args[0].immediate();
                             let raw_shift = args[1].immediate();
                             // rotate = funnel shift with first two args the same
@@ -527,8 +574,8 @@ fn codegen_intrinsic_call(
                             let llfn = self.get_intrinsic(llvm_name);
                             self.call(llfn, &[val, val, raw_shift], None)
                         }
-                        "saturating_add" | "saturating_sub" => {
-                            let is_add = name == "saturating_add";
+                        sym::saturating_add | sym::saturating_sub => {
+                            let is_add = name == sym::saturating_add;
                             let lhs = args[0].immediate();
                             let rhs = args[1].immediate();
                             let llvm_name = &format!(
@@ -556,14 +603,14 @@ fn codegen_intrinsic_call(
                     }
                 }
             }
-            "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
+            sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
                 match float_type_width(arg_tys[0]) {
                     Some(_width) => match name {
-                        "fadd_fast" => self.fadd_fast(args[0].immediate(), args[1].immediate()),
-                        "fsub_fast" => self.fsub_fast(args[0].immediate(), args[1].immediate()),
-                        "fmul_fast" => self.fmul_fast(args[0].immediate(), args[1].immediate()),
-                        "fdiv_fast" => self.fdiv_fast(args[0].immediate(), args[1].immediate()),
-                        "frem_fast" => self.frem_fast(args[0].immediate(), args[1].immediate()),
+                        sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()),
+                        sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()),
+                        sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()),
+                        sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()),
+                        sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()),
                         _ => bug!(),
                     },
                     None => {
@@ -581,7 +628,7 @@ fn codegen_intrinsic_call(
                 }
             }
 
-            "float_to_int_unchecked" => {
+            sym::float_to_int_unchecked => {
                 if float_type_width(arg_tys[0]).is_none() {
                     span_invalid_monomorphization_error(
                         tcx.sess,
@@ -619,7 +666,7 @@ fn codegen_intrinsic_call(
                 }
             }
 
-            "discriminant_value" => {
+            sym::discriminant_value => {
                 if ret_ty.is_integral() {
                     args[0].deref(self.cx()).codegen_get_discr(self, ret_ty)
                 } else {
@@ -627,7 +674,7 @@ fn codegen_intrinsic_call(
                 }
             }
 
-            name if name.starts_with("simd_") => {
+            _ if name_str.starts_with("simd_") => {
                 match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
                     Ok(llval) => llval,
                     Err(()) => return,
@@ -635,11 +682,11 @@ fn codegen_intrinsic_call(
             }
             // This requires that atomic intrinsics follow a specific naming pattern:
             // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
-            name if name.starts_with("atomic_") => {
+            name if name_str.starts_with("atomic_") => {
                 use rustc_codegen_ssa::common::AtomicOrdering::*;
                 use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope};
 
-                let split: Vec<&str> = name.split('_').collect();
+                let split: Vec<&str> = name_str.split('_').collect();
 
                 let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak";
                 let (order, failorder) = match split.len() {
@@ -769,23 +816,23 @@ fn codegen_intrinsic_call(
                 }
             }
 
-            "nontemporal_store" => {
+            sym::nontemporal_store => {
                 let dst = args[0].deref(self.cx());
                 args[1].val.nontemporal_store(self, dst);
                 return;
             }
 
-            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
                 let a = args[0].immediate();
                 let b = args[1].immediate();
-                if name == "ptr_guaranteed_eq" {
+                if name == sym::ptr_guaranteed_eq {
                     self.icmp(IntPredicate::IntEQ, a, b)
                 } else {
                     self.icmp(IntPredicate::IntNE, a, b)
                 }
             }
 
-            "ptr_offset_from" => {
+            sym::ptr_offset_from => {
                 let ty = substs.type_at(0);
                 let pointee_size = self.size_of(ty);
 
@@ -1172,7 +1219,7 @@ fn get_rust_try_fn<'ll, 'tcx>(
 
 fn generic_simd_intrinsic(
     bx: &mut Builder<'a, 'll, 'tcx>,
-    name: &str,
+    name: Symbol,
     callee_ty: Ty<'tcx>,
     args: &[OperandRef<'tcx, &'ll Value>],
     ret_ty: Ty<'tcx>,
@@ -1219,8 +1266,9 @@ macro_rules! require_simd {
     let sig = tcx
         .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &callee_ty.fn_sig(tcx));
     let arg_tys = sig.inputs();
+    let name_str = &*name.as_str();
 
-    if name == "simd_select_bitmask" {
+    if name == sym::simd_select_bitmask {
         let in_ty = arg_tys[0];
         let m_len = match in_ty.kind {
             // Note that this `.unwrap()` crashes for isize/usize, that's sort
@@ -1250,12 +1298,12 @@ macro_rules! require_simd {
     let in_len = arg_tys[0].simd_size(tcx);
 
     let comparison = match name {
-        "simd_eq" => Some(hir::BinOpKind::Eq),
-        "simd_ne" => Some(hir::BinOpKind::Ne),
-        "simd_lt" => Some(hir::BinOpKind::Lt),
-        "simd_le" => Some(hir::BinOpKind::Le),
-        "simd_gt" => Some(hir::BinOpKind::Gt),
-        "simd_ge" => Some(hir::BinOpKind::Ge),
+        sym::simd_eq => Some(hir::BinOpKind::Eq),
+        sym::simd_ne => Some(hir::BinOpKind::Ne),
+        sym::simd_lt => Some(hir::BinOpKind::Lt),
+        sym::simd_le => Some(hir::BinOpKind::Le),
+        sym::simd_gt => Some(hir::BinOpKind::Gt),
+        sym::simd_ge => Some(hir::BinOpKind::Ge),
         _ => None,
     };
 
@@ -1289,8 +1337,8 @@ macro_rules! require_simd {
         ));
     }
 
-    if name.starts_with("simd_shuffle") {
-        let n: u64 = name["simd_shuffle".len()..].parse().unwrap_or_else(|_| {
+    if name_str.starts_with("simd_shuffle") {
+        let n: u64 = name_str["simd_shuffle".len()..].parse().unwrap_or_else(|_| {
             span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
         });
 
@@ -1351,7 +1399,7 @@ macro_rules! require_simd {
         ));
     }
 
-    if name == "simd_insert" {
+    if name == sym::simd_insert {
         require!(
             in_elem == arg_tys[2],
             "expected inserted type `{}` (element of input `{}`), found `{}`",
@@ -1365,7 +1413,7 @@ macro_rules! require_simd {
             args[1].immediate(),
         ));
     }
-    if name == "simd_extract" {
+    if name == sym::simd_extract {
         require!(
             ret_ty == in_elem,
             "expected return type `{}` (element of input `{}`), found `{}`",
@@ -1376,7 +1424,7 @@ macro_rules! require_simd {
         return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()));
     }
 
-    if name == "simd_select" {
+    if name == sym::simd_select {
         let m_elem_ty = in_elem;
         let m_len = in_len;
         require_simd!(arg_tys[1], "argument");
@@ -1398,7 +1446,7 @@ macro_rules! require_simd {
         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
     }
 
-    if name == "simd_bitmask" {
+    if name == sym::simd_bitmask {
         // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
         // vector mask and returns an unsigned integer containing the most
         // significant bit (MSB) of each lane.
@@ -1513,46 +1561,46 @@ macro_rules! return_error {
     }
 
     match name {
-        "simd_fsqrt" => {
+        sym::simd_fsqrt => {
             return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fsin" => {
+        sym::simd_fsin => {
             return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fcos" => {
+        sym::simd_fcos => {
             return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fabs" => {
+        sym::simd_fabs => {
             return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_floor" => {
+        sym::simd_floor => {
             return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_ceil" => {
+        sym::simd_ceil => {
             return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fexp" => {
+        sym::simd_fexp => {
             return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fexp2" => {
+        sym::simd_fexp2 => {
             return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_flog10" => {
+        sym::simd_flog10 => {
             return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_flog2" => {
+        sym::simd_flog2 => {
             return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_flog" => {
+        sym::simd_flog => {
             return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fpowi" => {
+        sym::simd_fpowi => {
             return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fpow" => {
+        sym::simd_fpow => {
             return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args);
         }
-        "simd_fma" => {
+        sym::simd_fma => {
             return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args);
         }
         _ => { /* fallthrough */ }
@@ -1591,7 +1639,7 @@ fn llvm_vector_ty(
         cx.type_vector(elem_ty, vec_len)
     }
 
-    if name == "simd_gather" {
+    if name == sym::simd_gather {
         // simd_gather(values: <N x T>, pointers: <N x *_ T>,
         //             mask: <N x i{M}>) -> <N x T>
         // * N: number of elements in the input vectors
@@ -1718,7 +1766,7 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
         return Ok(v);
     }
 
-    if name == "simd_scatter" {
+    if name == sym::simd_scatter {
         // simd_scatter(values: <N x T>, pointers: <N x *mut T>,
         //             mask: <N x i{M}>) -> ()
         // * N: number of elements in the input vectors
@@ -1841,8 +1889,9 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
     }
 
     macro_rules! arith_red {
-        ($name:tt : $integer_reduce:ident, $float_reduce:ident, $ordered:expr) => {
-            if name == $name {
+        ($name:ident : $integer_reduce:ident, $float_reduce:ident, $ordered:expr, $op:ident,
+         $identity:expr) => {
+            if name == sym::$name {
                 require!(
                     ret_ty == in_elem,
                     "expected return type `{}` (element of input `{}`), found `{}`",
@@ -1856,11 +1905,7 @@ macro_rules! arith_red {
                         if $ordered {
                             // if overflow occurs, the result is the
                             // mathematical result modulo 2^n:
-                            if name.contains("mul") {
-                                Ok(bx.mul(args[1].immediate(), r))
-                            } else {
-                                Ok(bx.add(args[1].immediate(), r))
-                            }
+                            Ok(bx.$op(args[1].immediate(), r))
                         } else {
                             Ok(bx.$integer_reduce(args[0].immediate()))
                         }
@@ -1871,14 +1916,13 @@ macro_rules! arith_red {
                             args[1].immediate()
                         } else {
                             // unordered arithmetic reductions use the identity accumulator
-                            let identity_acc = if $name.contains("mul") { 1.0 } else { 0.0 };
                             match f.bit_width() {
-                                32 => bx.const_real(bx.type_f32(), identity_acc),
-                                64 => bx.const_real(bx.type_f64(), identity_acc),
+                                32 => bx.const_real(bx.type_f32(), $identity),
+                                64 => bx.const_real(bx.type_f64(), $identity),
                                 v => return_error!(
                                     r#"
 unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
-                                    $name,
+                                    sym::$name,
                                     in_ty,
                                     in_elem,
                                     v,
@@ -1890,7 +1934,7 @@ macro_rules! arith_red {
                     }
                     _ => return_error!(
                         "unsupported {} from `{}` with element `{}` to `{}`",
-                        $name,
+                        sym::$name,
                         in_ty,
                         in_elem,
                         ret_ty
@@ -1900,14 +1944,26 @@ macro_rules! arith_red {
         };
     }
 
-    arith_red!("simd_reduce_add_ordered": vector_reduce_add, vector_reduce_fadd, true);
-    arith_red!("simd_reduce_mul_ordered": vector_reduce_mul, vector_reduce_fmul, true);
-    arith_red!("simd_reduce_add_unordered": vector_reduce_add, vector_reduce_fadd_fast, false);
-    arith_red!("simd_reduce_mul_unordered": vector_reduce_mul, vector_reduce_fmul_fast, false);
+    arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, 0.0);
+    arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0);
+    arith_red!(
+        simd_reduce_add_unordered: vector_reduce_add,
+        vector_reduce_fadd_fast,
+        false,
+        add,
+        0.0
+    );
+    arith_red!(
+        simd_reduce_mul_unordered: vector_reduce_mul,
+        vector_reduce_fmul_fast,
+        false,
+        mul,
+        1.0
+    );
 
     macro_rules! minmax_red {
-        ($name:tt: $int_red:ident, $float_red:ident) => {
-            if name == $name {
+        ($name:ident: $int_red:ident, $float_red:ident) => {
+            if name == sym::$name {
                 require!(
                     ret_ty == in_elem,
                     "expected return type `{}` (element of input `{}`), found `{}`",
@@ -1921,7 +1977,7 @@ macro_rules! minmax_red {
                     ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())),
                     _ => return_error!(
                         "unsupported {} from `{}` with element `{}` to `{}`",
-                        $name,
+                        sym::$name,
                         in_ty,
                         in_elem,
                         ret_ty
@@ -1931,15 +1987,15 @@ macro_rules! minmax_red {
         };
     }
 
-    minmax_red!("simd_reduce_min": vector_reduce_min, vector_reduce_fmin);
-    minmax_red!("simd_reduce_max": vector_reduce_max, vector_reduce_fmax);
+    minmax_red!(simd_reduce_min: vector_reduce_min, vector_reduce_fmin);
+    minmax_red!(simd_reduce_max: vector_reduce_max, vector_reduce_fmax);
 
-    minmax_red!("simd_reduce_min_nanless": vector_reduce_min, vector_reduce_fmin_fast);
-    minmax_red!("simd_reduce_max_nanless": vector_reduce_max, vector_reduce_fmax_fast);
+    minmax_red!(simd_reduce_min_nanless: vector_reduce_min, vector_reduce_fmin_fast);
+    minmax_red!(simd_reduce_max_nanless: vector_reduce_max, vector_reduce_fmax_fast);
 
     macro_rules! bitwise_red {
-        ($name:tt : $red:ident, $boolean:expr) => {
-            if name == $name {
+        ($name:ident : $red:ident, $boolean:expr) => {
+            if name == sym::$name {
                 let input = if !$boolean {
                     require!(
                         ret_ty == in_elem,
@@ -1954,7 +2010,7 @@ macro_rules! bitwise_red {
                         ty::Int(_) | ty::Uint(_) => {}
                         _ => return_error!(
                             "unsupported {} from `{}` with element `{}` to `{}`",
-                            $name,
+                            sym::$name,
                             in_ty,
                             in_elem,
                             ret_ty
@@ -1973,7 +2029,7 @@ macro_rules! bitwise_red {
                     }
                     _ => return_error!(
                         "unsupported {} from `{}` with element `{}` to `{}`",
-                        $name,
+                        sym::$name,
                         in_ty,
                         in_elem,
                         ret_ty
@@ -1983,13 +2039,13 @@ macro_rules! bitwise_red {
         };
     }
 
-    bitwise_red!("simd_reduce_and": vector_reduce_and, false);
-    bitwise_red!("simd_reduce_or": vector_reduce_or, false);
-    bitwise_red!("simd_reduce_xor": vector_reduce_xor, false);
-    bitwise_red!("simd_reduce_all": vector_reduce_and, true);
-    bitwise_red!("simd_reduce_any": vector_reduce_or, true);
+    bitwise_red!(simd_reduce_and: vector_reduce_and, false);
+    bitwise_red!(simd_reduce_or: vector_reduce_or, false);
+    bitwise_red!(simd_reduce_xor: vector_reduce_xor, false);
+    bitwise_red!(simd_reduce_all: vector_reduce_and, true);
+    bitwise_red!(simd_reduce_any: vector_reduce_or, true);
 
-    if name == "simd_cast" {
+    if name == sym::simd_cast {
         require_simd!(ret_ty, "return");
         let out_len = ret_ty.simd_size(tcx);
         require!(
@@ -2077,7 +2133,7 @@ enum Style {
     }
     macro_rules! arith {
         ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
-            $(if name == stringify!($name) {
+            $(if name == sym::$name {
                 match in_elem.kind {
                     $($(ty::$p(_))|* => {
                         return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
@@ -2107,10 +2163,10 @@ macro_rules! arith {
 
     }
 
-    if name == "simd_saturating_add" || name == "simd_saturating_sub" {
+    if name == sym::simd_saturating_add || name == sym::simd_saturating_sub {
         let lhs = args[0].immediate();
         let rhs = args[1].immediate();
-        let is_add = name == "simd_saturating_add";
+        let is_add = name == sym::simd_saturating_add;
         let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _;
         let (signed, elem_width, elem_ty) = match in_elem.kind {
             ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
@@ -2186,3 +2242,7 @@ fn float_type_width(ty: Ty<'_>) -> Option<u64> {
 fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 {
     Operand::scalar_from_const(op).to_u32().expect("Scalar is u32")
 }
+
+fn op_to_u64<'tcx>(op: &Operand<'tcx>) -> u64 {
+    Operand::scalar_from_const(op).to_u64().expect("Scalar is u64")
+}
index 64f5e103f0b0dbd5f06c46f84042e3a0fdbf4086..9784beaa079de7f2b892b710ad730ec129fc325e 100644 (file)
@@ -1,6 +1,8 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
+use super::coverageinfo::{SmallVectorCounterExpression, SmallVectorCounterMappingRegion};
+
 use super::debuginfo::{
     DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
     DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DINameSpace, DISPFlags, DIScope,
@@ -650,6 +652,16 @@ struct InvariantOpaque<'a> {
 pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
 pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
 
+pub mod coverageinfo {
+    use super::InvariantOpaque;
+
+    #[repr(C)]
+    pub struct SmallVectorCounterExpression<'a>(InvariantOpaque<'a>);
+
+    #[repr(C)]
+    pub struct SmallVectorCounterMappingRegion<'a>(InvariantOpaque<'a>);
+}
+
 pub mod debuginfo {
     use super::{InvariantOpaque, Metadata};
     use bitflags::bitflags;
@@ -1365,7 +1377,7 @@ pub fn LLVMBuildFCmp(
 
     // Miscellaneous instructions
     pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
-    pub fn LLVMRustGetInstrprofIncrementIntrinsic(M: &Module) -> &'a Value;
+    pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &'a Value;
     pub fn LLVMRustBuildCall(
         B: &Builder<'a>,
         Fn: &'a Value,
@@ -1633,6 +1645,58 @@ pub fn LLVMRustInlineAsmVerify(
         ConstraintsLen: size_t,
     ) -> bool;
 
+    pub fn LLVMRustCoverageSmallVectorCounterExpressionCreate()
+    -> &'a mut SmallVectorCounterExpression<'a>;
+    pub fn LLVMRustCoverageSmallVectorCounterExpressionDispose(
+        Container: &'a mut SmallVectorCounterExpression<'a>,
+    );
+    pub fn LLVMRustCoverageSmallVectorCounterExpressionAdd(
+        Container: &mut SmallVectorCounterExpression<'a>,
+        Kind: rustc_codegen_ssa::coverageinfo::CounterOp,
+        LeftIndex: c_uint,
+        RightIndex: c_uint,
+    );
+
+    pub fn LLVMRustCoverageSmallVectorCounterMappingRegionCreate()
+    -> &'a mut SmallVectorCounterMappingRegion<'a>;
+    pub fn LLVMRustCoverageSmallVectorCounterMappingRegionDispose(
+        Container: &'a mut SmallVectorCounterMappingRegion<'a>,
+    );
+    pub fn LLVMRustCoverageSmallVectorCounterMappingRegionAdd(
+        Container: &mut SmallVectorCounterMappingRegion<'a>,
+        Index: c_uint,
+        FileID: c_uint,
+        LineStart: c_uint,
+        ColumnStart: c_uint,
+        LineEnd: c_uint,
+        ColumnEnd: c_uint,
+    );
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
+        Filenames: *const *const c_char,
+        FilenamesLen: size_t,
+        BufferOut: &RustString,
+    );
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteMappingToBuffer(
+        VirtualFileMappingIDs: *const c_uint,
+        NumVirtualFileMappingIDs: c_uint,
+        Expressions: *const SmallVectorCounterExpression<'_>,
+        MappingRegions: *const SmallVectorCounterMappingRegion<'_>,
+        BufferOut: &RustString,
+    );
+
+    pub fn LLVMRustCoverageComputeHash(Name: *const c_char) -> u64;
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteSectionNameToString(M: &Module, Str: &RustString);
+
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
+
+    pub fn LLVMRustCoverageMappingVersion() -> u32;
     pub fn LLVMRustDebugMetadataVersion() -> u32;
     pub fn LLVMRustVersionMajor() -> u32;
     pub fn LLVMRustVersionMinor() -> u32;
index b7f1e1789c9e2cd0c8ced4247a2cdd8bf9c7b986..c09e3659f80a20053b6819df530bee4d783b78f8 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_llvm::RustString;
 use std::cell::RefCell;
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
 use std::str::FromStr;
 use std::string::FromUtf8Error;
 
@@ -189,6 +189,42 @@ pub fn mk_section_iter(llof: &ffi::ObjectFile) -> SectionIter<'_> {
     unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
 }
 
+pub fn set_section(llglobal: &Value, section_name: &str) {
+    let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
+    unsafe {
+        LLVMSetSection(llglobal, section_name_cstr.as_ptr());
+    }
+}
+
+pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name: &str) -> &'a Value {
+    let name_cstr = CString::new(name).expect("unexpected CString error");
+    unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
+}
+
+pub fn set_initializer(llglobal: &Value, constant_val: &Value) {
+    unsafe {
+        LLVMSetInitializer(llglobal, constant_val);
+    }
+}
+
+pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
+    unsafe {
+        LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
+    }
+}
+
+pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
+    unsafe {
+        LLVMRustSetLinkage(llglobal, linkage);
+    }
+}
+
+pub fn set_alignment(llglobal: &Value, bytes: usize) {
+    unsafe {
+        ffi::LLVMSetAlignment(llglobal, bytes as c_uint);
+    }
+}
+
 /// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
 pub fn get_param(llfn: &Value, index: c_uint) -> &Value {
     unsafe {
@@ -225,6 +261,12 @@ pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error
     String::from_utf8(sr.bytes.into_inner())
 }
 
+pub fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
+    let sr = RustString { bytes: RefCell::new(Vec::new()) };
+    f(&sr);
+    sr.bytes.into_inner()
+}
+
 pub fn twine_to_string(tr: &Twine) -> String {
     unsafe {
         build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM")
index eeb6b4aabcf29c8e83a9e633cd3188102d293f94..e100e0095c92a4bfd37142ee7c9310b8ad8f2f86 100644 (file)
@@ -18,6 +18,7 @@ log = "0.4.5"
 libc = "0.2.50"
 jobserver = "0.1.11"
 tempfile = "3.1"
+pathdiff = "0.2.0"
 
 rustc_serialize = { path = "../librustc_serialize" }
 rustc_ast = { path = "../librustc_ast" }
index 3adaa07db91b012c054e80fa1a274fbf53db9184..2d65282ce7798751268970eb62534bf7349201b6 100644 (file)
@@ -1659,7 +1659,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // FIXME: Order dependent, applies to the following objects. Where should it be placed?
     // Try to strip as much out of the generated object by removing unused
     // sections if possible. See more comments in linker.rs
-    if !sess.opts.cg.link_dead_code {
+    if sess.opts.cg.link_dead_code != Some(true) {
         let keep_metadata = crate_type == CrateType::Dylib;
         cmd.gc_sections(keep_metadata);
     }
@@ -1695,7 +1695,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     );
 
     // OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.opts.cg.profile_generate.enabled() {
+    if sess.opts.cg.profile_generate.enabled() || sess.opts.debugging_opts.instrument_coverage {
         cmd.pgo_gen();
     }
 
index c02e4f279b1fbea67e2990c6f0b6db5540372441..005d2efdd3b26ab95bff7995c2c7a5f5778eb61d 100644 (file)
@@ -1,3 +1,4 @@
+use pathdiff::diff_paths;
 use rustc_data_structures::fx::FxHashSet;
 use std::env;
 use std::fs;
@@ -109,37 +110,7 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> Str
 // In particular, this handles the case on unix where both paths are
 // absolute but with only the root as the common directory.
 fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
-    use std::path::Component;
-
-    if path.is_absolute() != base.is_absolute() {
-        path.is_absolute().then(|| PathBuf::from(path))
-    } else {
-        let mut ita = path.components();
-        let mut itb = base.components();
-        let mut comps: Vec<Component<'_>> = vec![];
-        loop {
-            match (ita.next(), itb.next()) {
-                (None, None) => break,
-                (Some(a), None) => {
-                    comps.push(a);
-                    comps.extend(ita.by_ref());
-                    break;
-                }
-                (None, _) => comps.push(Component::ParentDir),
-                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
-                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
-                (Some(_), Some(b)) if b == Component::ParentDir => return None,
-                (Some(a), Some(_)) => {
-                    comps.push(Component::ParentDir);
-                    comps.extend(itb.map(|_| Component::ParentDir));
-                    comps.push(a);
-                    comps.extend(ita.by_ref());
-                    break;
-                }
-            }
-        }
-        Some(comps.iter().map(|c| c.as_os_str()).collect())
-    }
+    diff_paths(path, base)
 }
 
 fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String {
index 2efbfcb995027bcef5825636460d6fe5746dcfd8..7d742e7a7afd2b35a613fb20f1b9569f2133507b 100644 (file)
@@ -107,7 +107,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
         })
         .map(|def_id| {
             let export_level = if special_runtime_crate {
-                let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name.as_str();
+                let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name;
                 // 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
@@ -115,13 +115,12 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
                 //
                 // In general though we won't link right if these
                 // symbols are stripped, and LTO currently strips them.
-                if name == "rust_eh_personality"
-                    || name == "rust_eh_register_frames"
-                    || name == "rust_eh_unregister_frames"
-                {
-                    SymbolExportLevel::C
-                } else {
-                    SymbolExportLevel::Rust
+                match name {
+                    "rust_eh_personality"
+                    | "rust_eh_register_frames"
+                    | "rust_eh_unregister_frames" =>
+                        SymbolExportLevel::C,
+                    _ => SymbolExportLevel::Rust,
                 }
             } else {
                 symbol_export_level(tcx, def_id.to_def_id())
@@ -177,7 +176,7 @@ fn exported_symbols_provider_local(
         .collect();
 
     if tcx.entry_fn(LOCAL_CRATE).is_some() {
-        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("main"));
+        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, "main"));
 
         symbols.push((exported_symbol, SymbolExportLevel::C));
     }
@@ -185,7 +184,7 @@ fn exported_symbols_provider_local(
     if tcx.allocator_kind().is_some() {
         for method in ALLOCATOR_METHODS {
             let symbol_name = format!("__rust_{}", method.name);
-            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
+            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
 
             symbols.push((exported_symbol, SymbolExportLevel::Rust));
         }
@@ -199,7 +198,18 @@ fn exported_symbols_provider_local(
             ["__llvm_profile_raw_version", "__llvm_profile_filename"];
 
         symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| {
-            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
+            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
+            (exported_symbol, SymbolExportLevel::C)
+        }));
+    }
+
+    if tcx.sess.opts.debugging_opts.instrument_coverage {
+        // Similar to PGO profiling, preserve symbols used by LLVM InstrProf coverage profiling.
+        const COVERAGE_WEAK_SYMBOLS: [&str; 3] =
+            ["__llvm_profile_filename", "__llvm_coverage_mapping", "__llvm_covmap"];
+
+        symbols.extend(COVERAGE_WEAK_SYMBOLS.iter().map(|sym| {
+            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
             (exported_symbol, SymbolExportLevel::C)
         }));
     }
@@ -209,14 +219,14 @@ fn exported_symbols_provider_local(
         const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
 
         symbols.extend(MSAN_WEAK_SYMBOLS.iter().map(|sym| {
-            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
+            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym));
             (exported_symbol, SymbolExportLevel::C)
         }));
     }
 
     if tcx.sess.crate_types().contains(&CrateType::Dylib) {
         let symbol_name = metadata_symbol_name(tcx);
-        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
+        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
 
         symbols.push((exported_symbol, SymbolExportLevel::Rust));
     }
@@ -249,9 +259,9 @@ fn exported_symbols_provider_local(
             }
 
             match *mono_item {
-                MonoItem::Fn(Instance { def: InstanceDef::Item(def_id), substs }) => {
+                MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => {
                     if substs.non_erasable_generics().next().is_some() {
-                        let symbol = ExportedSymbol::Generic(def_id, substs);
+                        let symbol = ExportedSymbol::Generic(def.did, substs);
                         symbols.push((symbol, SymbolExportLevel::Rust));
                     }
                 }
index 3bd262cf2b21374915a0b2ff9c9bc82cf2cd82cd..a8ffef8bc5b6b2fae298aac14e5cdd8509bc45e9 100644 (file)
-use rustc_data_structures::fx::FxHashMap;
-use std::collections::hash_map;
-use std::slice;
+use rustc_data_structures::sync::Lrc;
+use rustc_middle::mir;
+use rustc_span::source_map::{Pos, SourceFile, SourceMap};
+use rustc_span::{BytePos, FileName, RealFileName};
+
+use std::cmp::{Ord, Ordering};
+use std::collections::BTreeMap;
+use std::fmt;
+use std::path::PathBuf;
 
 #[derive(Copy, Clone, Debug)]
+#[repr(C)]
 pub enum CounterOp {
-    Add,
+    // Note the order (and therefore the default values) is important. With the attribute
+    // `#[repr(C)]`, this enum matches the layout of the LLVM enum defined for the nested enum,
+    // `llvm::coverage::CounterExpression::ExprKind`, as shown in the following source snippet:
+    // https://github.com/rust-lang/llvm-project/blob/f208b70fbc4dee78067b3c5bd6cb92aa3ba58a1e/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L146
     Subtract,
+    Add,
 }
 
+#[derive(Copy, Clone, Debug)]
 pub enum CoverageKind {
     Counter,
     CounterExpression(u32, CounterOp, u32),
+    Unreachable,
 }
 
-pub struct CoverageSpan {
+#[derive(Clone, Debug)]
+pub struct CoverageRegion {
+    pub kind: CoverageKind,
     pub start_byte_pos: u32,
     pub end_byte_pos: u32,
 }
 
-pub struct CoverageRegion {
-    pub kind: CoverageKind,
-    pub coverage_span: CoverageSpan,
+impl CoverageRegion {
+    pub fn source_loc(&self, source_map: &SourceMap) -> Option<(Lrc<SourceFile>, CoverageLoc)> {
+        let (start_file, start_line, start_col) =
+            lookup_file_line_col(source_map, BytePos::from_u32(self.start_byte_pos));
+        let (end_file, end_line, end_col) =
+            lookup_file_line_col(source_map, BytePos::from_u32(self.end_byte_pos));
+        let start_file_path = match &start_file.name {
+            FileName::Real(RealFileName::Named(path)) => path,
+            _ => {
+                bug!("start_file_path should be a RealFileName, but it was: {:?}", start_file.name)
+            }
+        };
+        let end_file_path = match &end_file.name {
+            FileName::Real(RealFileName::Named(path)) => path,
+            _ => bug!("end_file_path should be a RealFileName, but it was: {:?}", end_file.name),
+        };
+        if start_file_path == end_file_path {
+            Some((start_file, CoverageLoc { start_line, start_col, end_line, end_col }))
+        } else {
+            None
+            // FIXME(richkadel): There seems to be a problem computing the file location in
+            // some cases. I need to investigate this more. When I generate and show coverage
+            // for the example binary in the crates.io crate `json5format`, I had a couple of
+            // notable problems:
+            //
+            //   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in
+            //      various comments (not corresponding to rustdoc code), indicating a possible
+            //      problem with the byte_pos-to-source-map implementation.
+            //
+            //   2. And (perhaps not related) when I build the aforementioned example binary with:
+            //      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`
+            //      and then run that binary with
+            //      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \
+            //      some.json5` for some reason the binary generates *TWO* `.profraw` files. One
+            //      named `default.profraw` and the other named `formatjson5.profraw` (the expected
+            //      name, in this case).
+            //
+            // If the byte range conversion is wrong, fix it. But if it
+            // is right, then it is possible for the start and end to be in different files.
+            // Can I do something other than ignore coverages that span multiple files?
+            //
+            // If I can resolve this, remove the "Option<>" result type wrapper
+            // `regions_in_file_order()` accordingly.
+        }
+    }
+}
+
+impl Default for CoverageRegion {
+    fn default() -> Self {
+        Self {
+            // The default kind (Unreachable) is a placeholder that will be overwritten before
+            // backend codegen.
+            kind: CoverageKind::Unreachable,
+            start_byte_pos: 0,
+            end_byte_pos: 0,
+        }
+    }
+}
+
+/// A source code region used with coverage information.
+#[derive(Debug, Eq, PartialEq)]
+pub struct CoverageLoc {
+    /// The (1-based) line number of the region start.
+    pub start_line: u32,
+    /// The (1-based) column number of the region start.
+    pub start_col: u32,
+    /// The (1-based) line number of the region end.
+    pub end_line: u32,
+    /// The (1-based) column number of the region end.
+    pub end_col: u32,
+}
+
+impl Ord for CoverageLoc {
+    fn cmp(&self, other: &Self) -> Ordering {
+        (self.start_line, &self.start_col, &self.end_line, &self.end_col).cmp(&(
+            other.start_line,
+            &other.start_col,
+            &other.end_line,
+            &other.end_col,
+        ))
+    }
+}
+
+impl PartialOrd for CoverageLoc {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl fmt::Display for CoverageLoc {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Customize debug format, and repeat the file name, so generated location strings are
+        // "clickable" in many IDEs.
+        write!(f, "{}:{} - {}:{}", self.start_line, self.start_col, self.end_line, self.end_col)
+    }
+}
+
+fn lookup_file_line_col(source_map: &SourceMap, byte_pos: BytePos) -> (Lrc<SourceFile>, u32, u32) {
+    let found = source_map
+        .lookup_line(byte_pos)
+        .expect("should find coverage region byte position in source");
+    let file = found.sf;
+    let line_pos = file.line_begin_pos(byte_pos);
+
+    // Use 1-based indexing.
+    let line = (found.line + 1) as u32;
+    let col = (byte_pos - line_pos).to_u32() + 1;
+
+    (file, line, col)
 }
 
 /// Collects all of the coverage regions associated with (a) injected counters, (b) counter
 /// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
 /// for a given Function. Counters and counter expressions are indexed because they can be operands
-/// in an expression.
+/// in an expression. This struct also stores the `function_source_hash`, computed during
+/// instrumentation and forwarded with counters.
 ///
 /// Note, it's important to distinguish the `unreachable` region type from what LLVM's refers to as
 /// a "gap region" (or "gap area"). A gap region is a code region within a counted region (either
@@ -34,50 +156,134 @@ pub struct CoverageRegion {
 /// lines with only whitespace or comments). According to LLVM Code Coverage Mapping documentation,
 /// "A count for a gap area is only used as the line execution count if there are no other regions
 /// on a line."
-#[derive(Default)]
-pub struct FunctionCoverageRegions {
-    indexed: FxHashMap<u32, CoverageRegion>,
-    unreachable: Vec<CoverageSpan>,
+pub struct FunctionCoverage {
+    source_hash: u64,
+    counters: Vec<CoverageRegion>,
+    expressions: Vec<CoverageRegion>,
+    unreachable: Vec<CoverageRegion>,
+    translated: bool,
 }
 
-impl FunctionCoverageRegions {
-    pub fn add_counter(&mut self, index: u32, start_byte_pos: u32, end_byte_pos: u32) {
-        self.indexed.insert(
-            index,
-            CoverageRegion {
-                kind: CoverageKind::Counter,
-                coverage_span: CoverageSpan { start_byte_pos, end_byte_pos },
-            },
-        );
+impl FunctionCoverage {
+    pub fn with_coverageinfo<'tcx>(coverageinfo: &'tcx mir::CoverageInfo) -> Self {
+        Self {
+            source_hash: 0, // will be set with the first `add_counter()`
+            counters: vec![CoverageRegion::default(); coverageinfo.num_counters as usize],
+            expressions: vec![CoverageRegion::default(); coverageinfo.num_expressions as usize],
+            unreachable: Vec::new(),
+            translated: false,
+        }
     }
 
-    pub fn add_counter_expression(
+    /// Adds a code region to be counted by an injected counter intrinsic. Return a counter ID
+    /// for the call.
+    pub fn add_counter(
         &mut self,
+        source_hash: u64,
         index: u32,
+        start_byte_pos: u32,
+        end_byte_pos: u32,
+    ) {
+        self.source_hash = source_hash;
+        self.counters[index as usize] =
+            CoverageRegion { kind: CoverageKind::Counter, start_byte_pos, end_byte_pos };
+    }
+
+    pub fn add_counter_expression(
+        &mut self,
+        translated_index: u32,
         lhs: u32,
         op: CounterOp,
         rhs: u32,
         start_byte_pos: u32,
         end_byte_pos: u32,
     ) {
-        self.indexed.insert(
-            index,
-            CoverageRegion {
-                kind: CoverageKind::CounterExpression(lhs, op, rhs),
-                coverage_span: CoverageSpan { start_byte_pos, end_byte_pos },
-            },
-        );
+        let index = u32::MAX - translated_index;
+        // Counter expressions start with "translated indexes", descending from `u32::MAX`, so
+        // the range of expression indexes is disjoint from the range of counter indexes. This way,
+        // both counters and expressions can be operands in other expressions.
+        //
+        // Once all counters have been added, the final "region index" for an expression is
+        // `counters.len() + expression_index` (where `expression_index` is its index in
+        // `self.expressions`), and the expression operands (`lhs` and `rhs`) can be converted to
+        // final "region index" references by the same conversion, after subtracting from
+        // `u32::MAX`.
+        self.expressions[index as usize] = CoverageRegion {
+            kind: CoverageKind::CounterExpression(lhs, op, rhs),
+            start_byte_pos,
+            end_byte_pos,
+        };
     }
 
     pub fn add_unreachable(&mut self, start_byte_pos: u32, end_byte_pos: u32) {
-        self.unreachable.push(CoverageSpan { start_byte_pos, end_byte_pos });
+        self.unreachable.push(CoverageRegion {
+            kind: CoverageKind::Unreachable,
+            start_byte_pos,
+            end_byte_pos,
+        });
+    }
+
+    pub fn source_hash(&self) -> u64 {
+        self.source_hash
+    }
+
+    fn regions(&'a mut self) -> impl Iterator<Item = &'a CoverageRegion> {
+        assert!(self.source_hash != 0);
+        self.ensure_expressions_translated();
+        self.counters.iter().chain(self.expressions.iter().chain(self.unreachable.iter()))
     }
 
-    pub fn indexed_regions(&self) -> hash_map::Iter<'_, u32, CoverageRegion> {
-        self.indexed.iter()
+    pub fn regions_in_file_order(
+        &'a mut self,
+        source_map: &SourceMap,
+    ) -> BTreeMap<PathBuf, BTreeMap<CoverageLoc, (usize, CoverageKind)>> {
+        let mut regions_in_file_order = BTreeMap::new();
+        for (region_id, region) in self.regions().enumerate() {
+            if let Some((source_file, region_loc)) = region.source_loc(source_map) {
+                // FIXME(richkadel): `region.source_loc()` sometimes fails with two different
+                // filenames for the start and end byte position. This seems wrong, but for
+                // now, if encountered, the region is skipped. If resolved, convert the result
+                // to a non-option value so regions are never skipped.
+                let real_file_path = match &(*source_file).name {
+                    FileName::Real(RealFileName::Named(path)) => path.clone(),
+                    _ => bug!("coverage mapping expected only real, named files"),
+                };
+                let file_coverage_regions =
+                    regions_in_file_order.entry(real_file_path).or_insert_with(|| BTreeMap::new());
+                file_coverage_regions.insert(region_loc, (region_id, region.kind));
+            }
+        }
+        regions_in_file_order
     }
 
-    pub fn unreachable_regions(&self) -> slice::Iter<'_, CoverageSpan> {
-        self.unreachable.iter()
+    /// A one-time translation of expression operands is needed, for any operands referencing
+    /// other CounterExpressions. CounterExpression operands get an initial operand ID that is
+    /// computed by the simple translation: `u32::max - expression_index` because, when created,
+    /// the total number of Counters is not yet known. This function recomputes region indexes
+    /// for expressions so they start with the next region index after the last counter index.
+    fn ensure_expressions_translated(&mut self) {
+        if !self.translated {
+            self.translated = true;
+            let start = self.counters.len() as u32;
+            assert!(
+                (start as u64 + self.expressions.len() as u64) < u32::MAX as u64,
+                "the number of counters and counter expressions in a single function exceeds {}",
+                u32::MAX
+            );
+            for region in self.expressions.iter_mut() {
+                match region.kind {
+                    CoverageKind::CounterExpression(lhs, op, rhs) => {
+                        let lhs = to_region_index(start, lhs);
+                        let rhs = to_region_index(start, rhs);
+                        region.kind = CoverageKind::CounterExpression(lhs, op, rhs);
+                    }
+                    _ => bug!("expressions must only contain CounterExpression kinds"),
+                }
+            }
+        }
     }
 }
+
+fn to_region_index(start: u32, index: u32) -> u32 {
+    if index < start { index } else { start + (u32::MAX - index) }
+}
index 7514eb8e889a8cc58f7beffc4b46e0b675e31a76..7116bb8c92517d3fbf1fba318f5db2e30700ac9e 100644 (file)
@@ -17,7 +17,8 @@
 use rustc_middle::mir::AssertKind;
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
-use rustc_span::{source_map::Span, symbol::Symbol};
+use rustc_span::source_map::Span;
+use rustc_span::{sym, Symbol};
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
 use rustc_target::abi::{self, LayoutOf};
 use rustc_target::spec::abi::Abi;
@@ -445,7 +446,7 @@ fn codegen_panic_intrinsic(
         &mut self,
         helper: &TerminatorCodegenHelper<'tcx>,
         bx: &mut Bx,
-        intrinsic: Option<&str>,
+        intrinsic: Option<Symbol>,
         instance: Option<Instance<'tcx>>,
         span: Span,
         destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
@@ -461,10 +462,9 @@ enum AssertIntrinsic {
             UninitValid,
         };
         let panic_intrinsic = intrinsic.and_then(|i| match i {
-            // FIXME: Move to symbols instead of strings.
-            "assert_inhabited" => Some(AssertIntrinsic::Inhabited),
-            "assert_zero_valid" => Some(AssertIntrinsic::ZeroValid),
-            "assert_uninit_valid" => Some(AssertIntrinsic::UninitValid),
+            sym::assert_inhabited => Some(AssertIntrinsic::Inhabited),
+            sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid),
+            sym::assert_uninit_valid => Some(AssertIntrinsic::UninitValid),
             _ => None,
         });
         if let Some(intrinsic) = panic_intrinsic {
@@ -568,10 +568,9 @@ fn codegen_call_terminator(
 
         // Handle intrinsics old codegen wants Expr's for, ourselves.
         let intrinsic = match def {
-            Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().item_name(def_id).as_str()),
+            Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().item_name(def_id)),
             _ => None,
         };
-        let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
 
         let extra_args = &args[sig.inputs().skip_binder().len()..];
         let extra_args = extra_args
@@ -587,7 +586,7 @@ fn codegen_call_terminator(
             None => FnAbi::of_fn_ptr(&bx, sig, &extra_args),
         };
 
-        if intrinsic == Some("transmute") {
+        if intrinsic == Some(sym::transmute) {
             if let Some(destination_ref) = destination.as_ref() {
                 let &(dest, target) = destination_ref;
                 self.codegen_transmute(&mut bx, &args[0], dest);
@@ -607,7 +606,7 @@ fn codegen_call_terminator(
         }
 
         // For normal codegen, this Miri-specific intrinsic should never occur.
-        if intrinsic == Some("miri_start_panic") {
+        if intrinsic == Some(sym::miri_start_panic) {
             bug!("`miri_start_panic` should never end up in compiled code");
         }
 
@@ -635,7 +634,7 @@ fn codegen_call_terminator(
             ReturnDest::Nothing
         };
 
-        if intrinsic == Some("caller_location") {
+        if intrinsic == Some(sym::caller_location) {
             if let Some((_, target)) = destination.as_ref() {
                 let location = self.get_caller_location(&mut bx, fn_span);
 
@@ -650,7 +649,7 @@ fn codegen_call_terminator(
             return;
         }
 
-        if intrinsic.is_some() && intrinsic != Some("drop_in_place") {
+        if intrinsic.is_some() && intrinsic != Some(sym::drop_in_place) {
             let intrinsic = intrinsic.unwrap();
 
             // `is_codegen_intrinsic()` allows the backend implementation to perform compile-time
@@ -682,7 +681,7 @@ fn codegen_call_terminator(
                     // third argument must be constant. This is
                     // checked by const-qualification, which also
                     // promotes any complex rvalues to constants.
-                    if i == 2 && intrinsic.starts_with("simd_shuffle") {
+                    if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
                         if let mir::Operand::Constant(constant) = arg {
                             let c = self.eval_mir_constant(constant);
                             let (llval, ty) = self.simd_shuffle_indices(
index 11ec62f96ed38d60179f5c37c357ab74eee9f954..4943e279c7e050836959ed02dd975b138f804bba 100644 (file)
@@ -25,10 +25,10 @@ pub fn eval_mir_constant(
         constant: &mir::Constant<'tcx>,
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
         match self.monomorphize(&constant.literal).val {
-            ty::ConstKind::Unevaluated(def_id, substs, promoted) => self
+            ty::ConstKind::Unevaluated(def, substs, promoted) => self
                 .cx
                 .tcx()
-                .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
+                .const_eval_resolve(ty::ParamEnv::reveal_all(), def, substs, promoted, None)
                 .map_err(|err| {
                     if promoted.is_none() {
                         self.cx
index 5994ef2be5467e0301115428398a8006591fff72..fc65149937ffe64a18adfbc0ad46af30e976d25b 100644 (file)
@@ -64,7 +64,7 @@ fn predefine<Bx: BuilderMethods<'a, 'tcx>>(
             cx.codegen_unit().name()
         );
 
-        let symbol_name = self.symbol_name(cx.tcx()).name.as_str();
+        let symbol_name = self.symbol_name(cx.tcx()).name;
 
         debug!("symbol {}", &symbol_name);
 
index d80f90fa4fa0d7eb6412b83aa7ef387c2d58ae4c..1b9faa42484f1ad536a21b3ccdc35e9a5b9f70d4 100644 (file)
@@ -10,6 +10,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
     fn add_counter_region(
         &mut self,
         instance: Instance<'tcx>,
+        function_source_hash: u64,
         index: u32,
         start_byte_pos: u32,
         end_byte_pos: u32,
index e713cc948c10d0869e77965a03610ff310943beb..425bea4cb1986d60d6eb1f9a330d690d6c46262a 100644 (file)
@@ -2,7 +2,7 @@
 use crate::mir::operand::OperandRef;
 use rustc_middle::mir::Operand;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use rustc_target::abi::call::FnAbi;
 
 pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
@@ -24,7 +24,7 @@ fn codegen_intrinsic_call(
     /// the intrinsic does not need code generation.
     fn is_codegen_intrinsic(
         &mut self,
-        intrinsic: &str,
+        intrinsic: Symbol,
         args: &Vec<Operand<'tcx>>,
         caller_instance: ty::Instance<'tcx>,
     ) -> bool;
index a6462b358347b3111a0c009662ac9a10867452f8..817fc02d166a35ba9dff5e61e3087e9628d59c3b 100644 (file)
@@ -5,6 +5,18 @@
 pub trait StaticMethods: BackendTypes {
     fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
     fn codegen_static(&self, def_id: DefId, is_mutable: bool);
+
+    /// Mark the given global value as "used", to prevent a backend from potentially removing a
+    /// static variable that may otherwise appear unused.
+    ///
+    /// Static variables in Rust can be annotated with the `#[used]` attribute to direct the `rustc`
+    /// compiler to mark the variable as a "used global".
+    ///
+    /// ```no_run
+    /// #[used]
+    /// static FOO: u32 = 0;
+    /// ```
+    fn add_used_global(&self, global: Self::Value);
 }
 
 pub trait StaticBuilderMethods: BackendTypes {
index c2c19b6b4056b50e3e5398f8445bdd3a4bc605ca..ab4eac9440b41ac3bdfc4fc720dab4a38aa9004c 100644 (file)
@@ -6,7 +6,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -65,8 +64,8 @@
 /// Exit status code used for compilation failures and invalid flags.
 pub const EXIT_FAILURE: i32 = 1;
 
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
-                              md#bug-reports";
+const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
+    ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
 
 const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["Z", "C", "crate-type"];
 
@@ -698,7 +697,7 @@ fn print_crate_info(
                         .parse_sess
                         .config
                         .iter()
-                        .filter_map(|&(name, ref value)| {
+                        .filter_map(|&(name, value)| {
                             // Note that crt-static is a specially recognized cfg
                             // directive that's printed out here as part of
                             // rust-lang/rust#37406, but in general the
@@ -707,9 +706,7 @@ fn print_crate_info(
                             // specifically allowing the crt-static cfg and that's
                             // it, this is intended to get into Cargo and then go
                             // through to build scripts.
-                            let value = value.as_ref().map(|s| s.as_str());
-                            let value = value.as_ref().map(|s| s.as_ref());
-                            if (name != sym::target_feature || value != Some("crt-static"))
+                            if (name != sym::target_feature || value != Some(sym::crt_dash_static))
                                 && !allow_unstable_cfg
                                 && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
                             {
index 6a34a310f735ad2651452db7b1e3841b597da25a..2864e46cadcf96c69a74029e8fe884606c37b68c 100644 (file)
@@ -80,7 +80,7 @@ fn call_with_pp_support_hir<A, F>(ppmode: &PpSourceMode, tcx: TyCtxt<'_>, f: F)
         PpmTyped => {
             abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
 
-            let annotation = TypedAnnotation { tcx, maybe_typeck_tables: Cell::new(None) };
+            let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
             tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate()))
         }
         _ => panic!("Should use call_with_pp_support"),
@@ -305,16 +305,18 @@ fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
 
 struct TypedAnnotation<'tcx> {
     tcx: TyCtxt<'tcx>,
-    maybe_typeck_tables: Cell<Option<&'tcx ty::TypeckTables<'tcx>>>,
+    maybe_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
 }
 
 impl<'tcx> TypedAnnotation<'tcx> {
-    /// Gets the type-checking side-tables for the current body.
+    /// Gets the type-checking results for the current body.
     /// As this will ICE if called outside bodies, only call when working with
     /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
     #[track_caller]
-    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
-        self.maybe_typeck_tables.get().expect("`TypedAnnotation::tables` called outside of body")
+    fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
+        self.maybe_typeck_results
+            .get()
+            .expect("`TypedAnnotation::typeck_results` called outside of body")
     }
 }
 
@@ -338,13 +340,13 @@ fn node_path(&self, id: hir::HirId) -> Option<String> {
 
 impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> {
     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.get();
+        let old_maybe_typeck_results = self.maybe_typeck_results.get();
         if let pprust_hir::Nested::Body(id) = nested {
-            self.maybe_typeck_tables.set(Some(self.tcx.body_tables(id)));
+            self.maybe_typeck_results.set(Some(self.tcx.typeck_body(id)));
         }
         let pp_ann = &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>);
         pprust_hir::PpAnn::nested(pp_ann, state, nested);
-        self.maybe_typeck_tables.set(old_maybe_typeck_tables);
+        self.maybe_typeck_results.set(old_maybe_typeck_results);
     }
     fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
         if let pprust_hir::AnnNode::Expr(_) = node {
@@ -356,7 +358,7 @@ fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
             s.s.space();
             s.s.word("as");
             s.s.space();
-            s.s.word(self.tables().expr_ty(expr).to_string());
+            s.s.word(self.typeck_results().expr_ty(expr).to_string());
             s.pclose();
         }
     }
index 136230d52d975d324f4988e816d4f10cb3e56cf4..bbbd8359f0126b229ccf8f6f9bd79082a8819c2b 100644 (file)
 E0766: include_str!("./error_codes/E0766.md"),
 E0767: include_str!("./error_codes/E0767.md"),
 E0768: include_str!("./error_codes/E0768.md"),
+E0769: include_str!("./error_codes/E0769.md"),
+E0770: include_str!("./error_codes/E0770.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
 //  E0420, merged into 532
 //  E0421, merged into 531
 //  E0427, merged into 530
-    E0456, // plugin `..` is not available for triple `..`
+//  E0456, // plugin `..` is not available for triple `..`
     E0457, // plugin `..` only found in rlib format, but must be available...
     E0460, // found possibly newer version of crate `..`
     E0461, // couldn't find crate `..` with expected target triple ..
index 449fb8ffc8945a999f5138755fb29e81612a68b6..a993ce826a737e0cfada3310469bf4b408bffefa 100644 (file)
@@ -3,7 +3,7 @@
 Const parameters cannot depend on type parameters.
 The following is therefore invalid:
 
-```compile_fail,E0741
+```compile_fail,E0770
 #![feature(const_generics)]
 
 fn const_id<T, const N: T>() -> T { // error
index cde46f52c27d75e9b48e3fa0f1cd916723083b8f..c22b274fb223e8e2b652e11188328fd5a056d85c 100644 (file)
@@ -1,6 +1,6 @@
-This error indicates that a incorrect visibility restriction was specified.
+An incorrect visibility restriction was specified.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0704
 mod foo {
@@ -12,6 +12,7 @@ mod foo {
 
 To make struct `Bar` only visible in module `foo` the `in` keyword should be
 used:
+
 ```
 mod foo {
     pub(in crate::foo) struct Bar {
index 8fa09fe8e725bf6cdee57e78b08444dee62d3b64..1edd47de4cbbd0d0b6238b5dd85cf8afe9586707 100644 (file)
@@ -1,5 +1,5 @@
-A `#![feature]` attribute was declared for a feature that is stable in
-the current edition, but not in all editions.
+A `#![feature]` attribute was declared for a feature that is stable in the
+current edition, but not in all editions.
 
 Erroneous code example:
 
index d9cefe2a6da7264ecf73217b820d20fa44977fd1..b7037ea611ba2685659aa5bd0d045b81399c201c 100644 (file)
@@ -1,4 +1,4 @@
-An unknown tool name found in scoped lint
+An unknown tool name was found in a scoped lint.
 
 Erroneous code examples:
 
index 8f0022d9425471de4ef3357962e6f5620bdd9865..b27702b3c26e27c473e73193b8b07979ce987ad1 100644 (file)
@@ -15,8 +15,7 @@ struct OverrideConst;
 impl Marker for OverrideConst { // error!
     const N: usize = 1;
 }
-
-fn main() {}
+# fn main() {}
 ```
 
 Because marker traits are allowed to have multiple implementations for the same
index 25567c1d12810607915107a802a4bcbff14d6efe..c6d0337ddda56d0c10efa53e415cb69d9eb5b35a 100644 (file)
@@ -1,5 +1,4 @@
-This error indicates that a temporary value is being dropped
-while a borrow is still in active use.
+A temporary value is being dropped while a borrow is still in active use.
 
 Erroneous code example:
 
@@ -11,12 +10,11 @@ let p = bar(&foo());
 let q = *p;
 ```
 
-Here, the expression `&foo()` is borrowing the expression
-`foo()`. As `foo()` is a call to a function, and not the name of
-a variable, this creates a **temporary** -- that temporary stores
-the return value from `foo()` so that it can be borrowed.
-You could imagine that `let p = bar(&foo());` is equivalent
-to this:
+Here, the expression `&foo()` is borrowing the expression `foo()`. As `foo()` is
+a call to a function, and not the name of a variable, this creates a
+**temporary** -- that temporary stores the return value from `foo()` so that it
+can be borrowed. You could imagine that `let p = bar(&foo());` is equivalent to
+this:
 
 ```compile_fail,E0597
 # fn foo() -> i32 { 22 }
@@ -28,16 +26,14 @@ let p = {
 let q = p;
 ```
 
-Whenever a temporary is created, it is automatically dropped (freed)
-according to fixed rules. Ordinarily, the temporary is dropped
-at the end of the enclosing statement -- in this case, after the `let`.
-This is illustrated in the example above by showing that `tmp` would
-be freed as we exit the block.
+Whenever a temporary is created, it is automatically dropped (freed) according
+to fixed rules. Ordinarily, the temporary is dropped at the end of the enclosing
+statement -- in this case, after the `let`. This is illustrated in the example
+above by showing that `tmp` would be freed as we exit the block.
 
-To fix this problem, you need to create a local variable
-to store the value in rather than relying on a temporary.
-For example, you might change the original program to
-the following:
+To fix this problem, you need to create a local variable to store the value in
+rather than relying on a temporary. For example, you might change the original
+program to the following:
 
 ```
 fn foo() -> i32 { 22 }
@@ -47,16 +43,15 @@ let p = bar(&value);
 let q = *p;
 ```
 
-By introducing the explicit `let value`, we allocate storage
-that will last until the end of the enclosing block (when `value`
-goes out of scope). When we borrow `&value`, we are borrowing a
-local variable that already exists, and hence no temporary is created.
+By introducing the explicit `let value`, we allocate storage that will last
+until the end of the enclosing block (when `value` goes out of scope). When we
+borrow `&value`, we are borrowing a local variable that already exists, and
+hence no temporary is created.
 
-Temporaries are not always dropped at the end of the enclosing
-statement. In simple cases where the `&` expression is immediately
-stored into a variable, the compiler will automatically extend
-the lifetime of the temporary until the end of the enclosing
-block. Therefore, an alternative way to fix the original
+Temporaries are not always dropped at the end of the enclosing statement. In
+simple cases where the `&` expression is immediately stored into a variable, the
+compiler will automatically extend the lifetime of the temporary until the end
+of the enclosing block. Therefore, an alternative way to fix the original
 program is to write `let tmp = &foo()` and not `let tmp = foo()`:
 
 ```
@@ -67,10 +62,10 @@ let p = bar(value);
 let q = *p;
 ```
 
-Here, we are still borrowing `foo()`, but as the borrow is assigned
-directly into a variable, the temporary will not be dropped until
-the end of the enclosing block. Similar rules apply when temporaries
-are stored into aggregate structures like a tuple or struct:
+Here, we are still borrowing `foo()`, but as the borrow is assigned directly
+into a variable, the temporary will not be dropped until the end of the
+enclosing block. Similar rules apply when temporaries are stored into aggregate
+structures like a tuple or struct:
 
 ```
 // Here, two temporaries are created, but
index 394ee057b0b0c09a0d0f9aeb027b2a6a21838d4d..95d47ab21cbd38d0ae2d10f7e19e3cfd6ebac4c5 100644 (file)
@@ -1,4 +1,4 @@
-An feature unstable in `const` contexts was used.
+An unstable feature in `const` contexts was used.
 
 Erroneous code example:
 
diff --git a/src/librustc_error_codes/error_codes/E0769.md b/src/librustc_error_codes/error_codes/E0769.md
new file mode 100644 (file)
index 0000000..d1995be
--- /dev/null
@@ -0,0 +1,39 @@
+A tuple struct or tuple variant was used in a pattern as if it were a
+struct or struct variant.
+
+Erroneous code example:
+
+```compile_fail,E0769
+enum E {
+    A(i32),
+}
+let e = E::A(42);
+match e {
+    E::A { number } => println!("{}", x),
+}
+```
+
+To fix this error, you can use the tuple pattern:
+
+```
+# enum E {
+#     A(i32),
+# }
+# let e = E::A(42);
+match e {
+    E::A(number) => println!("{}", number),
+}
+```
+
+Alternatively, you can also use the struct pattern by using the correct
+field names and binding them to new identifiers:
+
+```
+# enum E {
+#     A(i32),
+# }
+# let e = E::A(42);
+match e {
+    E::A { 0: number } => println!("{}", number),
+}
+```
diff --git a/src/librustc_error_codes/error_codes/E0770.md b/src/librustc_error_codes/error_codes/E0770.md
new file mode 100644 (file)
index 0000000..278bf9b
--- /dev/null
@@ -0,0 +1,15 @@
+The type of a const parameter references other generic parameters.
+
+Erroneous code example:
+
+```compile_fail,E0770
+#![feature(const_generics)]
+fn foo<T, const N: T>() {} // error!
+```
+
+To fix this error, use a concrete type for the const parameter:
+
+```
+#![feature(const_generics)]
+fn foo<T, const N: usize>() {}
+```
index 362913ceadf18aa4e911617156cacd2e16c260e9..73d71063b23620931cd13ac56ea15e0c8b8e6df9 100644 (file)
@@ -5,7 +5,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(crate_visibility_modifier)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 
 pub use emitter::ColorConfig;
 
index 3e48224ef9f2006995ec15c49e33b3cc5325d282..64e2d5b3a467c84fd18b28223e40141680d8431b 100644 (file)
@@ -1061,9 +1061,6 @@ pub fn trace_macros(&self) -> bool {
     pub fn set_trace_macros(&mut self, x: bool) {
         self.ecfg.trace_mac = x
     }
-    pub fn ident_of(&self, st: &str, sp: Span) -> Ident {
-        Ident::from_str_and_span(st, sp)
-    }
     pub fn std_path(&self, components: &[Symbol]) -> Vec<Ident> {
         let def_site = self.with_def_site_ctxt(DUMMY_SP);
         iter::once(Ident::new(kw::DollarCrate, def_site))
index 20d2ea0a215d4ac8ced615dda3f0443944b7a9dd..81ff4b3157845e94b65b29cf19aa757ba8265a92 100644 (file)
@@ -368,7 +368,7 @@ pub fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> {
         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", sp);
+        let binding_variable = Ident::new(sym::__try_var, sp);
         let binding_pat = self.pat_ident(sp, binding_variable);
         let binding_expr = self.expr_ident(sp, binding_variable);
 
index ce53b9c0b66c8fb017a1ff1c5ed57c2ce01c8db9..2805b4203f92848e8d8ca2fcb70787f9cbc7b9dc 100644 (file)
@@ -149,8 +149,8 @@ macro_rules! op {
             }
             Literal(lit) => tt!(Literal { lit }),
             DocComment(c) => {
-                let style = comments::doc_comment_style(&c.as_str());
-                let stripped = comments::strip_doc_comment_decoration(&c.as_str());
+                let style = comments::doc_comment_style(c);
+                let stripped = comments::strip_doc_comment_decoration(c);
                 let mut escaped = String::new();
                 for ch in stripped.chars() {
                     escaped.extend(ch.escape_debug());
index 0da3693af4fb694447d64a87a4fbe1d7140c337c..d7c310a8b4c8b2111e3a77f3e6564ac100fae3bb 100644 (file)
@@ -368,6 +368,9 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// 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),
 
diff --git a/src/librustc_hir/fake_lang_items.rs b/src/librustc_hir/fake_lang_items.rs
new file mode 100644 (file)
index 0000000..91db580
--- /dev/null
@@ -0,0 +1,37 @@
+//! Validity checking for fake lang items
+
+use crate::def_id::DefId;
+use crate::{lang_items, LangItem, LanguageItems};
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::{sym, Symbol};
+
+use lazy_static::lazy_static;
+
+macro_rules! fake_lang_items {
+    ($($item:ident, $name:ident, $method:ident;)*) => (
+
+lazy_static! {
+    pub static ref FAKE_ITEMS_REFS: FxHashMap<Symbol, LangItem> = {
+        let mut map = FxHashMap::default();
+        $(map.insert(sym::$name, lang_items::$item);)*
+        map
+    };
+}
+
+impl LanguageItems {
+    pub fn is_fake_lang_item(&self, item_def_id: DefId) -> bool {
+        let did = Some(item_def_id);
+
+        $(self.$method() == did)||*
+    }
+}
+
+) }
+
+fake_lang_items! {
+//  Variant name,                      Symbol,                    Method name,
+    CountCodeRegionFnLangItem,         count_code_region,         count_code_region_fn;
+    CoverageCounterAddFnLangItem,      coverage_counter_add,      coverage_counter_add_fn;
+    CoverageCounterSubtractFnLangItem, coverage_counter_subtract, coverage_counter_subtract_fn;
+}
index f3dfec7ca72150386063bb74dacc5dd9df1508a1..f56522406b0a707f36cda83862b4bc684f47fb6b 100644 (file)
@@ -1571,7 +1571,7 @@ pub enum ExprKind<'hir> {
     /// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with
     /// the `hir_id` of the `MethodCall` node itself.
     ///
-    /// [`type_dependent_def_id`]: ../ty/struct.TypeckTables.html#method.type_dependent_def_id
+    /// [`type_dependent_def_id`]: ../ty/struct.TypeckResults.html#method.type_dependent_def_id
     MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>], Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(&'hir [Expr<'hir>]),
@@ -1659,7 +1659,7 @@ pub enum ExprKind<'hir> {
 ///
 /// To resolve the path to a `DefId`, call [`qpath_res`].
 ///
-/// [`qpath_res`]: ../rustc_middle/ty/struct.TypeckTables.html#method.qpath_res
+/// [`qpath_res`]: ../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res
 #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
 pub enum QPath<'hir> {
     /// Path to a definition, optionally "fully-qualified" with a `Self`
@@ -2148,6 +2148,7 @@ pub struct Param<'hir> {
     pub attrs: &'hir [Attribute],
     pub hir_id: HirId,
     pub pat: &'hir Pat<'hir>,
+    pub ty_span: Span,
     pub span: Span,
 }
 
@@ -2686,7 +2687,7 @@ pub enum Node<'hir> {
     Crate(&'hir CrateItem<'hir>),
 }
 
-impl Node<'_> {
+impl<'hir> Node<'hir> {
     pub fn ident(&self) -> Option<Ident> {
         match self {
             Node::TraitItem(TraitItem { ident, .. })
@@ -2697,7 +2698,7 @@ pub fn ident(&self) -> Option<Ident> {
         }
     }
 
-    pub fn fn_decl(&self) -> Option<&FnDecl<'_>> {
+    pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
         match self {
             Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
             | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
@@ -2721,7 +2722,7 @@ pub fn body_id(&self) -> Option<BodyId> {
         }
     }
 
-    pub fn generics(&self) -> Option<&Generics<'_>> {
+    pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
         match self {
             Node::TraitItem(TraitItem { generics, .. })
             | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
index 5aaf219b315bdc22b69dca21de23531cc104c681..4b71407acfb8cf44c57f7b202dd6900b13174326 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable_Generic;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
 use lazy_static::lazy_static;
@@ -52,10 +52,10 @@ pub enum LangItem {
         }
 
         impl LangItem {
-            /// Returns the `name` in `#[lang = "$name"]`.
+            /// Returns the `name` symbol in `#[lang = "$name"]`.
             /// For example, `LangItem::EqTraitLangItem`,
-            /// that is `#[lang = "eq"]` would result in `"eq"`.
-            pub fn name(self) -> &'static str {
+            /// that is `#[lang = "eq"]` would result in `sym::eq`.
+            pub fn name(self) -> Symbol {
                 match self {
                     $( $variant => $name, )*
                 }
@@ -110,9 +110,8 @@ pub fn group(&self, group: LangItemGroup) -> &[DefId] {
             }
 
             $(
-                /// Returns the corresponding `DefId` for the lang item
-                #[doc = $name]
-                /// if it exists.
+                /// Returns the corresponding `DefId` for the lang item if it
+                /// exists.
                 #[allow(dead_code)]
                 pub fn $method(&self) -> Option<DefId> {
                     self.items[$variant as usize]
@@ -122,7 +121,7 @@ pub fn $method(&self) -> Option<DefId> {
 
         lazy_static! {
             /// A mapping from the name of the lang item to its order and the form it must be of.
-            pub static ref ITEM_REFS: FxHashMap<&'static str, (usize, Target)> = {
+            pub static ref ITEM_REFS: FxHashMap<Symbol, (usize, Target)> = {
                 let mut item_refs = FxHashMap::default();
                 $( item_refs.insert($name, ($variant as usize, $target)); )*
                 item_refs
@@ -154,100 +153,103 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
 }
 
 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;
-    SliceU8ImplItem,             "slice_u8",           slice_u8_impl,           Target::Impl;
-    StrAllocImplItem,            "str_alloc",          str_alloc_impl,          Target::Impl;
-    SliceAllocImplItem,          "slice_alloc",        slice_alloc_impl,        Target::Impl;
-    SliceU8AllocImplItem,        "slice_u8_alloc",     slice_u8_alloc_impl,     Target::Impl;
-    ConstPtrImplItem,            "const_ptr",          const_ptr_impl,          Target::Impl;
-    MutPtrImplItem,              "mut_ptr",            mut_ptr_impl,            Target::Impl;
-    ConstSlicePtrImplItem,       "const_slice_ptr",    const_slice_ptr_impl,    Target::Impl;
-    MutSlicePtrImplItem,         "mut_slice_ptr",      mut_slice_ptr_impl,      Target::Impl;
-    I8ImplItem,                  "i8",                 i8_impl,                 Target::Impl;
-    I16ImplItem,                 "i16",                i16_impl,                Target::Impl;
-    I32ImplItem,                 "i32",                i32_impl,                Target::Impl;
-    I64ImplItem,                 "i64",                i64_impl,                Target::Impl;
-    I128ImplItem,                "i128",               i128_impl,               Target::Impl;
-    IsizeImplItem,               "isize",              isize_impl,              Target::Impl;
-    U8ImplItem,                  "u8",                 u8_impl,                 Target::Impl;
-    U16ImplItem,                 "u16",                u16_impl,                Target::Impl;
-    U32ImplItem,                 "u32",                u32_impl,                Target::Impl;
-    U64ImplItem,                 "u64",                u64_impl,                Target::Impl;
-    U128ImplItem,                "u128",               u128_impl,               Target::Impl;
-    UsizeImplItem,               "usize",              usize_impl,              Target::Impl;
-    F32ImplItem,                 "f32",                f32_impl,                Target::Impl;
-    F64ImplItem,                 "f64",                f64_impl,                Target::Impl;
-    F32RuntimeImplItem,          "f32_runtime",        f32_runtime_impl,        Target::Impl;
-    F64RuntimeImplItem,          "f64_runtime",        f64_runtime_impl,        Target::Impl;
-
-    SizedTraitLangItem,          "sized",              sized_trait,             Target::Trait;
-    UnsizeTraitLangItem,         "unsize",             unsize_trait,            Target::Trait;
+//  Variant name,                  Name,                    Method name,             Target;
+    BoolImplItem,                  sym::bool,               bool_impl,               Target::Impl;
+    CharImplItem,                  sym::char,               char_impl,               Target::Impl;
+    StrImplItem,                   sym::str,                str_impl,                Target::Impl;
+    SliceImplItem,                 sym::slice,              slice_impl,              Target::Impl;
+    SliceU8ImplItem,               sym::slice_u8,           slice_u8_impl,           Target::Impl;
+    StrAllocImplItem,              sym::str_alloc,          str_alloc_impl,          Target::Impl;
+    SliceAllocImplItem,            sym::slice_alloc,        slice_alloc_impl,        Target::Impl;
+    SliceU8AllocImplItem,          sym::slice_u8_alloc,     slice_u8_alloc_impl,     Target::Impl;
+    ConstPtrImplItem,              sym::const_ptr,          const_ptr_impl,          Target::Impl;
+    MutPtrImplItem,                sym::mut_ptr,            mut_ptr_impl,            Target::Impl;
+    ConstSlicePtrImplItem,         sym::const_slice_ptr,    const_slice_ptr_impl,    Target::Impl;
+    MutSlicePtrImplItem,           sym::mut_slice_ptr,      mut_slice_ptr_impl,      Target::Impl;
+    I8ImplItem,                    sym::i8,                 i8_impl,                 Target::Impl;
+    I16ImplItem,                   sym::i16,                i16_impl,                Target::Impl;
+    I32ImplItem,                   sym::i32,                i32_impl,                Target::Impl;
+    I64ImplItem,                   sym::i64,                i64_impl,                Target::Impl;
+    I128ImplItem,                  sym::i128,               i128_impl,               Target::Impl;
+    IsizeImplItem,                 sym::isize,              isize_impl,              Target::Impl;
+    U8ImplItem,                    sym::u8,                 u8_impl,                 Target::Impl;
+    U16ImplItem,                   sym::u16,                u16_impl,                Target::Impl;
+    U32ImplItem,                   sym::u32,                u32_impl,                Target::Impl;
+    U64ImplItem,                   sym::u64,                u64_impl,                Target::Impl;
+    U128ImplItem,                  sym::u128,               u128_impl,               Target::Impl;
+    UsizeImplItem,                 sym::usize,              usize_impl,              Target::Impl;
+    F32ImplItem,                   sym::f32,                f32_impl,                Target::Impl;
+    F64ImplItem,                   sym::f64,                f64_impl,                Target::Impl;
+    F32RuntimeImplItem,            sym::f32_runtime,        f32_runtime_impl,        Target::Impl;
+    F64RuntimeImplItem,            sym::f64_runtime,        f64_runtime_impl,        Target::Impl;
+
+    SizedTraitLangItem,            sym::sized,              sized_trait,             Target::Trait;
+    UnsizeTraitLangItem,           sym::unsize,             unsize_trait,            Target::Trait;
     // trait injected by #[derive(PartialEq)], (i.e. "Partial EQ").
-    StructuralPeqTraitLangItem,  "structural_peq",     structural_peq_trait,    Target::Trait;
+    StructuralPeqTraitLangItem,    sym::structural_peq,     structural_peq_trait,    Target::Trait;
     // trait injected by #[derive(Eq)], (i.e. "Total EQ"; no, I will not apologize).
-    StructuralTeqTraitLangItem,  "structural_teq",     structural_teq_trait,    Target::Trait;
-    CopyTraitLangItem,           "copy",               copy_trait,              Target::Trait;
-    CloneTraitLangItem,          "clone",              clone_trait,             Target::Trait;
-    SyncTraitLangItem,           "sync",               sync_trait,              Target::Trait;
-    DiscriminantKindTraitLangItem,"discriminant_kind", discriminant_kind_trait, Target::Trait;
-    FreezeTraitLangItem,         "freeze",             freeze_trait,            Target::Trait;
-
-    DropTraitLangItem,           "drop",               drop_trait,              Target::Trait;
-
-    CoerceUnsizedTraitLangItem,  "coerce_unsized",     coerce_unsized_trait,    Target::Trait;
-    DispatchFromDynTraitLangItem,"dispatch_from_dyn",  dispatch_from_dyn_trait, Target::Trait;
-
-    AddTraitLangItem(Op),        "add",                add_trait,               Target::Trait;
-    SubTraitLangItem(Op),        "sub",                sub_trait,               Target::Trait;
-    MulTraitLangItem(Op),        "mul",                mul_trait,               Target::Trait;
-    DivTraitLangItem(Op),        "div",                div_trait,               Target::Trait;
-    RemTraitLangItem(Op),        "rem",                rem_trait,               Target::Trait;
-    NegTraitLangItem(Op),        "neg",                neg_trait,               Target::Trait;
-    NotTraitLangItem(Op),        "not",                not_trait,               Target::Trait;
-    BitXorTraitLangItem(Op),     "bitxor",             bitxor_trait,            Target::Trait;
-    BitAndTraitLangItem(Op),     "bitand",             bitand_trait,            Target::Trait;
-    BitOrTraitLangItem(Op),      "bitor",              bitor_trait,             Target::Trait;
-    ShlTraitLangItem(Op),        "shl",                shl_trait,               Target::Trait;
-    ShrTraitLangItem(Op),        "shr",                shr_trait,               Target::Trait;
-    AddAssignTraitLangItem(Op),  "add_assign",         add_assign_trait,        Target::Trait;
-    SubAssignTraitLangItem(Op),  "sub_assign",         sub_assign_trait,        Target::Trait;
-    MulAssignTraitLangItem(Op),  "mul_assign",         mul_assign_trait,        Target::Trait;
-    DivAssignTraitLangItem(Op),  "div_assign",         div_assign_trait,        Target::Trait;
-    RemAssignTraitLangItem(Op),  "rem_assign",         rem_assign_trait,        Target::Trait;
-    BitXorAssignTraitLangItem(Op),"bitxor_assign",     bitxor_assign_trait,     Target::Trait;
-    BitAndAssignTraitLangItem(Op),"bitand_assign",     bitand_assign_trait,     Target::Trait;
-    BitOrAssignTraitLangItem(Op),"bitor_assign",       bitor_assign_trait,      Target::Trait;
-    ShlAssignTraitLangItem(Op),  "shl_assign",         shl_assign_trait,        Target::Trait;
-    ShrAssignTraitLangItem(Op),  "shr_assign",         shr_assign_trait,        Target::Trait;
-    IndexTraitLangItem(Op),      "index",              index_trait,             Target::Trait;
-    IndexMutTraitLangItem(Op),   "index_mut",          index_mut_trait,         Target::Trait;
-
-    UnsafeCellTypeLangItem,      "unsafe_cell",        unsafe_cell_type,        Target::Struct;
-    VaListTypeLangItem,          "va_list",            va_list,                 Target::Struct;
-
-    DerefTraitLangItem,          "deref",              deref_trait,             Target::Trait;
-    DerefMutTraitLangItem,       "deref_mut",          deref_mut_trait,         Target::Trait;
-    ReceiverTraitLangItem,       "receiver",           receiver_trait,          Target::Trait;
-
-    FnTraitLangItem,             "fn",                 fn_trait,                Target::Trait;
-    FnMutTraitLangItem,          "fn_mut",             fn_mut_trait,            Target::Trait;
-    FnOnceTraitLangItem,         "fn_once",            fn_once_trait,           Target::Trait;
-
-    FnOnceOutputLangItem,        "fn_once_output",     fn_once_output,          Target::AssocTy;
-
-    FutureTraitLangItem,         "future_trait",       future_trait,            Target::Trait;
-    GeneratorStateLangItem,      "generator_state",    gen_state,               Target::Enum;
-    GeneratorTraitLangItem,      "generator",          gen_trait,               Target::Trait;
-    UnpinTraitLangItem,          "unpin",              unpin_trait,             Target::Trait;
-    PinTypeLangItem,             "pin",                pin_type,                Target::Struct;
+    StructuralTeqTraitLangItem,    sym::structural_teq,     structural_teq_trait,    Target::Trait;
+    CopyTraitLangItem,             sym::copy,               copy_trait,              Target::Trait;
+    CloneTraitLangItem,            sym::clone,              clone_trait,             Target::Trait;
+    SyncTraitLangItem,             sym::sync,               sync_trait,              Target::Trait;
+    DiscriminantKindTraitLangItem, sym::discriminant_kind,  discriminant_kind_trait, Target::Trait;
+    // The associated item of `trait DiscriminantKind`.
+    DiscriminantTypeLangItem,      sym::discriminant_type,  discriminant_type,       Target::AssocTy;
+
+    FreezeTraitLangItem,           sym::freeze,             freeze_trait,            Target::Trait;
+
+    DropTraitLangItem,             sym::drop,               drop_trait,              Target::Trait;
+
+    CoerceUnsizedTraitLangItem,    sym::coerce_unsized,     coerce_unsized_trait,    Target::Trait;
+    DispatchFromDynTraitLangItem,  sym::dispatch_from_dyn,  dispatch_from_dyn_trait, Target::Trait;
+
+    AddTraitLangItem(Op),          sym::add,                add_trait,               Target::Trait;
+    SubTraitLangItem(Op),          sym::sub,                sub_trait,               Target::Trait;
+    MulTraitLangItem(Op),          sym::mul,                mul_trait,               Target::Trait;
+    DivTraitLangItem(Op),          sym::div,                div_trait,               Target::Trait;
+    RemTraitLangItem(Op),          sym::rem,                rem_trait,               Target::Trait;
+    NegTraitLangItem(Op),          sym::neg,                neg_trait,               Target::Trait;
+    NotTraitLangItem(Op),          sym::not,                not_trait,               Target::Trait;
+    BitXorTraitLangItem(Op),       sym::bitxor,             bitxor_trait,            Target::Trait;
+    BitAndTraitLangItem(Op),       sym::bitand,             bitand_trait,            Target::Trait;
+    BitOrTraitLangItem(Op),        sym::bitor,              bitor_trait,             Target::Trait;
+    ShlTraitLangItem(Op),          sym::shl,                shl_trait,               Target::Trait;
+    ShrTraitLangItem(Op),          sym::shr,                shr_trait,               Target::Trait;
+    AddAssignTraitLangItem(Op),    sym::add_assign,         add_assign_trait,        Target::Trait;
+    SubAssignTraitLangItem(Op),    sym::sub_assign,         sub_assign_trait,        Target::Trait;
+    MulAssignTraitLangItem(Op),    sym::mul_assign,         mul_assign_trait,        Target::Trait;
+    DivAssignTraitLangItem(Op),    sym::div_assign,         div_assign_trait,        Target::Trait;
+    RemAssignTraitLangItem(Op),    sym::rem_assign,         rem_assign_trait,        Target::Trait;
+    BitXorAssignTraitLangItem(Op), sym::bitxor_assign,      bitxor_assign_trait,     Target::Trait;
+    BitAndAssignTraitLangItem(Op), sym::bitand_assign,      bitand_assign_trait,     Target::Trait;
+    BitOrAssignTraitLangItem(Op),  sym::bitor_assign,       bitor_assign_trait,      Target::Trait;
+    ShlAssignTraitLangItem(Op),    sym::shl_assign,         shl_assign_trait,        Target::Trait;
+    ShrAssignTraitLangItem(Op),    sym::shr_assign,         shr_assign_trait,        Target::Trait;
+    IndexTraitLangItem(Op),        sym::index,              index_trait,             Target::Trait;
+    IndexMutTraitLangItem(Op),     sym::index_mut,          index_mut_trait,         Target::Trait;
+
+    UnsafeCellTypeLangItem,        sym::unsafe_cell,        unsafe_cell_type,        Target::Struct;
+    VaListTypeLangItem,            sym::va_list,            va_list,                 Target::Struct;
+
+    DerefTraitLangItem,            sym::deref,              deref_trait,             Target::Trait;
+    DerefMutTraitLangItem,         sym::deref_mut,          deref_mut_trait,         Target::Trait;
+    ReceiverTraitLangItem,         sym::receiver,           receiver_trait,          Target::Trait;
+
+    FnTraitLangItem,               kw::Fn,                  fn_trait,                Target::Trait;
+    FnMutTraitLangItem,            sym::fn_mut,             fn_mut_trait,            Target::Trait;
+    FnOnceTraitLangItem,           sym::fn_once,            fn_once_trait,           Target::Trait;
+
+    FnOnceOutputLangItem,          sym::fn_once_output,     fn_once_output,          Target::AssocTy;
+
+    FutureTraitLangItem,           sym::future_trait,       future_trait,            Target::Trait;
+    GeneratorStateLangItem,        sym::generator_state,    gen_state,               Target::Enum;
+    GeneratorTraitLangItem,        sym::generator,          gen_trait,               Target::Trait;
+    UnpinTraitLangItem,            sym::unpin,              unpin_trait,             Target::Trait;
+    PinTypeLangItem,               sym::pin,                pin_type,                Target::Struct;
 
     // Don't be fooled by the naming here: this lang item denotes `PartialEq`, not `Eq`.
-    EqTraitLangItem,             "eq",                 eq_trait,                Target::Trait;
-    PartialOrdTraitLangItem,     "partial_ord",        partial_ord_trait,       Target::Trait;
+    EqTraitLangItem,               sym::eq,                 eq_trait,                Target::Trait;
+    PartialOrdTraitLangItem,       sym::partial_ord,        partial_ord_trait,       Target::Trait;
 
     // A number of panic-related lang items. The `panic` item corresponds to
     // divide-by-zero and various panic cases with `match`. The
@@ -258,39 +260,42 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     // defined to use it, but a final product is required to define it
     // somewhere. Additionally, there are restrictions on crates that use a weak
     // lang item, but do not have it defined.
-    PanicFnLangItem,             "panic",              panic_fn,                Target::Fn;
-    PanicBoundsCheckFnLangItem,  "panic_bounds_check", panic_bounds_check_fn,   Target::Fn;
-    PanicInfoLangItem,           "panic_info",         panic_info,              Target::Struct;
-    PanicLocationLangItem,       "panic_location",     panic_location,          Target::Struct;
-    PanicImplLangItem,           "panic_impl",         panic_impl,              Target::Fn;
+    PanicFnLangItem,               sym::panic,              panic_fn,                Target::Fn;
+    PanicBoundsCheckFnLangItem,    sym::panic_bounds_check, panic_bounds_check_fn,   Target::Fn;
+    PanicInfoLangItem,             sym::panic_info,         panic_info,              Target::Struct;
+    PanicLocationLangItem,         sym::panic_location,     panic_location,          Target::Struct;
+    PanicImplLangItem,             sym::panic_impl,         panic_impl,              Target::Fn;
     // Libstd panic entry point. Necessary for const eval to be able to catch it
-    BeginPanicFnLangItem,        "begin_panic",        begin_panic_fn,          Target::Fn;
+    BeginPanicFnLangItem,          sym::begin_panic,        begin_panic_fn,          Target::Fn;
 
-    ExchangeMallocFnLangItem,    "exchange_malloc",    exchange_malloc_fn,      Target::Fn;
-    BoxFreeFnLangItem,           "box_free",           box_free_fn,             Target::Fn;
-    DropInPlaceFnLangItem,       "drop_in_place",      drop_in_place_fn,        Target::Fn;
-    OomLangItem,                 "oom",                oom,                     Target::Fn;
-    AllocLayoutLangItem,         "alloc_layout",       alloc_layout,            Target::Struct;
+    ExchangeMallocFnLangItem,      sym::exchange_malloc,    exchange_malloc_fn,      Target::Fn;
+    BoxFreeFnLangItem,             sym::box_free,           box_free_fn,             Target::Fn;
+    DropInPlaceFnLangItem,         sym::drop_in_place,      drop_in_place_fn,        Target::Fn;
+    OomLangItem,                   sym::oom,                oom,                     Target::Fn;
+    AllocLayoutLangItem,           sym::alloc_layout,       alloc_layout,            Target::Struct;
 
-    StartFnLangItem,             "start",              start_fn,                Target::Fn;
+    StartFnLangItem,               sym::start,              start_fn,                Target::Fn;
 
-    CountCodeRegionFnLangItem,   "count_code_region",  count_code_region_fn,    Target::Fn;
+    EhPersonalityLangItem,         sym::eh_personality,     eh_personality,          Target::Fn;
+    EhCatchTypeinfoLangItem,       sym::eh_catch_typeinfo,  eh_catch_typeinfo,       Target::Static;
 
-    EhPersonalityLangItem,       "eh_personality",     eh_personality,          Target::Fn;
-    EhCatchTypeinfoLangItem,     "eh_catch_typeinfo",  eh_catch_typeinfo,       Target::Static;
+    OwnedBoxLangItem,              sym::owned_box,          owned_box,               Target::Struct;
 
-    OwnedBoxLangItem,            "owned_box",          owned_box,               Target::Struct;
+    PhantomDataItem,               sym::phantom_data,       phantom_data,            Target::Struct;
 
-    PhantomDataItem,             "phantom_data",       phantom_data,            Target::Struct;
+    ManuallyDropItem,              sym::manually_drop,      manually_drop,           Target::Struct;
 
-    ManuallyDropItem,            "manually_drop",      manually_drop,           Target::Struct;
-
-    MaybeUninitLangItem,         "maybe_uninit",       maybe_uninit,            Target::Union;
+    MaybeUninitLangItem,           sym::maybe_uninit,       maybe_uninit,            Target::Union;
 
     // Align offset for stride != 1; must not panic.
-    AlignOffsetLangItem,         "align_offset",       align_offset_fn,         Target::Fn;
+    AlignOffsetLangItem,           sym::align_offset,       align_offset_fn,         Target::Fn;
+
+    TerminationTraitLangItem,      sym::termination,        termination,             Target::Trait;
 
-    TerminationTraitLangItem,    "termination",        termination,             Target::Trait;
+    TryTraitLangItem,              kw::Try,                 try_trait,               Target::Trait;
 
-    TryTraitLangItem,            "try",                try_trait,               Target::Trait;
+    // language items related to source code coverage instrumentation (-Zinstrument-coverage)
+    CountCodeRegionFnLangItem,         sym::count_code_region,         count_code_region_fn,         Target::Fn;
+    CoverageCounterAddFnLangItem,      sym::coverage_counter_add,      coverage_counter_add_fn,      Target::Fn;
+    CoverageCounterSubtractFnLangItem, sym::coverage_counter_subtract, coverage_counter_subtract_fn, Target::Fn;
 }
index 20ac2a04b474fa7f690e831c9db3a85aaadb4e29..52131cb3d3d4cab03a12ae46f2ef769aaa9b93f0 100644 (file)
@@ -3,7 +3,6 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 #![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)] // For the unsizing cast on `&[]`
 #![feature(const_panic)]
 #![feature(in_band_lifetimes)]
@@ -18,6 +17,7 @@
 pub mod def;
 pub mod definitions;
 pub use rustc_span::def_id;
+pub mod fake_lang_items;
 mod hir;
 pub mod hir_id;
 pub mod intravisit;
index c16b7c63e31471a2303708433f38b110eaa39458..2298a80ae4f1f67b40aab3a66bbf077d1b590f5b 100644 (file)
@@ -1557,7 +1557,7 @@ enum AsmArg<'a> {
                 let i = &a.inner;
                 self.s.word("llvm_asm!");
                 self.popen();
-                self.print_string(&i.asm.as_str(), i.asm_str_style);
+                self.print_symbol(i.asm, i.asm_str_style);
                 self.word_space(":");
 
                 let mut out_idx = 0;
@@ -1579,8 +1579,8 @@ enum AsmArg<'a> {
                 self.word_space(":");
 
                 let mut in_idx = 0;
-                self.commasep(Inconsistent, &i.inputs, |s, co| {
-                    s.print_string(&co.as_str(), ast::StrStyle::Cooked);
+                self.commasep(Inconsistent, &i.inputs, |s, &co| {
+                    s.print_symbol(co, ast::StrStyle::Cooked);
                     s.popen();
                     s.print_expr(&a.inputs_exprs[in_idx]);
                     s.pclose();
@@ -1589,8 +1589,8 @@ enum AsmArg<'a> {
                 self.s.space();
                 self.word_space(":");
 
-                self.commasep(Inconsistent, &i.clobbers, |s, co| {
-                    s.print_string(&co.as_str(), ast::StrStyle::Cooked);
+                self.commasep(Inconsistent, &i.clobbers, |s, &co| {
+                    s.print_symbol(co, ast::StrStyle::Cooked);
                 });
 
                 let mut options = vec![];
index eee6e73ed10734860b3f4135b684c2cf52b7b1f8..cd5da7a67685c930c4d576ad07122f43be170c64 100644 (file)
@@ -62,11 +62,11 @@ fn check_attr(&self, attr: &ast::Attribute) {
         } else if attr.check_name(sym::rustc_partition_codegened) {
             (CguReuse::No, ComparisonKind::Exact)
         } else if attr.check_name(sym::rustc_expected_cgu_reuse) {
-            match &*self.field(attr, sym::kind).as_str() {
-                "no" => (CguReuse::No, ComparisonKind::Exact),
-                "pre-lto" => (CguReuse::PreLto, ComparisonKind::Exact),
-                "post-lto" => (CguReuse::PostLto, ComparisonKind::Exact),
-                "any" => (CguReuse::PreLto, ComparisonKind::AtLeast),
+            match self.field(attr, sym::kind) {
+                sym::no => (CguReuse::No, ComparisonKind::Exact),
+                sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
+                sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
+                sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
                 other => {
                     self.tcx.sess.span_fatal(
                         attr.span,
@@ -139,7 +139,7 @@ fn check_attr(&self, attr: &ast::Attribute) {
         }
 
         self.tcx.sess.cgu_reuse_tracker.set_expectation(
-            &cgu_name.as_str(),
+            cgu_name,
             &user_path,
             attr.span,
             expected_reuse,
index 043aff90ce404fd5fed5edfe47437556f4b7c20c..d48810f1cf103a0c5eee130e32e9fd23d79ab01f 100644 (file)
@@ -3,9 +3,9 @@
 //! we will compare the fingerprint from the current and from the previous
 //! compilation session as appropriate:
 //!
-//! - `#[rustc_clean(cfg="rev2", except="typeck_tables_of")]` if we are
+//! - `#[rustc_clean(cfg="rev2", except="typeck")]` if we are
 //!   in `#[cfg(rev2)]`, then the fingerprints associated with
-//!   `DepNode::typeck_tables_of(X)` must be DIFFERENT (`X` is the `DefId` of the
+//!   `DepNode::typeck(X)` must be DIFFERENT (`X` is the `DefId` of the
 //!   current node).
 //! - `#[rustc_clean(cfg="rev2")]` same as above, except that the
 //!   fingerprints must be the SAME (along with all other fingerprints).
@@ -48,7 +48,7 @@
     label_strs::type_of,
     // And a big part of compilation (that we eventually want to cache) is type inference
     // information:
-    label_strs::typeck_tables_of,
+    label_strs::typeck,
 ];
 
 /// DepNodes for Hir, which is pretty much everything
@@ -64,8 +64,7 @@
 
 /// DepNodes for mir_built/Optimized, which is relevant in "executable"
 /// code, i.e., functions+methods
-const BASE_MIR: &[&str] =
-    &[label_strs::optimized_mir, label_strs::promoted_mir, label_strs::mir_built];
+const BASE_MIR: &[&str] = &[label_strs::optimized_mir, label_strs::promoted_mir];
 
 /// Struct, Enum and Union DepNodes
 ///
@@ -234,7 +233,7 @@ fn labels(&self, attr: &Attribute) -> Option<Labels> {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
             if item.check_name(LABEL) {
                 let value = expect_associated_value(self.tcx, &item);
-                return Some(self.resolve_labels(&item, &value.as_str()));
+                return Some(self.resolve_labels(&item, value));
             }
         }
         None
@@ -245,7 +244,7 @@ fn except(&self, attr: &Attribute) -> Labels {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
             if item.check_name(EXCEPT) {
                 let value = expect_associated_value(self.tcx, &item);
-                return self.resolve_labels(&item, &value.as_str());
+                return self.resolve_labels(&item, value);
             }
         }
         // if no `label` or `except` is given, only the node's group are asserted
@@ -347,9 +346,9 @@ fn auto_labels(&mut self, item_id: hir::HirId, attr: &Attribute) -> (&'static st
         (name, labels)
     }
 
-    fn resolve_labels(&self, item: &NestedMetaItem, value: &str) -> Labels {
+    fn resolve_labels(&self, item: &NestedMetaItem, value: Symbol) -> Labels {
         let mut out = Labels::default();
-        for label in value.split(',') {
+        for label in value.as_str().split(',') {
             let label = label.trim();
             if DepNode::has_label_string(label) {
                 if out.contains(label) {
@@ -376,7 +375,7 @@ fn dep_nodes<'l>(
         let def_path_hash = self.tcx.def_path_hash(def_id);
         labels.iter().map(move |label| match DepNode::from_label_string(label, def_path_hash) {
             Ok(dep_node) => dep_node,
-            Err(()) => unreachable!(),
+            Err(()) => unreachable!("label: {}", label),
         })
     }
 
index f0422b1af1b973618979affefc8cc3fb04561021..00b23760182a229510d25480298bc0abd9ca292f 100644 (file)
@@ -11,4 +11,4 @@ doctest = false
 
 [dependencies]
 rustc_serialize = { path = "../librustc_serialize" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+arrayvec = "0.5.1"
index cb8b30830c5dec905b7b672804bf1d6837a9b043..3e1d4b68c6fa104f1184d1908c8740009174ceaf 100644 (file)
@@ -1,5 +1,5 @@
 use crate::vec::{Idx, IndexVec};
-use smallvec::SmallVec;
+use arrayvec::ArrayVec;
 use std::fmt;
 use std::iter;
 use std::marker::PhantomData;
@@ -355,20 +355,19 @@ fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
 const SPARSE_MAX: usize = 8;
 
 /// A fixed-size bitset type with a sparse representation and a maximum of
-/// `SPARSE_MAX` elements. The elements are stored as a sorted `SmallVec` with
-/// no duplicates; although `SmallVec` can spill its elements to the heap, that
-/// never happens within this type because of the `SPARSE_MAX` limit.
+/// `SPARSE_MAX` elements. The elements are stored as a sorted `ArrayVec` with
+/// no duplicates.
 ///
 /// This type is used by `HybridBitSet`; do not use directly.
 #[derive(Clone, Debug)]
 pub struct SparseBitSet<T: Idx> {
     domain_size: usize,
-    elems: SmallVec<[T; SPARSE_MAX]>,
+    elems: ArrayVec<[T; SPARSE_MAX]>,
 }
 
 impl<T: Idx> SparseBitSet<T> {
     fn new_empty(domain_size: usize) -> Self {
-        SparseBitSet { domain_size, elems: SmallVec::new() }
+        SparseBitSet { domain_size, elems: ArrayVec::new() }
     }
 
     fn len(&self) -> usize {
index 6fef49668da5fc38d7558dfccfebf0b72dee8d79..eaef4c7b54a625d05f72ce44e88acd074481f30d 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(allow_internal_unstable)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(extend_one)]
index b1ea222370742e893f50a91a93d23d2c6947ef2d..633589db2704cd7e37ed882b7d3f64b64bfcb997 100644 (file)
@@ -624,8 +624,9 @@ fn note_error_origin(
                         let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
                         let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_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))
+                            self.in_progress_typeck_results.and_then(|typeck_results| {
+                                typeck_results.borrow().expr_ty_opt(arg_expr)
+                            })
                         } else {
                             bug!("try desugaring w/out call expr as scrutinee");
                         };
@@ -1683,9 +1684,11 @@ pub fn construct_generic_bound_failure(
         let hir = &self.tcx.hir();
         // Attempt to obtain the span of the parameter so we can
         // suggest adding an explicit lifetime bound to it.
-        let generics =
-            self.in_progress_tables.map(|table| table.borrow().hir_owner).map(|table_owner| {
-                let hir_id = hir.as_local_hir_id(table_owner);
+        let generics = self
+            .in_progress_typeck_results
+            .map(|typeck_results| typeck_results.borrow().hir_owner)
+            .map(|owner| {
+                let hir_id = hir.as_local_hir_id(owner);
                 let parent_id = hir.get_parent_item(hir_id);
                 (
                     // Parent item could be a `mod`, so we check the HIR before calling:
@@ -1698,7 +1701,7 @@ pub fn construct_generic_bound_failure(
                     } else {
                         None
                     },
-                    self.tcx.generics_of(table_owner.to_def_id()),
+                    self.tcx.generics_of(owner.to_def_id()),
                 )
             });
         let type_param_span = match (generics, bound_kind) {
index 1687bcc1556367900976f3ce64074720feceabba..bf087dfacfa43c0be057c025832e47559821bd67 100644 (file)
@@ -42,8 +42,10 @@ fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Sp
     }
 
     fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        let ty_opt =
-            self.infcx.in_progress_tables.and_then(|tables| tables.borrow().node_type_opt(hir_id));
+        let ty_opt = self
+            .infcx
+            .in_progress_typeck_results
+            .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id));
         match ty_opt {
             Some(ty) => {
                 let ty = self.infcx.resolve_vars_if_possible(&ty);
@@ -123,8 +125,11 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind {
             if call_span == self.target_span
                 && Some(self.target)
-                    == self.infcx.in_progress_tables.and_then(|tables| {
-                        tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into)
+                    == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
+                        typeck_results
+                            .borrow()
+                            .node_type_opt(exprs.first().unwrap().hir_id)
+                            .map(Into::into)
                     })
             {
                 self.found_exact_method_call = Some(&expr);
@@ -580,8 +585,8 @@ fn annotate_method_call(
         e: &Expr<'_>,
         err: &mut DiagnosticBuilder<'_>,
     ) {
-        if let (Some(tables), None) = (self.in_progress_tables, &segment.args) {
-            let borrow = tables.borrow();
+        if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
+            let borrow = typeck_results.borrow();
             if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
                 let generics = self.tcx.generics_of(did);
                 if !generics.params.is_empty() {
index 27da514a17f4d8e3b8dd24c24101b52bf4ec95cd..37883fcb07468e7256f7e50b7fe2b671695860e2 100644 (file)
@@ -283,11 +283,11 @@ pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tc
 pub struct InferCtxt<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
-    /// During type-checking/inference of a body, `in_progress_tables`
-    /// contains a reference to the tables being built up, which are
+    /// During type-checking/inference of a body, `in_progress_typeck_results`
+    /// contains a reference to the typeck results being built up, which are
     /// used for reading closure kinds/signatures as they are inferred,
     /// and for error reporting logic to read arbitrary node types.
-    pub in_progress_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>,
+    pub in_progress_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
 
     pub inner: RefCell<InferCtxtInner<'tcx>>,
 
@@ -571,7 +571,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`.
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
+    fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -580,15 +580,15 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder { tcx: self, fresh_tables: None }
+        InferCtxtBuilder { tcx: self, fresh_typeck_results: None }
     }
 }
 
 impl<'tcx> InferCtxtBuilder<'tcx> {
     /// Used only by `rustc_typeck` during body type-checking/inference,
-    /// will initialize `in_progress_tables` with fresh `TypeckTables`.
-    pub fn with_fresh_in_progress_tables(mut self, table_owner: LocalDefId) -> Self {
-        self.fresh_tables = Some(RefCell::new(ty::TypeckTables::new(table_owner)));
+    /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
+    pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
+        self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
         self
     }
 
@@ -616,11 +616,11 @@ pub fn enter_with_canonical<T, R>(
     }
 
     pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder { tcx, ref fresh_tables } = *self;
-        let in_progress_tables = fresh_tables.as_ref();
+        let InferCtxtBuilder { tcx, ref fresh_typeck_results } = *self;
+        let in_progress_typeck_results = fresh_typeck_results.as_ref();
         f(InferCtxt {
             tcx,
-            in_progress_tables,
+            in_progress_typeck_results,
             inner: RefCell::new(InferCtxtInner::new()),
             lexical_region_resolutions: RefCell::new(None),
             selection_cache: Default::default(),
@@ -667,7 +667,7 @@ pub struct CombinedSnapshot<'a, 'tcx> {
     region_constraints_snapshot: RegionSnapshot,
     universe: ty::UniverseIndex,
     was_in_snapshot: bool,
-    _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
+    _in_progress_typeck_results: Option<Ref<'a, ty::TypeckResults<'tcx>>>,
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -789,9 +789,11 @@ fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
             region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
             universe: self.universe(),
             was_in_snapshot: in_snapshot,
-            // Borrow tables "in progress" (i.e., during typeck)
+            // Borrow typeck results "in progress" (i.e., during typeck)
             // to ban writes from within a snapshot to them.
-            _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()),
+            _in_progress_typeck_results: self
+                .in_progress_typeck_results
+                .map(|typeck_results| typeck_results.borrow()),
         }
     }
 
@@ -802,7 +804,7 @@ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
             region_constraints_snapshot,
             universe,
             was_in_snapshot,
-            _in_progress_tables,
+            _in_progress_typeck_results,
         } = snapshot;
 
         self.in_snapshot.set(was_in_snapshot);
@@ -820,7 +822,7 @@ fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
             region_constraints_snapshot: _,
             universe: _,
             was_in_snapshot,
-            _in_progress_tables,
+            _in_progress_typeck_results,
         } = snapshot;
 
         self.in_snapshot.set(was_in_snapshot);
@@ -1536,7 +1538,7 @@ pub fn create_next_universe(&self) -> ty::UniverseIndex {
     pub fn const_eval_resolve(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        def_id: DefId,
+        def: ty::WithOptConstParam<DefId>,
         substs: SubstsRef<'tcx>,
         promoted: Option<mir::Promoted>,
         span: Option<Span>,
@@ -1547,7 +1549,7 @@ pub fn const_eval_resolve(
         let (param_env, substs) = canonical.value;
         // The return value is the evaluated value which doesn't contain any reference to inference
         // variables, thus we don't need to substitute back the original values.
-        self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, span)
+        self.tcx.const_eval_resolve(param_env, def, substs, promoted, span)
     }
 
     /// If `typ` is a type variable of some kind, resolve it one level
index 27e086f1d5002f67521920f3552e5a0fcec040f0..0cd6585163c4e9ce2a6df197881ded29be98563e 100644 (file)
@@ -17,7 +17,6 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(const_fn)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(never_type)]
index 0650d09003486d620bde8fdee48d3709de8079cc..fe40c615f79c96f4aec3fd521be3f5d6c657f358 100644 (file)
@@ -14,6 +14,7 @@
 pub mod util;
 
 pub use interface::{run_compiler, Config};
+pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS};
 pub use queries::Queries;
 
 #[cfg(test)]
index 6d85c2f1825447c8ebf6a577684a7f055a2cecc4..f1b9fafc78158ae98dd6e913861ba883f5e8237c 100644 (file)
@@ -3,6 +3,7 @@
 use crate::util;
 
 use log::{info, log_enabled, warn};
+use once_cell::sync::Lazy;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::{self, ast, visit};
 use rustc_codegen_ssa::back::link::emit_metadata;
@@ -19,6 +20,7 @@
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::middle;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn};
+use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc_mir as mir;
@@ -352,13 +354,7 @@ fn configure_and_expand_inner<'a>(
         )
     });
 
-    // If we're actually rustdoc then there's no need to actually compile
-    // anything, so switch everything to just looping
-    let mut should_loop = sess.opts.actually_rustdoc;
     if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
-        should_loop |= true;
-    }
-    if should_loop {
         log::debug!("replacing bodies with loop {{}}");
         util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
     }
@@ -719,7 +715,8 @@ pub fn prepare_outputs(
     Ok(outputs)
 }
 
-pub fn default_provide(providers: &mut ty::query::Providers) {
+pub static DEFAULT_QUERY_PROVIDERS: Lazy<Providers> = Lazy::new(|| {
+    let providers = &mut Providers::default();
     providers.analysis = analysis;
     proc_macro_decls::provide(providers);
     plugin::build::provide(providers);
@@ -738,12 +735,15 @@ pub fn default_provide(providers: &mut ty::query::Providers) {
     rustc_lint::provide(providers);
     rustc_symbol_mangling::provide(providers);
     rustc_codegen_ssa::provide(providers);
-}
+    *providers
+});
 
-pub fn default_provide_extern(providers: &mut ty::query::Providers) {
-    rustc_metadata::provide_extern(providers);
-    rustc_codegen_ssa::provide_extern(providers);
-}
+pub static DEFAULT_EXTERN_QUERY_PROVIDERS: Lazy<Providers> = Lazy::new(|| {
+    let mut extern_providers = *DEFAULT_QUERY_PROVIDERS;
+    rustc_metadata::provide_extern(&mut extern_providers);
+    rustc_codegen_ssa::provide_extern(&mut extern_providers);
+    extern_providers
+});
 
 pub struct QueryContext<'tcx>(&'tcx GlobalCtxt<'tcx>);
 
@@ -780,12 +780,11 @@ pub fn create_global_ctxt<'tcx>(
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
     let codegen_backend = compiler.codegen_backend();
-    let mut local_providers = ty::query::Providers::default();
-    default_provide(&mut local_providers);
+    let mut local_providers = *DEFAULT_QUERY_PROVIDERS;
     codegen_backend.provide(&mut local_providers);
 
-    let mut extern_providers = local_providers;
-    default_provide_extern(&mut extern_providers);
+    let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS;
+    codegen_backend.provide(&mut extern_providers);
     codegen_backend.provide_extern(&mut extern_providers);
 
     if let Some(callback) = compiler.override_queries {
@@ -891,7 +890,8 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
             mir::transform::check_unsafety::check_unsafety(tcx, def_id);
 
             if tcx.hir().body_const_context(def_id).is_some() {
-                tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
+                tcx.ensure()
+                    .mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(def_id));
             }
         }
     });
index 4a41c3e97cafc3c99ee59ad811c8d9a01688b9ac..4265e6dca6a240acfbda3cad626052c7ea0b1d03 100644 (file)
@@ -18,7 +18,6 @@
 use rustc_span::symbol::sym;
 use std::any::Any;
 use std::cell::{Ref, RefCell, RefMut};
-use std::mem;
 use std::rc::Rc;
 
 /// Represent the result of a query.
@@ -395,37 +394,4 @@ pub fn enter<F, T>(&self, f: F) -> T
 
         ret
     }
-
-    // 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<()> {
-        let linker = self.enter(|queries| {
-            queries.prepare_outputs()?;
-
-            if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
-                && self.session().opts.output_types.len() == 1
-            {
-                return Ok(None);
-            }
-
-            queries.global_ctxt()?;
-
-            // Drop AST after creating GlobalCtxt to free memory.
-            mem::drop(queries.expansion()?.take());
-
-            queries.ongoing_codegen()?;
-
-            let linker = queries.linker()?;
-            Ok(Some(linker))
-        })?;
-
-        if let Some(linker) = linker {
-            linker.link()?
-        }
-
-        Ok(())
-    }
 }
index 651a77912c6d046ebff69a3a7f674fc0b3122849..3c549b88523684fa812623d87bfb0aa48fdd9614 100644 (file)
@@ -401,7 +401,7 @@ macro_rules! untracked {
     untracked!(incremental, Some(String::from("abc")));
     // `link_arg` is omitted because it just forwards to `link_args`.
     untracked!(link_args, vec![String::from("abc"), String::from("def")]);
-    untracked!(link_dead_code, true);
+    untracked!(link_dead_code, Some(true));
     untracked!(linker, Some(PathBuf::from("linker")));
     untracked!(linker_flavor, Some(LinkerFlavor::Gcc));
     untracked!(no_stack_check, true);
index 0c8c713c4cf0c7e329800d4dddc7a4c4c6c5fdf4..5b648608b6b434aacc7b530546e41bd2b287fdac 100644 (file)
@@ -53,7 +53,7 @@ pub fn add_configuration(
     cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));
 
     if sess.crt_static(None) {
-        cfg.insert((tf, Some(Symbol::intern("crt-static"))));
+        cfg.insert((tf, Some(sym::crt_dash_static)));
     }
 }
 
@@ -235,13 +235,8 @@ pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
     static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
 
     INIT.call_once(|| {
-        let codegen_name = sess
-            .opts
-            .debugging_opts
-            .codegen_backend
-            .as_ref()
-            .unwrap_or(&sess.target.target.options.codegen_backend);
-        let backend = match &codegen_name[..] {
+        let codegen_name = sess.opts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm");
+        let backend = match codegen_name {
             filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
             codegen_name => get_builtin_codegen_backend(codegen_name),
         };
@@ -427,11 +422,8 @@ pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut
 
                 if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().kind {
                     let span = spanned.span;
-                    let lev_candidate = find_best_match_for_name(
-                        CRATE_TYPES.iter().map(|(k, _)| k),
-                        &n.as_str(),
-                        None,
-                    );
+                    let lev_candidate =
+                        find_best_match_for_name(CRATE_TYPES.iter().map(|(k, _)| k), n, None);
                     if let Some(candidate) = lev_candidate {
                         lint_buffer.buffer_lint_with_diagnostic(
                             lint::builtin::UNKNOWN_CRATE_TYPES,
index 31faad3368fdbe93025608b45bd6937e9ab1d867..9d74ad3b2f558c3982d89462c2b4046d2a66f851 100644 (file)
@@ -31,7 +31,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
 
             // Check if the method call actually calls the libcore
             // `IntoIterator::into_iter`.
-            let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
+            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
             match cx.tcx.trait_of_item(def_id) {
                 Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
                 _ => return,
@@ -45,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
             // `Box` is the only thing that values can be moved out of via
             // method call. `Box::new([1]).into_iter()` should trigger this
             // lint.
-            let mut recv_ty = cx.tables().expr_ty(receiver_arg);
+            let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg);
             let mut num_box_derefs = 0;
             while recv_ty.is_box() {
                 num_box_derefs += 1;
@@ -60,13 +60,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
             // Make sure that there is an autoref coercion at the expected
             // position. The first `num_box_derefs` adjustments are the derefs
             // of the box.
-            match cx.tables().expr_adjustments(receiver_arg).get(num_box_derefs) {
+            match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) {
                 Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
                 _ => return,
             }
 
             // Emit lint diagnostic.
-            let target = match cx.tables().expr_ty_adjusted(receiver_arg).kind {
+            let target = match cx.typeck_results().expr_ty_adjusted(receiver_arg).kind {
                 ty::Ref(_, ty::TyS { kind: ty::Array(..), .. }, _) => "[T; N]",
                 ty::Ref(_, ty::TyS { kind: ty::Slice(..), .. }, _) => "[T]",
 
index 75e8d1cebdb8af12dc7e818151e34e7956b21748..5c4be715add79de0552f88b8f82909b74865fdeb 100644 (file)
@@ -144,7 +144,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
-        let ty = cx.tables().node_type(e.hir_id);
+        let ty = cx.typeck_results().node_type(e.hir_id);
         self.check_heap_type(cx, e.span, ty);
     }
 }
@@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
         if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
             let variant = cx
-                .tables()
+                .typeck_results()
                 .pat_ty(pat)
                 .ty_adt_def()
                 .expect("struct pattern type is not an ADT")
@@ -178,7 +178,7 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
                 }
                 if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
                     if cx.tcx.find_field_index(ident, &variant)
-                        == Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables()))
+                        == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
                     {
                         cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
                             let mut err = lint
@@ -909,7 +909,7 @@ fn get_transmute_from_to<'tcx>(
                 if !def_id_is_transmute(cx, did) {
                     return None;
                 }
-                let sig = cx.tables().node_type(expr.hir_id).fn_sig(cx.tcx);
+                let sig = cx.typeck_results().node_type(expr.hir_id).fn_sig(cx.tcx);
                 let from = sig.inputs().skip_binder()[0];
                 let to = sig.output().skip_binder();
                 return Some((from, to));
@@ -1901,7 +1901,7 @@ fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitK
                 }
             } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
                 // Find problematic calls to `MaybeUninit::assume_init`.
-                let def_id = cx.tables().type_dependent_def_id(expr.hir_id)?;
+                let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
                 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
                     // This is a call to *some* method named `assume_init`.
                     // See if the `self` parameter is one of the dangerous constructors.
@@ -1922,6 +1922,14 @@ fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitK
             None
         }
 
+        /// Test if this enum has several actually "existing" variants.
+        /// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
+        fn is_multi_variant(adt: &ty::AdtDef) -> bool {
+            // As an approximation, we only count dataless variants. Those are definitely inhabited.
+            let existing_variants = adt.variants.iter().filter(|v| v.fields.is_empty()).count();
+            existing_variants > 1
+        }
+
         /// Return `Some` only if we are sure this type does *not*
         /// allow zero initialization.
         fn ty_find_init_error<'tcx>(
@@ -1950,7 +1958,7 @@ fn ty_find_init_error<'tcx>(
                 }
                 // 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).
+                    // First check if 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
@@ -2001,10 +2009,20 @@ fn ty_find_init_error<'tcx>(
                                 )
                             })
                         }
-                        // 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.
+                        // Multi-variant enum.
+                        _ => {
+                            if init == InitKind::Uninit && is_multi_variant(adt_def) {
+                                let span = tcx.def_span(adt_def.did);
+                                Some((
+                                    "enums have to be initialized to a variant".to_string(),
+                                    Some(span),
+                                ))
+                            } else {
+                                // In principle, for zero-initialization we could figure out which variant corresponds
+                                // to tag 0, and check that... but for now we just accept all zero-initializations.
+                                None
+                            }
+                        }
                     }
                 }
                 Tuple(..) => {
@@ -2020,7 +2038,7 @@ fn ty_find_init_error<'tcx>(
             // 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);
+            let conjured_ty = cx.typeck_results().expr_ty(expr);
             if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
                 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
                     let mut err = lint.build(&format!(
index edbeea6db41cdbb2b5859bca9735a51203538270..84f5ea7bcda85cd11056c80acc5eb24ce132160d 100644 (file)
@@ -394,8 +394,11 @@ fn check_tool_name_for_backwards_compat(
                     let symbols =
                         self.by_name.keys().map(|name| Symbol::intern(&name)).collect::<Vec<_>>();
 
-                    let suggestion =
-                        find_best_match_for_name(symbols.iter(), &lint_name.to_lowercase(), None);
+                    let suggestion = find_best_match_for_name(
+                        symbols.iter(),
+                        Symbol::intern(&lint_name.to_lowercase()),
+                        None,
+                    );
 
                     CheckLintNameResult::NoLint(suggestion)
                 }
@@ -428,11 +431,11 @@ pub struct LateContext<'tcx> {
     /// Current body, or `None` if outside a body.
     pub enclosing_body: Option<hir::BodyId>,
 
-    /// Type-checking side-tables for the current body. Access using the `tables`
-    /// and `maybe_tables` methods, which handle querying the tables on demand.
+    /// Type-checking results for the current body. Access using the `typeck_results`
+    /// and `maybe_typeck_results` methods, which handle querying the typeck results on demand.
     // FIXME(eddyb) move all the code accessing internal fields like this,
     // to this module, to avoid exposing it to lint logic.
-    pub(super) cached_typeck_tables: Cell<Option<&'tcx ty::TypeckTables<'tcx>>>,
+    pub(super) cached_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
 
     /// Parameter environment for the item we are in.
     pub param_env: ty::ParamEnv<'tcx>,
@@ -674,35 +677,35 @@ fn lookup<S: Into<MultiSpan>>(
 }
 
 impl<'tcx> LateContext<'tcx> {
-    /// Gets the type-checking side-tables for the current body,
+    /// Gets the type-checking results for the current body,
     /// or `None` if outside a body.
-    pub fn maybe_typeck_tables(&self) -> Option<&'tcx ty::TypeckTables<'tcx>> {
-        self.cached_typeck_tables.get().or_else(|| {
+    pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
+        self.cached_typeck_results.get().or_else(|| {
             self.enclosing_body.map(|body| {
-                let tables = self.tcx.body_tables(body);
-                self.cached_typeck_tables.set(Some(tables));
-                tables
+                let typeck_results = self.tcx.typeck_body(body);
+                self.cached_typeck_results.set(Some(typeck_results));
+                typeck_results
             })
         })
     }
 
-    /// Gets the type-checking side-tables for the current body.
+    /// Gets the type-checking results for the current body.
     /// As this will ICE if called outside bodies, only call when working with
     /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
     #[track_caller]
-    pub fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
-        self.maybe_typeck_tables().expect("`LateContext::tables` called outside of body")
+    pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
+        self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body")
     }
 
     /// Returns the final resolution of a `QPath`, or `Res::Err` if unavailable.
-    /// Unlike `.tables().qpath_res(qpath, id)`, this can be used even outside
+    /// Unlike `.typeck_results().qpath_res(qpath, id)`, this can be used even outside
     /// bodies (e.g. for paths in `hir::Ty`), without any risk of ICE-ing.
     pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
         match *qpath {
             hir::QPath::Resolved(_, ref path) => path.res,
             hir::QPath::TypeRelative(..) => self
-                .maybe_typeck_tables()
-                .and_then(|tables| tables.type_dependent_def(id))
+                .maybe_typeck_results()
+                .and_then(|typeck_results| typeck_results.type_dependent_def(id))
                 .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
         }
     }
index 5feb17af24f7cce740c99dacf6cd44a029288c4b..f43c197d2d201ace7a1fa4ea8d44bbdfa71991b6 100644 (file)
@@ -105,13 +105,13 @@ fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
         let old_enclosing_body = self.context.enclosing_body.replace(body_id);
-        let old_cached_typeck_tables = self.context.cached_typeck_tables.get();
+        let old_cached_typeck_results = self.context.cached_typeck_results.get();
 
-        // HACK(eddyb) avoid trashing `cached_typeck_tables` when we're
+        // HACK(eddyb) avoid trashing `cached_typeck_results` when we're
         // nested in `visit_fn`, which may have already resulted in them
         // being queried.
         if old_enclosing_body != Some(body_id) {
-            self.context.cached_typeck_tables.set(None);
+            self.context.cached_typeck_results.set(None);
         }
 
         let body = self.context.tcx.hir().body(body_id);
@@ -120,7 +120,7 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
 
         // See HACK comment above.
         if old_enclosing_body != Some(body_id) {
-            self.context.cached_typeck_tables.set(old_cached_typeck_tables);
+            self.context.cached_typeck_results.set(old_cached_typeck_results);
         }
     }
 
@@ -191,16 +191,16 @@ fn visit_fn(
         span: Span,
         id: hir::HirId,
     ) {
-        // Wrap in tables here, not just in visit_nested_body,
+        // Wrap in typeck results here, not just in visit_nested_body,
         // in order for `check_fn` to be able to use them.
         let old_enclosing_body = self.context.enclosing_body.replace(body_id);
-        let old_cached_typeck_tables = self.context.cached_typeck_tables.take();
+        let old_cached_typeck_results = self.context.cached_typeck_results.take();
         let body = self.context.tcx.hir().body(body_id);
         lint_callback!(self, check_fn, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
         lint_callback!(self, check_fn_post, fk, decl, body, span, id);
         self.context.enclosing_body = old_enclosing_body;
-        self.context.cached_typeck_tables.set(old_cached_typeck_tables);
+        self.context.cached_typeck_results.set(old_cached_typeck_results);
     }
 
     fn visit_variant_data(
@@ -375,7 +375,7 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
     let context = LateContext {
         tcx,
         enclosing_body: None,
-        cached_typeck_tables: Cell::new(None),
+        cached_typeck_results: Cell::new(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
         lint_store: unerased_lint_store(tcx),
@@ -423,7 +423,7 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T)
     let context = LateContext {
         tcx,
         enclosing_body: None,
-        cached_typeck_tables: Cell::new(None),
+        cached_typeck_results: Cell::new(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
         lint_store: unerased_lint_store(tcx),
index 6b5353e033fc8136dbac699037f66f5b4f5d27ec..ab30d545edfc3111439c1ccdaf85c059da5d2981 100644 (file)
@@ -34,7 +34,6 @@
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(or_patterns)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![recursion_limit = "256"]
 
 #[macro_use]
index b3015dcc2aee87df5e55b178bcfddeb1d7056a87..1affc9457b89e167492782df5bd0b1d8314b96f6 100644 (file)
@@ -168,7 +168,7 @@ fn report_bin_hex_error(
             repr_str, val, t, actually, t
         ));
         if let Some(sugg_ty) =
-            get_type_suggestion(&cx.tables().node_type(expr.hir_id), val, negative)
+            get_type_suggestion(&cx.typeck_results().node_type(expr.hir_id), val, negative)
         {
             if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
                 let (sans_suffix, _) = repr_str.split_at(pos);
@@ -302,7 +302,7 @@ fn lint_uint_literal<'tcx>(
         if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) {
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
-                    if let ty::Char = cx.tables().expr_ty(par_e).kind {
+                    if let ty::Char = cx.typeck_results().expr_ty(par_e).kind {
                         cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
                             lint.build("only `u8` can be cast into `char`")
                                 .span_suggestion(
@@ -353,7 +353,7 @@ fn lint_literal<'tcx>(
     e: &'tcx hir::Expr<'tcx>,
     lit: &hir::Lit,
 ) {
-    match cx.tables().node_type(e.hir_id).kind {
+    match cx.typeck_results().node_type(e.hir_id).kind {
         ty::Int(t) => {
             match lit.node {
                 ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => {
@@ -449,7 +449,7 @@ fn check_limits(
             // 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).kind {
+            match cx.typeck_results().node_type(expr.hir_id).kind {
                 ty::Int(int_ty) => {
                     let (min, max) = int_ty_range(int_ty);
                     let lit_val: i128 = match lit.kind {
@@ -531,23 +531,28 @@ fn ty_is_known_nonnull(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind {
             ty::FnPtr(_) => true,
             ty::Ref(..) => true,
-            ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
-                for field in field_def.all_fields() {
-                    let field_ty = self.cx.tcx.normalize_erasing_regions(
-                        self.cx.param_env,
-                        field.ty(self.cx.tcx, substs),
-                    );
-                    if field_ty.is_zst(self.cx.tcx, field.did) {
-                        continue;
-                    }
+            ty::Adt(def, _)
+                if def.is_box() && matches!(self.mode, ImproperCTypesMode::Definitions) =>
+            {
+                true
+            }
+            ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => {
+                let guaranteed_nonnull_optimization = self
+                    .cx
+                    .tcx
+                    .get_attrs(def.did)
+                    .iter()
+                    .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed));
+
+                if guaranteed_nonnull_optimization {
+                    return true;
+                }
 
-                    let attrs = self.cx.tcx.get_attrs(field_def.did);
-                    if attrs
-                        .iter()
-                        .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
-                        || self.ty_is_known_nonnull(field_ty)
-                    {
-                        return true;
+                for variant in &def.variants {
+                    if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) {
+                        if self.ty_is_known_nonnull(field.ty(self.cx.tcx, substs)) {
+                            return true;
+                        }
                     }
                 }
 
@@ -558,7 +563,7 @@ fn ty_is_known_nonnull(&self, ty: Ty<'tcx>) -> bool {
     }
 
     /// Check if this enum can be safely exported based on the "nullable pointer optimization".
-    /// Currently restricted to function pointers, references, `core::num::NonZero*`,
+    /// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`,
     /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
     fn is_repr_nullable_ptr(
         &self,
@@ -692,6 +697,12 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
         }
 
         match ty.kind {
+            ty::Adt(def, _)
+                if def.is_box() && matches!(self.mode, ImproperCTypesMode::Definitions) =>
+            {
+                FfiSafe
+            }
+
             ty::Adt(def, substs) => {
                 if def.is_phantom_data() {
                     return FfiPhantom(ty);
index 2431f7ba54b36edacb66ce34e48007eb461d1162..6d6c7b24101ca3d3587d0185ccafefcd12bc11dc 100644 (file)
@@ -46,7 +46,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
             return;
         }
 
-        let ty = cx.tables().expr_ty(&expr);
+        let ty = cx.typeck_results().expr_ty(&expr);
         let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1);
 
         let mut fn_warned = false;
@@ -65,7 +65,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
                     _ => None,
                 }
             }
-            hir::ExprKind::MethodCall(..) => cx.tables().type_dependent_def_id(expr.hir_id),
+            hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
             _ => None,
         };
         if let Some(def_id) = maybe_def_id {
@@ -950,7 +950,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
             _ => return,
         }
 
-        for adj in cx.tables().expr_adjustments(e) {
+        for adj in cx.typeck_results().expr_adjustments(e) {
             if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
                 cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
                     let msg = match m {
index d25f8bd1b8c58c9bbbc78ab1e1d920c436f7a910..78e27b10ec657e35f83d37d51256f567aa0d5986 100644 (file)
@@ -104,8 +104,16 @@ fn main() {
         optional_components.push("riscv");
     }
 
-    let required_components =
-        &["ipo", "bitreader", "bitwriter", "linker", "asmparser", "lto", "instrumentation"];
+    let required_components = &[
+        "ipo",
+        "bitreader",
+        "bitwriter",
+        "linker",
+        "asmparser",
+        "lto",
+        "coverage",
+        "instrumentation",
+    ];
 
     let components = output(Command::new(&llvm_config).arg("--components"));
     let mut components = components.split_whitespace().collect::<Vec<_>>();
@@ -169,6 +177,7 @@ fn main() {
     cfg.file("../rustllvm/PassWrapper.cpp")
         .file("../rustllvm/RustWrapper.cpp")
         .file("../rustllvm/ArchiveWrapper.cpp")
+        .file("../rustllvm/CoverageMappingWrapper.cpp")
         .file("../rustllvm/Linker.cpp")
         .cpp(true)
         .cpp_link_stdlib(None) // we handle this below
@@ -275,6 +284,11 @@ fn main() {
         "stdc++"
     };
 
+    // RISC-V requires libatomic for sub-word atomic operations
+    if target.starts_with("riscv") {
+        println!("cargo:rustc-link-lib=atomic");
+    }
+
     // C++ runtime library
     if !target.contains("msvc") {
         if let Some(s) = llvm_static_stdcpp {
index f54ed9b92029ecbb0e34f511356432e9c05f91aa..9d23397ade08e80e170bd9b41ebce4e72c5c7982 100644 (file)
@@ -13,9 +13,15 @@ pub struct RustString {
     pub bytes: RefCell<Vec<u8>>,
 }
 
+impl RustString {
+    pub fn len(&self) -> usize {
+        self.bytes.borrow().len()
+    }
+}
+
 /// Appending to a Rust string -- used by RawRustStringOstream.
 #[no_mangle]
-#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
+#[allow(improper_ctypes_definitions)]
 pub unsafe extern "C" fn LLVMRustStringWriteImpl(
     sr: &RustString,
     ptr: *const c_char,
index 0f8bc4323070b17a8ed169face61fb55a5f97030..2e9b3a2a2562f276ee8fcd99ca7b9fe06d962f04 100644 (file)
@@ -87,18 +87,29 @@ pub fn symbols(input: TokenStream) -> TokenStream {
     let mut prefill_stream = quote! {};
     let mut counter = 0u32;
     let mut keys = HashSet::<String>::new();
+    let mut prev_key: Option<String> = None;
+    let mut errors = Vec::<String>::new();
 
-    let mut check_dup = |str: &str| {
+    let mut check_dup = |str: &str, errors: &mut Vec<String>| {
         if !keys.insert(str.to_string()) {
-            panic!("Symbol `{}` is duplicated", str);
+            errors.push(format!("Symbol `{}` is duplicated", str));
         }
     };
 
+    let mut check_order = |str: &str, errors: &mut Vec<String>| {
+        if let Some(ref prev_str) = prev_key {
+            if str < prev_str {
+                errors.push(format!("Symbol `{}` must precede `{}`", str, prev_str));
+            }
+        }
+        prev_key = Some(str.to_string());
+    };
+
     // Generate the listed keywords.
     for keyword in &input.keywords.0 {
         let name = &keyword.name;
         let value = &keyword.value;
-        check_dup(&value.value());
+        check_dup(&value.value(), &mut errors);
         prefill_stream.extend(quote! {
             #value,
         });
@@ -116,7 +127,8 @@ pub fn symbols(input: TokenStream) -> TokenStream {
             Some(value) => value.value(),
             None => name.to_string(),
         };
-        check_dup(&value);
+        check_dup(&value, &mut errors);
+        check_order(&name.to_string(), &mut errors);
         prefill_stream.extend(quote! {
             #value,
         });
@@ -131,7 +143,7 @@ pub fn symbols(input: TokenStream) -> TokenStream {
     // Generate symbols for the strings "0", "1", ..., "9".
     for n in 0..10 {
         let n = n.to_string();
-        check_dup(&n);
+        check_dup(&n, &mut errors);
         prefill_stream.extend(quote! {
             #n,
         });
@@ -141,6 +153,13 @@ pub fn symbols(input: TokenStream) -> TokenStream {
         counter += 1;
     }
 
+    if !errors.is_empty() {
+        for error in errors.into_iter() {
+            eprintln!("error: {}", error)
+        }
+        panic!("errors in `Keywords` and/or `Symbols`");
+    }
+
     let tt = TokenStream::from(quote! {
         macro_rules! keywords {
             () => {
index 2c80c846681a66e60eba35f04fca53d0e5f40289..0d2101cb2cb0821f5bec673e3580f00f6291f4b1 100644 (file)
@@ -1,6 +1,7 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::locator::{CrateLocator, CratePaths};
+use crate::dynamic_lib::DynamicLibrary;
+use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
 use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind};
@@ -8,15 +9,12 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
-use rustc_middle::middle::cstore::DepKind;
-use rustc_middle::middle::cstore::{
-    CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn,
-};
+use rustc_middle::middle::cstore::{CrateSource, DepKind, ExternCrate};
+use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, ExternLocation};
 use rustc_session::lint;
@@ -31,7 +29,7 @@
 use log::{debug, info, log_enabled};
 use proc_macro::bridge::client::ProcMacro;
 use std::path::Path;
-use std::{cmp, fs};
+use std::{cmp, env, fs};
 
 #[derive(Clone)]
 pub struct CStore {
@@ -69,18 +67,6 @@ enum LoadResult {
     Loaded(Library),
 }
 
-enum LoadError<'a> {
-    LocatorError(CrateLocator<'a>),
-}
-
-impl<'a> LoadError<'a> {
-    fn report(self) -> ! {
-        match self {
-            LoadError::LocatorError(locator) => locator.report_errs(),
-        }
-    }
-}
-
 /// A reference to `CrateMetadata` that can also give access to whole crate store when necessary.
 #[derive(Clone, Copy)]
 crate struct CrateMetadataRef<'a> {
@@ -280,60 +266,43 @@ fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Opt
         ret
     }
 
-    fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
+    fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
         // Check for (potential) conflicts with the local crate
         if self.local_crate_name == root.name()
             && self.sess.local_crate_disambiguator() == root.disambiguator()
         {
-            struct_span_err!(
-                self.sess,
-                span,
-                E0519,
-                "the current crate is indistinguishable from one of its \
-                         dependencies: it has the same crate-name `{}` and was \
-                         compiled with the same `-C metadata` arguments. This \
-                         will result in symbol conflicts between the two.",
-                root.name()
-            )
-            .emit()
+            return Err(CrateError::SymbolConflictsCurrent(root.name()));
         }
 
         // Check for conflicts with any crate loaded so far
+        let mut res = Ok(());
         self.cstore.iter_crate_data(|_, other| {
             if other.name() == root.name() && // same crate-name
-               other.disambiguator() == root.disambiguator() &&  // same crate-disambiguator
+               other.disambiguator() == root.disambiguator() && // same crate-disambiguator
                other.hash() != root.hash()
             {
                 // but different SVH
-                struct_span_err!(
-                    self.sess,
-                    span,
-                    E0523,
-                    "found two different crates with name `{}` that are \
-                         not distinguished by differing `-C metadata`. This \
-                         will result in symbol conflicts between the two.",
-                    root.name()
-                )
-                .emit();
+                res = Err(CrateError::SymbolConflictsOthers(root.name()));
             }
         });
+
+        res
     }
 
     fn register_crate(
         &mut self,
         host_lib: Option<Library>,
         root: Option<&CratePaths>,
-        span: Span,
         lib: Library,
         dep_kind: DepKind,
         name: Symbol,
-    ) -> CrateNum {
+    ) -> Result<CrateNum, CrateError> {
         let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
 
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-        self.verify_no_symbol_conflicts(span, &crate_root);
+        self.verify_no_symbol_conflicts(&crate_root)?;
 
         let private_dep =
             self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false);
@@ -353,7 +322,7 @@ fn register_crate(
             &crate_paths
         };
 
-        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
+        let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, dep_kind)?;
 
         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
             let temp_root;
@@ -365,7 +334,7 @@ fn register_crate(
                 None => (&source, &crate_root),
             };
             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
-            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator(), span))
+            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator())?)
         } else {
             None
         };
@@ -386,14 +355,14 @@ fn register_crate(
             ),
         );
 
-        cnum
+        Ok(cnum)
     }
 
     fn load_proc_macro<'b>(
         &self,
         locator: &mut CrateLocator<'b>,
         path_kind: PathKind,
-    ) -> Option<(LoadResult, Option<Library>)>
+    ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
     where
         'a: 'b,
     {
@@ -408,8 +377,11 @@ fn load_proc_macro<'b>(
         let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
             proc_macro_locator.reset();
             let result = match self.load(&mut proc_macro_locator)? {
-                LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
-                LoadResult::Loaded(library) => Some(LoadResult::Loaded(library)),
+                Some(LoadResult::Previous(cnum)) => {
+                    return Ok(Some((LoadResult::Previous(cnum), None)));
+                }
+                Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
+                None => return Ok(None),
             };
             locator.hash = locator.host_hash;
             // Use the locator when looking for the host proc macro crate, as that is required
@@ -427,9 +399,12 @@ fn load_proc_macro<'b>(
         locator.triple = TargetTriple::from_triple(config::host_triple());
         locator.filesearch = self.sess.host_filesearch(path_kind);
 
-        let host_result = self.load(locator)?;
+        let host_result = match self.load(locator)? {
+            Some(host_result) => host_result,
+            None => return Ok(None),
+        };
 
-        Some(if self.sess.opts.debugging_opts.dual_proc_macros {
+        Ok(Some(if self.sess.opts.debugging_opts.dual_proc_macros {
             let host_result = match host_result {
                 LoadResult::Previous(..) => {
                     panic!("host and target proc macros must be loaded in lock-step")
@@ -439,7 +414,7 @@ fn load_proc_macro<'b>(
             (target_result.unwrap(), Some(host_result))
         } else {
             (host_result, None)
-        })
+        }))
     }
 
     fn resolve_crate<'b>(
@@ -452,25 +427,20 @@ fn resolve_crate<'b>(
         if dep.is_none() {
             self.used_extern_options.insert(name);
         }
-        if !name.as_str().is_ascii() {
-            self.sess
-                .struct_span_err(
-                    span,
-                    &format!("cannot load a crate with a non-ascii name `{}`", name,),
-                )
-                .emit();
-        }
-        self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
+        self.maybe_resolve_crate(name, dep_kind, dep)
+            .unwrap_or_else(|err| err.report(self.sess, span))
     }
 
     fn maybe_resolve_crate<'b>(
         &'b mut self,
         name: Symbol,
-        span: Span,
         mut dep_kind: DepKind,
         dep: Option<(&'b CratePaths, &'b CrateDep)>,
-    ) -> Result<CrateNum, LoadError<'b>> {
+    ) -> Result<CrateNum, CrateError> {
         info!("resolving crate `{}`", name);
+        if !name.as_str().is_ascii() {
+            return Err(CrateError::NonAsciiName(name));
+        }
         let (root, hash, host_hash, extra_filename, path_kind) = match dep {
             Some((root, dep)) => (
                 Some(root),
@@ -494,18 +464,20 @@ fn maybe_resolve_crate<'b>(
                 extra_filename,
                 false, // is_host
                 path_kind,
-                span,
                 root,
                 Some(false), // is_proc_macro
             );
 
-            self.load(&mut locator)
-                .map(|r| (r, None))
-                .or_else(|| {
+            match self.load(&mut locator)? {
+                Some(res) => (res, None),
+                None => {
                     dep_kind = DepKind::MacrosOnly;
-                    self.load_proc_macro(&mut locator, path_kind)
-                })
-                .ok_or_else(move || LoadError::LocatorError(locator))?
+                    match self.load_proc_macro(&mut locator, path_kind)? {
+                        Some(res) => res,
+                        None => return Err(locator.into_error()),
+                    }
+                }
+            }
         };
 
         match result {
@@ -518,14 +490,17 @@ fn maybe_resolve_crate<'b>(
                 Ok(cnum)
             }
             (LoadResult::Loaded(library), host_library) => {
-                Ok(self.register_crate(host_library, root, span, library, dep_kind, name))
+                self.register_crate(host_library, root, library, dep_kind, name)
             }
             _ => panic!(),
         }
     }
 
-    fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
-        let library = locator.maybe_load_library_crate()?;
+    fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> {
+        let library = match locator.maybe_load_library_crate()? {
+            Some(library) => library,
+            None => return Ok(None),
+        };
 
         // In the case that we're loading a crate, but not matching
         // against a hash, we could load a crate which has the same hash
@@ -536,7 +511,7 @@ fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
         // don't want to match a host crate against an equivalent target one
         // already loaded.
         let root = library.metadata.get_root();
-        if locator.triple == self.sess.opts.target_triple {
+        Ok(Some(if locator.triple == self.sess.opts.target_triple {
             let mut result = LoadResult::Loaded(library);
             self.cstore.iter_crate_data(|cnum, data| {
                 if data.name() == root.name() && root.hash() == data.hash() {
@@ -545,10 +520,10 @@ fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
                     result = LoadResult::Previous(cnum);
                 }
             });
-            Some(result)
+            result
         } else {
-            Some(LoadResult::Loaded(library))
-        }
+            LoadResult::Loaded(library)
+        }))
     }
 
     fn update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate) {
@@ -569,53 +544,51 @@ fn resolve_crate_deps(
         crate_root: &CrateRoot<'_>,
         metadata: &MetadataBlob,
         krate: CrateNum,
-        span: Span,
         dep_kind: DepKind,
-    ) -> CrateNumMap {
+    ) -> Result<CrateNumMap, CrateError> {
         debug!("resolving deps of external crate");
         if crate_root.is_proc_macro_crate() {
-            return CrateNumMap::new();
+            return Ok(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.decode_crate_deps(metadata).map(|dep| {
-                info!(
-                    "resolving dep crate {} hash: `{}` extra filename: `{}`",
-                    dep.name, dep.hash, dep.extra_filename
-                );
-                let dep_kind = match dep_kind {
-                    DepKind::MacrosOnly => DepKind::MacrosOnly,
-                    _ => dep.kind,
-                };
-                self.resolve_crate(dep.name, span, dep_kind, Some((root, &dep)))
-            }))
-            .collect()
+        let deps = crate_root.decode_crate_deps(metadata);
+        let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());
+        crate_num_map.push(krate);
+        for dep in deps {
+            info!(
+                "resolving dep crate {} hash: `{}` extra filename: `{}`",
+                dep.name, dep.hash, dep.extra_filename
+            );
+            let dep_kind = match dep_kind {
+                DepKind::MacrosOnly => DepKind::MacrosOnly,
+                _ => dep.kind,
+            };
+            let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((root, &dep)))?;
+            crate_num_map.push(cnum);
+        }
+        Ok(crate_num_map)
     }
 
     fn dlsym_proc_macros(
         &self,
         path: &Path,
         disambiguator: CrateDisambiguator,
-        span: Span,
-    ) -> &'static [ProcMacro] {
-        use crate::dynamic_lib::DynamicLibrary;
-        use std::env;
-
+    ) -> Result<&'static [ProcMacro], CrateError> {
         // 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(&path) {
             Ok(lib) => lib,
-            Err(err) => self.sess.span_fatal(span, &err),
+            Err(s) => return Err(CrateError::DlOpen(s)),
         };
 
         let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator);
         let decls = unsafe {
             let sym = match lib.symbol(&sym) {
                 Ok(f) => f,
-                Err(err) => self.sess.span_fatal(span, &err),
+                Err(s) => return Err(CrateError::DlSym(s)),
             };
             *(sym as *const &[ProcMacro])
         };
@@ -624,7 +597,7 @@ fn dlsym_proc_macros(
         // since the library can make things that will live arbitrarily long.
         std::mem::forget(lib);
 
-        decls
+        Ok(decls)
     }
 
     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@@ -679,8 +652,8 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // in terms of everyone has a compatible panic runtime format, that's
         // performed later as part of the `dependency_format` module.
         let name = match desired_strategy {
-            PanicStrategy::Unwind => Symbol::intern("panic_unwind"),
-            PanicStrategy::Abort => Symbol::intern("panic_abort"),
+            PanicStrategy::Unwind => sym::panic_unwind,
+            PanicStrategy::Abort => sym::panic_abort,
         };
         info!("panic runtime not found -- loading {}", name);
 
@@ -713,7 +686,7 @@ fn inject_profiler_runtime(&mut self) {
         {
             info!("loading profiler");
 
-            let name = Symbol::intern("profiler_builtins");
+            let name = sym::profiler_builtins;
             let cnum = self.resolve_crate(name, DUMMY_SP, DepKind::Implicit, None);
             let data = self.cstore.get_crate_data(cnum);
 
@@ -952,7 +925,7 @@ pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum {
         cnum
     }
 
-    pub fn maybe_process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
-        self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok()
+    pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
+        self.maybe_resolve_crate(name, DepKind::Explicit, None).ok()
     }
 }
index 2dd4a9c9dbcb114a113cc0951ed430365bb968cb..c5a43b91b5e9b050baabbd28ad1481c10fff6870 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
@@ -11,7 +11,7 @@
     for attr in tcx.hir().krate().item.attrs.iter() {
         if attr.has_name(sym::link_args) {
             if let Some(linkarg) = attr.value_str() {
-                collector.add_link_args(&linkarg.as_str());
+                collector.add_link_args(linkarg);
             }
         }
     }
@@ -36,7 +36,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
         // First, add all of the custom #[link_args] attributes
         for m in it.attrs.iter().filter(|a| a.check_name(sym::link_args)) {
             if let Some(linkarg) = m.value_str() {
-                self.add_link_args(&linkarg.as_str());
+                self.add_link_args(linkarg);
             }
         }
     }
@@ -46,7 +46,7 @@ fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
 }
 
 impl Collector {
-    fn add_link_args(&mut self, args: &str) {
-        self.args.extend(args.split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string()))
+    fn add_link_args(&mut self, args: Symbol) {
+        self.args.extend(args.as_str().split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string()))
     }
 }
index 1bdac1039b55a48e07bb179599993968857b0fdf..371ec4cd91148686345129677de65ed4b2735503 100644 (file)
 use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
-use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_errors::struct_span_err;
 use rustc_middle::middle::cstore::{CrateSource, MetadataLoader};
 use rustc_session::config::{self, CrateType};
 use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
 
-use std::cmp;
-use std::fmt;
-use std::fs;
-use std::io::{self, Read};
-use std::ops::Deref;
-use std::path::{Path, PathBuf};
-use std::time::Instant;
-
 use flate2::read::DeflateDecoder;
-
-use rustc_data_structures::owning_ref::OwningRef;
-
 use log::{debug, info, warn};
-
-#[derive(Clone)]
-struct CrateMismatch {
-    path: PathBuf,
-    got: String,
-}
+use std::io::{Read, Result as IoResult, Write};
+use std::ops::Deref;
+use std::path::{Path, PathBuf};
+use std::{cmp, fmt, fs};
 
 #[derive(Clone)]
 crate struct CrateLocator<'a> {
@@ -263,7 +251,6 @@ struct CrateMismatch {
     pub target: &'a Target,
     pub triple: TargetTriple,
     pub filesearch: FileSearch<'a>,
-    span: Span,
     root: Option<&'a CratePaths>,
     pub is_proc_macro: Option<bool>,
 
@@ -275,6 +262,7 @@ struct CrateMismatch {
     rejected_via_filename: Vec<CrateMismatch>,
 }
 
+#[derive(Clone)]
 crate struct CratePaths {
     name: Symbol,
     source: CrateSource,
@@ -287,7 +275,7 @@ impl CratePaths {
 }
 
 #[derive(Copy, Clone, PartialEq)]
-enum CrateFlavor {
+crate enum CrateFlavor {
     Rlib,
     Rmeta,
     Dylib,
@@ -313,7 +301,6 @@ impl<'a> CrateLocator<'a> {
         extra_filename: Option<&'a str>,
         is_host: bool,
         path_kind: PathKind,
-        span: Span,
         root: Option<&'a CratePaths>,
         is_proc_macro: Option<bool>,
     ) -> CrateLocator<'a> {
@@ -349,7 +336,6 @@ impl<'a> CrateLocator<'a> {
             } else {
                 sess.target_filesearch(path_kind)
             },
-            span,
             root,
             is_proc_macro,
             rejected_via_hash: Vec::new(),
@@ -368,166 +354,30 @@ impl<'a> CrateLocator<'a> {
         self.rejected_via_filename.clear();
     }
 
-    crate fn maybe_load_library_crate(&mut self) -> Option<Library> {
+    crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
         if !self.exact_paths.is_empty() {
             return self.find_commandline_library();
         }
         let mut seen_paths = FxHashSet::default();
-        match self.extra_filename {
-            Some(s) => self
-                .find_library_crate(s, &mut seen_paths)
-                .or_else(|| self.find_library_crate("", &mut seen_paths)),
-            None => self.find_library_crate("", &mut seen_paths),
-        }
-    }
-
-    crate fn report_errs(self) -> ! {
-        let add = match self.root {
-            None => String::new(),
-            Some(r) => format!(" which `{}` depends on", r.name),
-        };
-        let mut msg = "the following crate versions were found:".to_string();
-        let mut err = if !self.rejected_via_hash.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0460,
-                "found possibly newer version of crate `{}`{}",
-                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.crate_name, path.display()));
-            }
-            match self.root {
-                None => {}
-                Some(r) => {
-                    for path in r.source.paths() {
-                        msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
-                    }
-                }
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_triple.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0461,
-                "couldn't find crate `{}` \
-                                            with expected target triple {}{}",
-                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.crate_name,
-                    got,
-                    path.display()
-                ));
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_kind.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0462,
-                "found staticlib `{}` instead of rlib or dylib{}",
-                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.crate_name, path.display()));
-            }
-            err.note(&msg);
-            err
-        } else if !self.rejected_via_version.is_empty() {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0514,
-                "found crate `{}` compiled by an incompatible version \
-                                            of rustc{}",
-                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.crate_name,
-                    got,
-                    path.display()
-                ));
-            }
-            err.note(&msg);
-            err
-        } else {
-            let mut err = struct_span_err!(
-                self.sess,
-                self.span,
-                E0463,
-                "can't find crate for `{}`{}",
-                self.crate_name,
-                add
-            );
-
-            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));
-            } else if self.crate_name == sym::profiler_builtins {
-                err.note(&"the compiler may have been built without the profiler runtime");
-            }
-            err.span_label(self.span, "can't find crate");
-            err
-        };
-
-        if !self.rejected_via_filename.is_empty() {
-            let dylibname = self.dylibname();
-            let mismatches = self.rejected_via_filename.iter();
-            for &CrateMismatch { ref path, .. } in mismatches {
-                err.note(&format!(
-                    "extern location for {} is of an unknown type: {}",
-                    self.crate_name,
-                    path.display()
-                ))
-                .help(&format!(
-                    "file name should be lib*.rlib or {}*.{}",
-                    dylibname.0, dylibname.1
-                ));
+        if let Some(extra_filename) = self.extra_filename {
+            if let library @ Some(_) = self.find_library_crate(extra_filename, &mut seen_paths)? {
+                return Ok(library);
             }
         }
-
-        err.emit();
-        self.sess.abort_if_errors();
-        unreachable!();
+        self.find_library_crate("", &mut seen_paths)
     }
 
     fn find_library_crate(
         &mut self,
         extra_prefix: &str,
         seen_paths: &mut FxHashSet<PathBuf>,
-    ) -> Option<Library> {
-        let dypair = self.dylibname();
-        let staticpair = self.staticlibname();
-
+    ) -> Result<Option<Library>, CrateError> {
         // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
-        let dylib_prefix = format!("{}{}{}", dypair.0, self.crate_name, extra_prefix);
+        let dylib_prefix =
+            format!("{}{}{}", self.target.options.dll_prefix, self.crate_name, extra_prefix);
         let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix);
-        let staticlib_prefix = format!("{}{}{}", staticpair.0, self.crate_name, extra_prefix);
+        let staticlib_prefix =
+            format!("{}{}{}", self.target.options.staticlib_prefix, self.crate_name, extra_prefix);
 
         let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
             Default::default();
@@ -555,10 +405,18 @@ fn find_library_crate(
                 (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
             } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") {
                 (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
-            } else if file.starts_with(&dylib_prefix) && file.ends_with(&dypair.1) {
-                (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib)
+            } else if file.starts_with(&dylib_prefix)
+                && file.ends_with(&self.target.options.dll_suffix)
+            {
+                (
+                    &file
+                        [(dylib_prefix.len())..(file.len() - self.target.options.dll_suffix.len())],
+                    CrateFlavor::Dylib,
+                )
             } else {
-                if file.starts_with(&staticlib_prefix) && file.ends_with(&staticpair.1) {
+                if file.starts_with(&staticlib_prefix)
+                    && file.ends_with(&self.target.options.staticlib_suffix)
+                {
                     staticlibs
                         .push(CrateMismatch { path: spf.path.clone(), got: "static".to_string() });
                 }
@@ -567,9 +425,7 @@ fn find_library_crate(
 
             info!("lib candidate: {}", spf.path.display());
 
-            let hash_str = hash.to_string();
-            let slot = candidates.entry(hash_str).or_default();
-            let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot;
+            let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
             fs::canonicalize(&spf.path)
                 .map(|p| {
                     if seen_paths.contains(&p) {
@@ -577,16 +433,10 @@ fn find_library_crate(
                     };
                     seen_paths.insert(p.clone());
                     match found_kind {
-                        CrateFlavor::Rlib => {
-                            rlibs.insert(p, kind);
-                        }
-                        CrateFlavor::Rmeta => {
-                            rmetas.insert(p, kind);
-                        }
-                        CrateFlavor::Dylib => {
-                            dylibs.insert(p, kind);
-                        }
-                    }
+                        CrateFlavor::Rlib => rlibs.insert(p, kind),
+                        CrateFlavor::Rmeta => rmetas.insert(p, kind),
+                        CrateFlavor::Dylib => dylibs.insert(p, kind),
+                    };
                     FileMatches
                 })
                 .unwrap_or(FileDoesntMatch)
@@ -603,7 +453,7 @@ fn find_library_crate(
         // search is being performed for.
         let mut libraries = FxHashMap::default();
         for (_hash, (rlibs, rmetas, dylibs)) in candidates {
-            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs) {
+            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
                 libraries.insert(svh, lib);
             }
         }
@@ -612,39 +462,9 @@ fn find_library_crate(
         // what we've got and figure out if we found multiple candidates for
         // libraries or not.
         match libraries.len() {
-            0 => None,
-            1 => Some(libraries.into_iter().next().unwrap().1),
-            _ => {
-                let mut err = struct_span_err!(
-                    self.sess,
-                    self.span,
-                    E0464,
-                    "multiple matching crates for `{}`",
-                    self.crate_name
-                );
-                let candidates = libraries
-                    .iter()
-                    .filter_map(|(_, lib)| {
-                        let crate_name = &lib.metadata.get_root().name().as_str();
-                        match &(&lib.source.dylib, &lib.source.rlib) {
-                            &(&Some((ref pd, _)), &Some((ref pr, _))) => Some(format!(
-                                "\ncrate `{}`: {}\n{:>padding$}",
-                                crate_name,
-                                pd.display(),
-                                pr.display(),
-                                padding = 8 + crate_name.len()
-                            )),
-                            &(&Some((ref p, _)), &None) | &(&None, &Some((ref p, _))) => {
-                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
-                            }
-                            &(&None, &None) => None,
-                        }
-                    })
-                    .collect::<String>();
-                err.note(&format!("candidates:{}", candidates));
-                err.emit();
-                None
-            }
+            0 => Ok(None),
+            1 => Ok(Some(libraries.into_iter().next().unwrap().1)),
+            _ => Err(CrateError::MultipleMatchingCrates(self.crate_name, libraries)),
         }
     }
 
@@ -653,16 +473,16 @@ fn extract_lib(
         rlibs: FxHashMap<PathBuf, PathKind>,
         rmetas: FxHashMap<PathBuf, PathKind>,
         dylibs: FxHashMap<PathBuf, PathKind>,
-    ) -> Option<(Svh, Library)> {
+    ) -> Result<Option<(Svh, Library)>, CrateError> {
         let mut slot = None;
         // Order here matters, rmeta should come first. See comment in
         // `extract_one` below.
         let source = CrateSource {
-            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot),
-            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
-            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot),
+            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
+            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
+            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?,
         };
-        slot.map(|(svh, metadata)| (svh, Library { source, metadata }))
+        Ok(slot.map(|(svh, metadata)| (svh, Library { source, metadata })))
     }
 
     fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
@@ -698,10 +518,7 @@ fn extract_one(
         m: FxHashMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
         slot: &mut Option<(Svh, MetadataBlob)>,
-    ) -> Option<(PathBuf, PathKind)> {
-        let mut ret: Option<(PathBuf, PathKind)> = None;
-        let mut error = 0;
-
+    ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
         // If we are producing an rlib, and we've already loaded metadata, then
         // we should not attempt to discover further crate sources (unless we're
         // locating a proc macro; exact logic is in needs_crate_flavor). This means
@@ -718,13 +535,14 @@ fn extract_one(
         // from the other crate sources.
         if slot.is_some() {
             if m.is_empty() || !self.needs_crate_flavor(flavor) {
-                return None;
+                return Ok(None);
             } else if m.len() == 1 {
-                return Some(m.into_iter().next().unwrap());
+                return Ok(Some(m.into_iter().next().unwrap()));
             }
         }
 
-        let mut err: Option<DiagnosticBuilder<'_>> = None;
+        let mut ret: Option<(PathBuf, PathKind)> = None;
+        let mut err_data: Option<Vec<PathBuf>> = None;
         for (lib, kind) in m {
             info!("{} reading metadata from: {}", flavor, lib.display());
             let (hash, metadata) =
@@ -744,30 +562,18 @@ fn extract_one(
                 };
             // If we see multiple hashes, emit an error about duplicate candidates.
             if slot.as_ref().map_or(false, |s| s.0 != hash) {
-                let mut e = struct_span_err!(
-                    self.sess,
-                    self.span,
-                    E0465,
-                    "multiple {} candidates for `{}` found",
-                    flavor,
-                    self.crate_name
-                );
-                e.span_note(
-                    self.span,
-                    &format!(r"candidate #1: {}", ret.as_ref().unwrap().0.display()),
-                );
-                if let Some(ref mut e) = err {
-                    e.emit();
+                if let Some(candidates) = err_data {
+                    return Err(CrateError::MultipleCandidates(
+                        self.crate_name,
+                        flavor,
+                        candidates,
+                    ));
                 }
-                err = Some(e);
-                error = 1;
+                err_data = Some(vec![ret.as_ref().unwrap().0.clone()]);
                 *slot = None;
             }
-            if error > 0 {
-                error += 1;
-                err.as_mut()
-                    .unwrap()
-                    .span_note(self.span, &format!(r"candidate #{}: {}", error, lib.display()));
+            if let Some(candidates) = &mut err_data {
+                candidates.push(lib);
                 continue;
             }
 
@@ -790,7 +596,7 @@ fn extract_one(
             // As a result, we favor the sysroot crate here. Note that the
             // candidates are all canonicalized, so we canonicalize the sysroot
             // as well.
-            if let Some((ref prev, _)) = ret {
+            if let Some((prev, _)) = &ret {
                 let sysroot = &self.sess.sysroot;
                 let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf());
                 if prev.starts_with(&sysroot) {
@@ -801,11 +607,10 @@ fn extract_one(
             ret = Some((lib, kind));
         }
 
-        if error > 0 {
-            err.unwrap().emit();
-            None
+        if let Some(candidates) = err_data {
+            Err(CrateError::MultipleCandidates(self.crate_name, flavor, candidates))
         } else {
-            ret
+            Ok(ret)
         }
     }
 
@@ -860,71 +665,29 @@ fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<S
         Some(hash)
     }
 
-    // Returns the corresponding (prefix, suffix) that files need to have for
-    // dynamic libraries
-    fn dylibname(&self) -> (String, String) {
-        let t = &self.target;
-        (t.options.dll_prefix.clone(), t.options.dll_suffix.clone())
-    }
-
-    // Returns the corresponding (prefix, suffix) that files need to have for
-    // static libraries
-    fn staticlibname(&self) -> (String, String) {
-        let t = &self.target;
-        (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone())
-    }
-
-    fn find_commandline_library(&mut self) -> Option<Library> {
+    fn find_commandline_library(&mut self) -> Result<Option<Library>, CrateError> {
         // First, filter out all libraries that look suspicious. We only accept
         // files which actually exist that have the correct naming scheme for
         // rlibs/dylibs.
-        let sess = self.sess;
-        let dylibname = self.dylibname();
         let mut rlibs = FxHashMap::default();
         let mut rmetas = FxHashMap::default();
         let mut dylibs = FxHashMap::default();
-        {
-            let crate_name = self.crate_name;
-            let rejected_via_filename = &mut self.rejected_via_filename;
-            let locs = self.exact_paths.iter().filter(|loc| {
-                if !loc.exists() {
-                    sess.err(&format!(
-                        "extern location for {} does not exist: {}",
-                        crate_name,
-                        loc.display()
-                    ));
-                    return false;
-                }
-                let file = match loc.file_name().and_then(|s| s.to_str()) {
-                    Some(file) => file,
-                    None => {
-                        sess.err(&format!(
-                            "extern location for {} is not a file: {}",
-                            crate_name,
-                            loc.display()
-                        ));
-                        return false;
-                    }
-                };
-                if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
-                {
-                    return true;
-                } else {
-                    let (ref prefix, ref suffix) = dylibname;
-                    if file.starts_with(&prefix[..]) && file.ends_with(&suffix[..]) {
-                        return true;
-                    }
+        for loc in &self.exact_paths {
+            if !loc.exists() {
+                return Err(CrateError::ExternLocationNotExist(self.crate_name, loc.clone()));
+            }
+            let file = match loc.file_name().and_then(|s| s.to_str()) {
+                Some(file) => file,
+                None => {
+                    return Err(CrateError::ExternLocationNotFile(self.crate_name, loc.clone()));
                 }
+            };
 
-                rejected_via_filename
-                    .push(CrateMismatch { path: (*loc).clone(), got: String::new() });
-
-                false
-            });
-
-            // Now that we have an iterator of good candidates, make sure
-            // there's at most one rlib and at most one dylib.
-            for loc in locs {
+            if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
+                || file.starts_with(&self.target.options.dll_prefix)
+                    && file.ends_with(&self.target.options.dll_suffix)
+            {
+                // Make sure there's at most one rlib and at most one dylib.
                 if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
                     rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
@@ -932,25 +695,30 @@ fn find_commandline_library(&mut self) -> Option<Library> {
                 } else {
                     dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 }
+            } else {
+                self.rejected_via_filename
+                    .push(CrateMismatch { path: loc.clone(), got: String::new() });
             }
-        };
+        }
 
         // Extract the dylib/rlib/rmeta triple.
-        self.extract_lib(rlibs, rmetas, dylibs).map(|(_, lib)| lib)
+        Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib))
     }
-}
 
-// Just a small wrapper to time how long reading metadata takes.
-fn get_metadata_section(
-    target: &Target,
-    flavor: CrateFlavor,
-    filename: &Path,
-    loader: &dyn MetadataLoader,
-) -> Result<MetadataBlob, String> {
-    let start = Instant::now();
-    let ret = get_metadata_section_imp(target, flavor, filename, loader);
-    info!("reading {:?} => {:?}", filename.file_name().unwrap(), start.elapsed());
-    ret
+    crate fn into_error(self) -> CrateError {
+        CrateError::LocatorCombined(CombinedLocatorError {
+            crate_name: self.crate_name,
+            root: self.root.cloned(),
+            triple: self.triple,
+            dll_prefix: self.target.options.dll_prefix.clone(),
+            dll_suffix: self.target.options.dll_suffix.clone(),
+            rejected_via_hash: self.rejected_via_hash,
+            rejected_via_triple: self.rejected_via_triple,
+            rejected_via_kind: self.rejected_via_kind,
+            rejected_via_version: self.rejected_via_version,
+            rejected_via_filename: self.rejected_via_filename,
+        })
+    }
 }
 
 /// A trivial wrapper for `Mmap` that implements `StableDeref`.
@@ -966,7 +734,7 @@ fn deref(&self) -> &[u8] {
 
 unsafe impl stable_deref_trait::StableDeref for StableDerefMmap {}
 
-fn get_metadata_section_imp(
+fn get_metadata_section(
     target: &Target,
     flavor: CrateFlavor,
     filename: &Path,
@@ -1026,12 +794,19 @@ pub fn find_plugin_registrar(
     metadata_loader: &dyn MetadataLoader,
     span: Span,
     name: Symbol,
-) -> Option<(PathBuf, CrateDisambiguator)> {
+) -> (PathBuf, CrateDisambiguator) {
+    match find_plugin_registrar_impl(sess, metadata_loader, name) {
+        Ok(res) => res,
+        Err(err) => err.report(sess, span),
+    }
+}
+
+fn find_plugin_registrar_impl<'a>(
+    sess: &'a Session,
+    metadata_loader: &dyn MetadataLoader,
+    name: Symbol,
+) -> Result<(PathBuf, CrateDisambiguator), CrateError> {
     info!("find plugin registrar `{}`", name);
-    let target_triple = sess.opts.target_triple.clone();
-    let host_triple = TargetTriple::from_triple(config::host_triple());
-    let is_cross = target_triple != host_triple;
-    let mut target_only = false;
     let mut locator = CrateLocator::new(
         sess,
         metadata_loader,
@@ -1041,57 +816,16 @@ pub fn find_plugin_registrar(
         None, // extra_filename
         true, // is_host
         PathKind::Crate,
-        span,
         None, // root
         None, // is_proc_macro
     );
 
-    let library = locator.maybe_load_library_crate().or_else(|| {
-        if !is_cross {
-            return None;
-        }
-        // Try loading from target crates. This will abort later if we
-        // try to load a plugin registrar function,
-        target_only = true;
-
-        locator.target = &sess.target.target;
-        locator.triple = target_triple;
-        locator.filesearch = sess.target_filesearch(PathKind::Crate);
-
-        locator.maybe_load_library_crate()
-    });
-    let library = match library {
-        Some(l) => l,
-        None => locator.report_errs(),
-    };
-
-    if target_only {
-        let message = format!(
-            "plugin `{}` is not available for triple `{}` (only found {})",
-            name,
-            config::host_triple(),
-            sess.opts.target_triple
-        );
-        struct_span_err!(sess, span, E0456, "{}", &message).emit();
-        return None;
-    }
-
-    match library.source.dylib {
-        Some(dylib) => Some((dylib.0, library.metadata.get_root().disambiguator())),
-        None => {
-            struct_span_err!(
-                sess,
-                span,
-                E0457,
-                "plugin `{}` only found in rlib format, but must be available \
-                        in dylib format",
-                name
-            )
-            .emit();
-            // No need to abort because the loading code will just ignore this
-            // empty dylib.
-            None
-        }
+    match locator.maybe_load_library_crate()? {
+        Some(library) => match library.source.dylib {
+            Some(dylib) => Ok((dylib.0, library.metadata.get_root().disambiguator())),
+            None => Err(CrateError::NonDylibPlugin(name)),
+        },
+        None => Err(locator.into_error()),
     }
 }
 
@@ -1100,8 +834,8 @@ pub fn list_file_metadata(
     target: &Target,
     path: &Path,
     metadata_loader: &dyn MetadataLoader,
-    out: &mut dyn io::Write,
-) -> io::Result<()> {
+    out: &mut dyn Write,
+) -> IoResult<()> {
     let filename = path.file_name().unwrap().to_str().unwrap();
     let flavor = if filename.ends_with(".rlib") {
         CrateFlavor::Rlib
@@ -1115,3 +849,259 @@ pub fn list_file_metadata(
         Err(msg) => write!(out, "{}\n", msg),
     }
 }
+
+// ------------------------------------------ Error reporting -------------------------------------
+
+#[derive(Clone)]
+struct CrateMismatch {
+    path: PathBuf,
+    got: String,
+}
+
+/// Candidate rejection reasons collected during crate search.
+/// If no candidate is accepted, then these reasons are presented to the user,
+/// otherwise they are ignored.
+crate struct CombinedLocatorError {
+    crate_name: Symbol,
+    root: Option<CratePaths>,
+    triple: TargetTriple,
+    dll_prefix: String,
+    dll_suffix: String,
+    rejected_via_hash: Vec<CrateMismatch>,
+    rejected_via_triple: Vec<CrateMismatch>,
+    rejected_via_kind: Vec<CrateMismatch>,
+    rejected_via_version: Vec<CrateMismatch>,
+    rejected_via_filename: Vec<CrateMismatch>,
+}
+
+crate enum CrateError {
+    NonAsciiName(Symbol),
+    ExternLocationNotExist(Symbol, PathBuf),
+    ExternLocationNotFile(Symbol, PathBuf),
+    MultipleCandidates(Symbol, CrateFlavor, Vec<PathBuf>),
+    MultipleMatchingCrates(Symbol, FxHashMap<Svh, Library>),
+    SymbolConflictsCurrent(Symbol),
+    SymbolConflictsOthers(Symbol),
+    DlOpen(String),
+    DlSym(String),
+    LocatorCombined(CombinedLocatorError),
+    NonDylibPlugin(Symbol),
+}
+
+impl CrateError {
+    crate fn report(self, sess: &Session, span: Span) -> ! {
+        let mut err = match self {
+            CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
+                span,
+                &format!("cannot load a crate with a non-ascii name `{}`", crate_name),
+            ),
+            CrateError::ExternLocationNotExist(crate_name, loc) => sess.struct_span_err(
+                span,
+                &format!("extern location for {} does not exist: {}", crate_name, loc.display()),
+            ),
+            CrateError::ExternLocationNotFile(crate_name, loc) => sess.struct_span_err(
+                span,
+                &format!("extern location for {} is not a file: {}", crate_name, loc.display()),
+            ),
+            CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
+                let mut err = struct_span_err!(
+                    sess,
+                    span,
+                    E0465,
+                    "multiple {} candidates for `{}` found",
+                    flavor,
+                    crate_name,
+                );
+                for (i, candidate) in candidates.iter().enumerate() {
+                    err.span_note(span, &format!("candidate #{}: {}", i + 1, candidate.display()));
+                }
+                err
+            }
+            CrateError::MultipleMatchingCrates(crate_name, libraries) => {
+                let mut err = struct_span_err!(
+                    sess,
+                    span,
+                    E0464,
+                    "multiple matching crates for `{}`",
+                    crate_name
+                );
+                let candidates = libraries
+                    .iter()
+                    .filter_map(|(_, lib)| {
+                        let crate_name = &lib.metadata.get_root().name().as_str();
+                        match (&lib.source.dylib, &lib.source.rlib) {
+                            (Some((pd, _)), Some((pr, _))) => Some(format!(
+                                "\ncrate `{}`: {}\n{:>padding$}",
+                                crate_name,
+                                pd.display(),
+                                pr.display(),
+                                padding = 8 + crate_name.len()
+                            )),
+                            (Some((p, _)), None) | (None, Some((p, _))) => {
+                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
+                            }
+                            (None, None) => None,
+                        }
+                    })
+                    .collect::<String>();
+                err.note(&format!("candidates:{}", candidates));
+                err
+            }
+            CrateError::SymbolConflictsCurrent(root_name) => struct_span_err!(
+                sess,
+                span,
+                E0519,
+                "the current crate is indistinguishable from one of its dependencies: it has the \
+                 same crate-name `{}` and was compiled with the same `-C metadata` arguments. \
+                 This will result in symbol conflicts between the two.",
+                root_name,
+            ),
+            CrateError::SymbolConflictsOthers(root_name) => struct_span_err!(
+                sess,
+                span,
+                E0523,
+                "found two different crates with name `{}` that are not distinguished by differing \
+                 `-C metadata`. This will result in symbol conflicts between the two.",
+                root_name,
+            ),
+            CrateError::DlOpen(s) | CrateError::DlSym(s) => sess.struct_span_err(span, &s),
+            CrateError::LocatorCombined(locator) => {
+                let crate_name = locator.crate_name;
+                let add = match &locator.root {
+                    None => String::new(),
+                    Some(r) => format!(" which `{}` depends on", r.name),
+                };
+                let mut msg = "the following crate versions were found:".to_string();
+                let mut err = if !locator.rejected_via_hash.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0460,
+                        "found possibly newer version of crate `{}`{}",
+                        crate_name,
+                        add,
+                    );
+                    err.note("perhaps that crate needs to be recompiled?");
+                    let mismatches = locator.rejected_via_hash.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                    }
+                    if let Some(r) = locator.root {
+                        for path in r.source.paths() {
+                            msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
+                        }
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_triple.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0461,
+                        "couldn't find crate `{}` with expected target triple {}{}",
+                        crate_name,
+                        locator.triple,
+                        add,
+                    );
+                    let mismatches = locator.rejected_via_triple.iter();
+                    for CrateMismatch { path, got } in mismatches {
+                        msg.push_str(&format!(
+                            "\ncrate `{}`, target triple {}: {}",
+                            crate_name,
+                            got,
+                            path.display(),
+                        ));
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_kind.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0462,
+                        "found staticlib `{}` instead of rlib or dylib{}",
+                        crate_name,
+                        add,
+                    );
+                    err.help("please recompile that crate using --crate-type lib");
+                    let mismatches = locator.rejected_via_kind.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
+                    }
+                    err.note(&msg);
+                    err
+                } else if !locator.rejected_via_version.is_empty() {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0514,
+                        "found crate `{}` compiled by an incompatible version of rustc{}",
+                        crate_name,
+                        add,
+                    );
+                    err.help(&format!(
+                        "please recompile that crate using this compiler ({})",
+                        rustc_version(),
+                    ));
+                    let mismatches = locator.rejected_via_version.iter();
+                    for CrateMismatch { path, got } in mismatches {
+                        msg.push_str(&format!(
+                            "\ncrate `{}` compiled by {}: {}",
+                            crate_name,
+                            got,
+                            path.display(),
+                        ));
+                    }
+                    err.note(&msg);
+                    err
+                } else {
+                    let mut err = struct_span_err!(
+                        sess,
+                        span,
+                        E0463,
+                        "can't find crate for `{}`{}",
+                        crate_name,
+                        add,
+                    );
+
+                    if (crate_name == sym::std || crate_name == sym::core)
+                        && locator.triple != TargetTriple::from_triple(config::host_triple())
+                    {
+                        err.note(&format!("the `{}` target may not be installed", locator.triple));
+                    } else if crate_name == sym::profiler_builtins {
+                        err.note(&"the compiler may have been built without the profiler runtime");
+                    }
+                    err.span_label(span, "can't find crate");
+                    err
+                };
+
+                if !locator.rejected_via_filename.is_empty() {
+                    let mismatches = locator.rejected_via_filename.iter();
+                    for CrateMismatch { path, .. } in mismatches {
+                        err.note(&format!(
+                            "extern location for {} is of an unknown type: {}",
+                            crate_name,
+                            path.display(),
+                        ))
+                        .help(&format!(
+                            "file name should be lib*.rlib or {}*.{}",
+                            locator.dll_prefix, locator.dll_suffix
+                        ));
+                    }
+                }
+                err
+            }
+            CrateError::NonDylibPlugin(crate_name) => struct_span_err!(
+                sess,
+                span,
+                E0457,
+                "plugin `{}` only found in rlib format, but must be available in dylib format",
+                crate_name,
+            ),
+        };
+
+        err.emit();
+        sess.abort_if_errors();
+        unreachable!();
+    }
+}
index 201a32d387779bc31084052007d0e86dc77394cc..be153758a2a0c0d0e76e2a1bb676148ef7388d2d 100644 (file)
@@ -111,8 +111,8 @@ fn into_args(self) -> (DefId, DefId) {
             bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
         })
     }
-    optimized_mir => { cdata.get_optimized_mir(tcx, def_id.index) }
-    promoted_mir => { cdata.get_promoted_mir(tcx, def_id.index) }
+    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) }
     fn_sig => { cdata.fn_sig(def_id.index, tcx) }
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
index fb4fee402abfb341b7de27d5e5263efba2673063..a8c46d3e32e6a7fedc2ed9dd11a5bd03b00641f7 100644 (file)
@@ -558,7 +558,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
         // Encode exported symbols info. This is prefetched in `encode_metadata` so we encode
         // this late to give the prefetching as much time as possible to complete.
         i = self.position();
-        let exported_symbols = self.tcx.exported_symbols(LOCAL_CRATE);
+        let exported_symbols = tcx.exported_symbols(LOCAL_CRATE);
         let exported_symbols = self.encode_exported_symbols(&exported_symbols);
         let exported_symbols_bytes = self.position() - i;
 
@@ -622,7 +622,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
 
         let total_bytes = self.position();
 
-        if self.tcx.sess.meta_stats() {
+        if tcx.sess.meta_stats() {
             let mut zero_bytes = 0;
             for e in self.opaque.data.iter() {
                 if *e == 0 {
@@ -1369,9 +1369,9 @@ fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
         debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
 
         // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
-        // including on the signature, which is inferred in `typeck_tables_of.
+        // including on the signature, which is inferred in `typeck.
         let hir_id = self.tcx.hir().as_local_hir_id(def_id);
-        let ty = self.tcx.typeck_tables_of(def_id).node_type(hir_id);
+        let ty = self.tcx.typeck(def_id).node_type(hir_id);
 
         record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind {
             ty::Generator(..) => {
@@ -1541,7 +1541,7 @@ fn encode_exported_symbols(
     ) -> 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));
+        let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx));
 
         self.lazy(
             exported_symbols
index 4f1889aeb162a4a4cc6b2824bdf5034a1ea86557..f2259e5e9f857bece5a479903f03b361cf0ccb45 100644 (file)
@@ -14,7 +14,37 @@ macro_rules! arena_types {
             [] layouts: rustc_target::abi::Layout, rustc_target::abi::Layout;
             // AdtDef are interned and compared by address
             [] adt_def: rustc_middle::ty::AdtDef, rustc_middle::ty::AdtDef;
-            [decode] tables: rustc_middle::ty::TypeckTables<$tcx>, rustc_middle::ty::TypeckTables<'_x>;
+            [] steal_mir:
+                rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>,
+                rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>;
+            [decode] mir: rustc_middle::mir::Body<$tcx>, rustc_middle::mir::Body<'_x>;
+            [] steal_promoted:
+                rustc_middle::ty::steal::Steal<
+                    rustc_index::vec::IndexVec<
+                        rustc_middle::mir::Promoted,
+                        rustc_middle::mir::Body<$tcx>
+                    >
+                >,
+                rustc_middle::ty::steal::Steal<
+                    rustc_index::vec::IndexVec<
+                        rustc_middle::mir::Promoted,
+                        rustc_middle::mir::Body<$tcx>
+                    >
+                >;
+            [decode] promoted:
+                rustc_index::vec::IndexVec<
+                    rustc_middle::mir::Promoted,
+                    rustc_middle::mir::Body<$tcx>
+                >,
+                rustc_index::vec::IndexVec<
+                    rustc_middle::mir::Promoted,
+                    rustc_middle::mir::Body<'_x>
+                >;
+            [decode] typeck_results: rustc_middle::ty::TypeckResults<$tcx>, rustc_middle::ty::TypeckResults<'_x>;
+            [decode] borrowck_result:
+                rustc_middle::mir::BorrowCheckResult<$tcx>,
+                rustc_middle::mir::BorrowCheckResult<'_x>;
+            [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, rustc_middle::mir::UnsafetyCheckResult;
             [] const_allocs: rustc_middle::mir::interpret::Allocation, rustc_middle::mir::interpret::Allocation;
             // Required for the incremental on-disk cache
             [few, decode] mir_keys: rustc_hir::def_id::DefIdSet, rustc_hir::def_id::DefIdSet;
index b14f17dee60603f4340116a64edd286038525ef7..98eed4045a34ad6d32443b359fb57511fe17cef4 100644 (file)
@@ -1,7 +1,9 @@
 //! This module defines the `DepNode` type which the compiler uses to represent
-//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which
+//! nodes in the dependency graph.
+//!
+//! A `DepNode` consists of a `DepKind` (which
 //! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
-//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which
+//! and a `Fingerprint`, a 128-bit hash value the exact meaning of which
 //! depends on the node's `DepKind`. Together, the kind and the fingerprint
 //! fully identify a dependency node, even across multiple compilation sessions.
 //! In other words, the value of the fingerprint does not depend on anything
@@ -11,9 +13,9 @@
 //! uniquely identify a given commit and has a few advantages:
 //!
 //! * A `DepNode` can simply be serialized to disk and loaded in another session
-//!   without the need to do any "rebasing (like we have to do for Spans and
-//!   NodeIds) or "retracing" like we had to do for `DefId` in earlier
-//!   implementations of the dependency graph.
+//!   without the need to do any "rebasing" (like we have to do for Spans and
+//!   NodeIds) or "retracing" (like we had to do for `DefId` in earlier
+//!   implementations of the dependency graph).
 //! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to
 //!   implement `Copy`, `Sync`, `Send`, `Freeze`, etc.
 //! * Since we just have a bit pattern, `DepNode` can be mapped from disk into
@@ -42,7 +44,7 @@
 //!   `DefId` it was computed from. In other cases, too much information gets
 //!   lost during fingerprint computation.
 //!
-//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only
+//! The `DepConstructor` enum, together with `DepNode::new()`, ensures that only
 //! valid `DepNode` instances can be constructed. For example, the API does not
 //! allow for constructing parameterless `DepNode`s with anything other
 //! than a zeroed out fingerprint. More generally speaking, it relieves the
index 485f9b7ce8a6c204e37933ab83e33cfc386dd6b1..b014f3c8eb7949635854fa1618581e7e5b4a660a 100644 (file)
@@ -4,6 +4,7 @@
 
 pub mod exports;
 pub mod map;
+pub mod place;
 
 use crate::ich::StableHashingContext;
 use crate::ty::query::Providers;
diff --git a/src/librustc_middle/hir/place.rs b/src/librustc_middle/hir/place.rs
new file mode 100644 (file)
index 0000000..d85165b
--- /dev/null
@@ -0,0 +1,115 @@
+use crate::ty;
+use crate::ty::Ty;
+
+use rustc_hir::HirId;
+use rustc_target::abi::VariantIdx;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+pub enum PlaceBase {
+    /// A temporary variable
+    Rvalue,
+    /// A named `static` item
+    StaticItem,
+    /// A named local variable
+    Local(HirId),
+    /// An upvar referenced by closure env
+    Upvar(ty::UpvarId),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+pub enum ProjectionKind {
+    /// A dereference of a pointer, reference or `Box<T>` of the given type
+    Deref,
+
+    /// `B.F` where `B` is the base expression and `F` is
+    /// the field. The field is identified by which variant
+    /// it appears in along with a field index. The variant
+    /// is used for enums.
+    Field(u32, VariantIdx),
+
+    /// Some index like `B[x]`, where `B` is the base
+    /// expression. We don't preserve the index `x` because
+    /// we won't need it.
+    Index,
+
+    /// A subslice covering a range of values like `B[x..y]`.
+    Subslice,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+pub struct Projection<'tcx> {
+    /// Type after the projection is being applied.
+    pub ty: Ty<'tcx>,
+
+    /// Defines the type of access
+    pub kind: ProjectionKind,
+}
+
+/// A `Place` represents how a value is located in memory.
+///
+/// This is an HIR version of `mir::Place`
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+pub struct Place<'tcx> {
+    /// The type of the `PlaceBase`
+    pub base_ty: Ty<'tcx>,
+    /// The "outermost" place that holds this value.
+    pub base: PlaceBase,
+    /// How this place is derived from the base place.
+    pub projections: Vec<Projection<'tcx>>,
+}
+
+/// A `PlaceWithHirId` represents how a value is located in memory.
+///
+/// This is an HIR version of `mir::Place`
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+pub struct PlaceWithHirId<'tcx> {
+    /// `HirId` of the expression or pattern producing this value.
+    pub hir_id: HirId,
+
+    /// Information about the `Place`
+    pub place: Place<'tcx>,
+}
+
+impl<'tcx> PlaceWithHirId<'tcx> {
+    pub fn new(
+        hir_id: HirId,
+        base_ty: Ty<'tcx>,
+        base: PlaceBase,
+        projections: Vec<Projection<'tcx>>,
+    ) -> PlaceWithHirId<'tcx> {
+        PlaceWithHirId {
+            hir_id: hir_id,
+            place: Place { base_ty: base_ty, base: base, projections: projections },
+        }
+    }
+}
+
+impl<'tcx> Place<'tcx> {
+    /// Returns an iterator of the types that have to be dereferenced to access
+    /// the `Place`.
+    ///
+    /// The types are in the reverse order that they are applied. So if
+    /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
+    ///`*const u32` then `&*const u32`.
+    pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
+        self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
+            if ProjectionKind::Deref == proj.kind {
+                Some(self.ty_before_projection(index))
+            } else {
+                None
+            }
+        })
+    }
+
+    /// Returns the type of this `Place` after all projections have been applied.
+    pub fn ty(&self) -> Ty<'tcx> {
+        self.projections.last().map_or_else(|| self.base_ty, |proj| proj.ty)
+    }
+
+    /// Returns the type of this `Place` immediately before `projection_index`th projection
+    /// is applied.
+    pub fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
+        assert!(projection_index < self.projections.len());
+        if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
+    }
+}
index c2b14cb2e8408cb66610f22d1593543383776a7d..a68301385b7a5b5a983609f57ce7d4057a438ebf 100644 (file)
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
+#![feature(cmp_min_max_by)]
 #![feature(const_fn)]
 #![feature(const_panic)]
-#![cfg_attr(not(bootstrap), feature(const_fn_transmute))]
+#![feature(const_fn_transmute)]
 #![feature(core_intrinsics)]
 #![feature(discriminant_kind)]
 #![feature(drain_filter)]
@@ -42,7 +42,6 @@
 #![feature(or_patterns)]
 #![feature(range_is_empty)]
 #![feature(min_specialization)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![feature(trusted_len)]
 #![feature(stmt_expr_attributes)]
 #![feature(test)]
index 1f4318fa537514bf33c0726f49e4db3bb188440a..569af70c5b5fc5063290ad4678bcb846317b7d54 100644 (file)
@@ -26,13 +26,13 @@ pub enum ExportedSymbol<'tcx> {
     NonGeneric(DefId),
     Generic(DefId, SubstsRef<'tcx>),
     DropGlue(Ty<'tcx>),
-    NoDefId(ty::SymbolName),
+    NoDefId(ty::SymbolName<'tcx>),
 }
 
 impl<'tcx> ExportedSymbol<'tcx> {
     /// This is the symbol name of an instance if it is instantiated in the
     /// local crate.
-    pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName {
+    pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName<'tcx> {
         match *self {
             ExportedSymbol::NonGeneric(def_id) => tcx.symbol_name(ty::Instance::mono(tcx, def_id)),
             ExportedSymbol::Generic(def_id, substs) => {
index 327f321bd7534d8eb02ba7890bdac3b30a11cb7c..1e06dadfa24532bbc5f3651679c4c57c3b9d21c6 100644 (file)
@@ -2,9 +2,10 @@
 
 /// Positional arguments to `libcore::count_code_region()`
 pub mod count_code_region_args {
-    pub const COUNTER_INDEX: usize = 0;
-    pub const START_BYTE_POS: usize = 1;
-    pub const END_BYTE_POS: usize = 2;
+    pub const FUNCTION_SOURCE_HASH: usize = 0;
+    pub const COUNTER_INDEX: usize = 1;
+    pub const START_BYTE_POS: usize = 2;
+    pub const END_BYTE_POS: usize = 3;
 }
 
 /// Positional arguments to `libcore::coverage_counter_add()` and
index a7953f0f900fb583fa243370a01a7ef94a099f7c..d7c0be058599fbbecec245afbcc92dc4c388aa73 100644 (file)
@@ -34,12 +34,12 @@ pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> {
     pub fn const_eval_resolve(
         self,
         param_env: ty::ParamEnv<'tcx>,
-        def_id: DefId,
+        def: ty::WithOptConstParam<DefId>,
         substs: SubstsRef<'tcx>,
         promoted: Option<mir::Promoted>,
         span: Option<Span>,
     ) -> ConstEvalResult<'tcx> {
-        match ty::Instance::resolve(self, param_env, def_id, substs) {
+        match ty::Instance::resolve_opt_const_arg(self, param_env, def, substs) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted };
                 self.const_eval_global_id(param_env, cid, span)
index 0e913ff58bb4af72999bd8c37142b6909b3ebd0a..ba2a2bd8a026f19550bf7309cb09c2eedf1f84c9 100644 (file)
@@ -60,6 +60,18 @@ pub fn try_to_bits(&self, size: Size) -> Option<u128> {
         self.try_to_scalar()?.to_bits(size).ok()
     }
 
+    pub fn try_to_bool(&self) -> Option<bool> {
+        match self.try_to_bits(Size::from_bytes(1))? {
+            0 => Some(false),
+            1 => Some(true),
+            _ => None,
+        }
+    }
+
+    pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+        Some(self.try_to_bits(tcx.data_layout.pointer_size)? as u64)
+    }
+
     pub fn try_to_bits_for_ty(
         &self,
         tcx: TyCtxt<'tcx>,
index f1c1b962ab997fbbd698cd6380083aa851240444..1ad5008d28a987f264550781c599d21debf8bebb 100644 (file)
@@ -68,13 +68,13 @@ pub fn is_generic_fn(&self) -> bool {
         }
     }
 
-    pub fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> SymbolName {
+    pub fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> SymbolName<'tcx> {
         match *self {
             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);
-                SymbolName { name: Symbol::intern(&format!("global_asm_{:?}", def_id)) }
+                SymbolName::new(tcx, &format!("global_asm_{:?}", def_id))
             }
         }
     }
@@ -86,7 +86,7 @@ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
             .debugging_opts
             .inline_in_all_cgus
             .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
-            && !tcx.sess.opts.cg.link_dead_code;
+            && tcx.sess.opts.cg.link_dead_code != Some(true);
 
         match *self {
             MonoItem::Fn(ref instance) => {
@@ -335,9 +335,9 @@ pub fn items_in_deterministic_order(
         // The codegen tests rely on items being process in the same order as
         // they appear in the file, so for local items, we sort by node_id first
         #[derive(PartialEq, Eq, PartialOrd, Ord)]
-        pub struct ItemSortKey(Option<HirId>, SymbolName);
+        pub struct ItemSortKey<'tcx>(Option<HirId>, SymbolName<'tcx>);
 
-        fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey {
+        fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'tcx> {
             ItemSortKey(
                 match item {
                     MonoItem::Fn(ref instance) => {
@@ -346,8 +346,8 @@ fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey {
                             // instances into account. The others don't matter for
                             // the codegen tests and can even make item order
                             // unstable.
-                            InstanceDef::Item(def_id) => {
-                                def_id.as_local().map(|def_id| tcx.hir().as_local_hir_id(def_id))
+                            InstanceDef::Item(def) => {
+                                def.did.as_local().map(|def_id| tcx.hir().as_local_hir_id(def_id))
                             }
                             InstanceDef::VtableShim(..)
                             | InstanceDef::ReifyShim(..)
@@ -448,8 +448,7 @@ pub fn build_cgu_name<I, C, S>(
         if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
             cgu_name
         } else {
-            let cgu_name = &cgu_name.as_str();
-            Symbol::intern(&CodegenUnit::mangle_name(cgu_name))
+            Symbol::intern(&CodegenUnit::mangle_name(&cgu_name.as_str()))
         }
     }
 
index 8dddaf40c8264a12b7651def9b9764e00e8c9a45..6ce5d61fbed1b82dcd710540511f874d32e38dc0 100644 (file)
@@ -1,13 +1,14 @@
 //! Values computed by queries that use MIR.
 
-use crate::ty::{self, Ty};
+use crate::mir::{Body, Promoted};
+use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::bit_set::BitMatrix;
 use rustc_index::vec::IndexVec;
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 use smallvec::SmallVec;
 use std::cell::Cell;
@@ -17,7 +18,7 @@
 
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub enum UnsafetyViolationKind {
-    /// Only permitted in regular `fn`s, prohibitted in `const fn`s.
+    /// Only permitted in regular `fn`s, prohibited in `const fn`s.
     General,
     /// Permitted both in `const fn`s and regular `fn`s.
     GeneralAndConstFn,
@@ -34,13 +35,97 @@ pub enum UnsafetyViolationKind {
     UnsafeFnBorrowPacked,
 }
 
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+pub enum UnsafetyViolationDetails {
+    CallToUnsafeFunction,
+    UseOfInlineAssembly,
+    InitializingTypeWith,
+    CastOfPointerToInt,
+    BorrowOfPackedField,
+    UseOfMutableStatic,
+    UseOfExternStatic,
+    DerefOfRawPointer,
+    AssignToNonCopyUnionField,
+    AccessToUnionField,
+    MutationOfLayoutConstrainedField,
+    BorrowOfLayoutConstrainedField,
+    CallToFunctionWith,
+}
+
+impl UnsafetyViolationDetails {
+    pub fn description_and_note(&self) -> (&'static str, &'static str) {
+        use UnsafetyViolationDetails::*;
+        match self {
+            CallToUnsafeFunction => (
+                "call to unsafe function",
+                "consult the function's documentation for information on how to avoid undefined \
+                 behavior",
+            ),
+            UseOfInlineAssembly => (
+                "use of inline assembly",
+                "inline assembly is entirely unchecked and can cause undefined behavior",
+            ),
+            InitializingTypeWith => (
+                "initializing type with `rustc_layout_scalar_valid_range` attr",
+                "initializing a layout restricted type's field with a value outside the valid \
+                 range is undefined behavior",
+            ),
+            CastOfPointerToInt => {
+                ("cast of pointer to int", "casting pointers to integers in constants")
+            }
+            BorrowOfPackedField => (
+                "borrow of packed field",
+                "fields of packed structs might be misaligned: dereferencing a misaligned pointer \
+                 or even just creating a misaligned reference is undefined behavior",
+            ),
+            UseOfMutableStatic => (
+                "use of mutable static",
+                "mutable statics can be mutated by multiple threads: aliasing violations or data \
+                 races will cause undefined behavior",
+            ),
+            UseOfExternStatic => (
+                "use of extern static",
+                "extern statics are not controlled by the Rust type system: invalid data, \
+                 aliasing violations or data races will cause undefined behavior",
+            ),
+            DerefOfRawPointer => (
+                "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",
+            ),
+            AssignToNonCopyUnionField => (
+                "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",
+            ),
+            AccessToUnionField => (
+                "access to union field",
+                "the field may not be properly initialized: using uninitialized data will cause \
+                 undefined behavior",
+            ),
+            MutationOfLayoutConstrainedField => (
+                "mutation of layout constrained field",
+                "mutating layout constrained fields cannot statically be checked for valid values",
+            ),
+            BorrowOfLayoutConstrainedField => (
+                "borrow of layout constrained field with interior mutability",
+                "references to fields of layout constrained fields lose the constraints. Coupled \
+                 with interior mutability, the field can be changed to invalid values",
+            ),
+            CallToFunctionWith => (
+                "call to function with `#[target_feature]`",
+                "can only be called if the required target features are available",
+            ),
+        }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UnsafetyViolation {
     pub source_info: SourceInfo,
     pub lint_root: hir::HirId,
-    pub description: Symbol,
-    pub details: Symbol,
     pub kind: UnsafetyViolationKind,
+    pub details: UnsafetyViolationDetails,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
@@ -138,7 +223,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[derive(Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct BorrowCheckResult<'tcx> {
     /// All the opaque types that are restricted to concrete types
-    /// by this function. Unlike the value in `TypeckTables`, this has
+    /// by this function. Unlike the value in `TypeckResults`, this has
     /// unerased regions.
     pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
     pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
@@ -315,11 +400,44 @@ pub struct DestructuredConst<'tcx> {
 /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct CoverageInfo {
-    /// A hash value that can be used by the consumer of the coverage profile data to detect
-    /// changes to the instrumented source of the associated MIR body (typically, for an
-    /// individual function).
-    pub hash: u64,
-
     /// The total number of coverage region counters added to the MIR `Body`.
     pub num_counters: u32,
+
+    /// The total number of coverage region counter expressions added to the MIR `Body`.
+    pub num_expressions: u32,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    pub fn mir_borrowck_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<LocalDefId>,
+    ) -> &'tcx BorrowCheckResult<'tcx> {
+        if let Some(param_did) = def.const_param_did {
+            self.mir_borrowck_const_arg((def.did, param_did))
+        } else {
+            self.mir_borrowck(def.did)
+        }
+    }
+
+    pub fn mir_const_qualif_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<LocalDefId>,
+    ) -> ConstQualifs {
+        if let Some(param_did) = def.const_param_did {
+            self.mir_const_qualif_const_arg((def.did, param_did))
+        } else {
+            self.mir_const_qualif(def.did)
+        }
+    }
+
+    pub fn promoted_mir_of_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<DefId>,
+    ) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.promoted_mir_of_const_arg((did, param_did))
+        } else {
+            self.promoted_mir(def.did)
+        }
+    }
 }
index ed8129b1e09a5eacd0302fb94ddd9fa86d9b7ea2..36e277d1a88f3d3e4a49504ee92b4fe173b136eb 100644 (file)
@@ -292,3 +292,20 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 }
 
 impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {}
+
+/// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular
+/// order.
+///
+/// This is clearer than writing `preorder` in cases where the order doesn't matter.
+pub fn reachable<'a, 'tcx>(
+    body: &'a Body<'tcx>,
+) -> impl 'a + Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> {
+    preorder(body)
+}
+
+/// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
+pub fn reachable_as_bitset(body: &Body<'tcx>) -> BitSet<BasicBlock> {
+    let mut iter = preorder(body);
+    (&mut iter).for_each(drop);
+    iter.visited
+}
index 0faf389aa385c617337be26b3ba4a19ec89ee97f..4dd8723bd72a11d4dc4069e0c8036c41b472db8b 100644 (file)
@@ -89,6 +89,25 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
         }
 
+        /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
+        /// const argument and returns `None` otherwise.
+        ///
+        /// ```rust
+        /// let a = foo::<7>();
+        /// //            ^ Calling `opt_const_param_of` for this argument,
+        ///
+        /// fn foo<const N: usize>()
+        /// //           ^ returns this `DefId`.
+        ///
+        /// fn bar() {
+        /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
+        /// }
+        /// ```
+        query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
+            desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
+            // FIXME(#74113): consider storing this query on disk.
+        }
+
         /// Records the type of every item.
         query type_of(key: DefId) -> Ty<'tcx> {
             desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
@@ -189,47 +208,66 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
             cache_on_disk_if { key.is_local() }
         }
+        query mir_const_qualif_const_arg(
+            key: (LocalDefId, DefId)
+        ) -> mir::ConstQualifs {
+            desc {
+                |tcx| "const checking the const argument `{}`",
+                tcx.def_path_str(key.0.to_def_id())
+            }
+        }
 
         /// Fetch the MIR for a given `DefId` right after it's built - this includes
         /// unreachable code.
-        query mir_built(key: LocalDefId) -> Steal<mir::Body<'tcx>> {
-            storage(ArenaCacheSelector<'tcx>)
-            desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.to_def_id()) }
+        query mir_built(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+            desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
         /// Fetch the MIR for a given `DefId` up till the point where it is
         /// ready for const qualification.
         ///
         /// See the README for the `mir` module for details.
-        query mir_const(key: DefId) -> Steal<mir::Body<'tcx>> {
-            desc { |tcx| "processing MIR for `{}`", tcx.def_path_str(key)  }
-            storage(ArenaCacheSelector<'tcx>)
+        query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+            desc {
+                |tcx| "processing MIR for {}`{}`",
+                if key.const_param_did.is_some() { "the const argument " } else { "" },
+                tcx.def_path_str(key.did.to_def_id()),
+            }
             no_hash
         }
 
-        query mir_drops_elaborated_and_const_checked(key: LocalDefId) -> Steal<mir::Body<'tcx>> {
-            storage(ArenaCacheSelector<'tcx>)
+        query mir_drops_elaborated_and_const_checked(
+            key: ty::WithOptConstParam<LocalDefId>
+        ) -> &'tcx Steal<mir::Body<'tcx>> {
             no_hash
-            desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.to_def_id()) }
+            desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
-        query mir_validated(key: LocalDefId) ->
+        query mir_validated(key: ty::WithOptConstParam<LocalDefId>) ->
             (
-                Steal<mir::Body<'tcx>>,
-                Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
+                &'tcx Steal<mir::Body<'tcx>>,
+                &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
             ) {
-            storage(ArenaCacheSelector<'tcx>)
             no_hash
-            desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
+            desc {
+                |tcx| "processing {}`{}`",
+                if key.const_param_did.is_some() { "the const argument " } else { "" },
+                tcx.def_path_str(key.did.to_def_id()),
+            }
         }
 
         /// MIR after our optimization passes have run. This is MIR that is ready
         /// for codegen. This is also the only query that can fetch non-local MIR, at present.
-        query optimized_mir(key: DefId) -> mir::Body<'tcx> {
+        query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
             desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
-            storage(ArenaCacheSelector<'tcx>)
             cache_on_disk_if { key.is_local() }
         }
+        query optimized_mir_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
+            desc {
+                |tcx| "optimizing MIR for the const argument `{}`",
+                tcx.def_path_str(key.0.to_def_id())
+            }
+        }
 
         /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
         /// MIR pass (assuming the -Zinstrument-coverage option is enabled).
@@ -239,11 +277,18 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             cache_on_disk_if { key.is_local() }
         }
 
-        query promoted_mir(key: DefId) -> IndexVec<mir::Promoted, mir::Body<'tcx>> {
+        query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
             desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
-            storage(ArenaCacheSelector<'tcx>)
             cache_on_disk_if { key.is_local() }
         }
+        query promoted_mir_of_const_arg(
+            key: (LocalDefId, DefId)
+        ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
+            desc {
+                |tcx| "optimizing promoted MIR for the const argument `{}`",
+                tcx.def_path_str(key.0.to_def_id()),
+            }
+        }
     }
 
     TypeChecking {
@@ -451,11 +496,16 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     }
 
     TypeChecking {
-        /// The result of unsafety-checking this `DefId`.
-        query unsafety_check_result(key: LocalDefId) -> mir::UnsafetyCheckResult {
+        /// The result of unsafety-checking this `LocalDefId`.
+        query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
             desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
             cache_on_disk_if { true }
-            storage(ArenaCacheSelector<'tcx>)
+        }
+        query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult {
+            desc {
+                |tcx| "unsafety-checking the const argument `{}`",
+                tcx.def_path_str(key.0.to_def_id())
+            }
         }
 
         /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error.
@@ -533,19 +583,27 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
             desc { "type-checking all item bodies" }
         }
 
-        query typeck_tables_of(key: LocalDefId) -> &'tcx ty::TypeckTables<'tcx> {
+        query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
             desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
             cache_on_disk_if { true }
         }
-        query diagnostic_only_typeck_tables_of(key: LocalDefId) -> &'tcx ty::TypeckTables<'tcx> {
+        query typeck_const_arg(
+            key: (LocalDefId, DefId)
+        ) -> &'tcx ty::TypeckResults<'tcx> {
+            desc {
+                |tcx| "type-checking the const argument `{}`",
+                tcx.def_path_str(key.0.to_def_id()),
+            }
+        }
+        query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
             desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
             cache_on_disk_if { true }
             load_cached(tcx, id) {
-                let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx
+                let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
                     .queries.on_disk_cache
                     .try_load_query_result(tcx, id);
 
-                typeck_tables.map(|x| &*tcx.arena.alloc(x))
+                typeck_results.map(|x| &*tcx.arena.alloc(x))
             }
         }
     }
@@ -558,7 +616,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     }
 
     TypeChecking {
-        query has_typeck_tables(def_id: DefId) -> bool {
+        query has_typeck_results(def_id: DefId) -> bool {
             desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) }
         }
 
@@ -570,14 +628,19 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     BorrowChecking {
         /// Borrow-checks the function body. If this is a closure, returns
         /// additional requirements that the closure's creator must verify.
-        query mir_borrowck(key: LocalDefId) -> mir::BorrowCheckResult<'tcx> {
-            storage(ArenaCacheSelector<'tcx>)
+        query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
             desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
             cache_on_disk_if(tcx, opt_result) {
                 tcx.is_closure(key.to_def_id())
                     || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
             }
         }
+        query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
+            desc {
+                |tcx| "borrow-checking the const argument`{}`",
+                tcx.def_path_str(key.0.to_def_id())
+            }
+        }
     }
 
     TypeChecking {
@@ -691,7 +754,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
         /// The `symbol_name` query provides the symbol name for calling a
         /// given instance from the local crate. In particular, it will also
         /// look up the correct symbol name of instances from upstream crates.
-        query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName {
+        query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName<'tcx> {
             desc { "computing the symbol for `{}`", key }
             cache_on_disk_if { true }
         }
@@ -1444,5 +1507,14 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
         ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
             desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
         }
+
+        query resolve_instance_of_const_arg(
+            key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>
+        ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
+            desc {
+                "resolving instance of the const argument `{}`",
+                ty::Instance::new(key.value.0.to_def_id(), key.value.2),
+            }
+        }
     }
 }
index fc37cb2504daaceff8bb7539ff2fb27239a754cf..c15c31a53f0c9fefafb2f06bdf6d086e95c08488 100644 (file)
@@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> {
     /// Type of each variable must be `Sized`.
     VariableType(hir::HirId),
     /// Argument type must be `Sized`.
-    SizedArgumentType,
+    SizedArgumentType(Option<Span>),
     /// Return type must be `Sized`.
     SizedReturnType,
     /// Yield type must be `Sized`.
@@ -229,6 +229,7 @@ pub enum ObligationCauseCode<'tcx> {
     /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
     FieldSized {
         adt_kind: AdtKind,
+        span: Span,
         last: bool,
     },
 
index faaa576f17903d5187bebb574723b1956a57880a..334462790edbcc5a2f03c2de543fcdf9148d0065 100644 (file)
@@ -151,12 +151,14 @@ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
             super::VariableType(id) => Some(super::VariableType(id)),
             super::ReturnValue(id) => Some(super::ReturnValue(id)),
             super::ReturnType => Some(super::ReturnType),
-            super::SizedArgumentType => Some(super::SizedArgumentType),
+            super::SizedArgumentType(sp) => Some(super::SizedArgumentType(sp)),
             super::SizedReturnType => Some(super::SizedReturnType),
             super::SizedYieldType => Some(super::SizedYieldType),
             super::InlineAsmSized => Some(super::InlineAsmSized),
             super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
-            super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
+            super::FieldSized { adt_kind, span, last } => {
+                Some(super::FieldSized { adt_kind, span, last })
+            }
             super::ConstSized => Some(super::ConstSized),
             super::ConstPatternStructural => Some(super::ConstPatternStructural),
             super::SharedStatic => Some(super::SharedStatic),
index 67ceaca103e9f172333b2f34a74bad96d067d64d..a7c7b16048039386290eef78c30dffe041f5074c 100644 (file)
@@ -262,6 +262,14 @@ pub fn decode_adt_def<D>(decoder: &mut D) -> Result<&'tcx ty::AdtDef, D::Error>
     Ok(decoder.tcx().adt_def(def_id))
 }
 
+#[inline]
+pub fn decode_symbol_name<D>(decoder: &mut D) -> Result<ty::SymbolName<'tcx>, D::Error>
+where
+    D: TyDecoder<'tcx>,
+{
+    Ok(ty::SymbolName::new(decoder.tcx(), &decoder.read_str()?))
+}
+
 #[inline]
 pub fn decode_existential_predicate_slice<D>(
     decoder: &mut D,
@@ -504,6 +512,13 @@ fn specialized_decode(&mut self) -> Result<&'_x ty::AdtDef, Self::Error> {
                 }
             }
 
+            impl<'_x, $($typaram),*> SpecializedDecoder<ty::SymbolName<'_x>>
+            for $DecoderName<$($typaram),*> {
+                fn specialized_decode(&mut self) -> Result<ty::SymbolName<'_x>, Self::Error> {
+                    unsafe { transmute(decode_symbol_name(self)) }
+                }
+            }
+
             impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x ty::List<ty::ExistentialPredicate<'_y>>>
             for $DecoderName<$($typaram),*>
             where &'_x ty::List<ty::ExistentialPredicate<'_y>>: UseSpecializedDecodable {
index ced0429deab934736c835b16d8f14220815424cb..f3a863c3fce62f5046603f282a153a21597d6623 100644 (file)
-use crate::mir::interpret::truncate;
-use rustc_target::abi::Size;
-
-#[derive(Copy, Clone)]
-/// A type for representing any integer. Only used for printing.
-// FIXME: Use this for the integer-tree representation needed for type level ints and
-// const generics?
-pub struct ConstInt {
-    /// Number of bytes of the integer. Only 1, 2, 4, 8, 16 are legal values.
-    size: u8,
-    /// Whether the value is of a signed integer type.
-    signed: bool,
-    /// Whether the value is a `usize` or `isize` type.
-    is_ptr_sized_integral: bool,
-    /// Raw memory of the integer. All bytes beyond the `size` are unused and must be zero.
-    raw: u128,
+use crate::mir::interpret::ConstValue;
+use crate::mir::interpret::{LitToConstInput, Scalar};
+use crate::ty::subst::InternalSubsts;
+use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{ParamEnv, ParamEnvAnd};
+use rustc_errors::ErrorReported;
+use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
+use rustc_macros::HashStable;
+
+mod int;
+mod kind;
+
+pub use int::*;
+pub use kind::*;
+
+/// Typed constant value.
+#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(HashStable)]
+pub struct Const<'tcx> {
+    pub ty: Ty<'tcx>,
+
+    pub val: ConstKind<'tcx>,
 }
 
-impl ConstInt {
-    pub fn new(raw: u128, size: Size, signed: bool, is_ptr_sized_integral: bool) -> Self {
-        assert!(raw <= truncate(u128::MAX, size));
-        Self { raw, size: size.bytes() as u8, signed, is_ptr_sized_integral }
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(Const<'_>, 48);
+
+impl<'tcx> Const<'tcx> {
+    /// Literals and const generic parameters are eagerly converted to a constant, everything else
+    /// becomes `Unevaluated`.
+    pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+        Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
     }
-}
 
-impl std::fmt::Debug for ConstInt {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let Self { size, signed, raw, is_ptr_sized_integral } = *self;
-        if signed {
-            let bit_size = size * 8;
-            let min = 1u128 << (bit_size - 1);
-            let max = min - 1;
-            if raw == min {
-                match (size, is_ptr_sized_integral) {
-                    (_, true) => write!(fmt, "isize::MIN"),
-                    (1, _) => write!(fmt, "i8::MIN"),
-                    (2, _) => write!(fmt, "i16::MIN"),
-                    (4, _) => write!(fmt, "i32::MIN"),
-                    (8, _) => write!(fmt, "i64::MIN"),
-                    (16, _) => write!(fmt, "i128::MIN"),
-                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
-                }
-            } else if raw == max {
-                match (size, is_ptr_sized_integral) {
-                    (_, true) => write!(fmt, "isize::MAX"),
-                    (1, _) => write!(fmt, "i8::MAX"),
-                    (2, _) => write!(fmt, "i16::MAX"),
-                    (4, _) => write!(fmt, "i32::MAX"),
-                    (8, _) => write!(fmt, "i64::MAX"),
-                    (16, _) => write!(fmt, "i128::MAX"),
-                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+    pub fn from_opt_const_arg_anon_const(
+        tcx: TyCtxt<'tcx>,
+        def: ty::WithOptConstParam<LocalDefId>,
+    ) -> &'tcx Self {
+        debug!("Const::from_anon_const(def={:?})", def);
+
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+
+        let body_id = match tcx.hir().get(hir_id) {
+            hir::Node::AnonConst(ac) => ac.body,
+            _ => span_bug!(
+                tcx.def_span(def.did.to_def_id()),
+                "from_anon_const can only process anonymous constants"
+            ),
+        };
+
+        let expr = &tcx.hir().body(body_id).value;
+
+        let ty = tcx.type_of(def.def_id_for_type_of());
+
+        let lit_input = match expr.kind {
+            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
+                hir::ExprKind::Lit(ref lit) => {
+                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
                 }
+                _ => None,
+            },
+            _ => None,
+        };
+
+        if let Some(lit_input) = lit_input {
+            // If an error occurred, ignore that it's a literal and leave reporting the error up to
+            // mir.
+            if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
+                return c;
             } else {
-                match size {
-                    1 => write!(fmt, "{}", raw as i8)?,
-                    2 => write!(fmt, "{}", raw as i16)?,
-                    4 => write!(fmt, "{}", raw as i32)?,
-                    8 => write!(fmt, "{}", raw as i64)?,
-                    16 => write!(fmt, "{}", raw as i128)?,
-                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
-                }
-                if fmt.alternate() {
-                    match (size, is_ptr_sized_integral) {
-                        (_, true) => write!(fmt, "_isize")?,
-                        (1, _) => write!(fmt, "_i8")?,
-                        (2, _) => write!(fmt, "_i16")?,
-                        (4, _) => write!(fmt, "_i32")?,
-                        (8, _) => write!(fmt, "_i64")?,
-                        (16, _) => write!(fmt, "_i128")?,
-                        _ => bug!(),
-                    }
-                }
-                Ok(())
+                tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
             }
-        } else {
-            let max = truncate(u128::MAX, Size::from_bytes(size));
-            if raw == max {
-                match (size, is_ptr_sized_integral) {
-                    (_, true) => write!(fmt, "usize::MAX"),
-                    (1, _) => write!(fmt, "u8::MAX"),
-                    (2, _) => write!(fmt, "u16::MAX"),
-                    (4, _) => write!(fmt, "u32::MAX"),
-                    (8, _) => write!(fmt, "u64::MAX"),
-                    (16, _) => write!(fmt, "u128::MAX"),
-                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
-                }
-            } else {
-                match size {
-                    1 => write!(fmt, "{}", raw as u8)?,
-                    2 => write!(fmt, "{}", raw as u16)?,
-                    4 => write!(fmt, "{}", raw as u32)?,
-                    8 => write!(fmt, "{}", raw as u64)?,
-                    16 => write!(fmt, "{}", raw as u128)?,
-                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
-                }
-                if fmt.alternate() {
-                    match (size, is_ptr_sized_integral) {
-                        (_, true) => write!(fmt, "_usize")?,
-                        (1, _) => write!(fmt, "_u8")?,
-                        (2, _) => write!(fmt, "_u16")?,
-                        (4, _) => write!(fmt, "_u32")?,
-                        (8, _) => write!(fmt, "_u64")?,
-                        (16, _) => write!(fmt, "_u128")?,
-                        _ => bug!(),
-                    }
-                }
-                Ok(())
+        }
+
+        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+        let expr = match &expr.kind {
+            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+                block.expr.as_ref().unwrap()
+            }
+            _ => expr,
+        };
+
+        use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
+        let val = match expr.kind {
+            ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
+                // Find the name and index of the const parameter by indexing the generics of
+                // the parent item and construct a `ParamConst`.
+                let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
+                let item_id = tcx.hir().get_parent_node(hir_id);
+                let item_def_id = tcx.hir().local_def_id(item_id);
+                let generics = tcx.generics_of(item_def_id.to_def_id());
+                let index =
+                    generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id).to_def_id()];
+                let name = tcx.hir().name(hir_id);
+                ty::ConstKind::Param(ty::ParamConst::new(index, name))
             }
+            _ => ty::ConstKind::Unevaluated(
+                def.to_global(),
+                InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+                None,
+            ),
+        };
+
+        tcx.mk_const(ty::Const { val, ty })
+    }
+
+    #[inline]
+    /// Interns the given value as a constant.
+    pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+        tcx.mk_const(Self { val: ConstKind::Value(val), ty })
+    }
+
+    #[inline]
+    /// Interns the given scalar as a constant.
+    pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self {
+        Self::from_value(tcx, ConstValue::Scalar(val), ty)
+    }
+
+    #[inline]
+    /// Creates a constant with the given integer value and interns it.
+    pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self {
+        let size = tcx
+            .layout_of(ty)
+            .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
+            .size;
+        Self::from_scalar(tcx, Scalar::from_uint(bits, size), ty.value)
+    }
+
+    #[inline]
+    /// Creates an interned zst constant.
+    pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+        Self::from_scalar(tcx, Scalar::zst(), ty)
+    }
+
+    #[inline]
+    /// Creates an interned bool constant.
+    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self {
+        Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
+    }
+
+    #[inline]
+    /// Creates an interned usize constant.
+    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self {
+        Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
+    }
+
+    #[inline]
+    /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
+    /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
+    /// contains const generic parameters or pointers).
+    pub fn try_eval_bits(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Option<u128> {
+        assert_eq!(self.ty, ty);
+        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.val.eval(tcx, param_env).try_to_bits(size)
+    }
+
+    #[inline]
+    pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+        self.val.eval(tcx, param_env).try_to_bool()
+    }
+
+    #[inline]
+    pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
+        self.val.eval(tcx, param_env).try_to_machine_usize(tcx)
+    }
+
+    #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
+    /// unevaluated constant.
+    pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
+        if let Some(val) = self.val.try_eval(tcx, param_env) {
+            match val {
+                Ok(val) => Const::from_value(tcx, val, self.ty),
+                Err(ErrorReported) => tcx.const_error(self.ty),
+            }
+        } else {
+            self
         }
     }
+
+    #[inline]
+    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+    pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
+        self.try_eval_bits(tcx, param_env, ty)
+            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
+    }
+
+    #[inline]
+    /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
+    pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
+        self.try_eval_usize(tcx, param_env)
+            .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
+    }
 }
diff --git a/src/librustc_middle/ty/consts/int.rs b/src/librustc_middle/ty/consts/int.rs
new file mode 100644 (file)
index 0000000..ced0429
--- /dev/null
@@ -0,0 +1,111 @@
+use crate::mir::interpret::truncate;
+use rustc_target::abi::Size;
+
+#[derive(Copy, Clone)]
+/// A type for representing any integer. Only used for printing.
+// FIXME: Use this for the integer-tree representation needed for type level ints and
+// const generics?
+pub struct ConstInt {
+    /// Number of bytes of the integer. Only 1, 2, 4, 8, 16 are legal values.
+    size: u8,
+    /// Whether the value is of a signed integer type.
+    signed: bool,
+    /// Whether the value is a `usize` or `isize` type.
+    is_ptr_sized_integral: bool,
+    /// Raw memory of the integer. All bytes beyond the `size` are unused and must be zero.
+    raw: u128,
+}
+
+impl ConstInt {
+    pub fn new(raw: u128, size: Size, signed: bool, is_ptr_sized_integral: bool) -> Self {
+        assert!(raw <= truncate(u128::MAX, size));
+        Self { raw, size: size.bytes() as u8, signed, is_ptr_sized_integral }
+    }
+}
+
+impl std::fmt::Debug for ConstInt {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let Self { size, signed, raw, is_ptr_sized_integral } = *self;
+        if signed {
+            let bit_size = size * 8;
+            let min = 1u128 << (bit_size - 1);
+            let max = min - 1;
+            if raw == min {
+                match (size, is_ptr_sized_integral) {
+                    (_, true) => write!(fmt, "isize::MIN"),
+                    (1, _) => write!(fmt, "i8::MIN"),
+                    (2, _) => write!(fmt, "i16::MIN"),
+                    (4, _) => write!(fmt, "i32::MIN"),
+                    (8, _) => write!(fmt, "i64::MIN"),
+                    (16, _) => write!(fmt, "i128::MIN"),
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+            } else if raw == max {
+                match (size, is_ptr_sized_integral) {
+                    (_, true) => write!(fmt, "isize::MAX"),
+                    (1, _) => write!(fmt, "i8::MAX"),
+                    (2, _) => write!(fmt, "i16::MAX"),
+                    (4, _) => write!(fmt, "i32::MAX"),
+                    (8, _) => write!(fmt, "i64::MAX"),
+                    (16, _) => write!(fmt, "i128::MAX"),
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+            } else {
+                match size {
+                    1 => write!(fmt, "{}", raw as i8)?,
+                    2 => write!(fmt, "{}", raw as i16)?,
+                    4 => write!(fmt, "{}", raw as i32)?,
+                    8 => write!(fmt, "{}", raw as i64)?,
+                    16 => write!(fmt, "{}", raw as i128)?,
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+                if fmt.alternate() {
+                    match (size, is_ptr_sized_integral) {
+                        (_, true) => write!(fmt, "_isize")?,
+                        (1, _) => write!(fmt, "_i8")?,
+                        (2, _) => write!(fmt, "_i16")?,
+                        (4, _) => write!(fmt, "_i32")?,
+                        (8, _) => write!(fmt, "_i64")?,
+                        (16, _) => write!(fmt, "_i128")?,
+                        _ => bug!(),
+                    }
+                }
+                Ok(())
+            }
+        } else {
+            let max = truncate(u128::MAX, Size::from_bytes(size));
+            if raw == max {
+                match (size, is_ptr_sized_integral) {
+                    (_, true) => write!(fmt, "usize::MAX"),
+                    (1, _) => write!(fmt, "u8::MAX"),
+                    (2, _) => write!(fmt, "u16::MAX"),
+                    (4, _) => write!(fmt, "u32::MAX"),
+                    (8, _) => write!(fmt, "u64::MAX"),
+                    (16, _) => write!(fmt, "u128::MAX"),
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+            } else {
+                match size {
+                    1 => write!(fmt, "{}", raw as u8)?,
+                    2 => write!(fmt, "{}", raw as u16)?,
+                    4 => write!(fmt, "{}", raw as u32)?,
+                    8 => write!(fmt, "{}", raw as u64)?,
+                    16 => write!(fmt, "{}", raw as u128)?,
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+                if fmt.alternate() {
+                    match (size, is_ptr_sized_integral) {
+                        (_, true) => write!(fmt, "_usize")?,
+                        (1, _) => write!(fmt, "_u8")?,
+                        (2, _) => write!(fmt, "_u16")?,
+                        (4, _) => write!(fmt, "_u32")?,
+                        (8, _) => write!(fmt, "_u64")?,
+                        (16, _) => write!(fmt, "_u128")?,
+                        _ => bug!(),
+                    }
+                }
+                Ok(())
+            }
+        }
+    }
+}
diff --git a/src/librustc_middle/ty/consts/kind.rs b/src/librustc_middle/ty/consts/kind.rs
new file mode 100644 (file)
index 0000000..75287ff
--- /dev/null
@@ -0,0 +1,135 @@
+use crate::mir::interpret::ConstValue;
+use crate::mir::interpret::Scalar;
+use crate::mir::Promoted;
+use crate::ty::subst::{InternalSubsts, SubstsRef};
+use crate::ty::ParamEnv;
+use crate::ty::{self, TyCtxt, TypeFoldable};
+use rustc_errors::ErrorReported;
+use rustc_hir::def_id::DefId;
+use rustc_macros::HashStable;
+use rustc_target::abi::Size;
+
+/// Represents a constant in Rust.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
+#[derive(HashStable)]
+pub enum ConstKind<'tcx> {
+    /// A const generic parameter.
+    Param(ty::ParamConst),
+
+    /// Infer the value of the const.
+    Infer(InferConst<'tcx>),
+
+    /// Bound const variable, used only when preparing a trait query.
+    Bound(ty::DebruijnIndex, ty::BoundVar),
+
+    /// A placeholder const - universally quantified higher-ranked const.
+    Placeholder(ty::PlaceholderConst),
+
+    /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
+    /// variants when the code is monomorphic enough for that.
+    Unevaluated(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>, Option<Promoted>),
+
+    /// Used to hold computed value.
+    Value(ConstValue<'tcx>),
+
+    /// A placeholder for a const which could not be computed; this is
+    /// propagated to avoid useless error messages.
+    Error(ty::sty::DelaySpanBugEmitted),
+}
+
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(ConstKind<'_>, 40);
+
+impl<'tcx> ConstKind<'tcx> {
+    #[inline]
+    pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
+        if let ConstKind::Value(val) = self { Some(val) } else { None }
+    }
+
+    #[inline]
+    pub fn try_to_scalar(self) -> Option<Scalar> {
+        self.try_to_value()?.try_to_scalar()
+    }
+
+    #[inline]
+    pub fn try_to_bits(self, size: Size) -> Option<u128> {
+        self.try_to_value()?.try_to_bits(size)
+    }
+
+    #[inline]
+    pub fn try_to_bool(self) -> Option<bool> {
+        self.try_to_value()?.try_to_bool()
+    }
+
+    #[inline]
+    pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+        self.try_to_value()?.try_to_machine_usize(tcx)
+    }
+}
+
+/// An inference variable for a const, for use in const generics.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
+#[derive(HashStable)]
+pub enum InferConst<'tcx> {
+    /// Infer the value of the const.
+    Var(ty::ConstVid<'tcx>),
+    /// A fresh const variable. See `infer::freshen` for more details.
+    Fresh(u32),
+}
+
+impl<'tcx> ConstKind<'tcx> {
+    #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
+    /// unevaluated constant.
+    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
+        self.try_eval(tcx, param_env).and_then(Result::ok).map(ConstKind::Value).unwrap_or(self)
+    }
+
+    #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
+    /// return `None`.
+    pub(super) fn try_eval(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+    ) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
+        if let ConstKind::Unevaluated(def, substs, promoted) = self {
+            use crate::mir::interpret::ErrorHandled;
+
+            let param_env_and_substs = param_env.with_reveal_all().and(substs);
+
+            // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
+            // also does later, but we want to do it before checking for
+            // inference variables.
+            let param_env_and_substs = tcx.erase_regions(&param_env_and_substs);
+
+            // HACK(eddyb) when the query key would contain inference variables,
+            // attempt using identity substs and `ParamEnv` instead, that will succeed
+            // when the expression doesn't depend on any parameters.
+            // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
+            // we can call `infcx.const_eval_resolve` which handles inference variables.
+            let param_env_and_substs = if param_env_and_substs.needs_infer() {
+                tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
+            } else {
+                param_env_and_substs
+            };
+
+            // FIXME(eddyb) maybe the `const_eval_*` methods should take
+            // `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
+            let (param_env, substs) = param_env_and_substs.into_parts();
+            // try to resolve e.g. associated constants to their definition on an impl, and then
+            // evaluate the const.
+            match tcx.const_eval_resolve(param_env, def, substs, promoted, None) {
+                // NOTE(eddyb) `val` contains no lifetimes/types/consts,
+                // and we use the original type, so nothing from `substs`
+                // (which may be identity substs, see above),
+                // can leak through `val` into the const we return.
+                Ok(val) => Some(Ok(val)),
+                Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
+                Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+            }
+        } else {
+            None
+        }
+    }
+}
index c4a5bc302227d00e7006785724f564101f579e79..3dd57eea2348f0b1871ef030e78975aa1206d023 100644 (file)
@@ -193,17 +193,17 @@ pub struct LocalTableInContext<'a, V> {
 }
 
 /// Validate that the given HirId (respectively its `local_id` part) can be
-/// safely used as a key in the tables of a TypeckTable. For that to be
+/// safely used as a key in the maps of a TypeckResults. For that to be
 /// the case, the HirId must have the same `owner` as all the other IDs in
 /// this table (signified by `hir_owner`). Otherwise the HirId
 /// would be in a different frame of reference and using its `local_id`
 /// would result in lookup errors, or worse, in silently wrong data being
 /// stored/returned.
-fn validate_hir_id_for_typeck_tables(hir_owner: LocalDefId, hir_id: hir::HirId) {
+fn validate_hir_id_for_typeck_results(hir_owner: LocalDefId, hir_id: hir::HirId) {
     if hir_id.owner != hir_owner {
         ty::tls::with(|tcx| {
             bug!(
-                "node {} with HirId::owner {:?} cannot be placed in TypeckTables with hir_owner {:?}",
+                "node {} with HirId::owner {:?} cannot be placed in TypeckResults with hir_owner {:?}",
                 tcx.hir().node_to_string(hir_id),
                 hir_id.owner,
                 hir_owner
@@ -214,12 +214,12 @@ fn validate_hir_id_for_typeck_tables(hir_owner: LocalDefId, hir_id: hir::HirId)
 
 impl<'a, V> LocalTableInContext<'a, V> {
     pub fn contains_key(&self, id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.contains_key(&id.local_id)
     }
 
     pub fn get(&self, id: hir::HirId) -> Option<&V> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.get(&id.local_id)
     }
 
@@ -243,22 +243,22 @@ pub struct LocalTableInContextMut<'a, V> {
 
 impl<'a, V> LocalTableInContextMut<'a, V> {
     pub fn get_mut(&mut self, id: hir::HirId) -> Option<&mut V> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.get_mut(&id.local_id)
     }
 
     pub fn entry(&mut self, id: hir::HirId) -> Entry<'_, hir::ItemLocalId, V> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.entry(id.local_id)
     }
 
     pub fn insert(&mut self, id: hir::HirId, val: V) -> Option<V> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.insert(id.local_id, val)
     }
 
     pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.data.remove(&id.local_id)
     }
 }
@@ -307,7 +307,7 @@ pub struct GeneratorInteriorTypeCause<'tcx> {
 }
 
 #[derive(RustcEncodable, RustcDecodable, Debug)]
-pub struct TypeckTables<'tcx> {
+pub struct TypeckResults<'tcx> {
     /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
     pub hir_owner: LocalDefId,
 
@@ -416,9 +416,9 @@ pub struct TypeckTables<'tcx> {
     pub generator_interior_types: Vec<GeneratorInteriorTypeCause<'tcx>>,
 }
 
-impl<'tcx> TypeckTables<'tcx> {
-    pub fn new(hir_owner: LocalDefId) -> TypeckTables<'tcx> {
-        TypeckTables {
+impl<'tcx> TypeckResults<'tcx> {
+    pub fn new(hir_owner: LocalDefId) -> TypeckResults<'tcx> {
+        TypeckResults {
             hir_owner,
             type_dependent_defs: Default::default(),
             field_indices: Default::default(),
@@ -459,7 +459,7 @@ pub fn type_dependent_defs(
     }
 
     pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
     }
 
@@ -506,7 +506,7 @@ pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
     }
 
     pub fn node_type_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.node_types.get(&id.local_id).cloned()
     }
 
@@ -515,12 +515,12 @@ pub fn node_substs_mut(&mut self) -> LocalTableInContextMut<'_, SubstsRef<'tcx>>
     }
 
     pub fn node_substs(&self, id: hir::HirId) -> SubstsRef<'tcx> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.node_substs.get(&id.local_id).cloned().unwrap_or_else(|| InternalSubsts::empty())
     }
 
     pub fn node_substs_opt(&self, id: hir::HirId) -> Option<SubstsRef<'tcx>> {
-        validate_hir_id_for_typeck_tables(self.hir_owner, id);
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
         self.node_substs.get(&id.local_id).cloned()
     }
 
@@ -563,7 +563,7 @@ pub fn adjustments_mut(
     }
 
     pub fn expr_adjustments(&self, expr: &hir::Expr<'_>) -> &[ty::adjustment::Adjustment<'tcx>] {
-        validate_hir_id_for_typeck_tables(self.hir_owner, expr.hir_id);
+        validate_hir_id_for_typeck_results(self.hir_owner, expr.hir_id);
         self.adjustments.get(&expr.hir_id.local_id).map_or(&[], |a| &a[..])
     }
 
@@ -642,7 +642,7 @@ pub fn fru_field_types_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>
     }
 
     pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
-        validate_hir_id_for_typeck_tables(self.hir_owner, hir_id);
+        validate_hir_id_for_typeck_results(self.hir_owner, hir_id);
         self.coercion_casts.contains(&hir_id.local_id)
     }
 
@@ -655,9 +655,9 @@ pub fn coercion_casts(&self) -> &ItemLocalSet {
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckTables<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let ty::TypeckTables {
+        let ty::TypeckResults {
             hir_owner,
             ref type_dependent_defs,
             ref field_indices,
@@ -980,15 +980,26 @@ pub struct GlobalCtxt<'tcx> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> Steal<Body<'tcx>> {
-        Steal::new(mir)
+    pub fn typeck_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<LocalDefId>,
+    ) -> &'tcx TypeckResults<'tcx> {
+        if let Some(param_did) = def.const_param_did {
+            self.typeck_const_arg((def.did, param_did))
+        } else {
+            self.typeck(def.did)
+        }
+    }
+
+    pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal<Body<'tcx>> {
+        self.arena.alloc(Steal::new(mir))
     }
 
     pub fn alloc_steal_promoted(
         self,
         promoted: IndexVec<Promoted, Body<'tcx>>,
-    ) -> Steal<IndexVec<Promoted, Body<'tcx>>> {
-        Steal::new(promoted)
+    ) -> &'tcx Steal<IndexVec<Promoted, Body<'tcx>>> {
+        self.arena.alloc(Steal::new(promoted))
     }
 
     pub fn alloc_adt_def(
index d628d6783d5b0d71f12ed4c9aaf900660dec040f..f627d05d3e9d28686f2265301a82f55d87120797 100644 (file)
@@ -29,7 +29,7 @@ pub enum InstanceDef<'tcx> {
     /// - `fn` items
     /// - closures
     /// - generators
-    Item(DefId),
+    Item(ty::WithOptConstParam<DefId>),
 
     /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI).
     ///
@@ -160,8 +160,8 @@ pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
         self.substs.non_erasable_generics().next()?;
 
         match self.def {
-            InstanceDef::Item(def_id) => tcx
-                .upstream_monomorphizations_for(def_id)
+            InstanceDef::Item(def) => tcx
+                .upstream_monomorphizations_for(def.did)
                 .and_then(|monos| monos.get(&self.substs).cloned()),
             InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs),
             _ => None,
@@ -171,10 +171,10 @@ pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
 
 impl<'tcx> InstanceDef<'tcx> {
     #[inline]
-    pub fn def_id(&self) -> DefId {
-        match *self {
-            InstanceDef::Item(def_id)
-            InstanceDef::VtableShim(def_id)
+    pub fn def_id(self) -> DefId {
+        match self {
+            InstanceDef::Item(def) => def.did,
+            InstanceDef::VtableShim(def_id)
             | InstanceDef::ReifyShim(def_id)
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
@@ -185,6 +185,21 @@ pub fn def_id(&self) -> DefId {
         }
     }
 
+    #[inline]
+    pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
+        match self {
+            InstanceDef::Item(def) => def,
+            InstanceDef::VtableShim(def_id)
+            | InstanceDef::ReifyShim(def_id)
+            | InstanceDef::FnPtrShim(def_id, _)
+            | InstanceDef::Virtual(def_id, _)
+            | InstanceDef::Intrinsic(def_id)
+            | InstanceDef::ClosureOnceShim { call_once: def_id }
+            | InstanceDef::DropGlue(def_id, _)
+            | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
+        }
+    }
+
     #[inline]
     pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> {
         tcx.get_attrs(self.def_id())
@@ -198,7 +213,7 @@ pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> {
     pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool {
         use rustc_hir::definitions::DefPathData;
         let def_id = match *self {
-            ty::InstanceDef::Item(def_id) => def_id,
+            ty::InstanceDef::Item(def) => def.did,
             ty::InstanceDef::DropGlue(_, Some(_)) => return false,
             _ => return true,
         };
@@ -244,8 +259,8 @@ pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool {
 
     pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
         match *self {
-            InstanceDef::Item(def_id) => {
-                tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+            InstanceDef::Item(def) => {
+                tcx.codegen_fn_attrs(def.did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
             }
             _ => false,
         }
@@ -283,7 +298,7 @@ pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> Instance<'tcx> {
             def_id,
             substs
         );
-        Instance { def: InstanceDef::Item(def_id), substs }
+        Instance { def: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), substs }
     }
 
     pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
@@ -323,6 +338,21 @@ pub fn resolve(
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
+    ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+        Instance::resolve_opt_const_arg(
+            tcx,
+            param_env,
+            ty::WithOptConstParam::unknown(def_id),
+            substs,
+        )
+    }
+
+    // This should be kept up to date with `resolve`.
+    pub fn resolve_opt_const_arg(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        def: ty::WithOptConstParam<DefId>,
+        substs: SubstsRef<'tcx>,
     ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
         // All regions in the result of this query are erased, so it's
         // fine to erase all of the input regions.
@@ -333,7 +363,13 @@ pub fn resolve(
         let substs = tcx.erase_regions(&substs);
 
         // FIXME(eddyb) should this always use `param_env.with_reveal_all()`?
-        tcx.resolve_instance(tcx.erase_regions(&param_env.and((def_id, substs))))
+        if let Some((did, param_did)) = def.as_const_arg() {
+            tcx.resolve_instance_of_const_arg(
+                tcx.erase_regions(&param_env.and((did, param_did, substs))),
+            )
+        } else {
+            tcx.resolve_instance(tcx.erase_regions(&param_env.and((def.did, substs))))
+        }
     }
 
     pub fn resolve_for_fn_ptr(
@@ -345,9 +381,9 @@ pub fn resolve_for_fn_ptr(
         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
         Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| {
             match resolved.def {
-                InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => {
+                InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
                     debug!(" => fn pointer created for function with #[track_caller]");
-                    resolved.def = InstanceDef::ReifyShim(def_id);
+                    resolved.def = InstanceDef::ReifyShim(def.did);
                 }
                 InstanceDef::Virtual(def_id, _) => {
                     debug!(" => fn pointer created for virtual call");
index 66ad923b8c00710a40481c71e82365e60e96831e..8ae9269a6bf684e566ee2fa0ef27c98f4758ac4a 100644 (file)
@@ -774,12 +774,12 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                     (present_variants.next(), present_variants.next())
                 };
                 let present_first = match present_first {
-                    present_first @ Some(_) => present_first,
+                    Some(present_first) => present_first,
                     // Uninhabited because it has no variants, or only absent ones.
                     None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
                     // If it's a struct, still compute a layout so that we can still compute the
                     // field offsets.
-                    None => Some(VariantIdx::new(0)),
+                    None => VariantIdx::new(0),
                 };
 
                 let is_struct = !def.is_enum() ||
@@ -791,7 +791,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                     // Struct, or univariant enum equivalent to a struct.
                     // (Typechecking will reject discriminant-sizing attrs.)
 
-                    let v = present_first.unwrap();
+                    let v = present_first;
                     let kind = if def.is_enum() || variants[v].is_empty() {
                         StructKind::AlwaysSized
                     } else {
@@ -876,6 +876,8 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                     .iter_enumerated()
                     .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
 
+                let mut niche_filling_layout = None;
+
                 // Niche-filling enum optimization.
                 if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants {
                     let mut dataful_variant = None;
@@ -972,7 +974,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                             let largest_niche =
                                 Niche::from_scalar(dl, offset, niche_scalar.clone());
 
-                            return Ok(tcx.intern_layout(Layout {
+                            niche_filling_layout = Some(Layout {
                                 variants: Variants::Multiple {
                                     tag: niche_scalar,
                                     tag_encoding: TagEncoding::Niche {
@@ -991,7 +993,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                                 largest_niche,
                                 size,
                                 align,
-                            }));
+                            });
                         }
                     }
                 }
@@ -1214,7 +1216,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
 
-                tcx.intern_layout(Layout {
+                let tagged_layout = Layout {
                     variants: Variants::Multiple {
                         tag,
                         tag_encoding: TagEncoding::Direct,
@@ -1229,7 +1231,23 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                     abi,
                     align,
                     size,
-                })
+                };
+
+                let best_layout = match (tagged_layout, niche_filling_layout) {
+                    (tagged_layout, Some(niche_filling_layout)) => {
+                        // Pick the smaller layout; otherwise,
+                        // pick the layout with the larger niche; otherwise,
+                        // pick tagged as it has simpler codegen.
+                        cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
+                            let niche_size =
+                                layout.largest_niche.as_ref().map_or(0, |n| n.available(dl));
+                            (layout.size, cmp::Reverse(niche_size))
+                        })
+                    }
+                    (tagged_layout, None) => tagged_layout,
+                };
+
+                tcx.intern_layout(best_layout)
             }
 
             // Types with no meaningful known layout.
index bec1200d7aa0fd592adad67610bfdf325bc29f93..21745977b04b1b805b9f84db86653b68ae05c486 100644 (file)
@@ -1,5 +1,4 @@
 // ignore-tidy-filelength
-
 pub use self::fold::{TypeFoldable, TypeVisitor};
 pub use self::AssocItemContainer::*;
 pub use self::BorrowKind::*;
@@ -50,6 +49,7 @@
 use std::marker::PhantomData;
 use std::ops::Range;
 use std::ptr;
+use std::str;
 
 pub use self::sty::BoundRegion::*;
 pub use self::sty::InferTy::*;
@@ -60,9 +60,9 @@
 pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
 pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig};
 pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts};
-pub use self::sty::{Const, ConstKind, ExistentialProjection, PolyExistentialProjection};
 pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid};
-pub use self::sty::{ExistentialPredicate, InferConst, InferTy, ParamConst, ParamTy, ProjectionTy};
+pub use self::sty::{ExistentialPredicate, InferTy, ParamConst, ParamTy, ProjectionTy};
+pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
 pub use self::sty::{PolyTraitRef, TraitRef, TyKind};
 pub use crate::ty::diagnostics::*;
@@ -76,7 +76,7 @@
     UserType, UserTypeAnnotationIndex,
 };
 pub use self::context::{
-    CtxtInterners, GeneratorInteriorTypeCause, GlobalCtxt, Lift, TypeckTables,
+    CtxtInterners, GeneratorInteriorTypeCause, GlobalCtxt, Lift, TypeckResults,
 };
 
 pub use self::instance::{Instance, InstanceDef};
@@ -87,7 +87,7 @@
 
 pub use self::query::queries;
 
-pub use self::consts::ConstInt;
+pub use self::consts::{Const, ConstInt, ConstKind, InferConst};
 
 pub mod adjustment;
 pub mod binding;
@@ -1100,7 +1100,7 @@ pub enum PredicateKind<'tcx> {
     Subtype(PolySubtypePredicate<'tcx>),
 
     /// Constant initializer must evaluate successfully.
-    ConstEvaluatable(DefId, SubstsRef<'tcx>),
+    ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
 
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
@@ -1571,6 +1571,95 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
 
 pub type PlaceholderConst = Placeholder<BoundVar>;
 
+/// A `DefId` which is potentially bundled with its corresponding generic parameter
+/// in case `did` is a const argument.
+///
+/// This is used to prevent cycle errors during typeck
+/// as `type_of(const_arg)` depends on `typeck(owning_body)`
+/// which once again requires the type of its generic arguments.
+///
+/// Luckily we only need to deal with const arguments once we
+/// know their corresponding parameters. We (ab)use this by
+/// calling `type_of(param_did)` for these arguments.
+///
+/// ```rust
+/// #![feature(const_generics)]
+///
+/// struct A;
+/// impl A {
+///     fn foo<const N: usize>(&self) -> usize { N }
+/// }
+/// struct B;
+/// impl B {
+///     fn foo<const N: u8>(&self) -> usize { 42 }
+/// }
+///
+/// fn main() {
+///     let a = A;
+///     a.foo::<7>();
+/// }
+/// ```
+#[derive(Copy, Clone, Debug, TypeFoldable, Lift, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Hash, HashStable)]
+pub struct WithOptConstParam<T> {
+    pub did: T,
+    /// The `DefId` of the corresponding generic paramter in case `did` is
+    /// a const argument.
+    ///
+    /// Note that even if `did` is a const argument, this may still be `None`.
+    /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)`
+    /// to potentially update `param_did` in case it `None`.
+    pub const_param_did: Option<DefId>,
+}
+
+impl<T> WithOptConstParam<T> {
+    /// Creates a new `WithOptConstParam` setting `const_param_did` to `None`.
+    pub fn unknown(did: T) -> WithOptConstParam<T> {
+        WithOptConstParam { did, const_param_did: None }
+    }
+}
+
+impl WithOptConstParam<LocalDefId> {
+    pub fn to_global(self) -> WithOptConstParam<DefId> {
+        WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did }
+    }
+
+    pub fn def_id_for_type_of(self) -> DefId {
+        if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() }
+    }
+}
+
+impl WithOptConstParam<DefId> {
+    pub fn as_local(self) -> Option<WithOptConstParam<LocalDefId>> {
+        self.did
+            .as_local()
+            .map(|did| WithOptConstParam { did, const_param_did: self.const_param_did })
+    }
+
+    pub fn as_const_arg(self) -> Option<(LocalDefId, DefId)> {
+        if let Some(param_did) = self.const_param_did {
+            if let Some(did) = self.did.as_local() {
+                return Some((did, param_did));
+            }
+        }
+
+        None
+    }
+
+    pub fn expect_local(self) -> WithOptConstParam<LocalDefId> {
+        self.as_local().unwrap()
+    }
+
+    pub fn is_local(self) -> bool {
+        self.did.is_local()
+    }
+
+    pub fn def_id_for_type_of(self) -> DefId {
+        self.const_param_did.unwrap_or(self.did)
+    }
+}
+
 /// When type checking, we use the `ParamEnv` to track
 /// details about the set of where-clauses that are in scope at this
 /// particular point.
@@ -2670,8 +2759,8 @@ pub enum ImplOverlapKind {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn body_tables(self, body: hir::BodyId) -> &'tcx TypeckTables<'tcx> {
-        self.typeck_tables_of(self.hir().body_owner_def_id(body))
+    pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> {
+        self.typeck(self.hir().body_owner_def_id(body))
     }
 
     /// Returns an iterator of the `DefId`s for all body-owners in this
@@ -2718,8 +2807,8 @@ pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
         is_associated_item.then(|| self.associated_item(def_id))
     }
 
-    pub fn field_index(self, hir_id: hir::HirId, tables: &TypeckTables<'_>) -> usize {
-        tables.field_indices().get(hir_id).cloned().expect("no index for a field")
+    pub fn field_index(self, hir_id: hir::HirId, typeck_results: &TypeckResults<'_>) -> usize {
+        typeck_results.field_indices().get(hir_id).cloned().expect("no index for a field")
     }
 
     pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
@@ -2842,7 +2931,13 @@ pub fn item_name(self, id: DefId) -> Symbol {
     /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
     pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         match instance {
-            ty::InstanceDef::Item(did) => self.optimized_mir(did),
+            ty::InstanceDef::Item(def) => {
+                if let Some((did, param_did)) = def.as_const_arg() {
+                    self.optimized_mir_of_const_arg((did, param_did))
+                } else {
+                    self.optimized_mir(def.did)
+                }
+            }
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::Intrinsic(..)
@@ -2988,40 +3083,37 @@ pub struct CrateInherentImpls {
     pub inherent_impls: DefIdMap<Vec<DefId>>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
-pub struct SymbolName {
-    // FIXME: we don't rely on interning or equality here - better have
-    // this be a `&'tcx str`.
-    pub name: Symbol,
-}
-
-impl SymbolName {
-    pub fn new(name: &str) -> SymbolName {
-        SymbolName { name: Symbol::intern(name) }
-    }
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+pub struct SymbolName<'tcx> {
+    /// `&str` gives a consistent ordering, which ensures reproducible builds.
+    pub name: &'tcx str,
 }
 
-impl PartialOrd for SymbolName {
-    fn partial_cmp(&self, other: &SymbolName) -> Option<Ordering> {
-        self.name.as_str().partial_cmp(&other.name.as_str())
+impl<'tcx> SymbolName<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, name: &str) -> SymbolName<'tcx> {
+        SymbolName {
+            name: unsafe { str::from_utf8_unchecked(tcx.arena.alloc_slice(name.as_bytes())) },
+        }
     }
 }
 
-/// Ordering must use the chars to ensure reproducible builds.
-impl Ord for SymbolName {
-    fn cmp(&self, other: &SymbolName) -> Ordering {
-        self.name.as_str().cmp(&other.name.as_str())
+impl<'tcx> fmt::Display for SymbolName<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.name, fmt)
     }
 }
 
-impl fmt::Display for SymbolName {
+impl<'tcx> fmt::Debug for SymbolName<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Display::fmt(&self.name, fmt)
     }
 }
 
-impl fmt::Debug for SymbolName {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&self.name, fmt)
+impl<'tcx> rustc_serialize::UseSpecializedEncodable for SymbolName<'tcx> {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_str(self.name)
     }
 }
+
+// The decoding takes place in `decode_symbol_name()`.
+impl<'tcx> rustc_serialize::UseSpecializedDecodable for SymbolName<'tcx> {}
index 3809c8d245bbe96ebbb682fe13ff81cdabfe0366..043d85cb6efa632f7800517b8db3a03918ac5957 100644 (file)
@@ -883,18 +883,18 @@ macro_rules! print_underscore {
         }
 
         match ct.val {
-            ty::ConstKind::Unevaluated(did, substs, promoted) => {
+            ty::ConstKind::Unevaluated(def, substs, promoted) => {
                 if let Some(promoted) = promoted {
-                    p!(print_value_path(did, substs));
+                    p!(print_value_path(def.did, substs));
                     p!(write("::{:?}", promoted));
                 } else {
-                    match self.tcx().def_kind(did) {
+                    match self.tcx().def_kind(def.did) {
                         DefKind::Static | DefKind::Const | DefKind::AssocConst => {
-                            p!(print_value_path(did, substs))
+                            p!(print_value_path(def.did, substs))
                         }
                         _ => {
-                            if did.is_local() {
-                                let span = self.tcx().def_span(did);
+                            if def.is_local() {
+                                let span = self.tcx().def_span(def.did);
                                 if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
                                 {
                                     p!(write("{}", snip))
@@ -1440,12 +1440,12 @@ fn path_append(
 
         // FIXME(eddyb) `name` should never be empty, but it
         // currently is for `extern { ... }` "foreign modules".
-        let name = disambiguated_data.data.as_symbol().as_str();
-        if !name.is_empty() {
+        let name = disambiguated_data.data.as_symbol();
+        if name != kw::Invalid {
             if !self.empty_path {
                 write!(self, "::")?;
             }
-            if Ident::from_str(&name).is_raw_guess() {
+            if Ident::with_dummy_span(name).is_raw_guess() {
                 write!(self, "r#")?;
             }
             write!(self, "{}", name)?;
@@ -2027,9 +2027,9 @@ pub fn print_only_trait_path(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx
                    print_value_path(closure_def_id, &[]),
                    write("` implements the trait `{}`", kind))
             }
-            &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+            &ty::PredicateKind::ConstEvaluatable(def, substs) => {
                 p!(write("the constant `"),
-                   print_value_path(def_id, substs),
+                   print_value_path(def.did, substs),
                    write("` can be evaluated"))
             }
             ty::PredicateKind::ConstEquate(c1, c2) => {
index 4acf766f033d8360daa4af60d4d9b292bcd91080..cb2b7a662cb4c0756067d652dcbc472a57873503 100644 (file)
@@ -105,6 +105,17 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
     }
 }
 
+impl Key for ty::WithOptConstParam<LocalDefId> {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        self.did.query_crate()
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.did.default_span(tcx)
+    }
+}
+
 impl Key for (DefId, DefId) {
     type CacheSelector = DefaultCacheSelector;
 
@@ -127,6 +138,17 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
     }
 }
 
+impl Key for (LocalDefId, DefId) {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
+
 impl Key for (CrateNum, DefId) {
     type CacheSelector = DefaultCacheSelector;
 
@@ -171,6 +193,17 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
     }
 }
 
+impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
+
 impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
     type CacheSelector = DefaultCacheSelector;
 
index c84a7c38d0a0e70f5417b0a7ff986f78ba9a73c1..1ba305e63fb9cc8cd06275c84c98e1df4491ae96 100644 (file)
@@ -35,7 +35,7 @@
 
 /// 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
+/// of a few selected queries (like `typeck` and `mir_optimized`) and
 /// any diagnostics that have been emitted during a query.
 pub struct OnDiskCache<'sess> {
     // The complete cache data in serialized form.
index 3c44662441890431f15e70a74d318aa4f4015759..0683dc0201129bddca91b54fc36d3a10b1df3c7f 100644 (file)
@@ -60,12 +60,12 @@ fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
 
         match def_key.disambiguated_data.data {
             DefPathData::CrateRoot => {
-                name = self.tcx.original_crate_name(def_id.krate).as_str();
+                name = self.tcx.original_crate_name(def_id.krate);
                 dis = "";
                 end_index = 3;
             }
             other => {
-                name = other.as_symbol().as_str();
+                name = other.as_symbol();
                 if def_key.disambiguated_data.disambiguator == 0 {
                     dis = "";
                     end_index = 3;
@@ -79,10 +79,11 @@ fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
             }
         }
 
+        let name = &*name.as_str();
         let components = [
             StringComponent::Ref(parent_string_id),
             StringComponent::Value("::"),
-            StringComponent::Value(&name[..]),
+            StringComponent::Value(name),
             StringComponent::Value(dis),
         ];
 
index 0a0ff101b52032fcf2066e08b35800b1c600aaf8..f28b0f499f082fe9ba3920c2121c80c5eb14bf72 100644 (file)
@@ -1,7 +1,5 @@
 use crate::ty::{self, AdtSizedConstraint, Ty, TyCtxt, TyS};
 
-use rustc_span::symbol::Symbol;
-
 pub(super) trait Value<'tcx>: Sized {
     fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self;
 }
@@ -21,9 +19,15 @@ fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
     }
 }
 
-impl<'tcx> Value<'tcx> for ty::SymbolName {
-    fn from_cycle_error(_: TyCtxt<'tcx>) -> Self {
-        ty::SymbolName { name: Symbol::intern("<error>") }
+impl<'tcx> Value<'tcx> for ty::SymbolName<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+        // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
+        // FIXME: Represent the above fact in the trait system somehow.
+        unsafe {
+            std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
+                tcx, "<error>",
+            ))
+        }
     }
 }
 
index 7946a27b4d9686759dca28551903c0a7cd4256a9..ae2820b460fe3d3a629efe5b9545b8d0718ed684 100644 (file)
@@ -578,12 +578,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
 
         // FIXME(const_generics): this is wrong, as it is a projection
         (
-            ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
-            ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
-        ) if a_def_id == b_def_id && a_promoted == b_promoted => {
+            ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted),
+            ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted),
+        ) if a_def == b_def && a_promoted == b_promoted => {
             let substs =
                 relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, substs, a_promoted))
+            Ok(ty::ConstKind::Unevaluated(a_def, substs, a_promoted))
         }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))),
     };
index 159af277d240b56bbd3b31e8a714bee702f8dea0..f04bfe648fb786719821b31d1aa7b674db3d087d 100644 (file)
@@ -272,6 +272,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     ::rustc_span::symbol::Symbol,
     ::rustc_hir::def::Res,
     ::rustc_hir::def_id::DefId,
+    ::rustc_hir::def_id::LocalDefId,
     ::rustc_hir::LlvmInlineAsmInner,
     ::rustc_hir::MatchSource,
     ::rustc_hir::Mutability,
@@ -719,6 +720,18 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
+impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
+    for (A, B, C)
+{
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> (A, B, C) {
+        (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.0.visit_with(visitor) || self.1.visit_with(visitor) || self.2.visit_with(visitor)
+    }
+}
+
 EnumTypeFoldableImpl! {
     impl<'tcx, T> TypeFoldable<'tcx> for Option<T> {
         (Some)(a),
@@ -838,7 +851,7 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         Self {
             substs: self.substs.fold_with(folder),
             def: match self.def {
-                Item(did) => Item(did.fold_with(folder)),
+                Item(def) => Item(def.fold_with(folder)),
                 VtableShim(did) => VtableShim(did.fold_with(folder)),
                 ReifyShim(did) => ReifyShim(did.fold_with(folder)),
                 Intrinsic(did) => Intrinsic(did.fold_with(folder)),
@@ -857,7 +870,8 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         use crate::ty::InstanceDef::*;
         self.substs.visit_with(visitor)
             || match self.def {
-                Item(did) | VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
+                Item(def) => def.visit_with(visitor),
+                VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
                     did.visit_with(visitor)
                 }
                 FnPtrShim(did, ty) | CloneShim(did, ty) => {
index c7683cefd82f6a6541c65bb6a5b6b0eedb00910f..2f17db6223362229db7180ba80a4e98efd8787ca 100644 (file)
@@ -6,24 +6,20 @@
 use self::TyKind::*;
 
 use crate::infer::canonical::Canonical;
-use crate::mir::interpret::ConstValue;
-use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::mir::Promoted;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::{
     self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
 };
-use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS};
+use crate::ty::{List, ParamEnv, TyS};
 use polonius_engine::Atom;
 use rustc_ast::ast;
 use rustc_data_structures::captures::Captures;
-use rustc_errors::ErrorReported;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_target::abi::{Size, VariantIdx};
+use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi;
 use std::borrow::Cow;
 use std::cmp::Ordering;
@@ -1122,7 +1118,7 @@ pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
         ParamConst::new(def.index, def.name)
     }
 
-    pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
+    pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
         tcx.mk_const_param(self.index, self.name, ty)
     }
 }
@@ -2193,270 +2189,3 @@ pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool {
         tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false)
     }
 }
-
-/// Typed constant value.
-#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
-#[derive(HashStable)]
-pub struct Const<'tcx> {
-    pub ty: Ty<'tcx>,
-
-    pub val: ConstKind<'tcx>,
-}
-
-#[cfg(target_arch = "x86_64")]
-static_assert_size!(Const<'_>, 48);
-
-impl<'tcx> Const<'tcx> {
-    /// Literals and const generic parameters are eagerly converted to a constant, everything else
-    /// becomes `Unevaluated`.
-    pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
-        debug!("Const::from_anon_const(id={:?})", def_id);
-
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
-        let body_id = match tcx.hir().get(hir_id) {
-            hir::Node::AnonConst(ac) => ac.body,
-            _ => span_bug!(
-                tcx.def_span(def_id.to_def_id()),
-                "from_anon_const can only process anonymous constants"
-            ),
-        };
-
-        let expr = &tcx.hir().body(body_id).value;
-
-        let ty = tcx.type_of(def_id.to_def_id());
-
-        let lit_input = match expr.kind {
-            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
-            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
-                hir::ExprKind::Lit(ref lit) => {
-                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
-                }
-                _ => None,
-            },
-            _ => None,
-        };
-
-        if let Some(lit_input) = lit_input {
-            // If an error occurred, ignore that it's a literal and leave reporting the error up to
-            // mir.
-            if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
-                return c;
-            } else {
-                tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
-            }
-        }
-
-        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
-        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
-        let expr = match &expr.kind {
-            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
-                block.expr.as_ref().unwrap()
-            }
-            _ => expr,
-        };
-
-        use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
-        let val = match expr.kind {
-            ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
-                // Find the name and index of the const parameter by indexing the generics of
-                // the parent item and construct a `ParamConst`.
-                let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
-                let item_id = tcx.hir().get_parent_node(hir_id);
-                let item_def_id = tcx.hir().local_def_id(item_id);
-                let generics = tcx.generics_of(item_def_id.to_def_id());
-                let index =
-                    generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id).to_def_id()];
-                let name = tcx.hir().name(hir_id);
-                ty::ConstKind::Param(ty::ParamConst::new(index, name))
-            }
-            _ => ty::ConstKind::Unevaluated(
-                def_id.to_def_id(),
-                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
-                None,
-            ),
-        };
-
-        tcx.mk_const(ty::Const { val, ty })
-    }
-
-    #[inline]
-    /// Interns the given value as a constant.
-    pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
-        tcx.mk_const(Self { val: ConstKind::Value(val), ty })
-    }
-
-    #[inline]
-    /// Interns the given scalar as a constant.
-    pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self {
-        Self::from_value(tcx, ConstValue::Scalar(val), ty)
-    }
-
-    #[inline]
-    /// Creates a constant with the given integer value and interns it.
-    pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self {
-        let size = tcx
-            .layout_of(ty)
-            .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
-            .size;
-        Self::from_scalar(tcx, Scalar::from_uint(bits, size), ty.value)
-    }
-
-    #[inline]
-    /// Creates an interned zst constant.
-    pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
-        Self::from_scalar(tcx, Scalar::zst(), ty)
-    }
-
-    #[inline]
-    /// Creates an interned bool constant.
-    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self {
-        Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
-    }
-
-    #[inline]
-    /// Creates an interned usize constant.
-    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self {
-        Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
-    }
-
-    #[inline]
-    /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
-    /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
-    /// contains const generic parameters or pointers).
-    pub fn try_eval_bits(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Option<u128> {
-        assert_eq!(self.ty, ty);
-        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]
-    /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
-    /// unevaluated constant.
-    pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
-        if let ConstKind::Unevaluated(did, substs, promoted) = self.val {
-            use crate::mir::interpret::ErrorHandled;
-
-            let param_env_and_substs = param_env.with_reveal_all().and(substs);
-
-            // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
-            // also does later, but we want to do it before checking for
-            // inference variables.
-            let param_env_and_substs = tcx.erase_regions(&param_env_and_substs);
-
-            // HACK(eddyb) when the query key would contain inference variables,
-            // attempt using identity substs and `ParamEnv` instead, that will succeed
-            // when the expression doesn't depend on any parameters.
-            // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
-            // we can call `infcx.const_eval_resolve` which handles inference variables.
-            let param_env_and_substs = if param_env_and_substs.needs_infer() {
-                tcx.param_env(did).and(InternalSubsts::identity_for_item(tcx, did))
-            } else {
-                param_env_and_substs
-            };
-
-            // FIXME(eddyb) maybe the `const_eval_*` methods should take
-            // `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
-            let (param_env, substs) = param_env_and_substs.into_parts();
-            // try to resolve e.g. associated constants to their definition on an impl, and then
-            // evaluate the const.
-            match tcx.const_eval_resolve(param_env, did, substs, promoted, None) {
-                // NOTE(eddyb) `val` contains no lifetimes/types/consts,
-                // and we use the original type, so nothing from `substs`
-                // (which may be identity substs, see above),
-                // can leak through `val` into the const we return.
-                Ok(val) => Const::from_value(tcx, val, self.ty),
-                Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
-                Err(ErrorHandled::Reported(ErrorReported)) => tcx.const_error(self.ty),
-            }
-        } else {
-            self
-        }
-    }
-
-    #[inline]
-    pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
-        self.try_eval_bits(tcx, param_env, tcx.types.bool).and_then(|v| match v {
-            0 => Some(false),
-            1 => Some(true),
-            _ => None,
-        })
-    }
-
-    #[inline]
-    pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
-        self.try_eval_bits(tcx, param_env, tcx.types.usize).map(|v| v as u64)
-    }
-
-    #[inline]
-    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
-    pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
-        self.try_eval_bits(tcx, param_env, ty)
-            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
-    }
-
-    #[inline]
-    /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
-    pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
-        self.eval_bits(tcx, param_env, tcx.types.usize) as u64
-    }
-}
-
-/// Represents a constant in Rust.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
-#[derive(HashStable)]
-pub enum ConstKind<'tcx> {
-    /// A const generic parameter.
-    Param(ParamConst),
-
-    /// Infer the value of the const.
-    Infer(InferConst<'tcx>),
-
-    /// Bound const variable, used only when preparing a trait query.
-    Bound(DebruijnIndex, BoundVar),
-
-    /// A placeholder const - universally quantified higher-ranked const.
-    Placeholder(ty::PlaceholderConst),
-
-    /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
-    /// variants when the code is monomorphic enough for that.
-    Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
-
-    /// Used to hold computed value.
-    Value(ConstValue<'tcx>),
-
-    /// A placeholder for a const which could not be computed; this is
-    /// propagated to avoid useless error messages.
-    Error(DelaySpanBugEmitted),
-}
-
-#[cfg(target_arch = "x86_64")]
-static_assert_size!(ConstKind<'_>, 40);
-
-impl<'tcx> ConstKind<'tcx> {
-    #[inline]
-    pub fn try_to_scalar(&self) -> Option<Scalar> {
-        if let ConstKind::Value(val) = self { val.try_to_scalar() } else { None }
-    }
-
-    #[inline]
-    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
-        if let ConstKind::Value(val) = self { val.try_to_bits(size) } else { None }
-    }
-}
-
-/// An inference variable for a const, for use in const generics.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
-#[derive(HashStable)]
-pub enum InferConst<'tcx> {
-    /// Infer the value of the const.
-    Var(ConstVid<'tcx>),
-    /// A fresh const variable. See `infer::freshen` for more details.
-    Fresh(u32),
-}
index 67ad7ee708267968560c9b5b1b97106d5b041ff2..adba45facc9b4beabc61f2101a59619e6a852876 100644 (file)
@@ -471,8 +471,8 @@ pub fn is_constructor(self, def_id: DefId) -> bool {
     /// This is a significant `DefId` because, when we do
     /// type-checking, we type-check this fn item and all of its
     /// (transitive) closures together. Therefore, when we fetch the
-    /// `typeck_tables_of` the closure, for example, we really wind up
-    /// fetching the `typeck_tables_of` the enclosing fn item.
+    /// `typeck` the closure, for example, we really wind up
+    /// fetching the `typeck` the enclosing fn item.
     pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
         while self.is_closure(def_id) {
index 17846055f6c9615290796c931375e39317239e59..8e7c97c4a1baca8c8cac927fd02b158b0348590e 100644 (file)
@@ -262,7 +262,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                     .ty;
             let needs_note = match ty.kind {
                 ty::Closure(id, _) => {
-                    let tables = self.infcx.tcx.typeck_tables_of(id.expect_local());
+                    let tables = self.infcx.tcx.typeck(id.expect_local());
                     let hir_id = self.infcx.tcx.hir().as_local_hir_id(id.expect_local());
 
                     tables.closure_kind_origins().get(hir_id).is_none()
@@ -966,12 +966,7 @@ fn report_local_value_does_not_live_long_enough(
                         .opt_name(fn_hir_id)
                         .map(|name| format!("function `{}`", name))
                         .unwrap_or_else(|| {
-                            match &self
-                                .infcx
-                                .tcx
-                                .typeck_tables_of(self.mir_def_id)
-                                .node_type(fn_hir_id)
-                                .kind
+                            match &self.infcx.tcx.typeck(self.mir_def_id).node_type(fn_hir_id).kind
                             {
                                 ty::Closure(..) => "enclosing closure",
                                 ty::Generator(..) => "enclosing generator",
index e94952e1c543cd6ee92ee7b7cdfb189bbdc3aa06..d8f6abd92f6b88a87dcc3fcacda7234a86f0cf77 100644 (file)
@@ -107,7 +107,7 @@ pub(super) fn add_moved_or_invoked_closure_note(
                     let hir_id = self.infcx.tcx.hir().as_local_hir_id(did);
 
                     if let Some((span, name)) =
-                        self.infcx.tcx.typeck_tables_of(did).closure_kind_origins().get(hir_id)
+                        self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
                     {
                         diag.span_note(
                             *span,
@@ -130,7 +130,7 @@ pub(super) fn add_moved_or_invoked_closure_note(
                 let hir_id = self.infcx.tcx.hir().as_local_hir_id(did);
 
                 if let Some((span, name)) =
-                    self.infcx.tcx.typeck_tables_of(did).closure_kind_origins().get(hir_id)
+                    self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
                 {
                     diag.span_note(
                         *span,
index 4883b08e424423a71265093c884a7d3e069d3476..bd3e20458b078bb72f8237a908656f02d9f5bf11 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty;
 use rustc_span::source_map::DesugaringKind;
-use rustc_span::{Span, Symbol};
+use rustc_span::{sym, Span};
 
 use crate::borrow_check::diagnostics::UseSpans;
 use crate::borrow_check::prefixes::PrefixSet;
@@ -394,10 +394,8 @@ fn report_cannot_move_from_borrowed_content(
                 | ty::Opaque(def_id, _) => def_id,
                 _ => return err,
             };
-            let is_option =
-                self.infcx.tcx.is_diagnostic_item(Symbol::intern("option_type"), def_id);
-            let is_result =
-                self.infcx.tcx.is_diagnostic_item(Symbol::intern("result_type"), def_id);
+            let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
+            let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
             if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
                 err.span_suggestion(
                     span,
@@ -409,7 +407,7 @@ fn report_cannot_move_from_borrowed_content(
                     Applicability::MaybeIncorrect,
                 );
             } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_)))
-                && self.infcx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id)
+                && self.infcx.tcx.is_diagnostic_item(sym::vec_type, def_id)
             {
                 // FIXME: suggest for anything that implements `IntoIterator`.
                 err.span_suggestion(
index b4bc89e827daa7010b7608ab5b68ee73abb8a98b..ef0fe71abecb25da3c077da05de1a86b8b10661e 100644 (file)
@@ -507,7 +507,7 @@ fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Spa
                 .map(|(pos, _)| pos)
                 .next();
             let def_id = hir.local_def_id(item_id);
-            let tables = self.infcx.tcx.typeck_tables_of(def_id);
+            let tables = self.infcx.tcx.typeck(def_id);
             if let Some(ty::FnDef(def_id, _)) =
                 tables.node_type_opt(func.hir_id).as_ref().map(|ty| &ty.kind)
             {
index beb5f1fe924ece19bac9235d3152dd4b0cdfef52..1972b7149d569fb42a1066dd06eefe71129099a8 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt};
 use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
 const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref];
 
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers { mir_borrowck, ..*providers };
+    *providers = Providers {
+        mir_borrowck: |tcx, did| mir_borrowck(tcx, ty::WithOptConstParam::unknown(did)),
+        mir_borrowck_const_arg: |tcx, (did, param_did)| {
+            mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
+        },
+        ..*providers
+    };
 }
 
-fn mir_borrowck(tcx: TyCtxt<'_>, def_id: LocalDefId) -> BorrowCheckResult<'_> {
-    let (input_body, promoted) = tcx.mir_validated(def_id);
-    debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id.to_def_id()));
+fn mir_borrowck<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> &'tcx BorrowCheckResult<'tcx> {
+    if def.const_param_did.is_none() {
+        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_borrowck_const_arg((def.did, param_did));
+        }
+    }
+
+    let (input_body, promoted) = tcx.mir_validated(def);
+    debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
 
     let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
-        do_mir_borrowck(&infcx, input_body, promoted, def_id)
+        do_mir_borrowck(&infcx, input_body, promoted, def)
     });
     debug!("mir_borrowck done");
 
-    opt_closure_req
+    tcx.arena.alloc(opt_closure_req)
 }
 
 fn do_mir_borrowck<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     input_body: &Body<'tcx>,
     input_promoted: &IndexVec<Promoted, Body<'tcx>>,
-    def_id: LocalDefId,
+    def: ty::WithOptConstParam<LocalDefId>,
 ) -> BorrowCheckResult<'tcx> {
-    debug!("do_mir_borrowck(def_id = {:?})", def_id);
+    debug!("do_mir_borrowck(def = {:?})", def);
 
     let tcx = infcx.tcx;
-    let param_env = tcx.param_env(def_id);
-    let id = tcx.hir().as_local_hir_id(def_id);
+    let param_env = tcx.param_env(def.did);
+    let id = tcx.hir().as_local_hir_id(def.did);
 
     let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
     for var_debug_info in &input_body.var_debug_info {
@@ -135,13 +150,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     }
 
     // Gather the upvars of a closure, if any.
-    let tables = tcx.typeck_tables_of(def_id);
+    let tables = tcx.typeck_opt_const_arg(def);
     if let Some(ErrorReported) = tables.tainted_by_errors {
         infcx.set_tainted_by_errors();
     }
     let upvars: Vec<_> = tables
         .closure_captures
-        .get(&def_id.to_def_id())
+        .get(&def.did.to_def_id())
         .into_iter()
         .flat_map(|v| v.values())
         .map(|upvar_id| {
@@ -171,8 +186,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     // will have a lifetime tied to the inference context.
     let mut body = input_body.clone();
     let mut promoted = input_promoted.clone();
-    let free_regions =
-        nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
+    let free_regions = nll::replace_regions_in_mir(infcx, def, param_env, &mut body, &mut promoted);
     let body = &body; // no further changes
 
     let location_table = &LocationTable::new(&body);
@@ -190,7 +204,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mdpe = MoveDataParamEnv { move_data, param_env };
 
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint()
         .into_results_cursor(&body);
 
@@ -207,7 +221,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         nll_errors,
     } = nll::compute_regions(
         infcx,
-        def_id,
+        def.did,
         free_regions,
         body,
         &promoted,
@@ -223,7 +237,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     // write unit-tests, as well as helping with debugging.
     nll::dump_mir_results(
         infcx,
-        MirSource::item(def_id.to_def_id()),
+        MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None },
         &body,
         &regioncx,
         &opt_closure_req,
@@ -234,7 +248,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     nll::dump_annotation(
         infcx,
         &body,
-        def_id.to_def_id(),
+        def.did.to_def_id(),
         &regioncx,
         &opt_closure_req,
         &opaque_type_values,
@@ -249,13 +263,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     let regioncx = Rc::new(regioncx);
 
     let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
     let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
     let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
 
     let movable_generator = match tcx.hir().get(id) {
@@ -274,7 +288,7 @@ fn do_mir_borrowck<'a, 'tcx>(
             let mut promoted_mbcx = MirBorrowckCtxt {
                 infcx,
                 body: promoted_body,
-                mir_def_id: def_id,
+                mir_def_id: def.did,
                 move_data: &move_data,
                 location_table: &LocationTable::new(promoted_body),
                 movable_generator,
@@ -307,7 +321,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mut mbcx = MirBorrowckCtxt {
         infcx,
         body,
-        mir_def_id: def_id,
+        mir_def_id: def.did,
         move_data: &mdpe.move_data,
         location_table,
         movable_generator,
index ea68364be37a339aa4e60d8dcf4dbfa78cb97cc6..f6b3be59d9576acc36cb5eb5e3e7de764036fc96 100644 (file)
@@ -9,7 +9,7 @@
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
 };
-use rustc_middle::ty::{self, RegionKind, RegionVid};
+use rustc_middle::ty::{self, InstanceDef, RegionKind, RegionVid};
 use rustc_span::symbol::sym;
 use std::env;
 use std::fmt::Debug;
 /// `compute_regions`.
 pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    def_id: LocalDefId,
+    def: ty::WithOptConstParam<LocalDefId>,
     param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexVec<Promoted, Body<'tcx>>,
 ) -> UniversalRegions<'tcx> {
-    debug!("replace_regions_in_mir(def_id={:?})", def_id);
+    debug!("replace_regions_in_mir(def={:?})", def);
 
     // Compute named region information. This also renumbers the inputs/outputs.
-    let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
+    let universal_regions = UniversalRegions::new(infcx, def, param_env);
 
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
 
-    let source = MirSource::item(def_id.to_def_id());
+    let source = MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None };
     mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
 
     universal_regions
index 8cebd3679345f6e84afe5104eaa3edb6d4c0f34e..4846ef06a8b6ab81eadc0f946ca4bf2ef5a62702 100644 (file)
@@ -36,9 +36,9 @@ pub(super) fn equate_inputs_and_outputs(
         if !self.tcx().is_closure(self.mir_def_id.to_def_id()) {
             user_provided_sig = None;
         } else {
-            let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
+            let typeck_results = self.tcx().typeck(self.mir_def_id);
             user_provided_sig =
-                match typeck_tables.user_provided_sigs.get(&self.mir_def_id.to_def_id()) {
+                match typeck_results.user_provided_sigs.get(&self.mir_def_id.to_def_id()) {
                     None => None,
                     Some(user_provided_poly_sig) => {
                         // Instantiate the canonicalized variables from
index 3532b6de003ba1d24054f8be92b02c48628354cd..bede9b22bbb0af46888c96d1953156bb19d4b95f 100644 (file)
@@ -321,7 +321,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
             }
         } else {
             let tcx = self.tcx();
-            if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
+            if let ty::ConstKind::Unevaluated(def, substs, promoted) = constant.literal.val {
                 if let Some(promoted) = promoted {
                     let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
                                      promoted: &Body<'tcx>,
@@ -357,7 +357,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
                         ConstraintCategory::Boring,
                         self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
                             constant.literal.ty,
-                            def_id,
+                            def.did,
                             UserSubsts { substs, user_self_ty: None },
                         )),
                     ) {
@@ -1239,7 +1239,7 @@ fn eq_opaque_type_and_type(
         let tcx = infcx.tcx;
         let param_env = self.param_env;
         let body = self.body;
-        let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types;
+        let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types;
         let mut opaque_type_values = Vec::new();
 
         debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
index 7b292ee71f99d22f49dbef2ad6e5f4256b0473e2..c5aa5c5ebc7f2368fce8dd59ed78391dc0c0e593 100644 (file)
@@ -227,12 +227,12 @@ impl<'tcx> UniversalRegions<'tcx> {
     /// known between those regions.
     pub fn new(
         infcx: &InferCtxt<'_, 'tcx>,
-        mir_def_id: LocalDefId,
+        mir_def: ty::WithOptConstParam<LocalDefId>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Self {
         let tcx = infcx.tcx;
-        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id);
-        UniversalRegionsBuilder { infcx, mir_def_id, mir_hir_id, param_env }.build()
+        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def.did);
+        UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build()
     }
 
     /// Given a reference to a closure type, extracts all the values
@@ -388,7 +388,7 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
 
 struct UniversalRegionsBuilder<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
-    mir_def_id: LocalDefId,
+    mir_def: ty::WithOptConstParam<LocalDefId>,
     mir_hir_id: HirId,
     param_env: ty::ParamEnv<'tcx>,
 }
@@ -397,7 +397,7 @@ struct UniversalRegionsBuilder<'cx, 'tcx> {
 
 impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     fn build(self) -> UniversalRegions<'tcx> {
-        debug!("build(mir_def_id={:?})", self.mir_def_id);
+        debug!("build(mir_def={:?})", self.mir_def);
 
         let param_env = self.param_env;
         debug!("build: param_env={:?}", param_env);
@@ -417,7 +417,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id.to_def_id());
+        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
 
         // If this is a closure or generator, then the late-bound regions from the enclosing
         // function are actually external regions to us. For example, here, 'a is not local
@@ -425,8 +425,9 @@ fn build(self) -> UniversalRegions<'tcx> {
         // fn foo<'a>() {
         //     let c = || { let x: &'a u32 = ...; }
         // }
-        if self.mir_def_id.to_def_id() != closure_base_def_id {
-            self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
+        if self.mir_def.did.to_def_id() != closure_base_def_id {
+            self.infcx
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
         }
 
         let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
@@ -436,15 +437,15 @@ fn build(self) -> UniversalRegions<'tcx> {
         let first_local_index = self.infcx.num_region_vars();
         let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
             FR,
-            self.mir_def_id,
+            self.mir_def.did,
             &bound_inputs_and_output,
             &mut indices,
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def_id.to_def_id() == closure_base_def_id {
+        if self.mir_def.did.to_def_id() == closure_base_def_id {
             self.infcx
-                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
         }
 
         let (unnormalized_output_ty, mut unnormalized_input_tys) =
@@ -456,7 +457,7 @@ fn build(self) -> UniversalRegions<'tcx> {
             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)),
+                    Some(self.infcx.tcx.def_span(self.mir_def.did)),
                 );
                 let region = self
                     .infcx
@@ -507,14 +508,14 @@ fn build(self) -> UniversalRegions<'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def_id.to_def_id() == closure_base_def_id {
+                let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
                     tcx.type_of(closure_base_def_id)
                 } else {
-                    let tables = tcx.typeck_tables_of(self.mir_def_id);
+                    let tables = tcx.typeck(self.mir_def.did);
                     tables.node_type(self.mir_hir_id)
                 };
 
@@ -530,20 +531,20 @@ fn defining_ty(&self) -> DefiningTy<'tcx> {
                     }
                     ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs),
                     _ => span_bug!(
-                        tcx.def_span(self.mir_def_id),
+                        tcx.def_span(self.mir_def.did),
                         "expected defining type for `{:?}`: `{:?}`",
-                        self.mir_def_id,
+                        self.mir_def.did,
                         defining_ty
                     ),
                 }
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(self.mir_def_id.to_def_id(), closure_base_def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
                 let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
                 let substs =
                     self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
-                DefiningTy::Const(self.mir_def_id.to_def_id(), substs)
+                DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
             }
         }
     }
@@ -558,7 +559,7 @@ fn compute_indices(
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
         let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
         let fr_substs = match defining_ty {
             DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
@@ -592,7 +593,7 @@ fn compute_inputs_and_output(
         let tcx = self.infcx.tcx;
         match defining_ty {
             DefiningTy::Closure(def_id, substs) => {
-                assert_eq!(self.mir_def_id.to_def_id(), def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let closure_sig = substs.as_closure().sig();
                 let inputs_and_output = closure_sig.inputs_and_output();
                 let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
@@ -616,7 +617,7 @@ fn compute_inputs_and_output(
             }
 
             DefiningTy::Generator(def_id, substs, movability) => {
-                assert_eq!(self.mir_def_id.to_def_id(), def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let resume_ty = substs.as_generator().resume_ty();
                 let output = substs.as_generator().return_ty();
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
@@ -634,8 +635,8 @@ fn compute_inputs_and_output(
             DefiningTy::Const(def_id, _) => {
                 // For a constant body, there are no inputs, and one
                 // "output" (the type of the constant).
-                assert_eq!(self.mir_def_id.to_def_id(), def_id);
-                let ty = tcx.type_of(def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
+                let ty = tcx.type_of(self.mir_def.def_id_for_type_of());
                 let ty = indices.fold_to_region_vids(tcx, &ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
             }
index 24a0107ab9689fb220b6a707e183eceaaca2bcba..dc3e01f3d156128793a69a789b1b25c187fb4bac 100644 (file)
@@ -288,21 +288,21 @@ pub fn const_eval_raw_provider<'tcx>(
     }
 
     let cid = key.value;
-    let def_id = cid.instance.def.def_id();
+    let def = cid.instance.def.with_opt_param();
 
-    if let Some(def_id) = def_id.as_local() {
-        if tcx.has_typeck_tables(def_id) {
-            if let Some(error_reported) = tcx.typeck_tables_of(def_id).tainted_by_errors {
+    if let Some(def) = def.as_local() {
+        if tcx.has_typeck_results(def.did) {
+            if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors {
                 return Err(ErrorHandled::Reported(error_reported));
             }
         }
     }
 
-    let is_static = tcx.is_static(def_id);
+    let is_static = tcx.is_static(def.did);
 
     let mut ecx = InterpCx::new(
         tcx,
-        tcx.def_span(cid.instance.def_id()),
+        tcx.def_span(def.did),
         key.param_env,
         CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
         MemoryExtra { can_access_statics: is_static },
@@ -334,9 +334,9 @@ pub fn const_eval_raw_provider<'tcx>(
                 }
 
                 v
-            } else if let Some(def_id) = def_id.as_local() {
+            } else if let Some(def) = def.as_local() {
                 // constant defined in this crate, we can figure out a lint level!
-                match tcx.def_kind(def_id.to_def_id()) {
+                match tcx.def_kind(def.did.to_def_id()) {
                     // constants never produce a hard error at the definition site. Anything else is
                     // a backwards compatibility hazard (and will break old versions of winapi for
                     // sure)
@@ -346,9 +346,9 @@ pub fn const_eval_raw_provider<'tcx>(
                     // validation thus preventing such a hard error from being a backwards
                     // compatibility hazard
                     DefKind::Const | DefKind::AssocConst => {
-                        let hir_id = tcx.hir().as_local_hir_id(def_id);
+                        let hir_id = tcx.hir().as_local_hir_id(def.did);
                         err.report_as_lint(
-                            tcx.at(tcx.def_span(def_id)),
+                            tcx.at(tcx.def_span(def.did)),
                             "any use of this value will cause an error",
                             hir_id,
                             Some(err.span),
@@ -359,7 +359,7 @@ pub fn const_eval_raw_provider<'tcx>(
                     // deny-by-default lint
                     _ => {
                         if let Some(p) = cid.promoted {
-                            let span = tcx.promoted_mir(def_id)[p].span;
+                            let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span;
                             if let err_inval!(ReferencedConstant) = err.error {
                                 err.report_as_error(
                                     tcx.at(span),
@@ -369,7 +369,7 @@ pub fn const_eval_raw_provider<'tcx>(
                                 err.report_as_lint(
                                     tcx.at(span),
                                     "reaching this expression at runtime will panic or abort",
-                                    tcx.hir().as_local_hir_id(def_id),
+                                    tcx.hir().as_local_hir_id(def.did),
                                     Some(err.span),
                                 )
                             }
index 8be0ab9019fe228d064b49dc921be8839bb31da4..6453630bb92ba07f03a178ed34d0f99e1823436c 100644 (file)
@@ -191,11 +191,11 @@ fn find_mir_or_eval_fn(
         debug!("find_mir_or_eval_fn: {:?}", instance);
 
         // Only check non-glue functions
-        if let ty::InstanceDef::Item(def_id) = instance.def {
+        if let ty::InstanceDef::Item(def) = instance.def {
             // Execution might have wandered off into other crates, so we cannot do a stability-
             // sensitive check here.  But we can at least rule out functions that are not const
             // at all.
-            if ecx.tcx.is_const_fn_raw(def_id) {
+            if ecx.tcx.is_const_fn_raw(def.did) {
                 // If this function is a `const fn` then under certain circumstances we
                 // can evaluate call via the query system, thus memoizing all future calls.
                 if ecx.try_eval_const_fn_call(instance, ret, args)? {
index 2ae353adfc7f3a792aa7590b14a000b9b8655685..4f5930dc3f5a209c9e3d6baccef11bdad4fcfcab 100644 (file)
@@ -34,6 +34,9 @@ pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
     ///
     /// When this flag is set, we need to reset to an entry set before doing a seek.
     state_needs_reset: bool,
+
+    #[cfg(debug_assertions)]
+    reachable_blocks: BitSet<BasicBlock>,
 }
 
 impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
@@ -55,6 +58,9 @@ pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
             state_needs_reset: true,
             state: BitSet::new_empty(bits_per_block),
             pos: CursorPosition::block_entry(mir::START_BLOCK),
+
+            #[cfg(debug_assertions)]
+            reachable_blocks: mir::traversal::reachable_as_bitset(body),
         }
     }
 
@@ -85,6 +91,9 @@ pub fn contains(&self, elem: A::Idx) -> bool {
     ///
     /// For backward dataflow analyses, this is the dataflow state after the terminator.
     pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) {
+        #[cfg(debug_assertions)]
+        assert!(self.reachable_blocks.contains(block));
+
         self.state.overwrite(&self.results.borrow().entry_set_for_block(block));
         self.pos = CursorPosition::block_entry(block);
         self.state_needs_reset = false;
index 243b3679f2984644e95eb94f0a29f7c23a672936..003c40f290b8d02db5cf163d5dd4b1ce7322906c 100644 (file)
@@ -52,6 +52,15 @@ pub fn visit_with(
         visit_results(body, blocks, self, vis)
     }
 
+    pub fn visit_reachable_with(
+        &self,
+        body: &'mir mir::Body<'tcx>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet<A::Idx>>,
+    ) {
+        let blocks = mir::traversal::reachable(body);
+        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
+    }
+
     pub fn visit_in_rpo_with(
         &self,
         body: &'mir mir::Body<'tcx>,
@@ -204,15 +213,6 @@ pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> {
             }
         }
 
-        // Add blocks that are not reachable from START_BLOCK to the work queue. These blocks will
-        // be processed after the ones added above.
-        //
-        // FIXME(ecstaticmorse): Is this actually necessary? In principle, we shouldn't need to
-        // know the dataflow state in unreachable basic blocks.
-        for bb in body.basic_blocks().indices() {
-            dirty_queue.insert(bb);
-        }
-
         let mut state = BitSet::new_empty(bits_per_block);
         while let Some(bb) = dirty_queue.pop() {
             let bb_data = &body[bb];
index 0df9322e7fe088e222a71fd632ad6d0817732a8f..257f3cb9a6dd0ddd1026b1041fbe6babc3e13238 100644 (file)
@@ -16,7 +16,13 @@ pub fn visit_results<F, V>(
 {
     let mut state = results.new_flow_state(body);
 
+    #[cfg(debug_assertions)]
+    let reachable_blocks = mir::traversal::reachable_as_bitset(body);
+
     for block in blocks {
+        #[cfg(debug_assertions)]
+        assert!(reachable_blocks.contains(block));
+
         let block_data = &body[block];
         V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
     }
index 602876e3de1686e97ce6bb1513e05ba6492c3a85..ba462ec35eacf100f8c26cea6a9398ad6017ea73 100644 (file)
@@ -394,24 +394,28 @@ pub fn load_mir(
         promoted: Option<mir::Promoted>,
     ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
         // do not continue if typeck errors occurred (can only occur in local crate)
-        let did = instance.def_id();
-        if let Some(did) = did.as_local() {
-            if self.tcx.has_typeck_tables(did) {
-                if let Some(error_reported) = self.tcx.typeck_tables_of(did).tainted_by_errors {
+        let def = instance.with_opt_param();
+        if let Some(def) = def.as_local() {
+            if self.tcx.has_typeck_results(def.did) {
+                if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors {
                     throw_inval!(TypeckError(error_reported))
                 }
             }
         }
         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
         if let Some(promoted) = promoted {
-            return Ok(&self.tcx.promoted_mir(did)[promoted]);
+            return Ok(&self.tcx.promoted_mir_of_opt_const_arg(def)[promoted]);
         }
         match instance {
-            ty::InstanceDef::Item(def_id) => {
-                if self.tcx.is_mir_available(did) {
-                    Ok(self.tcx.optimized_mir(did))
+            ty::InstanceDef::Item(def) => {
+                if self.tcx.is_mir_available(def.did) {
+                    if let Some((did, param_did)) = def.as_const_arg() {
+                        Ok(self.tcx.optimized_mir_of_const_arg((did, param_did)))
+                    } else {
+                        Ok(self.tcx.optimized_mir(def.did))
+                    }
                 } else {
-                    throw_unsup!(NoMirFor(def_id))
+                    throw_unsup!(NoMirFor(def.did))
                 }
             }
             _ => Ok(self.tcx.instance_mir(instance)),
index 851862640226f5a2b303c135b83ba000a93c144c..5836fc9c95a80af6cb330c332a4446f3094665e6 100644 (file)
@@ -95,6 +95,7 @@ pub fn emulate_intrinsic(
         let (dest, ret) = match ret {
             None => match intrinsic_name {
                 sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
+                sym::unreachable => throw_ub!(Unreachable),
                 sym::abort => M::abort(self)?,
                 // Unsupported diverging intrinsic.
                 _ => return Ok(false),
index b02b5219ba1a4f95c718983d27f127e942b26a42..face72d70cea0b6d36fd2f7265f2a36024cd9998 100644 (file)
@@ -549,8 +549,8 @@ pub(super) fn eval_operands(
         let val_val = match val.val {
             ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
-            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
-                let instance = self.resolve(def_id, substs)?;
+            ty::ConstKind::Unevaluated(def, substs, promoted) => {
+                let instance = self.resolve(def.did, substs)?;
                 // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
                 // The reason we use `const_eval_raw` everywhere else is to prevent cycles during
                 // validation, because validation automatically reads through any references, thus
index 3868150c6bd288f71cb2f076b60a0f356c4de628..270be98606454516c75556e848315006030428b9 100644 (file)
@@ -922,7 +922,7 @@ pub fn copy_op_transmute(
             // FIXME: This should be an assert instead of an error, but if we transmute within an
             // array length computation, `typeck` may not have yet been run and errored out. In fact
             // most likey we *are* running `typeck` right now. Investigate whether we can bail out
-            // on `typeck_tables().has_errors` at all const eval entry points.
+            // on `typeck_results().has_errors` at all const eval entry points.
             debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
             self.tcx.sess.delay_span_bug(
                 self.cur_span(),
index f95ac309424d04201d0976bd6dfe04ddfaec7d5b..84f39ac8955b6f0d91e7033801bff073e6f604f9 100644 (file)
@@ -226,7 +226,7 @@ fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize)
             ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
                 let mut name = None;
                 if let Some(def_id) = def_id.as_local() {
-                    let tables = self.ecx.tcx.typeck_tables_of(def_id);
+                    let tables = self.ecx.tcx.typeck(def_id);
                     if let Some(upvars) = tables.closure_captures.get(&def_id.to_def_id()) {
                         // Sometimes the index is beyond the number of upvars (seen
                         // for a generator).
index eff1dc135554fd9cc1efcdd9e1e21e52bedf9c8e..cd6c38997f18f6a7d843214aad8d2e2c00af0a81 100644 (file)
@@ -10,8 +10,6 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(const_fn)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
-#![cfg_attr(bootstrap, feature(const_loop))]
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
index f9b3c319c1f66654463ee89ff3c6386007f9325c..35fb950ce66b9397eeb632da6c2dd240f9d07184 100644 (file)
@@ -622,12 +622,12 @@ fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location)
 
         match substituted_constant.val {
             ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
-            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
-                match self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
+            ty::ConstKind::Unevaluated(def, substs, promoted) => {
+                match self.tcx.const_eval_resolve(param_env, def, substs, promoted, None) {
                     Ok(val) => collect_const_value(self.tcx, val, self.output),
                     Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
                     Err(ErrorHandled::TooGeneric) => span_bug!(
-                        self.tcx.def_span(def_id),
+                        self.tcx.def_span(def.did),
                         "collection encountered polymorphic constant",
                     ),
                 }
@@ -768,8 +768,8 @@ fn visit_instance_use<'tcx>(
 // need a mono item.
 fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
     let def_id = match instance.def {
-        ty::InstanceDef::Item(def_id) | ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
-
+        ty::InstanceDef::Item(def) => def.did,
+        ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
         ty::InstanceDef::VtableShim(..)
         | ty::InstanceDef::ReifyShim(..)
         | ty::InstanceDef::ClosureOnceShim { .. }
index ebea65c8f96f288f795346ed3bd39a2a348ace1f..6162651db14a0b8d8780a5fadd6e32351eaa5f74 100644 (file)
@@ -161,7 +161,7 @@ pub fn partition<'tcx, I>(
 
     // 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 {
+    if tcx.sess.opts.cg.link_dead_code != Some(true) {
         let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
         internalize_symbols(tcx, &mut post_inlining, inlining_map);
     }
@@ -314,7 +314,8 @@ fn mono_item_visibility(
     };
 
     let def_id = match instance.def {
-        InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id,
+        InstanceDef::Item(def) => def.did,
+        InstanceDef::DropGlue(def_id, Some(_)) => def_id,
 
         // These are all compiler glue and such, never exported, always hidden.
         InstanceDef::VtableShim(..)
@@ -704,7 +705,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
     match mono_item {
         MonoItem::Fn(instance) => {
             let def_id = match instance.def {
-                ty::InstanceDef::Item(def_id) => def_id,
+                ty::InstanceDef::Item(def) => def.did,
                 ty::InstanceDef::VtableShim(..)
                 | ty::InstanceDef::ReifyShim(..)
                 | ty::InstanceDef::FnPtrShim(..)
@@ -817,7 +818,7 @@ fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
             debug!("CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate());
 
             for (mono_item, linkage) in cgu.items() {
-                let symbol_name = mono_item.symbol_name(tcx).name.as_str();
+                let symbol_name = mono_item.symbol_name(tcx).name;
                 let symbol_hash_start = symbol_name.rfind('h');
                 let symbol_hash =
                     symbol_hash_start.map(|i| &symbol_name[i..]).unwrap_or("<no hash>");
@@ -905,7 +906,7 @@ fn collect_and_partition_mono_items(
             }
         }
         None => {
-            if tcx.sess.opts.cg.link_dead_code {
+            if tcx.sess.opts.cg.link_dead_code == Some(true) {
                 MonoItemCollectionMode::Eager
             } else {
                 MonoItemCollectionMode::Lazy
index 3dddd9c1c1766cea6845b18c7de17dac227fdee9..445a0230afd3a977d144b3240eb9e2f4236c67c2 100644 (file)
@@ -244,11 +244,16 @@ pub fn in_operand<Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, operand: &Oper
     };
 
     // Check the qualifs of the value of `const` items.
-    if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val {
+    if let ty::ConstKind::Unevaluated(def, _, promoted) = constant.literal.val {
         assert!(promoted.is_none());
         // Don't peek inside trait associated constants.
-        if cx.tcx.trait_of_item(def_id).is_none() {
-            let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def_id);
+        if cx.tcx.trait_of_item(def.did).is_none() {
+            let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
+                cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
+            } else {
+                cx.tcx.at(constant.span).mir_const_qualif(def.did)
+            };
+
             if !Q::in_qualifs(&qualifs) {
                 return false;
             }
index 5cb161ebcfb5ea4ca8f3f62a642e4c13b1052780..f64c72e7b362dfce3c0621308d4d1f3951fef38a 100644 (file)
@@ -520,8 +520,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs);
                     debug!("Resolving ({:?}) -> {:?}", def_id, instance);
                     if let Ok(Some(func)) = instance {
-                        if let InstanceDef::Item(def_id) = func.def {
-                            if is_const_fn(self.tcx, def_id) {
+                        if let InstanceDef::Item(def) = func.def {
+                            if is_const_fn(self.tcx, def.did) {
                                 return;
                             }
                         }
index f218dd397c0c8d9e59558b9d7b5da3adede2e6e9..81d7ac089262206aa24957a226f5c50ea627701e 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
 
 use std::ops::Bound;
 
@@ -86,10 +86,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 let sig = func_ty.fn_sig(self.tcx);
                 if let hir::Unsafety::Unsafe = sig.unsafety() {
                     self.require_unsafe(
-                        "call to unsafe function",
-                        "consult the function's documentation for information on how to avoid \
-                         undefined behavior",
                         UnsafetyViolationKind::GeneralAndConstFn,
+                        UnsafetyViolationDetails::CallToUnsafeFunction,
                     )
                 }
 
@@ -99,9 +97,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             }
 
             TerminatorKind::InlineAsm { .. } => self.require_unsafe(
-                "use of inline assembly",
-                "inline assembly is entirely unchecked and can cause undefined behavior",
                 UnsafetyViolationKind::General,
+                UnsafetyViolationDetails::UseOfInlineAssembly,
             ),
         }
         self.super_terminator(terminator, location);
@@ -122,9 +119,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             }
 
             StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
-                "use of inline assembly",
-                "inline assembly is entirely unchecked and can cause undefined behavior",
                 UnsafetyViolationKind::General,
+                UnsafetyViolationDetails::UseOfInlineAssembly,
             ),
         }
         self.super_statement(statement, location);
@@ -138,10 +134,8 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     match self.tcx.layout_scalar_valid_range(def.did) {
                         (Bound::Unbounded, Bound::Unbounded) => {}
                         _ => self.require_unsafe(
-                            "initializing type with `rustc_layout_scalar_valid_range` attr",
-                            "initializing a layout restricted type's field with a value \
-                                outside the valid range is undefined behavior",
                             UnsafetyViolationKind::GeneralAndConstFn,
+                            UnsafetyViolationDetails::InitializingTypeWith,
                         ),
                     }
                 }
@@ -163,9 +157,8 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 match (cast_in, cast_out) {
                     (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
                         self.require_unsafe(
-                            "cast of pointer to int",
-                            "casting pointers to integers in constants",
                             UnsafetyViolationKind::General,
+                            UnsafetyViolationDetails::CastOfPointerToInt,
                         );
                     }
                     _ => {}
@@ -190,11 +183,8 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
         if context.is_borrow() {
             if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
                 self.require_unsafe(
-                    "borrow of packed field",
-                    "fields of packed structs might be misaligned: dereferencing a \
-                    misaligned pointer or even just creating a misaligned reference \
-                    is undefined behavior",
                     UnsafetyViolationKind::BorrowPacked,
+                    UnsafetyViolationDetails::BorrowOfPackedField,
                 );
             }
         }
@@ -204,11 +194,8 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
             if context.is_borrow() {
                 if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
                     self.require_unsafe(
-                        "borrow of packed field",
-                        "fields of packed structs might be misaligned: dereferencing a \
-                        misaligned pointer or even just creating a misaligned reference \
-                        is undefined behavior",
                         UnsafetyViolationKind::BorrowPacked,
+                        UnsafetyViolationDetails::BorrowOfPackedField,
                     );
                 }
             }
@@ -219,19 +206,14 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                     if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
                         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,
+                                UnsafetyViolationDetails::UseOfMutableStatic,
                             );
                             return;
                         } else if self.tcx.is_foreign_item(def_id) {
                             self.require_unsafe(
-                                "use of extern static",
-                                "extern statics are not controlled by the Rust type system: \
-                            invalid data, aliasing violations or data races will cause \
-                            undefined behavior",
                                 UnsafetyViolationKind::General,
+                                UnsafetyViolationDetails::UseOfExternStatic,
                             );
                             return;
                         }
@@ -246,11 +228,8 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
             let base_ty = Place::ty_from(place.local, 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,
+                    UnsafetyViolationDetails::DerefOfRawPointer,
                 ),
                 ty::Adt(adt, _) => {
                     if adt.is_union() {
@@ -271,21 +250,16 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                                 self.param_env,
                             ) {
                                 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,
+                                    UnsafetyViolationDetails::AssignToNonCopyUnionField,
                                 )
                             } else {
                                 // 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,
+                                UnsafetyViolationDetails::AccessToUnionField,
                             )
                         }
                     }
@@ -298,12 +272,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
 }
 
 impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn require_unsafe(
-        &mut self,
-        description: &'static str,
-        details: &'static str,
-        kind: UnsafetyViolationKind,
-    ) {
+    fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
         let source_info = self.source_info;
         let lint_root = self.body.source_scopes[self.source_info.scope]
             .local_data
@@ -311,13 +280,7 @@ fn require_unsafe(
             .assert_crate_local()
             .lint_root;
         self.register_violations(
-            &[UnsafetyViolation {
-                source_info,
-                lint_root,
-                description: Symbol::intern(description),
-                details: Symbol::intern(details),
-                kind,
-            }],
+            &[UnsafetyViolation { source_info, lint_root, kind, details }],
             &[],
         );
     }
@@ -434,12 +397,8 @@ fn check_mut_borrowing_layout_constrained_field(
                         if self.tcx.layout_scalar_valid_range(def.did)
                             != (Bound::Unbounded, Bound::Unbounded)
                         {
-                            let (description, details) = if is_mut_use {
-                                (
-                                    "mutation of layout constrained field",
-                                    "mutating layout constrained fields cannot statically be \
-                                        checked for valid values",
-                                )
+                            let details = if is_mut_use {
+                                UnsafetyViolationDetails::MutationOfLayoutConstrainedField
 
                             // Check `is_freeze` as late as possible to avoid cycle errors
                             // with opaque types.
@@ -448,21 +407,11 @@ fn check_mut_borrowing_layout_constrained_field(
                                 .ty
                                 .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
                             {
-                                (
-                                    "borrow of layout constrained field with interior \
-                                        mutability",
-                                    "references to fields of layout constrained fields \
-                                        lose the constraints. Coupled with interior mutability, \
-                                        the field can be changed to invalid values",
-                                )
+                                UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
                             } else {
                                 continue;
                             };
-                            self.require_unsafe(
-                                description,
-                                details,
-                                UnsafetyViolationKind::GeneralAndConstFn,
-                            );
+                            self.require_unsafe(UnsafetyViolationKind::GeneralAndConstFn, details);
                         }
                     }
                 }
@@ -480,16 +429,27 @@ fn check_target_features(&mut self, func_did: DefId) {
         // Is `callee_features` a subset of `calling_features`?
         if !callee_features.iter().all(|feature| self_features.contains(feature)) {
             self.require_unsafe(
-                "call to function with `#[target_feature]`",
-                "can only be called if the required target features are available",
                 UnsafetyViolationKind::GeneralAndConstFn,
+                UnsafetyViolationDetails::CallToFunctionWith,
             )
         }
     }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { unsafety_check_result, unsafe_derive_on_repr_packed, ..*providers };
+    *providers = Providers {
+        unsafety_check_result: |tcx, def_id| {
+            unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
+        },
+        unsafety_check_result_for_const_arg: |tcx, (did, param_did)| {
+            unsafety_check_result(
+                tcx,
+                ty::WithOptConstParam { did, const_param_did: Some(param_did) },
+            )
+        },
+        unsafe_derive_on_repr_packed,
+        ..*providers
+    };
 }
 
 struct UnusedUnsafeVisitor<'a> {
@@ -535,32 +495,42 @@ fn check_unused_unsafe(
     intravisit::Visitor::visit_body(&mut visitor, body);
 }
 
-fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckResult {
-    debug!("unsafety_violations({:?})", def_id);
+fn unsafety_check_result<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> &'tcx UnsafetyCheckResult {
+    if def.const_param_did.is_none() {
+        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
+            return tcx.unsafety_check_result_for_const_arg((def.did, param_did));
+        }
+    }
+
+    debug!("unsafety_violations({:?})", def);
 
     // N.B., this borrow is valid because all the consumers of
     // `mir_built` force this.
-    let body = &tcx.mir_built(def_id).borrow();
+    let body = &tcx.mir_built(def).borrow();
 
-    let param_env = tcx.param_env(def_id);
+    let param_env = tcx.param_env(def.did);
 
-    let id = tcx.hir().as_local_hir_id(def_id);
+    let id = tcx.hir().as_local_hir_id(def.did);
     let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
         hir::BodyOwnerKind::Closure => (false, false),
         hir::BodyOwnerKind::Fn => {
-            (tcx.is_const_fn_raw(def_id.to_def_id()), is_min_const_fn(tcx, def_id.to_def_id()))
+            (tcx.is_const_fn_raw(def.did.to_def_id()), is_min_const_fn(tcx, def.did.to_def_id()))
         }
         hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
     };
     let mut checker =
-        UnsafetyChecker::new(const_context, min_const_fn, body, def_id, tcx, param_env);
+        UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env);
     checker.visit_body(&body);
 
-    check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks);
-    UnsafetyCheckResult {
+    check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
+
+    tcx.arena.alloc(UnsafetyCheckResult {
         violations: checker.violations.into(),
         unsafe_blocks: checker.inherited_blocks.into(),
-    }
+    })
 }
 
 fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
@@ -653,9 +623,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
     let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id);
 
-    for &UnsafetyViolation { source_info, lint_root, description, details, kind } in
-        violations.iter()
-    {
+    for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
+        let (description, note) = details.description_and_note();
+
         // Report an error.
         let unsafe_fn_msg =
             if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
@@ -671,8 +641,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     description,
                     unsafe_fn_msg,
                 )
-                .span_label(source_info.span, &*description.as_str())
-                .note(&details.as_str())
+                .span_label(source_info.span, description)
+                .note(note)
                 .emit();
             }
             UnsafetyViolationKind::BorrowPacked => {
@@ -690,7 +660,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                                 "{} is unsafe and requires unsafe{} block (error E0133)",
                                 description, unsafe_fn_msg,
                             ))
-                            .note(&details.as_str())
+                            .note(note)
                             .emit()
                         },
                     )
@@ -705,8 +675,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                         "{} is unsafe and requires unsafe block (error E0133)",
                         description,
                     ))
-                    .span_label(source_info.span, &*description.as_str())
-                    .note(&details.as_str())
+                    .span_label(source_info.span, description)
+                    .note(note)
                     .emit();
                 },
             ),
@@ -734,8 +704,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                         "{} is unsafe and requires unsafe block (error E0133)",
                         description,
                     ))
-                    .span_label(source_info.span, &*description.as_str())
-                    .note(&details.as_str())
+                    .span_label(source_info.span, description)
+                    .note(note)
                     .emit();
                 })
             }
index fbe3377d87500f754797dfb1845d83c42594a379..237a5a64f8bf851cc600a24ff2f782d48c3dd6b8 100644 (file)
@@ -484,7 +484,7 @@ fn report_assert_as_lint(
         lint: &'static lint::Lint,
         source_info: SourceInfo,
         message: &'static str,
-        panic: AssertKind<ConstInt>,
+        panic: AssertKind<impl std::fmt::Debug>,
     ) -> Option<()> {
         let lint_root = self.lint_root(source_info)?;
         self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
@@ -1004,11 +1004,27 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
                     let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected));
                     let value_const = self.ecx.read_scalar(value).unwrap();
                     if expected != value_const {
+                        enum DbgVal<T> {
+                            Val(T),
+                            Underscore,
+                        }
+                        impl<T: std::fmt::Debug> std::fmt::Debug for DbgVal<T> {
+                            fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                                match self {
+                                    Self::Val(val) => val.fmt(fmt),
+                                    Self::Underscore => fmt.write_str("_"),
+                                }
+                            }
+                        }
                         let mut eval_to_int = |op| {
-                            let op = self
-                                .eval_operand(op, source_info)
-                                .expect("if we got here, it must be const");
-                            self.ecx.read_immediate(op).unwrap().to_const_int()
+                            // This can be `None` if the lhs wasn't const propagated and we just
+                            // triggered the assert on the value of the rhs.
+                            match self.eval_operand(op, source_info) {
+                                Some(op) => {
+                                    DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int())
+                                }
+                                None => DbgVal::Underscore,
+                            }
                         };
                         let msg = match msg {
                             AssertKind::DivisionByZero(op) => {
index 523d3c9af3f68c0dfde4f15e4272545618479c9d..8618cc126c563e336919ef366d306752ff1282ee 100644 (file)
@@ -624,9 +624,7 @@ fn compute_storage_conflicts(
         local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
     };
 
-    // Visit only reachable basic blocks. The exact order is not important.
-    let reachable_blocks = traversal::preorder(body).map(|(bb, _)| bb);
-    requires_storage.visit_with(body, reachable_blocks, &mut visitor);
+    requires_storage.visit_reachable_with(body, &mut visitor);
 
     let local_conflicts = visitor.local_conflicts;
 
index 76904b7edd533525da8d826d0c9c0bbe6fb8fd1a..9933a975e4dac194f98fe19a806e203280a6bdc9 100644 (file)
@@ -35,46 +35,64 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> Coverage
     // represents a single function. Validate and/or correct if inlining (which should be disabled
     // if -Zinstrument-coverage is enabled) and/or monomorphization invalidates these assumptions.
     let count_code_region_fn = tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None);
+    let coverage_counter_add_fn =
+        tcx.require_lang_item(lang_items::CoverageCounterAddFnLangItem, None);
+    let coverage_counter_subtract_fn =
+        tcx.require_lang_item(lang_items::CoverageCounterSubtractFnLangItem, None);
 
     // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected
     // counters, with each counter having an index from `0..num_counters-1`. MIR optimization
     // may split and duplicate some BasicBlock sequences. Simply counting the calls may not
     // not work; but computing the num_counters by adding `1` to the highest index (for a given
     // instrumented function) is valid.
+    //
+    // `num_expressions` is the number of counter expressions added to the MIR body. Both
+    // `num_counters` and `num_expressions` are used to initialize new vectors, during backend
+    // code generate, to lookup counters and expressions by their simple u32 indexes.
     let mut num_counters: u32 = 0;
-    for terminator in traversal::preorder(mir_body)
-        .map(|(_, data)| (data, count_code_region_fn))
-        .filter_map(terminators_that_call_given_fn)
+    let mut num_expressions: u32 = 0;
+    for terminator in
+        traversal::preorder(mir_body).map(|(_, data)| data).filter_map(call_terminators)
     {
-        if let TerminatorKind::Call { args, .. } = &terminator.kind {
-            let index_arg = args.get(count_code_region_args::COUNTER_INDEX).expect("arg found");
-            let index =
-                mir::Operand::scalar_from_const(index_arg).to_u32().expect("index arg is u32");
-            num_counters = std::cmp::max(num_counters, index + 1);
-        }
-    }
-    let hash = if num_counters > 0 { hash_mir_source(tcx, mir_def_id) } else { 0 };
-    CoverageInfo { num_counters, hash }
-}
-
-fn terminators_that_call_given_fn(
-    (data, fn_def_id): (&'tcx BasicBlockData<'tcx>, DefId),
-) -> Option<&'tcx Terminator<'tcx>> {
-    if let Some(terminator) = &data.terminator {
-        if let TerminatorKind::Call { func: Operand::Constant(func), .. } = &terminator.kind {
-            if let FnDef(called_fn_def_id, _) = func.literal.ty.kind {
-                if called_fn_def_id == fn_def_id {
-                    return Some(&terminator);
+        if let TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind {
+            match func.literal.ty.kind {
+                FnDef(id, _) if id == count_code_region_fn => {
+                    let index_arg =
+                        args.get(count_code_region_args::COUNTER_INDEX).expect("arg found");
+                    let counter_index = mir::Operand::scalar_from_const(index_arg)
+                        .to_u32()
+                        .expect("index arg is u32");
+                    num_counters = std::cmp::max(num_counters, counter_index + 1);
+                }
+                FnDef(id, _)
+                    if id == coverage_counter_add_fn || id == coverage_counter_subtract_fn =>
+                {
+                    let index_arg = args
+                        .get(coverage_counter_expression_args::COUNTER_EXPRESSION_INDEX)
+                        .expect("arg found");
+                    let translated_index = mir::Operand::scalar_from_const(index_arg)
+                        .to_u32()
+                        .expect("index arg is u32");
+                    // Counter expressions start with "translated indexes", descending from
+                    // `u32::MAX`, so the range of expression indexes is disjoint from the range of
+                    // counter indexes. This way, both counters and expressions can be operands in
+                    // other expressions.
+                    let expression_index = u32::MAX - translated_index;
+                    num_expressions = std::cmp::max(num_expressions, expression_index + 1);
                 }
+                _ => {}
             }
         }
     }
-    None
+    CoverageInfo { num_counters, num_expressions }
 }
 
-struct Instrumentor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    num_counters: u32,
+fn call_terminators(data: &'tcx BasicBlockData<'tcx>) -> Option<&'tcx Terminator<'tcx>> {
+    let terminator = data.terminator();
+    match terminator.kind {
+        TerminatorKind::Call { .. } => Some(terminator),
+        _ => None,
+    }
 }
 
 impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
@@ -83,42 +101,106 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &mut mir::
             // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
             // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
             if src.promoted.is_none() {
-                debug!(
-                    "instrumenting {:?}, span: {}",
-                    src.def_id(),
-                    tcx.sess.source_map().span_to_string(mir_body.span)
-                );
-                Instrumentor::new(tcx).inject_counters(mir_body);
+                Instrumentor::new(tcx, src, mir_body).inject_counters();
             }
         }
     }
 }
 
-impl<'tcx> Instrumentor<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        Self { tcx, num_counters: 0 }
+/// Distinguishes the expression operators.
+enum Op {
+    Add,
+    Subtract,
+}
+
+struct Instrumentor<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    mir_def_id: DefId,
+    mir_body: &'a mut mir::Body<'tcx>,
+    hir_body: &'tcx rustc_hir::Body<'tcx>,
+    function_source_hash: Option<u64>,
+    num_counters: u32,
+    num_expressions: u32,
+}
+
+impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
+        let mir_def_id = src.def_id();
+        let hir_body = hir_body(tcx, mir_def_id);
+        Self {
+            tcx,
+            mir_def_id,
+            mir_body,
+            hir_body,
+            function_source_hash: None,
+            num_counters: 0,
+            num_expressions: 0,
+        }
     }
 
+    /// Counter IDs start from zero and go up.
     fn next_counter(&mut self) -> u32 {
+        assert!(self.num_counters < u32::MAX - self.num_expressions);
         let next = self.num_counters;
         self.num_counters += 1;
         next
     }
 
-    fn inject_counters(&mut self, mir_body: &mut mir::Body<'tcx>) {
+    /// Expression IDs start from u32::MAX and go down because a CounterExpression can reference
+    /// (add or subtract counts) of both Counter regions and CounterExpression regions. The indexes
+    /// of each type of region must be contiguous, but also must be unique across both sets.
+    /// The expression IDs are eventually translated into region indexes (starting after the last
+    /// counter index, for the given function), during backend code generation, by the helper method
+    /// `rustc_codegen_ssa::coverageinfo::map::FunctionCoverage::translate_expressions()`.
+    fn next_expression(&mut self) -> u32 {
+        assert!(self.num_counters < u32::MAX - self.num_expressions);
+        let next = u32::MAX - self.num_expressions;
+        self.num_expressions += 1;
+        next
+    }
+
+    fn function_source_hash(&mut self) -> u64 {
+        match self.function_source_hash {
+            Some(hash) => hash,
+            None => {
+                let hash = hash_mir_source(self.tcx, self.hir_body);
+                self.function_source_hash.replace(hash);
+                hash
+            }
+        }
+    }
+
+    fn inject_counters(&mut self) {
+        let body_span = self.hir_body.value.span;
+        debug!(
+            "instrumenting {:?}, span: {}",
+            self.mir_def_id,
+            self.tcx.sess.source_map().span_to_string(body_span)
+        );
+
         // FIXME(richkadel): As a first step, counters are only injected at the top of each
         // function. The complete solution will inject counters at each conditional code branch.
-        let code_region = mir_body.span;
         let next_block = START_BLOCK;
-        self.inject_counter(mir_body, code_region, next_block);
+        self.inject_counter(body_span, next_block);
+
+        // FIXME(richkadel): The next step to implement source based coverage analysis will be
+        // instrumenting branches within functions, and some regions will be counted by "counter
+        // expression". The function to inject counter expression is implemented. Replace this
+        // "fake use" with real use.
+        let fake_use = false;
+        if fake_use {
+            let add = false;
+            if add {
+                self.inject_counter_expression(body_span, next_block, 1, Op::Add, 2);
+            } else {
+                self.inject_counter_expression(body_span, next_block, 1, Op::Subtract, 2);
+            }
+        }
     }
 
-    fn inject_counter(
-        &mut self,
-        mir_body: &mut mir::Body<'tcx>,
-        code_region: Span,
-        next_block: BasicBlock,
-    ) {
+    fn inject_counter(&mut self, code_region: Span, next_block: BasicBlock) -> u32 {
+        let counter_id = self.next_counter();
+        let function_source_hash = self.function_source_hash();
         let injection_point = code_region.shrink_to_lo();
 
         let count_code_region_fn = function_handle(
@@ -127,13 +209,14 @@ fn inject_counter(
             injection_point,
         );
 
-        let index = self.next_counter();
-
         let mut args = Vec::new();
 
         use count_code_region_args::*;
+        debug_assert_eq!(FUNCTION_SOURCE_HASH, args.len());
+        args.push(self.const_u64(function_source_hash, injection_point));
+
         debug_assert_eq!(COUNTER_INDEX, args.len());
-        args.push(self.const_u32(index, injection_point));
+        args.push(self.const_u32(counter_id, injection_point));
 
         debug_assert_eq!(START_BYTE_POS, args.len());
         args.push(self.const_u32(code_region.lo().to_u32(), injection_point));
@@ -141,36 +224,98 @@ fn inject_counter(
         debug_assert_eq!(END_BYTE_POS, args.len());
         args.push(self.const_u32(code_region.hi().to_u32(), injection_point));
 
-        let mut patch = MirPatch::new(mir_body);
+        self.inject_call(count_code_region_fn, args, injection_point, next_block);
 
-        let temp = patch.new_temp(self.tcx.mk_unit(), code_region);
-        let new_block = patch.new_block(placeholder_block(code_region));
+        counter_id
+    }
+
+    fn inject_counter_expression(
+        &mut self,
+        code_region: Span,
+        next_block: BasicBlock,
+        lhs: u32,
+        op: Op,
+        rhs: u32,
+    ) -> u32 {
+        let expression_id = self.next_expression();
+        let injection_point = code_region.shrink_to_lo();
+
+        let count_code_region_fn = function_handle(
+            self.tcx,
+            self.tcx.require_lang_item(
+                match op {
+                    Op::Add => lang_items::CoverageCounterAddFnLangItem,
+                    Op::Subtract => lang_items::CoverageCounterSubtractFnLangItem,
+                },
+                None,
+            ),
+            injection_point,
+        );
+
+        let mut args = Vec::new();
+
+        use coverage_counter_expression_args::*;
+        debug_assert_eq!(COUNTER_EXPRESSION_INDEX, args.len());
+        args.push(self.const_u32(expression_id, injection_point));
+
+        debug_assert_eq!(LEFT_INDEX, args.len());
+        args.push(self.const_u32(lhs, injection_point));
+
+        debug_assert_eq!(RIGHT_INDEX, args.len());
+        args.push(self.const_u32(rhs, injection_point));
+
+        debug_assert_eq!(START_BYTE_POS, args.len());
+        args.push(self.const_u32(code_region.lo().to_u32(), injection_point));
+
+        debug_assert_eq!(END_BYTE_POS, args.len());
+        args.push(self.const_u32(code_region.hi().to_u32(), injection_point));
+
+        self.inject_call(count_code_region_fn, args, injection_point, next_block);
+
+        expression_id
+    }
+
+    fn inject_call(
+        &mut self,
+        func: Operand<'tcx>,
+        args: Vec<Operand<'tcx>>,
+        fn_span: Span,
+        next_block: BasicBlock,
+    ) {
+        let mut patch = MirPatch::new(self.mir_body);
+
+        let temp = patch.new_temp(self.tcx.mk_unit(), fn_span);
+        let new_block = patch.new_block(placeholder_block(fn_span));
         patch.patch_terminator(
             new_block,
             TerminatorKind::Call {
-                func: count_code_region_fn,
+                func,
                 args,
                 // new_block will swapped with the next_block, after applying patch
                 destination: Some((Place::from(temp), new_block)),
                 cleanup: None,
                 from_hir_call: false,
-                fn_span: injection_point,
+                fn_span,
             },
         );
 
         patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp));
         patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp));
 
-        patch.apply(mir_body);
+        patch.apply(self.mir_body);
 
         // To insert the `new_block` in front of the first block in the counted branch (the
         // `next_block`), just swap the indexes, leaving the rest of the graph unchanged.
-        mir_body.basic_blocks_mut().swap(next_block, new_block);
+        self.mir_body.basic_blocks_mut().swap(next_block, new_block);
     }
 
     fn const_u32(&self, value: u32, span: Span) -> Operand<'tcx> {
         Operand::const_from_scalar(self.tcx, self.tcx.types.u32, Scalar::from_u32(value), span)
     }
+
+    fn const_u64(&self, value: u64, span: Span) -> Operand<'tcx> {
+        Operand::const_from_scalar(self.tcx, self.tcx.types.u64, Scalar::from_u64(value), span)
+    }
 }
 
 fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Operand<'tcx> {
@@ -192,10 +337,13 @@ fn placeholder_block(span: Span) -> BasicBlockData<'tcx> {
     }
 }
 
-fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> u64 {
+fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
     let hir_node = tcx.hir().get_if_local(def_id).expect("DefId is local");
     let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
-    let hir_body = tcx.hir().body(fn_body_id);
+    tcx.hir().body(fn_body_id)
+}
+
+fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
     let mut hcx = tcx.create_no_span_stable_hashing_context();
     hash(&mut hcx, &hir_body.value).to_smaller_hash()
 }
index 816cf08a6da488c739e6f0952a87857c08d5d9e4..51a9e76e762ebe50a66548dd4db53e0214da7417 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::steal::Steal;
-use rustc_middle::ty::{InstanceDef, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, InstanceDef, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
@@ -48,12 +48,23 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         mir_keys,
         mir_const,
-        mir_const_qualif,
+        mir_const_qualif: |tcx, did| {
+            mir_const_qualif(tcx, ty::WithOptConstParam::unknown(did.expect_local()))
+        },
+        mir_const_qualif_const_arg: |tcx, (did, param_did)| {
+            mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
+        },
         mir_validated,
         mir_drops_elaborated_and_const_checked,
         optimized_mir,
+        optimized_mir_of_const_arg,
         is_mir_available,
-        promoted_mir,
+        promoted_mir: |tcx, def_id| {
+            promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id.expect_local()))
+        },
+        promoted_mir_of_const_arg: |tcx, (did, param_did)| {
+            promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
+        },
         ..*providers
     };
     instrument_coverage::provide(providers);
@@ -116,7 +127,14 @@ pub struct MirSource<'tcx> {
 
 impl<'tcx> MirSource<'tcx> {
     pub fn item(def_id: DefId) -> Self {
-        MirSource { instance: InstanceDef::Item(def_id), promoted: None }
+        MirSource {
+            instance: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+            promoted: None,
+        }
+    }
+
+    pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
+        self.instance.with_opt_param()
     }
 
     #[inline]
@@ -202,9 +220,14 @@ pub fn run_passes(
     }
 }
 
-fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
-    let def_id = def_id.expect_local();
-    let const_kind = tcx.hir().body_const_context(def_id);
+fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
+    if def.const_param_did.is_none() {
+        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_const_qualif_const_arg((def.did, param_did));
+        }
+    }
+
+    let const_kind = tcx.hir().body_const_context(def.did);
 
     // No need to const-check a non-const `fn`.
     if const_kind.is_none() {
@@ -215,15 +238,20 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
     // cannot yet be stolen), because `mir_validated()`, which steals
     // from `mir_const(), forces this query to execute before
     // performing the steal.
-    let body = &tcx.mir_const(def_id.to_def_id()).borrow();
+    let body = &tcx.mir_const(def).borrow();
 
     if body.return_ty().references_error() {
         tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
         return Default::default();
     }
 
-    let ccx =
-        check_consts::ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
+    let ccx = check_consts::ConstCx {
+        body,
+        tcx,
+        def_id: def.did,
+        const_kind,
+        param_env: tcx.param_env(def.did),
+    };
 
     let mut validator = check_consts::validation::Validator::new(&ccx);
     validator.check_body();
@@ -234,22 +262,39 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
 }
 
 /// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
-fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal<Body<'_>> {
-    let def_id = def_id.expect_local();
+fn mir_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> &'tcx Steal<Body<'tcx>> {
+    if def.const_param_did.is_none() {
+        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_const(ty::WithOptConstParam { const_param_did, ..def });
+        }
+    }
 
     // Unsafety check uses the raw mir, so make sure it is run.
-    let _ = tcx.unsafety_check_result(def_id);
+    if let Some(param_did) = def.const_param_did {
+        tcx.ensure().unsafety_check_result_for_const_arg((def.did, param_did));
+    } else {
+        tcx.ensure().unsafety_check_result(def.did);
+    }
 
-    let mut body = tcx.mir_built(def_id).steal();
+    let mut body = tcx.mir_built(def).steal();
 
-    util::dump_mir(tcx, None, "mir_map", &0, MirSource::item(def_id.to_def_id()), &body, |_, _| {
-        Ok(())
-    });
+    util::dump_mir(
+        tcx,
+        None,
+        "mir_map",
+        &0,
+        MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None },
+        &body,
+        |_, _| Ok(()),
+    );
 
     run_passes(
         tcx,
         &mut body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(def.to_global()),
         None,
         MirPhase::Const,
         &[&[
@@ -265,13 +310,19 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal<Body<'_>> {
 
 fn mir_validated(
     tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> (Steal<Body<'tcx>>, Steal<IndexVec<Promoted, Body<'tcx>>>) {
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
+    if def.const_param_did.is_none() {
+        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_validated(ty::WithOptConstParam { const_param_did, ..def });
+        }
+    }
+
     // Ensure that we compute the `mir_const_qualif` for constants at
     // this point, before we steal the mir-const result.
-    let _ = tcx.mir_const_qualif(def_id.to_def_id());
+    let _ = tcx.mir_const_qualif_opt_const_arg(def);
 
-    let mut body = tcx.mir_const(def_id.to_def_id()).steal();
+    let mut body = tcx.mir_const(def).steal();
 
     let mut required_consts = Vec::new();
     let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
@@ -284,7 +335,7 @@ fn mir_validated(
     run_passes(
         tcx,
         &mut body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(def.to_global()),
         None,
         MirPhase::Validated,
         &[&[
@@ -304,17 +355,30 @@ fn mir_validated(
 
 fn mir_drops_elaborated_and_const_checked<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> Steal<Body<'tcx>> {
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> &'tcx Steal<Body<'tcx>> {
+    if def.const_param_did.is_none() {
+        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam {
+                const_param_did,
+                ..def
+            });
+        }
+    }
+
     // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
     // execute before we can steal.
-    tcx.ensure().mir_borrowck(def_id);
+    if let Some(param_did) = def.const_param_did {
+        tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
+    } else {
+        tcx.ensure().mir_borrowck(def.did);
+    }
 
-    let (body, _) = tcx.mir_validated(def_id);
+    let (body, _) = tcx.mir_validated(def);
     let mut body = body.steal();
 
-    run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, None);
-    check_consts::post_drop_elaboration::check_live_drops(tcx, def_id, &body);
+    run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, None);
+    check_consts::post_drop_elaboration::check_live_drops(tcx, def.did, &body);
     tcx.alloc_steal_mir(body)
 }
 
@@ -350,7 +414,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(
     run_passes(
         tcx,
         body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())),
         promoted,
         MirPhase::DropElab,
         &[post_borrowck_cleanup],
@@ -414,7 +478,7 @@ fn run_optimization_passes<'tcx>(
     run_passes(
         tcx,
         body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())),
         promoted,
         MirPhase::Optimized,
         &[
@@ -424,42 +488,70 @@ fn run_optimization_passes<'tcx>(
     );
 }
 
-fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
-    if tcx.is_constructor(def_id) {
+fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
+    let did = did.expect_local();
+    if let Some(param_did) = tcx.opt_const_param_of(did) {
+        tcx.optimized_mir_of_const_arg((did, param_did))
+    } else {
+        tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did)))
+    }
+}
+
+fn optimized_mir_of_const_arg<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (did, param_did): (LocalDefId, DefId),
+) -> &'tcx Body<'tcx> {
+    tcx.arena.alloc(inner_optimized_mir(
+        tcx,
+        ty::WithOptConstParam { did, const_param_did: Some(param_did) },
+    ))
+}
+
+fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+    if tcx.is_constructor(def.did.to_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);
+        return shim::build_adt_ctor(tcx, def.did.to_def_id());
     }
 
-    let def_id = def_id.expect_local();
-
-    let mut body = tcx.mir_drops_elaborated_and_const_checked(def_id).steal();
-    run_optimization_passes(tcx, &mut body, def_id, None);
+    let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
+    run_optimization_passes(tcx, &mut body, def.did, None);
 
     debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
 
     body
 }
 
-fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> IndexVec<Promoted, Body<'_>> {
-    if tcx.is_constructor(def_id) {
-        return IndexVec::new();
+fn promoted_mir<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
+    if def.const_param_did.is_none() {
+        if let Some(param_did) = tcx.opt_const_param_of(def.did) {
+            return tcx.promoted_mir_of_const_arg((def.did, param_did));
+        }
     }
 
-    let def_id = def_id.expect_local();
+    if tcx.is_constructor(def.did.to_def_id()) {
+        return tcx.arena.alloc(IndexVec::new());
+    }
 
-    tcx.ensure().mir_borrowck(def_id);
-    let (_, promoted) = tcx.mir_validated(def_id);
+    if let Some(param_did) = def.const_param_did {
+        tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
+    } else {
+        tcx.ensure().mir_borrowck(def.did);
+    }
+    let (_, promoted) = tcx.mir_validated(def);
     let mut promoted = promoted.steal();
 
     for (p, mut body) in promoted.iter_enumerated_mut() {
-        run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, Some(p));
-        run_optimization_passes(tcx, &mut body, def_id, Some(p));
+        run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, Some(p));
+        run_optimization_passes(tcx, &mut body, def.did, Some(p));
     }
 
     debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
 
-    promoted
+    tcx.arena.alloc(promoted)
 }
index 5aa67227994d918a1ac679cf6bee3394b4c65a5b..59a8415ef96f04d14cbb34a1ff0cba5699c02c9f 100644 (file)
@@ -60,16 +60,15 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx
             return;
         }
 
-        let def_id = src.def_id().expect_local();
+        let def = src.with_opt_param().expect_local();
 
         let mut rpo = traversal::reverse_postorder(body);
-        let ccx = ConstCx::new(tcx, def_id, body);
+        let ccx = ConstCx::new(tcx, def.did, body);
         let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
 
         let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
 
-        let promoted =
-            promote_candidates(def_id.to_def_id(), body, tcx, temps, promotable_candidates);
+        let promoted = promote_candidates(def.to_global(), body, tcx, temps, promotable_candidates);
         self.promoted_fragments.set(promoted);
     }
 }
@@ -937,7 +936,7 @@ fn promote_temp(&mut self, temp: Local) -> Local {
 
     fn promote_candidate(
         mut self,
-        def_id: DefId,
+        def: ty::WithOptConstParam<DefId>,
         candidate: Candidate,
         next_promoted_id: usize,
     ) -> Option<Body<'tcx>> {
@@ -955,8 +954,8 @@ fn promote_candidate(
                     literal: tcx.mk_const(ty::Const {
                         ty,
                         val: ty::ConstKind::Unevaluated(
-                            def_id,
-                            InternalSubsts::for_item(tcx, def_id, |param, _| {
+                            def,
+                            InternalSubsts::for_item(tcx, def.did, |param, _| {
                                 if let ty::GenericParamDefKind::Lifetime = param.kind {
                                     tcx.lifetimes.re_erased.into()
                                 } else {
@@ -1100,7 +1099,7 @@ fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
 }
 
 pub fn promote_candidates<'tcx>(
-    def_id: DefId,
+    def: ty::WithOptConstParam<DefId>,
     body: &mut Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     mut temps: IndexVec<Local, TempState>,
@@ -1157,7 +1156,7 @@ pub fn promote_candidates<'tcx>(
         };
 
         //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()) {
+        if let Some(promoted) = promoter.promote_candidate(def, candidate, promotions.len()) {
             promotions.push(promoted);
         }
     }
index db45481e4fd259acbd6114f6fb9768aba7727d7f..990bfc064c2beb0a1d9728b608eec7d7352ae47b 100644 (file)
@@ -248,7 +248,10 @@ pub fn write_mir_pretty<'tcx>(
 
         for (i, body) in tcx.promoted_mir(def_id).iter_enumerated() {
             writeln!(w)?;
-            let src = MirSource { instance: ty::InstanceDef::Item(def_id), promoted: Some(i) };
+            let src = MirSource {
+                instance: ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+                promoted: Some(i),
+            };
             write_mir_fn(tcx, src, body, &mut |_, _| Ok(()), w)?;
         }
     }
index 0d5bd4c7e61b90a5448f5c593a25bc9930b2a827..eaef6bb37faa591a40ee9b4e4bafbeabe52eb474 100644 (file)
@@ -188,10 +188,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let ptr_ty = ptr.ty;
                     // Create an *internal* temp for the pointer, so that unsafety
                     // checking won't complain about the raw pointer assignment.
-                    let ptr_temp = this.local_decls.push(LocalDecl::with_source_info(
-                        ptr_ty,
-                        source_info,
-                    ).internal());
+                    let ptr_temp = this
+                        .local_decls
+                        .push(LocalDecl::with_source_info(ptr_ty, source_info).internal());
                     let ptr_temp = Place::from(ptr_temp);
                     let block = unpack!(this.into(ptr_temp, block, ptr));
                     this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val)
@@ -224,7 +223,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 Some((destination, success))
                             },
                             from_hir_call,
-                            fn_span
+                            fn_span,
                         },
                     );
                     success.unit()
@@ -387,15 +386,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // These cases don't actually need a destination
             ExprKind::Assign { .. }
             | ExprKind::AssignOp { .. }
-            | ExprKind::Continue { .. }
-            | ExprKind::Break { .. }
-            | ExprKind::LlvmInlineAsm { .. }
-            | ExprKind::Return { .. } => {
+            | ExprKind::LlvmInlineAsm { .. } => {
                 unpack!(block = this.stmt_expr(block, expr, None));
                 this.cfg.push_assign_unit(block, source_info, destination, this.hir.tcx());
                 block.unit()
             }
 
+            ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Return { .. } => {
+                unpack!(block = this.stmt_expr(block, expr, None));
+                // No assign, as these have type `!`.
+                block.unit()
+            }
+
             // Avoid creating a temporary
             ExprKind::VarRef { .. }
             | ExprKind::SelfRef
index e69f6b30abd5cb89c27c87597a1640bb98484300..eb47195c06278d189fff0ac7c9c8204af936e97e 100644 (file)
 
 use super::lints;
 
-crate fn mir_built(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::steal::Steal<Body<'_>> {
-    tcx.alloc_steal_mir(mir_build(tcx, def_id))
+crate fn mir_built<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> &'tcx ty::steal::Steal<Body<'tcx>> {
+    if def.const_param_did.is_none() {
+        if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_built(ty::WithOptConstParam { const_param_did, ..def });
+        }
+    }
+
+    tcx.alloc_steal_mir(mir_build(tcx, def))
 }
 
 /// Construct the MIR for a given `DefId`.
-fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
-    let id = tcx.hir().as_local_hir_id(def_id);
+fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+    let id = tcx.hir().as_local_hir_id(def.did);
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span) = match tcx.hir().get(id) {
@@ -57,17 +66,17 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
         }) => (*body_id, ty.span),
         Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id)),
 
-        _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def_id),
+        _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did),
     };
 
     tcx.infer_ctxt().enter(|infcx| {
-        let cx = Cx::new(&infcx, id);
-        let body = if let Some(ErrorReported) = cx.tables().tainted_by_errors {
+        let cx = Cx::new(&infcx, def, id);
+        let body = if let Some(ErrorReported) = cx.typeck_results().tainted_by_errors {
             build::construct_error(cx, body_id)
         } else if cx.body_owner_kind.is_fn_or_closure() {
             // fetch the fully liberated fn signature (that is, all bound
             // types/lifetimes replaced)
-            let fn_sig = cx.tables().liberated_fn_sigs()[id];
+            let fn_sig = cx.typeck_results().liberated_fn_sigs()[id];
             let fn_def_id = tcx.hir().local_def_id(id);
 
             let safety = match fn_sig.unsafety {
@@ -86,7 +95,7 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
                     vec![ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None)]
                 }
                 ty::Generator(..) => {
-                    let gen_ty = tcx.body_tables(body_id).node_type(id);
+                    let gen_ty = tcx.typeck_body(body_id).node_type(id);
 
                     // The resume argument may be missing, in that case we need to provide it here.
                     // It will always be `()` in this case.
@@ -141,7 +150,7 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
             let arguments = implicit_argument.into_iter().chain(explicit_arguments);
 
             let (yield_ty, return_ty) = if body.generator_kind.is_some() {
-                let gen_ty = tcx.body_tables(body_id).node_type(id);
+                let gen_ty = tcx.typeck_body(body_id).node_type(id);
                 let gen_sig = match gen_ty.kind {
                     ty::Generator(_, gen_substs, ..) => gen_substs.as_generator().sig(),
                     _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty),
@@ -176,12 +185,12 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
             // place to be the type of the constant because NLL typeck will
             // equate them.
 
-            let return_ty = cx.tables().node_type(id);
+            let return_ty = cx.typeck_results().node_type(id);
 
             build::construct_const(cx, body_id, return_ty, return_ty_span)
         };
 
-        lints::check(tcx, &body, def_id);
+        lints::check(tcx, &body, def.did);
 
         // The borrow checker will replace all the regions here with its own
         // inference variables. There's no point having non-erased regions here.
@@ -208,7 +217,7 @@ fn liberated_closure_env_ty(
     closure_expr_id: hir::HirId,
     body_id: hir::BodyId,
 ) -> Ty<'_> {
-    let closure_ty = tcx.body_tables(body_id).node_type(closure_expr_id);
+    let closure_ty = tcx.typeck_body(body_id).node_type(closure_expr_id);
 
     let (closure_def_id, closure_substs) = match closure_ty.kind {
         ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs),
@@ -810,14 +819,14 @@ fn args_and_body(
 
         let tcx = self.hir.tcx();
         let tcx_hir = tcx.hir();
-        let hir_tables = self.hir.tables();
+        let hir_typeck_results = self.hir.typeck_results();
 
         // In analyze_closure() in upvar.rs we gathered a list of upvars used by a
-        // indexed closure and we stored in a map called closure_captures in TypeckTables
+        // indexed closure and we stored in a map called closure_captures in TypeckResults
         // with the closure's DefId. Here, we run through that vec of UpvarIds for
         // the given closure and use the necessary information to create upvar
         // debuginfo and to fill `self.upvar_mutbls`.
-        if let Some(upvars) = hir_tables.closure_captures.get(&fn_def_id) {
+        if let Some(upvars) = hir_typeck_results.closure_captures.get(&fn_def_id) {
             let closure_env_arg = Local::new(1);
             let mut closure_env_projs = vec![];
             let mut closure_ty = self.local_decls[closure_env_arg].ty;
@@ -835,14 +844,16 @@ fn args_and_body(
             self.upvar_mutbls = upvars_with_tys
                 .enumerate()
                 .map(|(i, ((&var_id, &upvar_id), ty))| {
-                    let capture = hir_tables.upvar_capture(upvar_id);
+                    let capture = hir_typeck_results.upvar_capture(upvar_id);
 
                     let mut mutability = Mutability::Not;
                     let mut name = kw::Invalid;
                     if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
                         if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
                             name = ident.name;
-                            match hir_tables.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) {
+                            match hir_typeck_results
+                                .extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
+                            {
                                 Some(ty::BindByValue(hir::Mutability::Mut)) => {
                                     mutability = Mutability::Mut;
                                 }
index c7b53024666d96b951e503460851c868f47a4f79..a5381781d1d8074e892a954d9b0ef4a009148ca0 100644 (file)
@@ -65,7 +65,7 @@ fn mirror_stmts<'a, 'tcx>(
                 let mut pattern = cx.pattern_from_hir(&local.pat);
 
                 if let Some(ty) = &local.ty {
-                    if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
+                    if let Some(&user_ty) = cx.typeck_results.user_provided_types().get(ty.hir_id) {
                         debug!("mirror_stmts: user_ty={:?}", user_ty);
                         pattern = Pat {
                             ty: pattern.ty,
@@ -105,7 +105,7 @@ fn mirror_stmts<'a, 'tcx>(
     cx: &mut Cx<'a, 'tcx>,
     block: &'tcx hir::Block<'tcx>,
 ) -> ExprRef<'tcx> {
-    let block_ty = cx.tables().node_type(block.hir_id);
+    let block_ty = cx.typeck_results().node_type(block.hir_id);
     let temp_lifetime = cx.region_scope_tree.temporary_scope(block.hir_id.local_id);
     let expr = Expr {
         ty: block_ty,
index d36990684e03b46ae2c0a1907322609c32e7fce1..6e1d8a8fc40121c6539d3eaa2e8804660830b3e6 100644 (file)
@@ -27,7 +27,7 @@ fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
         let mut expr = make_mirror_unadjusted(cx, self);
 
         // Now apply adjustments, if any.
-        for adjustment in cx.tables().expr_adjustments(self) {
+        for adjustment in cx.typeck_results().expr_adjustments(self) {
             debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
             expr = apply_adjustment(cx, self, expr, adjustment);
         }
@@ -134,7 +134,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
     cx: &mut Cx<'a, 'tcx>,
     expr: &'tcx hir::Expr<'tcx>,
 ) -> Expr<'tcx> {
-    let expr_ty = cx.tables().expr_ty(expr);
+    let expr_ty = cx.typeck_results().expr_ty(expr);
     let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
     let kind = match expr.kind {
@@ -147,7 +147,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
 
         hir::ExprKind::Call(ref fun, ref args) => {
-            if cx.tables().is_method_call(expr) {
+            if cx.typeck_results().is_method_call(expr) {
                 // The callee is something implementing Fn, FnMut, or FnOnce.
                 // Find the actual method implementation being called and
                 // build the appropriate UFCS call expression with the
@@ -157,7 +157,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
 
                 let method = method_callee(cx, expr, fun.span, None);
 
-                let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
+                let arg_tys = args.iter().map(|e| cx.typeck_results().expr_ty_adjusted(e));
                 let tupled_args = Expr {
                     ty: cx.tcx.mk_tup(arg_tys),
                     temp_lifetime,
@@ -187,8 +187,8 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                         None
                     };
                 if let Some((adt_def, index)) = adt_data {
-                    let substs = cx.tables().node_substs(fun.hir_id);
-                    let user_provided_types = cx.tables().user_provided_types();
+                    let substs = cx.typeck_results().node_substs(fun.hir_id);
+                    let user_provided_types = cx.typeck_results().user_provided_types();
                     let user_ty = user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| {
                         if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
                             *did = adt_def.did;
@@ -212,7 +212,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                     }
                 } else {
                     ExprKind::Call {
-                        ty: cx.tables().node_type(fun.hir_id),
+                        ty: cx.typeck_results().node_type(fun.hir_id),
                         fun: fun.to_ref(),
                         args: args.to_ref(),
                         from_hir_call: true,
@@ -237,7 +237,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
 
         hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-            if cx.tables().is_method_call(expr) {
+            if cx.typeck_results().is_method_call(expr) {
                 overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
             } else {
                 ExprKind::AssignOp { op: bin_op(op.node), lhs: lhs.to_ref(), rhs: rhs.to_ref() }
@@ -250,7 +250,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         },
 
         hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
-            if cx.tables().is_method_call(expr) {
+            if cx.typeck_results().is_method_call(expr) {
                 overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
             } else {
                 // FIXME overflow
@@ -275,7 +275,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
 
         hir::ExprKind::Index(ref lhs, ref index) => {
-            if cx.tables().is_method_call(expr) {
+            if cx.typeck_results().is_method_call(expr) {
                 overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
             } else {
                 ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() }
@@ -283,7 +283,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
 
         hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
-            if cx.tables().is_method_call(expr) {
+            if cx.typeck_results().is_method_call(expr) {
                 overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()])
             } else {
                 ExprKind::Deref { arg: arg.to_ref() }
@@ -291,7 +291,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
 
         hir::ExprKind::Unary(hir::UnOp::UnNot, ref arg) => {
-            if cx.tables().is_method_call(expr) {
+            if cx.typeck_results().is_method_call(expr) {
                 overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
                 ExprKind::Unary { op: UnOp::Not, arg: arg.to_ref() }
@@ -299,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
 
         hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => {
-            if cx.tables().is_method_call(expr) {
+            if cx.typeck_results().is_method_call(expr) {
                 overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
                 if let hir::ExprKind::Lit(ref lit) = arg.kind {
@@ -316,7 +316,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind {
             ty::Adt(adt, substs) => match adt.adt_kind() {
                 AdtKind::Struct | AdtKind::Union => {
-                    let user_provided_types = cx.tables().user_provided_types();
+                    let user_provided_types = cx.typeck_results().user_provided_types();
                     let user_ty = user_provided_types.get(expr.hir_id).copied();
                     debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
                     ExprKind::Adt {
@@ -327,18 +327,18 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                         fields: field_refs(cx, fields),
                         base: base.as_ref().map(|base| FruInfo {
                             base: base.to_ref(),
-                            field_types: cx.tables().fru_field_types()[expr.hir_id].clone(),
+                            field_types: cx.typeck_results().fru_field_types()[expr.hir_id].clone(),
                         }),
                     }
                 }
                 AdtKind::Enum => {
-                    let res = cx.tables().qpath_res(qpath, expr.hir_id);
+                    let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
                     match res {
                         Res::Def(DefKind::Variant, variant_id) => {
                             assert!(base.is_none());
 
                             let index = adt.variant_index_with_id(variant_id);
-                            let user_provided_types = cx.tables().user_provided_types();
+                            let user_provided_types = cx.typeck_results().user_provided_types();
                             let user_ty = user_provided_types.get(expr.hir_id).copied();
                             debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
                             ExprKind::Adt {
@@ -362,7 +362,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         },
 
         hir::ExprKind::Closure(..) => {
-            let closure_ty = cx.tables().expr_ty(expr);
+            let closure_ty = cx.typeck_results().expr_ty(expr);
             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) => {
@@ -384,7 +384,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
 
         hir::ExprKind::Path(ref qpath) => {
-            let res = cx.tables().qpath_res(qpath, expr.hir_id);
+            let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
             convert_path_expr(cx, expr, res)
         }
 
@@ -433,11 +433,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                             };
                             let temp_lifetime =
                                 cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-                            let res = cx.tables().qpath_res(qpath, expr.hir_id);
+                            let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
                             let ty;
                             match res {
                                 Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
-                                    ty = cx.tables().node_type(expr.hir_id);
+                                    ty = cx.typeck_results().node_type(expr.hir_id);
                                     let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
                                     InlineAsmOperand::SymFn {
                                         expr: Expr {
@@ -523,11 +523,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
         }
         hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
             lhs: source.to_ref(),
-            name: Field::new(cx.tcx.field_index(expr.hir_id, cx.tables)),
+            name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),
         },
         hir::ExprKind::Cast(ref source, ref cast_ty) => {
             // Check for a user-given type annotation on this `cast`
-            let user_provided_types = cx.tables.user_provided_types();
+            let user_provided_types = cx.typeck_results.user_provided_types();
             let user_ty = user_provided_types.get(cast_ty.hir_id);
 
             debug!(
@@ -537,10 +537,10 @@ fn make_mirror_unadjusted<'a, 'tcx>(
 
             // Check to see if this cast is a "coercion cast", where the cast is actually done
             // using a coercion (or is a no-op).
-            let cast = if cx.tables().is_coercion_cast(source.hir_id) {
+            let cast = if cx.typeck_results().is_coercion_cast(source.hir_id) {
                 // Convert the lexpr to a vexpr.
                 ExprKind::Use { source: source.to_ref() }
-            } else if cx.tables().expr_ty(source).is_region_ptr() {
+            } else if cx.typeck_results().expr_ty(source).is_region_ptr() {
                 // Special cased so that we can type check that the element
                 // type of the source matches the pointed to type of the
                 // destination.
@@ -558,9 +558,9 @@ 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.kind {
-                    let res = cx.tables().qpath_res(qpath, source.hir_id);
-                    cx.tables().node_type(source.hir_id).ty_adt_def().and_then(
-                        |adt_def| match res {
+                    let res = cx.typeck_results().qpath_res(qpath, source.hir_id);
+                    cx.typeck_results().node_type(source.hir_id).ty_adt_def().and_then(|adt_def| {
+                        match res {
                             Res::Def(
                                 DefKind::Ctor(CtorOf::Variant, CtorKind::Const),
                                 variant_ctor_id,
@@ -573,8 +573,8 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                                 Some((d, o, ty))
                             }
                             _ => None,
-                        },
-                    )
+                        }
+                    })
                 } else {
                     None
                 };
@@ -600,7 +600,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
                             let lhs = mk_const(cx.tcx().mk_const(ty::Const {
-                                val: ty::ConstKind::Unevaluated(did, substs, None),
+                                val: ty::ConstKind::Unevaluated(
+                                    ty::WithOptConstParam::unknown(did),
+                                    substs,
+                                    None,
+                                ),
                                 ty: var_ty,
                             }));
                             let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
@@ -630,7 +634,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             }
         }
         hir::ExprKind::Type(ref source, ref ty) => {
-            let user_provided_types = cx.tables.user_provided_types();
+            let user_provided_types = cx.typeck_results.user_provided_types();
             let user_ty = user_provided_types.get(ty.hir_id).copied();
             debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
             if source.is_syntactic_place_expr() {
@@ -666,7 +670,7 @@ fn user_substs_applied_to_res<'tcx>(
         | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
         | Res::Def(DefKind::Const, _)
         | Res::Def(DefKind::AssocConst, _) => {
-            cx.tables().user_provided_types().get(hir_id).copied()
+            cx.typeck_results().user_provided_types().get(hir_id).copied()
         }
 
         // A unit struct/variant which is used as a value (e.g.,
@@ -697,12 +701,12 @@ fn method_callee<'a, 'tcx>(
         Some((def_id, substs)) => (def_id, substs, None),
         None => {
             let (kind, def_id) = cx
-                .tables()
+                .typeck_results()
                 .type_dependent_def(expr.hir_id)
                 .unwrap_or_else(|| span_bug!(expr.span, "no type-dependent def for method callee"));
             let user_ty = user_substs_applied_to_res(cx, expr.hir_id, Res::Def(kind, def_id));
             debug!("method_callee: user_ty={:?}", user_ty);
-            (def_id, cx.tables().node_substs(expr.hir_id), user_ty)
+            (def_id, cx.typeck_results().node_substs(expr.hir_id), user_ty)
         }
     };
     let ty = cx.tcx().mk_fn_def(def_id, substs);
@@ -761,7 +765,7 @@ fn convert_path_expr<'a, 'tcx>(
     expr: &'tcx hir::Expr<'tcx>,
     res: Res,
 ) -> ExprKind<'tcx> {
-    let substs = cx.tables().node_substs(expr.hir_id);
+    let substs = cx.typeck_results().node_substs(expr.hir_id);
     match res {
         // A regular function, constructor function or a constant.
         Res::Def(DefKind::Fn, _)
@@ -771,7 +775,7 @@ fn convert_path_expr<'a, 'tcx>(
             let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
             debug!("convert_path_expr: user_ty={:?}", user_ty);
             ExprKind::Literal {
-                literal: ty::Const::zero_sized(cx.tcx, cx.tables().node_type(expr.hir_id)),
+                literal: ty::Const::zero_sized(cx.tcx, cx.typeck_results().node_type(expr.hir_id)),
                 user_ty,
             }
         }
@@ -786,7 +790,9 @@ fn convert_path_expr<'a, 'tcx>(
             let name = cx.tcx.hir().name(hir_id);
             let val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
             ExprKind::Literal {
-                literal: cx.tcx.mk_const(ty::Const { val, ty: cx.tables().node_type(expr.hir_id) }),
+                literal: cx
+                    .tcx
+                    .mk_const(ty::Const { val, ty: cx.typeck_results().node_type(expr.hir_id) }),
                 user_ty: None,
             }
         }
@@ -796,18 +802,22 @@ fn convert_path_expr<'a, 'tcx>(
             debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
             ExprKind::Literal {
                 literal: cx.tcx.mk_const(ty::Const {
-                    val: ty::ConstKind::Unevaluated(def_id, substs, None),
-                    ty: cx.tables().node_type(expr.hir_id),
+                    val: ty::ConstKind::Unevaluated(
+                        ty::WithOptConstParam::unknown(def_id),
+                        substs,
+                        None,
+                    ),
+                    ty: cx.typeck_results().node_type(expr.hir_id),
                 }),
                 user_ty,
             }
         }
 
         Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => {
-            let user_provided_types = cx.tables.user_provided_types();
+            let user_provided_types = cx.typeck_results.user_provided_types();
             let user_provided_type = user_provided_types.get(expr.hir_id).copied();
             debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
-            let ty = cx.tables().node_type(expr.hir_id);
+            let ty = cx.typeck_results().node_type(expr.hir_id);
             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.
@@ -852,7 +862,7 @@ fn convert_var<'tcx>(
     var_hir_id: hir::HirId,
 ) -> ExprKind<'tcx> {
     let upvar_index = cx
-        .tables()
+        .typeck_results()
         .closure_captures
         .get(&cx.body_owner)
         .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
@@ -873,11 +883,11 @@ fn convert_var<'tcx>(
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
                 closure_expr_id: closure_def_id.expect_local(),
             };
-            let var_ty = cx.tables().node_type(var_hir_id);
+            let var_ty = cx.typeck_results().node_type(var_hir_id);
 
             // FIXME free regions in closures are not right
             let closure_ty = cx
-                .tables()
+                .typeck_results()
                 .node_type(cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
 
             // FIXME we're just hard-coding the idea that the
@@ -948,7 +958,7 @@ fn convert_var<'tcx>(
 
             // ...but the upvar might be an `&T` or `&mut T` capture, at which
             // point we need an implicit deref
-            match cx.tables().upvar_capture(upvar_id) {
+            match cx.typeck_results().upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue => field_kind,
                 ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref {
                     arg: Expr {
@@ -1010,7 +1020,7 @@ fn overloaded_place<'a, 'tcx>(
     // line up (this is because `*x` and `x[y]` represent places):
 
     let recv_ty = match args[0] {
-        ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e),
+        ExprRef::Hair(e) => cx.typeck_results().expr_ty_adjusted(e),
         ExprRef::Mirror(ref e) => e.ty,
     };
 
@@ -1054,9 +1064,9 @@ fn capture_upvar<'tcx>(
         var_path: ty::UpvarPath { hir_id: var_hir_id },
         closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id),
     };
-    let upvar_capture = cx.tables().upvar_capture(upvar_id);
+    let upvar_capture = cx.typeck_results().upvar_capture(upvar_id);
     let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
-    let var_ty = cx.tables().node_type(var_hir_id);
+    let var_ty = cx.typeck_results().node_type(var_hir_id);
     let captured_var = Expr {
         temp_lifetime,
         ty: var_ty,
@@ -1090,7 +1100,7 @@ fn field_refs<'a, 'tcx>(
     fields
         .iter()
         .map(|field| FieldExprRef {
-            name: Field::new(cx.tcx.field_index(field.hir_id, cx.tables)),
+            name: Field::new(cx.tcx.field_index(field.hir_id, cx.typeck_results)),
             expr: field.expr.to_ref(),
         })
         .collect()
index d8b3ac79e6b9c81c32db548e40ad53197898ca80..2694cde14fde70e44db9a5cbf6660c67bd226921 100644 (file)
@@ -1,4 +1,4 @@
-//! This module contains the fcuntaiontliy to convert from the wacky tcx data
+//! This module contains the functionality to convert from the wacky tcx data
 //! structures into the HAIR. The `builder` is generally ignorant of the tcx,
 //! etc., and instead goes through the `Cx` for most of its work.
 
@@ -8,7 +8,7 @@
 use rustc_ast::ast;
 use rustc_ast::attr;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
@@ -33,7 +33,7 @@
     crate identity_substs: &'tcx InternalSubsts<'tcx>,
 
     crate region_scope_tree: &'tcx region::ScopeTree,
-    crate tables: &'a ty::TypeckTables<'tcx>,
+    crate typeck_results: &'a ty::TypeckResults<'tcx>,
 
     /// This is `Constness::Const` if we are compiling a `static`,
     /// `const`, or the body of a `const fn`.
 }
 
 impl<'a, 'tcx> Cx<'a, 'tcx> {
-    crate fn new(infcx: &'a InferCtxt<'a, 'tcx>, src_id: hir::HirId) -> Cx<'a, 'tcx> {
+    crate fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        def: ty::WithOptConstParam<LocalDefId>,
+        src_id: hir::HirId,
+    ) -> Cx<'a, 'tcx> {
         let tcx = infcx.tcx;
-        let src_def_id = tcx.hir().local_def_id(src_id);
-        let tables = tcx.typeck_tables_of(src_def_id);
+        let typeck_results = tcx.typeck_opt_const_arg(def);
         let body_owner_kind = tcx.hir().body_owner_kind(src_id);
 
         let constness = match body_owner_kind {
@@ -78,12 +81,12 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
             tcx,
             infcx,
             root_lint_level: src_id,
-            param_env: tcx.param_env(src_def_id),
-            identity_substs: InternalSubsts::identity_for_item(tcx, src_def_id.to_def_id()),
-            region_scope_tree: tcx.region_scope_tree(src_def_id),
-            tables,
+            param_env: tcx.param_env(def.did),
+            identity_substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+            region_scope_tree: tcx.region_scope_tree(def.did),
+            typeck_results,
             constness,
-            body_owner: src_def_id.to_def_id(),
+            body_owner: def.did.to_def_id(),
             body_owner_kind,
             check_overflow,
         }
@@ -150,7 +153,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
             Node::Pat(p) | Node::Binding(p) => p,
             node => bug!("pattern became {:?}", node),
         };
-        Pat::from_hir(self.tcx, self.param_env, self.tables(), p)
+        Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
     }
 
     crate fn trait_method(
@@ -188,8 +191,8 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
         self.tcx
     }
 
-    crate fn tables(&self) -> &'a ty::TypeckTables<'tcx> {
-        self.tables
+    crate fn typeck_results(&self) -> &'a ty::TypeckResults<'tcx> {
+        self.typeck_results
     }
 
     crate fn check_overflow(&self) -> bool {
@@ -206,8 +209,8 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx()
     }
 
-    fn tables(&self) -> &ty::TypeckTables<'tcx> {
-        self.tables()
+    fn typeck_results(&self) -> &ty::TypeckResults<'tcx> {
+        self.typeck_results()
     }
 }
 
index 2ae20f551be414defa7aa5be8eee6fe60a0e98bb..744f319205f94a18bf18eaec1699344d9d346c72 100644 (file)
@@ -28,7 +28,7 @@
 
     let mut visitor = MatchVisitor {
         tcx,
-        tables: tcx.body_tables(body_id),
+        typeck_results: tcx.typeck_body(body_id),
         param_env: tcx.param_env(def_id),
         pattern_arena: TypedArena::default(),
     };
@@ -41,7 +41,7 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu
 
 struct MatchVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     pattern_arena: TypedArena<super::Pat<'tcx>>,
 }
@@ -136,7 +136,7 @@ fn lower_pattern<'p>(
         pat: &'tcx hir::Pat<'tcx>,
         have_errors: &mut bool,
     ) -> (&'p super::Pat<'tcx>, Ty<'tcx>) {
-        let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
+        let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.typeck_results);
         patcx.include_lint_checks();
         let pattern = patcx.lower_pattern(pat);
         let pattern_ty = pattern.ty;
@@ -190,7 +190,7 @@ fn check_match(
         // Fifth, check if the match is exhaustive.
         // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
         // since an empty matrix can occur when there are arms, if those arms all have guards.
-        let scrut_ty = self.tables.expr_ty_adjusted(scrut);
+        let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut);
         let is_empty_match = inlined_arms.is_empty();
         check_exhaustive(&mut cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
     }
@@ -286,9 +286,9 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
     pat.walk_always(|p| {
         if let hir::PatKind::Binding(_, _, ident, None) = p.kind {
             if let Some(ty::BindByValue(hir::Mutability::Not)) =
-                cx.tables.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span)
+                cx.typeck_results.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span)
             {
-                let pat_ty = cx.tables.pat_ty(p).peel_refs();
+                let pat_ty = cx.typeck_results.pat_ty(p).peel_refs();
                 if let ty::Adt(edef, _) = pat_ty.kind {
                     if edef.is_enum()
                         && edef.variants.iter().any(|variant| {
@@ -598,18 +598,20 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec<Span>
 
 /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
 fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> bool {
-    !cx.tables.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
+    !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
 }
 
 /// Check the legality of legality of by-move bindings.
 fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat<'_>) {
     let sess = cx.tcx.sess;
-    let tables = cx.tables;
+    let typeck_results = cx.typeck_results;
 
     // Find all by-ref spans.
     let mut by_ref_spans = Vec::new();
     pat.each_binding(|_, hir_id, span, _| {
-        if let Some(ty::BindByReference(_)) = tables.extract_binding_mode(sess, hir_id, span) {
+        if let Some(ty::BindByReference(_)) =
+            typeck_results.extract_binding_mode(sess, hir_id, span)
+        {
             by_ref_spans.push(span);
         }
     });
@@ -630,7 +632,9 @@ fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: boo
     };
     pat.walk_always(|p| {
         if let hir::PatKind::Binding(.., sub) = &p.kind {
-            if let Some(ty::BindByValue(_)) = tables.extract_binding_mode(sess, p.hir_id, p.span) {
+            if let Some(ty::BindByValue(_)) =
+                typeck_results.extract_binding_mode(sess, p.hir_id, p.span)
+            {
                 if is_binding_by_move(cx, p.hir_id, p.span) {
                     check_move(p, sub.as_deref());
                 }
@@ -674,16 +678,16 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_
     };
     let binding_span = pat.span.with_hi(name.span.hi());
 
-    let tables = cx.tables;
+    let typeck_results = cx.typeck_results;
     let sess = cx.tcx.sess;
 
     // Get the binding move, extract the mutability if by-ref.
-    let mut_outer = match tables.extract_binding_mode(sess, pat.hir_id, pat.span) {
+    let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) {
         Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id, pat.span) => {
             // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
             let mut conflicts_ref = Vec::new();
             sub.each_binding(|_, hir_id, span, _| {
-                match tables.extract_binding_mode(sess, hir_id, span) {
+                match typeck_results.extract_binding_mode(sess, hir_id, span) {
                     Some(ty::BindByValue(_)) | None => {}
                     Some(ty::BindByReference(_)) => conflicts_ref.push(span),
                 }
@@ -692,7 +696,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_
                 let occurs_because = format!(
                     "move occurs because `{}` has type `{}` which does not implement the `Copy` trait",
                     name,
-                    tables.node_type(pat.hir_id),
+                    typeck_results.node_type(pat.hir_id),
                 );
                 sess.struct_span_err(pat.span, "borrow of moved value")
                     .span_label(binding_span, format!("value moved into `{}` here", name))
@@ -712,7 +716,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_
     let mut conflicts_mut_mut = Vec::new();
     let mut conflicts_mut_ref = Vec::new();
     sub.each_binding(|_, hir_id, span, name| {
-        match tables.extract_binding_mode(sess, hir_id, span) {
+        match typeck_results.extract_binding_mode(sess, hir_id, span) {
             Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) {
                 (Mutability::Not, Mutability::Not) => {} // Both sides are `ref`.
                 (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
index 5c30b2a448c6d3a6b6d86f6c161df8870355f1ef..4fa23906a35684c0b3048eba6a1155885f1a9393 100644 (file)
@@ -349,7 +349,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 crate struct PatCtxt<'a, 'tcx> {
     crate tcx: TyCtxt<'tcx>,
     crate param_env: ty::ParamEnv<'tcx>,
-    crate tables: &'a ty::TypeckTables<'tcx>,
+    crate typeck_results: &'a ty::TypeckResults<'tcx>,
     crate errors: Vec<PatternError>,
     include_lint_checks: bool,
 }
@@ -358,10 +358,10 @@ impl<'a, 'tcx> Pat<'tcx> {
     crate fn from_hir(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        tables: &'a ty::TypeckTables<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
         pat: &'tcx hir::Pat<'tcx>,
     ) -> Self {
-        let mut pcx = PatCtxt::new(tcx, param_env, tables);
+        let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
         let result = pcx.lower_pattern(pat);
         if !pcx.errors.is_empty() {
             let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
@@ -376,9 +376,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     crate fn new(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        tables: &'a ty::TypeckTables<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
     ) -> Self {
-        PatCtxt { tcx, param_env, tables, errors: vec![], include_lint_checks: false }
+        PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false }
     }
 
     crate fn include_lint_checks(&mut self) -> &mut Self {
@@ -407,7 +407,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // 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);
-        self.tables.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
+        self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
             unadjusted_pat,
             |pat, ref_ty| {
                 debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
@@ -507,7 +507,7 @@ fn normalize_range_pattern_ends(
     }
 
     fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
-        let mut ty = self.tables.node_type(pat.hir_id);
+        let mut ty = self.typeck_results.node_type(pat.hir_id);
 
         if let ty::Error(_) = ty.kind {
             // Avoid ICEs (e.g., #50577 and #50585).
@@ -573,8 +573,11 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
             }
 
             hir::PatKind::Binding(_, id, ident, ref sub) => {
-                let bm =
-                    *self.tables.pat_binding_modes().get(pat.hir_id).expect("missing binding mode");
+                let bm = *self
+                    .typeck_results
+                    .pat_binding_modes()
+                    .get(pat.hir_id)
+                    .expect("missing binding mode");
                 let (mutability, mode) = match bm {
                     ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue),
                     ty::BindByReference(hir::Mutability::Mut) => (
@@ -609,7 +612,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
             }
 
             hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => {
-                let res = self.tables.qpath_res(qpath, pat.hir_id);
+                let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
                 let adt_def = match ty.kind {
                     ty::Adt(adt_def, _) => adt_def,
                     _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty),
@@ -620,11 +623,11 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
             }
 
             hir::PatKind::Struct(ref qpath, ref fields, _) => {
-                let res = self.tables.qpath_res(qpath, pat.hir_id);
+                let res = self.typeck_results.qpath_res(qpath, pat.hir_id);
                 let subpatterns = fields
                     .iter()
                     .map(|field| FieldPat {
-                        field: Field::new(self.tcx.field_index(field.hir_id, self.tables)),
+                        field: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
                         pattern: self.lower_pattern(&field.pat),
                     })
                     .collect();
@@ -764,8 +767,8 @@ fn lower_variant_or_leaf(
     /// it to `const_to_pat`. Any other path (like enum variants without fields)
     /// is converted to the corresponding pattern via `lower_variant_or_leaf`.
     fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> {
-        let ty = self.tables.node_type(id);
-        let res = self.tables.qpath_res(qpath, id);
+        let ty = self.typeck_results.node_type(id);
+        let res = self.typeck_results.qpath_res(qpath, id);
 
         let pat_from_kind = |kind| Pat { span, ty, kind: Box::new(kind) };
 
@@ -779,7 +782,7 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
         // Use `Reveal::All` here because patterns are always monomorphic even if their function
         // isn't.
         let param_env_reveal_all = self.param_env.with_reveal_all();
-        let substs = self.tables.node_substs(id);
+        let substs = self.typeck_results.node_substs(id);
         let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) {
             Ok(Some(i)) => i,
             Ok(None) => {
@@ -806,7 +809,8 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
 
         match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
             Ok(value) => {
-                let const_ = ty::Const::from_value(self.tcx, value, self.tables.node_type(id));
+                let const_ =
+                    ty::Const::from_value(self.tcx, value, self.typeck_results.node_type(id));
 
                 let pattern = self.const_to_pat(&const_, id, span, mir_structural_match_violation);
 
@@ -814,7 +818,7 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
                     return pattern;
                 }
 
-                let user_provided_types = self.tables().user_provided_types();
+                let user_provided_types = self.typeck_results().user_provided_types();
                 if let Some(u_ty) = user_provided_types.get(id) {
                     let user_ty = PatTyProj::from_user_type(*u_ty);
                     Pat {
@@ -862,7 +866,8 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
                 _ => span_bug!(expr.span, "not a literal: {:?}", expr),
             };
 
-            let lit_input = LitToConstInput { lit: &lit.node, ty: self.tables.expr_ty(expr), neg };
+            let lit_input =
+                LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
             match self.tcx.at(expr.span).lit_to_const(lit_input) {
                 Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
                 Err(LitToConstError::UnparseableFloat) => {
@@ -881,8 +886,8 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
-    fn tables(&self) -> &ty::TypeckTables<'tcx> {
-        self.tables
+    fn typeck_results(&self) -> &ty::TypeckResults<'tcx> {
+        self.typeck_results
     }
 }
 
index 0ea0d5d1b0c19118753428f99b17017a6e64dfb5..7de60ddda41a3fcbdba2b65c3006bf27d88838b5 100644 (file)
@@ -4,7 +4,7 @@
 crate trait UserAnnotatedTyHelpers<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
-    fn tables(&self) -> &ty::TypeckTables<'tcx>;
+    fn typeck_results(&self) -> &ty::TypeckResults<'tcx>;
 
     /// Looks up the type associated with this hir-id and applies the
     /// user-given substitutions; the hir-id must map to a suitable
@@ -13,10 +13,10 @@ fn user_substs_applied_to_ty_of_hir_id(
         &self,
         hir_id: hir::HirId,
     ) -> Option<CanonicalUserType<'tcx>> {
-        let user_provided_types = self.tables().user_provided_types();
+        let user_provided_types = self.typeck_results().user_provided_types();
         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);
+        let ty = self.typeck_results().node_type(hir_id);
         match ty.kind {
             ty::Adt(adt_def, ..) => {
                 if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value {
index be495e431eb3cf3262610cf47d3e13e1ee8bb380..ed154b9dc6f11e86c68e5ca173d89ce7e18fd6ae 100644 (file)
@@ -4,7 +4,6 @@
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
index 803f14a2a228a6789915694fe27ee9ec38541dbb..8b67f4743c6b6e1fa02bec4129ccc1691c82b9a5 100644 (file)
@@ -74,7 +74,7 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribut
     }
 
     fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
-        attr::mk_doc_comment(comments::doc_comment_style(&s.as_str()), s, self.token.span)
+        attr::mk_doc_comment(comments::doc_comment_style(s), s, self.token.span)
     }
 
     /// Matches `attribute = # ! [ meta_item ]`.
index 61c680469f03ce15e0b95e60abbd36414464cde2..72866468b6560b96a94d0c33c310aad767427c0a 100644 (file)
@@ -213,7 +213,7 @@ fn next_desugared(&mut self) -> Token {
             tok => return tok,
         };
 
-        let stripped = strip_doc_comment_decoration(&name.as_str());
+        let stripped = strip_doc_comment_decoration(name);
 
         // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
         // required to wrap the text.
@@ -250,7 +250,7 @@ fn next_desugared(&mut self) -> Token {
             TokenCursorFrame::new(
                 delim_span,
                 token::NoDelim,
-                &if doc_comment_style(&name.as_str()) == AttrStyle::Inner {
+                &if doc_comment_style(name) == AttrStyle::Inner {
                     [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
                         .iter()
                         .cloned()
index 53f32b7c800bdaf74af35dfcba588571e1be4f16..d04920de47f09c44a70f7cada631d53f13c1c6cd 100644 (file)
@@ -162,13 +162,19 @@ fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
             match self.parse_ty() {
                 Ok(ty) => (None, Some(ty)),
                 Err(mut err) => {
-                    // Rewind to before attempting to parse the type and continue parsing.
-                    let parser_snapshot_after_type =
-                        mem::replace(self, parser_snapshot_before_type);
                     if let Ok(snip) = self.span_to_snippet(pat.span) {
                         err.span_label(pat.span, format!("while parsing the type for `{}`", snip));
                     }
-                    (Some((parser_snapshot_after_type, colon_sp, err)), None)
+                    let err = if self.check(&token::Eq) {
+                        err.emit();
+                        None
+                    } else {
+                        // Rewind to before attempting to parse the type and continue parsing.
+                        let parser_snapshot_after_type =
+                            mem::replace(self, parser_snapshot_before_type);
+                        Some((parser_snapshot_after_type, colon_sp, err))
+                    };
+                    (err, None)
                 }
             }
         } else {
index 46aa5a4dcdff5c03acea06999b31234ef95a8d74..3e63a63d9d0f950cc7ad903a2c456a7cf417b1df 100644 (file)
@@ -70,6 +70,8 @@ fn check_attributes(
                 self.check_target_feature(attr, span, target)
             } else if attr.check_name(sym::track_caller) {
                 self.check_track_caller(&attr.span, attrs, span, target)
+            } else if attr.check_name(sym::doc) {
+                self.check_doc_alias(attr)
             } else {
                 true
             };
@@ -216,6 +218,34 @@ fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) ->
         }
     }
 
+    fn check_doc_alias(&self, attr: &Attribute) -> bool {
+        if let Some(mi) = attr.meta() {
+            if let Some(list) = mi.meta_item_list() {
+                for meta in list {
+                    if meta.check_name(sym::alias) {
+                        if !meta.is_value_str()
+                            || meta
+                                .value_str()
+                                .map(|s| s.to_string())
+                                .unwrap_or_else(String::new)
+                                .is_empty()
+                        {
+                            self.tcx
+                                .sess
+                                .struct_span_err(
+                                    meta.span(),
+                                    "doc alias attribute expects a string: #[doc(alias = \"0\")]",
+                                )
+                                .emit();
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        true
+    }
+
     /// Checks if the `#[repr]` attributes on `item` are valid.
     fn check_repr(
         &self,
index 87348894a5ad9296012efde1930e7d201247bcd3..ab75c8ebf4c89f13469aa3c6d37243adf9b04e35 100644 (file)
@@ -40,7 +40,7 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
 struct MarkSymbolVisitor<'tcx> {
     worklist: Vec<hir::HirId>,
     tcx: TyCtxt<'tcx>,
-    maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
     live_symbols: FxHashSet<hir::HirId>,
     repr_has_repr_c: bool,
     in_pat: bool,
@@ -51,12 +51,13 @@ struct MarkSymbolVisitor<'tcx> {
 }
 
 impl<'tcx> MarkSymbolVisitor<'tcx> {
-    /// Gets the type-checking side-tables for the current body.
+    /// Gets the type-checking results for the current body.
     /// As this will ICE if called outside bodies, only call when working with
     /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
     #[track_caller]
-    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
-        self.maybe_typeck_tables.expect("`MarkSymbolVisitor::tables` called outside of body")
+    fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
+        self.maybe_typeck_results
+            .expect("`MarkSymbolVisitor::typeck_results` called outside of body")
     }
 
     fn check_def_id(&mut self, def_id: DefId) {
@@ -115,7 +116,7 @@ fn handle_res(&mut self, res: Res) {
     }
 
     fn lookup_and_handle_method(&mut self, id: hir::HirId) {
-        if let Some(def_id) = self.tables().type_dependent_def_id(id) {
+        if let Some(def_id) = self.typeck_results().type_dependent_def_id(id) {
             self.check_def_id(def_id);
         } else {
             bug!("no type-dependent def for method");
@@ -123,9 +124,9 @@ fn lookup_and_handle_method(&mut self, id: hir::HirId) {
     }
 
     fn handle_field_access(&mut self, lhs: &hir::Expr<'_>, hir_id: hir::HirId) {
-        match self.tables().expr_ty_adjusted(lhs).kind {
+        match self.typeck_results().expr_ty_adjusted(lhs).kind {
             ty::Adt(def, _) => {
-                let index = self.tcx.field_index(hir_id, self.tables());
+                let index = self.tcx.field_index(hir_id, self.typeck_results());
                 self.insert_def_id(def.non_enum_variant().fields[index].did);
             }
             ty::Tuple(..) => {}
@@ -139,7 +140,7 @@ fn handle_field_pattern_match(
         res: Res,
         pats: &[hir::FieldPat<'_>],
     ) {
-        let variant = match self.tables().node_type(lhs.hir_id).kind {
+        let variant = match self.typeck_results().node_type(lhs.hir_id).kind {
             ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => span_bug!(lhs.span, "non-ADT in struct pattern"),
         };
@@ -147,7 +148,7 @@ fn handle_field_pattern_match(
             if let PatKind::Wild = pat.pat.kind {
                 continue;
             }
-            let index = self.tcx.field_index(pat.hir_id, self.tables());
+            let index = self.tcx.field_index(pat.hir_id, self.typeck_results());
             self.insert_def_id(variant.fields[index].did);
         }
     }
@@ -212,7 +213,7 @@ fn visit_node(&mut self, node: Node<'tcx>) {
     fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &[hir::Field<'_>]) {
         if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() {
             for field in fields {
-                let index = self.tcx.field_index(field.hir_id, self.tables());
+                let index = self.tcx.field_index(field.hir_id, self.typeck_results());
                 self.insert_def_id(adt.non_enum_variant().fields[index].did);
             }
         }
@@ -227,10 +228,11 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
+        let old_maybe_typeck_results =
+            self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
         let body = self.tcx.hir().body(body);
         self.visit_body(body);
-        self.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
     fn visit_variant_data(
@@ -255,7 +257,7 @@ fn visit_variant_data(
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         match expr.kind {
             hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
-                let res = self.tables().qpath_res(qpath, expr.hir_id);
+                let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
                 self.handle_res(res);
             }
             hir::ExprKind::MethodCall(..) => {
@@ -265,9 +267,9 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 self.handle_field_access(&lhs, expr.hir_id);
             }
             hir::ExprKind::Struct(ref qpath, ref fields, _) => {
-                let res = self.tables().qpath_res(qpath, expr.hir_id);
+                let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
                 self.handle_res(res);
-                if let ty::Adt(ref adt, _) = self.tables().expr_ty(expr).kind {
+                if let ty::Adt(ref adt, _) = self.typeck_results().expr_ty(expr).kind {
                     self.mark_as_used_if_union(adt, fields);
                 }
             }
@@ -290,11 +292,11 @@ fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
     fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         match pat.kind {
             PatKind::Struct(ref path, ref fields, _) => {
-                let res = self.tables().qpath_res(path, pat.hir_id);
+                let res = self.typeck_results().qpath_res(path, pat.hir_id);
                 self.handle_field_pattern_match(pat, res, fields);
             }
             PatKind::Path(ref qpath) => {
-                let res = self.tables().qpath_res(qpath, pat.hir_id);
+                let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_res(res);
             }
             _ => (),
@@ -480,7 +482,7 @@ fn find_live<'tcx>(
     let mut symbol_visitor = MarkSymbolVisitor {
         worklist,
         tcx,
-        maybe_typeck_tables: None,
+        maybe_typeck_results: None,
         live_symbols: Default::default(),
         repr_has_repr_c: false,
         in_pat: false,
index 25edfad86e8ec8a932fa84ffd6188b9e33305b2f..931a8cb5f7d02e19ce05b7207e95a926be5a9c14 100644 (file)
@@ -28,7 +28,7 @@ struct ItemVisitor<'tcx> {
 
 struct ExprVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    tables: &'tcx ty::TypeckTables<'tcx>,
+    typeck_results: &'tcx ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 }
 
@@ -142,7 +142,7 @@ fn check_asm_operand_type(
         tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
     ) -> Option<InlineAsmType> {
         // Check the type against the allowed types for inline asm.
-        let ty = self.tables.expr_ty_adjusted(expr);
+        let ty = self.typeck_results.expr_ty_adjusted(expr);
         let asm_ty_isize = match self.tcx.sess.target.ptr_width {
             16 => InlineAsmType::I16,
             32 => InlineAsmType::I32,
@@ -236,7 +236,7 @@ fn check_asm_operand_type(
                 let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg);
                 err.span_label(
                     in_expr.span,
-                    &format!("type `{}`", self.tables.expr_ty_adjusted(in_expr)),
+                    &format!("type `{}`", self.typeck_results.expr_ty_adjusted(in_expr)),
                 );
                 err.span_label(expr.span, &format!("type `{}`", ty));
                 err.note(
@@ -373,7 +373,7 @@ fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
                     }
                 }
                 hir::InlineAsmOperand::Const { ref expr } => {
-                    let ty = self.tables.expr_ty_adjusted(expr);
+                    let ty = self.typeck_results.expr_ty_adjusted(expr);
                     match ty.kind {
                         ty::Int(_) | ty::Uint(_) | ty::Float(_) => {}
                         _ => {
@@ -400,8 +400,8 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
         let owner_def_id = self.tcx.hir().body_owner_def_id(body_id);
         let body = self.tcx.hir().body(body_id);
         let param_env = self.tcx.param_env(owner_def_id.to_def_id());
-        let tables = self.tcx.typeck_tables_of(owner_def_id);
-        ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
+        let typeck_results = self.tcx.typeck(owner_def_id);
+        ExprVisitor { tcx: self.tcx, param_env, typeck_results }.visit_body(body);
         self.visit_body(body);
     }
 }
@@ -416,10 +416,10 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         match expr.kind {
             hir::ExprKind::Path(ref qpath) => {
-                let res = self.tables.qpath_res(qpath, expr.hir_id);
+                let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
                 if let Res::Def(DefKind::Fn, did) = res {
                     if self.def_id_is_transmute(did) {
-                        let typ = self.tables.node_type(expr.hir_id);
+                        let typ = self.typeck_results.node_type(expr.hir_id);
                         let sig = typ.fn_sig(self.tcx);
                         let from = sig.inputs().skip_binder()[0];
                         let to = sig.output().skip_binder();
index 809697134b759c89c02cf37341e725d78ce8977c..e07c71b41d82714ad13b1dafcfcb787cac87bef9 100644 (file)
@@ -57,7 +57,7 @@ fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
 
     fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
         if let Some((value, span)) = extract(&attrs) {
-            match ITEM_REFS.get(&*value.as_str()).cloned() {
+            match ITEM_REFS.get(&value).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
                     let def_id = self.tcx.hir().local_def_id(hir_id);
index 3f10c418811b71c62f94e248bb4637720c747942..95b236ba1c9e4ee5de5d59f82fc2d5136aaf43e7 100644 (file)
@@ -8,7 +8,6 @@
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(or_patterns)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 3675a987644daef2d3cfea1f44b521e3007f3ffb..45193c4556962bcac596243c78a3d8bd6f7a7a7c 100644 (file)
@@ -650,7 +650,7 @@ struct Specials {
 
 struct Liveness<'a, 'tcx> {
     ir: &'a mut IrMaps<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     s: Specials,
     successors: Vec<LiveNode>,
@@ -670,7 +670,7 @@ fn new(ir: &'a mut IrMaps<'tcx>, def_id: LocalDefId) -> Liveness<'a, 'tcx> {
             exit_ln: ir.add_live_node(ExitNode),
         };
 
-        let tables = ir.tcx.typeck_tables_of(def_id);
+        let typeck_results = ir.tcx.typeck(def_id);
         let param_env = ir.tcx.param_env(def_id);
 
         let num_live_nodes = ir.num_live_nodes;
@@ -678,7 +678,7 @@ fn new(ir: &'a mut IrMaps<'tcx>, def_id: LocalDefId) -> Liveness<'a, 'tcx> {
 
         Liveness {
             ir,
-            tables,
+            typeck_results,
             param_env,
             s: specials,
             successors: vec![invalid_node(); num_live_nodes],
@@ -939,7 +939,7 @@ fn compute(
                     var_path: ty::UpvarPath { hir_id: var_hir_id },
                     closure_expr_id: self.ir.body_owner,
                 };
-                match self.tables.upvar_capture(upvar_id) {
+                match self.typeck_results.upvar_capture(upvar_id) {
                     ty::UpvarCapture::ByRef(_) => {
                         let var = self.variable(var_hir_id, upvar.span);
                         self.acc(self.s.exit_ln, var, ACC_READ | ACC_USE);
@@ -956,7 +956,7 @@ fn compute(
             FnKind::Closure(..) => {}
         }
 
-        let ty = self.tables.node_type(id);
+        let ty = self.typeck_results.node_type(id);
         match ty.kind {
             ty::Closure(_def_id, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => {}
@@ -1151,7 +1151,7 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
 
             hir::ExprKind::AssignOp(_, ref l, ref r) => {
                 // an overloaded assign op is like a method call
-                if self.tables.is_method_call(expr) {
+                if self.typeck_results.is_method_call(expr) {
                     let succ = self.propagate_through_expr(&l, succ);
                     self.propagate_through_expr(&r, succ)
                 } else {
@@ -1178,7 +1178,7 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
                 let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
                 let succ = if self.ir.tcx.is_ty_uninhabited_from(
                     m,
-                    self.tables.expr_ty(expr),
+                    self.typeck_results.expr_ty(expr),
                     self.param_env,
                 ) {
                     self.s.exit_ln
@@ -1193,7 +1193,7 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
                 let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
                 let succ = if self.ir.tcx.is_ty_uninhabited_from(
                     m,
-                    self.tables.expr_ty(expr),
+                    self.typeck_results.expr_ty(expr),
                     self.param_env,
                 ) {
                     self.s.exit_ln
@@ -1497,7 +1497,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         }
 
         hir::ExprKind::AssignOp(_, ref l, _) => {
-            if !this.tables.is_method_call(expr) {
+            if !this.typeck_results.is_method_call(expr) {
                 this.check_place(&l);
             }
         }
@@ -1607,7 +1607,7 @@ fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
                 closure_expr_id: self.ir.body_owner,
             };
-            match self.tables.upvar_capture(upvar_id) {
+            match self.typeck_results.upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue => {}
                 ty::UpvarCapture::ByRef(..) => continue,
             };
index c46f4856cfe3a84e520852ca3605ae69382a0dd2..c71dbdf515aa932dd677a9a78bf1fbff27787fd4 100644 (file)
@@ -63,7 +63,7 @@ fn method_might_be_inlined(
 struct ReachableContext<'tcx> {
     // The type context.
     tcx: TyCtxt<'tcx>,
-    maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
     // The set of items which must be exported in the linkage sense.
     reachable_symbols: HirIdSet,
     // A worklist of item IDs. Each item ID in this worklist will be inlined
@@ -81,17 +81,20 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
+        let old_maybe_typeck_results =
+            self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
         let body = self.tcx.hir().body(body);
         self.visit_body(body);
-        self.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         let res = match expr.kind {
-            hir::ExprKind::Path(ref qpath) => Some(self.tables().qpath_res(qpath, expr.hir_id)),
+            hir::ExprKind::Path(ref qpath) => {
+                Some(self.typeck_results().qpath_res(qpath, expr.hir_id))
+            }
             hir::ExprKind::MethodCall(..) => self
-                .tables()
+                .typeck_results()
                 .type_dependent_def(expr.hir_id)
                 .map(|(kind, def_id)| Res::Def(kind, def_id)),
             _ => None,
@@ -133,12 +136,13 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
 }
 
 impl<'tcx> ReachableContext<'tcx> {
-    /// Gets the type-checking side-tables for the current body.
+    /// Gets the type-checking results for the current body.
     /// As this will ICE if called outside bodies, only call when working with
     /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
     #[track_caller]
-    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
-        self.maybe_typeck_tables.expect("`ReachableContext::tables` called outside of body")
+    fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
+        self.maybe_typeck_results
+            .expect("`ReachableContext::typeck_results` called outside of body")
     }
 
     // Returns true if the given def ID represents a local item that is
@@ -388,7 +392,7 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> &'tcx HirIdSet
         });
     let mut reachable_context = ReachableContext {
         tcx,
-        maybe_typeck_tables: None,
+        maybe_typeck_results: None,
         reachable_symbols: Default::default(),
         worklist: Vec::new(),
         any_library,
index 5bacab671ec146febe32eb4ddf6630d48821ac58..5d972c70d139255f27b137c08895167d1c9f572d 100644 (file)
@@ -502,7 +502,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         match item.kind {
             hir::ItemKind::ExternCrate(_) => {
                 // compiler-generated `extern crate` items have a dummy span.
-                if item.span.is_dummy() {
+                // `std` is still checked for the `restricted-std` feature.
+                if item.span.is_dummy() && item.ident.as_str() != "std" {
                     return;
                 }
 
@@ -620,7 +621,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     // available as we'd like it to be.
     // FIXME: only remove `libc` when `stdbuild` is active.
     // FIXME: remove special casing for `test`.
-    remaining_lib_features.remove(&Symbol::intern("libc"));
+    remaining_lib_features.remove(&sym::libc);
     remaining_lib_features.remove(&sym::test);
 
     let check_features = |remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &[_]| {
index 12925af8170f0b4458239dadbe8c046e692c5306..3b11fb379625f717b78521c34de778f7d69d04c0 100644 (file)
@@ -3,14 +3,13 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_hir::fake_lang_items::FAKE_ITEMS_REFS;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::lang_items;
-use rustc_hir::lang_items::ITEM_REFS;
 use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
 use rustc_middle::middle::lang_items::required;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
-use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
@@ -77,15 +76,14 @@ fn register(&mut self, name: Symbol, span: Span, hir_id: hir::HirId) {
             if self.items.require(item).is_err() {
                 self.items.missing.push(item);
             }
-        } else if name == sym::count_code_region {
-            // `core::intrinsics::code_count_region()` is (currently) the only `extern` lang item
-            // that is never actually linked. It is not a `weak_lang_item` that can be registered
-            // when used, and should be registered here instead.
-            if let Some((item_index, _)) = ITEM_REFS.get(&*name.as_str()).cloned() {
-                if self.items.items[item_index].is_none() {
-                    let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
-                    self.items.items[item_index] = Some(item_def_id);
-                }
+        } else if let Some(&item) = FAKE_ITEMS_REFS.get(&name) {
+            // Ensure "fake lang items" are registered. These are `extern` lang items that are
+            // injected into the MIR automatically (such as source code coverage counters), but are
+            // never actually linked; therefore, unlike "weak lang items", they cannot by registered
+            // when used, because they never appear to be used.
+            if self.items.items[item as usize].is_none() {
+                let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
+                self.items.items[item as usize] = Some(item_def_id);
             }
         } else {
             struct_span_err!(self.tcx.sess, span, E0264, "unknown external lang item: `{}`", name)
index c3a60166968888c41799308ce85c4b98d9529b39..62a87b47a2f74e7215a85d1310841273289f7a16 100644 (file)
@@ -55,13 +55,11 @@ fn load_plugin(
     metadata_loader: &dyn MetadataLoader,
     ident: Ident,
 ) {
-    let registrar = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
-
-    if let Some((lib, disambiguator)) = registrar {
-        let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
-        let fun = dylink_registrar(sess, ident.span, lib, symbol);
-        plugins.push(fun);
-    }
+    let (lib, disambiguator) =
+        locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
+    let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
+    let fun = dylink_registrar(sess, ident.span, lib, symbol);
+    plugins.push(fun);
 }
 
 // Dynamically link a registrar function into the compiler process.
index 2c5cbed2192ef35b1a38f8e418bd66b9101845ae..1ecb0320744ff8753abb10b985926f39af7232d2 100644 (file)
@@ -2,7 +2,6 @@
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(or_patterns)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![recursion_limit = "256"]
 
 use rustc_attr as attr;
@@ -1021,17 +1020,18 @@ fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display
 
 struct NamePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
     current_item: Option<hir::HirId>,
 }
 
 impl<'tcx> NamePrivacyVisitor<'tcx> {
-    /// Gets the type-checking side-tables for the current body.
+    /// Gets the type-checking results for the current body.
     /// As this will ICE if called outside bodies, only call when working with
     /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
     #[track_caller]
-    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
-        self.maybe_typeck_tables.expect("`NamePrivacyVisitor::tables` called outside of body")
+    fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
+        self.maybe_typeck_results
+            .expect("`NamePrivacyVisitor::typeck_results` called outside of body")
     }
 
     // Checks that a field in a struct constructor (expression or pattern) is accessible.
@@ -1084,10 +1084,11 @@ fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
+        let old_maybe_typeck_results =
+            self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
         let body = self.tcx.hir().body(body);
         self.visit_body(body);
-        self.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -1098,17 +1099,17 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Struct(ref qpath, fields, ref base) = expr.kind {
-            let res = self.tables().qpath_res(qpath, expr.hir_id);
-            let adt = self.tables().expr_ty(expr).ty_adt_def().unwrap();
+            let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+            let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
             let variant = adt.variant_of_res(res);
             if let Some(ref base) = *base {
                 // If the expression uses FRU we need to make sure all the unmentioned fields
                 // are checked for privacy (RFC 736). Rather than computing the set of
                 // unmentioned fields, just check them all.
                 for (vf_index, variant_field) in variant.fields.iter().enumerate() {
-                    let field = fields
-                        .iter()
-                        .find(|f| self.tcx.field_index(f.hir_id, self.tables()) == vf_index);
+                    let field = fields.iter().find(|f| {
+                        self.tcx.field_index(f.hir_id, self.typeck_results()) == vf_index
+                    });
                     let (use_ctxt, span) = match field {
                         Some(field) => (field.ident.span, field.span),
                         None => (base.span, base.span),
@@ -1118,7 +1119,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
             } else {
                 for field in fields {
                     let use_ctxt = field.ident.span;
-                    let index = self.tcx.field_index(field.hir_id, self.tables());
+                    let index = self.tcx.field_index(field.hir_id, self.typeck_results());
                     self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
                 }
             }
@@ -1129,12 +1130,12 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
 
     fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
-            let res = self.tables().qpath_res(qpath, pat.hir_id);
-            let adt = self.tables().pat_ty(pat).ty_adt_def().unwrap();
+            let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
+            let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
             let variant = adt.variant_of_res(res);
             for field in fields {
                 let use_ctxt = field.ident.span;
-                let index = self.tcx.field_index(field.hir_id, self.tables());
+                let index = self.tcx.field_index(field.hir_id, self.typeck_results());
                 self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false);
             }
         }
@@ -1151,18 +1152,19 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
 
 struct TypePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
     current_item: LocalDefId,
     span: Span,
 }
 
 impl<'tcx> TypePrivacyVisitor<'tcx> {
-    /// Gets the type-checking side-tables for the current body.
+    /// Gets the type-checking results for the current body.
     /// As this will ICE if called outside bodies, only call when working with
     /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
     #[track_caller]
-    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
-        self.maybe_typeck_tables.expect("`TypePrivacyVisitor::tables` called outside of body")
+    fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
+        self.maybe_typeck_results
+            .expect("`TypePrivacyVisitor::typeck_results` called outside of body")
     }
 
     fn item_is_accessible(&self, did: DefId) -> bool {
@@ -1174,11 +1176,11 @@ fn item_is_accessible(&self, did: DefId) -> bool {
     // Take node-id of an expression or pattern and check its type for privacy.
     fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
         self.span = span;
-        let tables = self.tables();
-        if self.visit(tables.node_type(id)) || self.visit(tables.node_substs(id)) {
+        let typeck_results = self.typeck_results();
+        if self.visit(typeck_results.node_type(id)) || self.visit(typeck_results.node_substs(id)) {
             return true;
         }
-        if let Some(adjustments) = tables.adjustments().get(id) {
+        if let Some(adjustments) = typeck_results.adjustments().get(id) {
             for adjustment in adjustments {
                 if self.visit(adjustment.target) {
                     return true;
@@ -1216,17 +1218,18 @@ fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.tcx.body_tables(body));
+        let old_maybe_typeck_results =
+            self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
         let body = self.tcx.hir().body(body);
         self.visit_body(body);
-        self.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
     fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
         self.span = hir_ty.span;
-        if let Some(tables) = self.maybe_typeck_tables {
+        if let Some(typeck_results) = self.maybe_typeck_results {
             // Types in bodies.
-            if self.visit(tables.node_type(hir_ty.hir_id)) {
+            if self.visit(typeck_results.node_type(hir_ty.hir_id)) {
                 return;
             }
         } else {
@@ -1243,7 +1246,7 @@ fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
 
     fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
         self.span = trait_ref.path.span;
-        if self.maybe_typeck_tables.is_none() {
+        if self.maybe_typeck_results.is_none() {
             // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
             // The traits' privacy in bodies is already checked as a part of trait object types.
             let bounds = rustc_typeck::hir_trait_to_predicates(
@@ -1289,7 +1292,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
             hir::ExprKind::MethodCall(_, span, _, _) => {
                 // Method calls have to be checked specially.
                 self.span = span;
-                if let Some(def_id) = self.tables().type_dependent_def_id(expr.hir_id) {
+                if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) {
                     if self.visit(self.tcx.type_of(def_id)) {
                         return;
                     }
@@ -1317,9 +1320,9 @@ fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: S
                 Res::Def(kind, def_id) => Some((kind, def_id)),
                 _ => None,
             },
-            hir::QPath::TypeRelative(..) => {
-                self.maybe_typeck_tables.and_then(|tables| tables.type_dependent_def(id))
-            }
+            hir::QPath::TypeRelative(..) => self
+                .maybe_typeck_results
+                .and_then(|typeck_results| typeck_results.type_dependent_def(id)),
         };
         let def = def.filter(|(kind, _)| match kind {
             DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static => true,
@@ -1375,9 +1378,9 @@ fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let orig_current_item =
             mem::replace(&mut self.current_item, self.tcx.hir().local_def_id(item.hir_id));
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.take();
+        let old_maybe_typeck_results = self.maybe_typeck_results.take();
         intravisit::walk_item(self, item);
-        self.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.maybe_typeck_results = old_maybe_typeck_results;
         self.current_item = orig_current_item;
     }
 }
@@ -2040,7 +2043,7 @@ pub fn provide(providers: &mut Providers) {
 
 fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     // Check privacy of names not checked in previous compilation stages.
-    let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_tables: None, current_item: None };
+    let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: None };
     let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
 
     intravisit::walk_mod(&mut visitor, module, hir_id);
@@ -2048,7 +2051,7 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     // Check privacy of explicitly written types and traits as well as
     // inferred types of expressions and patterns.
     let mut visitor =
-        TypePrivacyVisitor { tcx, maybe_typeck_tables: None, current_item: module_def_id, span };
+        TypePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id, span };
     intravisit::walk_mod(&mut visitor, module, hir_id);
 }
 
index 74a54176774ca65e29a8d060038a065e857dd727..b7615b25c4a6cb16bf3ab738f3b2a8cd1bf8c515 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(bool_to_option)]
 #![feature(const_fn)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_panic)]
 #![feature(core_intrinsics)]
 #![feature(hash_raw_entry)]
index bca65c63e91986c476325156d3efa231869746e8..45253fc878222affc6e6a60618b63e7f63a85834 100644 (file)
@@ -111,12 +111,17 @@ impl<'a> Resolver<'a> {
             (self.cstore().crate_name_untracked(def_id.krate), None)
         } else {
             let def_key = self.cstore().def_key(def_id);
-            (
-                // This unwrap is safe: crates must always have a name
-                def_key.disambiguated_data.data.get_opt_name().unwrap(),
-                // This unwrap is safe since we know this isn't the root
-                Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id })),
-            )
+            let name = def_key
+                .disambiguated_data
+                .data
+                .get_opt_name()
+                .expect("given a DefId that wasn't a module");
+            // This unwrap is safe since we know this isn't the root
+            let parent = Some(self.get_module(DefId {
+                index: def_key.parent.expect("failed to get parent for module"),
+                ..def_id
+            }));
+            (name, parent)
         };
 
         // Allocate and return a new module with the information we found
@@ -300,9 +305,7 @@ fn insert_field_names_local(&mut self, def_id: DefId, vdata: &ast::VariantData)
     }
 
     fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Spanned<Symbol>>) {
-        if !field_names.is_empty() {
-            self.r.field_names.insert(def_id, field_names);
-        }
+        self.r.field_names.insert(def_id, field_names);
     }
 
     fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
@@ -1428,6 +1431,8 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         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));
+        // Record field names for error reporting.
+        self.insert_field_names_local(ctor_def_id, &variant.data);
 
         visit::walk_variant(self, variant);
     }
index 561890723b30b4d315a183e96ab3409aac40e6a6..a7a005bdeb9f2e3b59b2d0796c2947bc6ae6dddd 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::SourceMap;
-use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, MultiSpan, Span};
 
 use crate::imports::{Import, ImportKind, ImportResolver};
@@ -442,6 +442,19 @@ impl<'a> Resolver<'a> {
                 );
                 err
             }
+            ResolutionError::ParamInTyOfConstArg(name) => {
+                let mut err = struct_span_err!(
+                    self.session,
+                    span,
+                    E0770,
+                    "the type of const parameters must not depend on other generic parameters"
+                );
+                err.span_label(
+                    span,
+                    format!("the type must not depend on the parameter `{}`", name),
+                );
+                err
+            }
             ResolutionError::SelfInTyParamDefault => {
                 let mut err = struct_span_err!(
                     self.session,
@@ -674,7 +687,7 @@ fn early_lookup_typo_candidate(
 
         match find_best_match_for_name(
             suggestions.iter().map(|suggestion| &suggestion.candidate),
-            &ident.as_str(),
+            ident.name,
             None,
         ) {
             Some(found) if found != ident.name => {
@@ -846,9 +859,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
                     // otherwise cause duplicate suggestions.
                     continue;
                 }
-                if let Some(crate_id) =
-                    self.crate_loader.maybe_process_path_extern(ident.name, ident.span)
-                {
+                if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) {
                     let crate_root =
                         self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
                     suggestions.extend(self.lookup_import_candidates_from_module(
@@ -882,8 +893,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
         );
         self.add_typo_suggestion(err, suggestion, ident.span);
 
-        if macro_kind == MacroKind::Derive && (ident.as_str() == "Send" || ident.as_str() == "Sync")
-        {
+        if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
             let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
             err.span_note(ident.span, &msg);
         }
index 4595a96ce24f53d166a735c869950f2ed0234d10..d3f45f962a025e5d3cbf2a51dffdb45373871e78 100644 (file)
@@ -1034,8 +1034,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                         let initial_res = source_bindings[ns].get().map(|initial_binding| {
                             all_ns_err = false;
                             if let Some(target_binding) = target_bindings[ns].get() {
-                                // Note that as_str() de-gensyms the Symbol
-                                if target.name.as_str() == "_"
+                                if target.name == kw::Underscore
                                     && initial_binding.is_extern_crate()
                                     && !initial_binding.is_import()
                                 {
@@ -1133,7 +1132,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                 });
 
                 let lev_suggestion =
-                    find_best_match_for_name(names, &ident.as_str(), None).map(|suggestion| {
+                    find_best_match_for_name(names, ident.name, None).map(|suggestion| {
                         (
                             vec![(ident.span, suggestion.to_string())],
                             String::from("a similar name exists in the module"),
index 679f5637686ff4eddbddd3c7a0cf59c4f7a3d552..ed88e5496921596a15f783c79c84a648f7a617f8 100644 (file)
@@ -123,6 +123,10 @@ enum PatBoundCtx {
     /// from the default of a type parameter because they're not declared
     /// before said type parameter. Also see the `visit_generics` override.
     ForwardTyParamBanRibKind,
+
+    /// We are inside of the type of a const parameter. Can't refer to any
+    /// parameters.
+    ConstParamTyRibKind,
 }
 
 impl RibKind<'_> {
@@ -135,7 +139,8 @@ impl RibKind<'_> {
             | FnItemRibKind
             | ConstantItemRibKind
             | ModuleRibKind(_)
-            | MacroDefinition(_) => false,
+            | MacroDefinition(_)
+            | ConstParamTyRibKind => false,
             AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true,
         }
     }
@@ -184,7 +189,7 @@ fn new(kind: RibKind<'a>) -> Rib<'a, R> {
     // Paths in struct expressions and patterns `Path { .. }`.
     Struct,
     // Paths in tuple struct patterns `Path(..)`.
-    TupleStruct,
+    TupleStruct(Span),
     // `m::A::B` in `<T as m::A>::B::C`.
     TraitItem(Namespace),
 }
@@ -193,7 +198,7 @@ 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::Expr(..) | PathSource::Pat | PathSource::TupleStruct(_) => ValueNS,
             PathSource::TraitItem(ns) => ns,
         }
     }
@@ -204,7 +209,7 @@ fn defer_to_typeck(self) -> bool {
             | PathSource::Expr(..)
             | PathSource::Pat
             | PathSource::Struct
-            | PathSource::TupleStruct => true,
+            | PathSource::TupleStruct(_) => true,
             PathSource::Trait(_) | PathSource::TraitItem(..) => false,
         }
     }
@@ -215,7 +220,7 @@ fn descr_expected(self) -> &'static str {
             PathSource::Trait(_) => "trait",
             PathSource::Pat => "unit struct, unit variant or constant",
             PathSource::Struct => "struct, variant or union type",
-            PathSource::TupleStruct => "tuple struct or tuple variant",
+            PathSource::TupleStruct(_) => "tuple struct or tuple variant",
             PathSource::TraitItem(ns) => match ns {
                 TypeNS => "associated type",
                 ValueNS => "method or associated constant",
@@ -301,7 +306,7 @@ fn is_call(self) -> bool {
                 | Res::SelfCtor(..) => true,
                 _ => false,
             },
-            PathSource::TupleStruct => match res {
+            PathSource::TupleStruct(_) => match res {
                 Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true,
                 _ => false,
             },
@@ -336,8 +341,8 @@ fn error_code(self, has_unexpected_resolution: bool) -> DiagnosticId {
             (PathSource::Struct, false) => error_code!(E0422),
             (PathSource::Expr(..), true) => error_code!(E0423),
             (PathSource::Expr(..), false) => error_code!(E0425),
-            (PathSource::Pat | PathSource::TupleStruct, true) => error_code!(E0532),
-            (PathSource::Pat | PathSource::TupleStruct, false) => error_code!(E0531),
+            (PathSource::Pat | PathSource::TupleStruct(_), true) => error_code!(E0532),
+            (PathSource::Pat | PathSource::TupleStruct(_), false) => error_code!(E0531),
             (PathSource::TraitItem(..), true) => error_code!(E0575),
             (PathSource::TraitItem(..), false) => error_code!(E0576),
         }
@@ -394,13 +399,23 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
 
     /// Fields used to add information to diagnostic errors.
     diagnostic_metadata: DiagnosticMetadata<'ast>,
+
+    /// State used to know whether to ignore resolution errors for function bodies.
+    ///
+    /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items.
+    /// In most cases this will be `None`, in which case errors will always be reported.
+    /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body.
+    in_func_body: bool,
 }
 
 /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
 impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     fn visit_item(&mut self, item: &'ast Item) {
         let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
+        // Always report errors in items we just entered.
+        let old_ignore = replace(&mut self.in_func_body, false);
         self.resolve_item(item);
+        self.in_func_body = old_ignore;
         self.diagnostic_metadata.current_item = prev;
     }
     fn visit_arm(&mut self, arm: &'ast Arm) {
@@ -497,6 +512,9 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
 
                 visit::walk_fn_ret_ty(this, &declaration.output);
 
+                // Ignore errors in function bodies if this is rustdoc
+                // Be sure not to set this until the function signature has been resolved.
+                let previous_state = replace(&mut this.in_func_body, true);
                 // Resolve the function body, potentially inside the body of an async closure
                 match fn_kind {
                     FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
@@ -504,6 +522,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
                 };
 
                 debug!("(resolving function) leaving function");
+                this.in_func_body = previous_state;
             })
         });
         self.diagnostic_metadata.current_function = previous_value;
@@ -562,7 +581,11 @@ fn visit_generics(&mut self, generics: &'ast Generics) {
                     for bound in &param.bounds {
                         self.visit_param_bound(bound);
                     }
+                    self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
+                    self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
                     self.visit_ty(ty);
+                    self.ribs[TypeNS].pop().unwrap();
+                    self.ribs[ValueNS].pop().unwrap();
                 }
             }
         }
@@ -644,6 +667,8 @@ fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> {
             label_ribs: Vec::new(),
             current_trait_ref: None,
             diagnostic_metadata: DiagnosticMetadata::default(),
+            // errors at module scope should always be reported
+            in_func_body: false,
         }
     }
 
@@ -757,10 +782,10 @@ fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
                 return if self.is_label_valid_from_rib(i) {
                     Some(*id)
                 } else {
-                    self.r.report_error(
+                    self.report_error(
                         original_span,
                         ResolutionError::UnreachableLabel {
-                            name: &label.name.as_str(),
+                            name: label.name,
                             definition_span: ident.span,
                             suggestion,
                         },
@@ -775,9 +800,9 @@ fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
             suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
         }
 
-        self.r.report_error(
+        self.report_error(
             original_span,
-            ResolutionError::UndeclaredLabel { name: &label.name.as_str(), suggestion },
+            ResolutionError::UndeclaredLabel { name: label.name, suggestion },
         );
         None
     }
@@ -798,7 +823,8 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
                 | ItemRibKind(..)
                 | ConstantItemRibKind
                 | ModuleRibKind(..)
-                | ForwardTyParamBanRibKind => {
+                | ForwardTyParamBanRibKind
+                | ConstParamTyRibKind => {
                     return false;
                 }
             }
@@ -833,7 +859,11 @@ fn future_proof_import(&mut self, use_tree: &UseTree) {
             };
             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));
+                if this.should_report_errs() {
+                    this.r
+                        .session
+                        .span_err(ident.span, &format!("imports cannot refer to {}", what));
+                }
             };
 
             for &ns in nss {
@@ -1008,7 +1038,7 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib
             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);
+                self.report_error(param.ident.span, err);
             }
             seen_bindings.entry(ident).or_insert(param.ident.span);
 
@@ -1274,7 +1304,7 @@ fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err:
                 .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)));
+                self.report_error(span, err(ident.name, &path_names_to_string(path)));
             }
         }
     }
@@ -1289,6 +1319,7 @@ fn resolve_params(&mut self, params: &'ast [Param]) {
     }
 
     fn resolve_local(&mut self, local: &'ast Local) {
+        debug!("resolving local ({:?})", local);
         // Resolve the type.
         walk_list!(self, visit_ty, &local.ty);
 
@@ -1390,7 +1421,7 @@ fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<BindingMap> {
             if inconsistent_vars.contains_key(name) {
                 v.could_be_path = false;
             }
-            self.r.report_error(
+            self.report_error(
                 *v.origin.iter().next().unwrap(),
                 ResolutionError::VariableNotBoundInPattern(v),
             );
@@ -1400,7 +1431,7 @@ fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) -> Vec<BindingMap> {
         let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
         inconsistent_vars.sort();
         for (name, v) in inconsistent_vars {
-            self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
+            self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
         }
 
         // 5) Finally bubble up all the binding maps.
@@ -1483,7 +1514,7 @@ fn resolve_pattern_inner(
                     self.r.record_partial_res(pat.id, PartialRes::new(res));
                 }
                 PatKind::TupleStruct(ref path, ..) => {
-                    self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
+                    self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span));
                 }
                 PatKind::Path(ref qself, ref path) => {
                     self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
@@ -1550,7 +1581,7 @@ fn fresh_binding(
                 // `Variant(a, a)`:
                 _ => IdentifierBoundMoreThanOnceInSamePattern,
             };
-            self.r.report_error(ident.span, error(&ident.as_str()));
+            self.report_error(ident.span, error(ident.name));
         }
 
         // Record as bound if it's valid:
@@ -1624,7 +1655,7 @@ fn try_resolve_as_non_binding(
                 // 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(
+                self.report_error(
                     ident.span,
                     ResolutionError::BindingShadowsSomethingUnacceptable(
                         pat_src.descr(),
@@ -1677,18 +1708,27 @@ fn smart_resolve_path_fragment(
         source: PathSource<'ast>,
         crate_lint: CrateLint,
     ) -> PartialRes {
+        log::debug!("smart_resolve_path_fragment(id={:?},qself={:?},path={:?}", id, qself, path);
         let ns = source.namespace();
         let is_expected = &|res| source.is_expected(res);
 
         let report_errors = |this: &mut Self, res: Option<Res>| {
-            let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
-
-            let def_id = this.parent_scope.module.normal_ancestor_id;
-            let instead = res.is_some();
-            let suggestion =
-                if res.is_none() { this.report_missing_type_error(path) } else { None };
-
-            this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion });
+            if this.should_report_errs() {
+                let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
+
+                let def_id = this.parent_scope.module.normal_ancestor_id;
+                let instead = res.is_some();
+                let suggestion =
+                    if res.is_none() { this.report_missing_type_error(path) } else { None };
+
+                this.r.use_injections.push(UseError {
+                    err,
+                    candidates,
+                    def_id,
+                    instead,
+                    suggestion,
+                });
+            }
 
             PartialRes::new(Res::Err)
         };
@@ -1746,13 +1786,17 @@ fn smart_resolve_path_fragment(
 
             let def_id = this.parent_scope.module.normal_ancestor_id;
 
-            this.r.use_injections.push(UseError {
-                err,
-                candidates,
-                def_id,
-                instead: false,
-                suggestion: None,
-            });
+            if this.should_report_errs() {
+                this.r.use_injections.push(UseError {
+                    err,
+                    candidates,
+                    def_id,
+                    instead: false,
+                    suggestion: None,
+                });
+            } else {
+                err.cancel();
+            }
 
             // We don't return `Some(parent_err)` here, because the error will
             // be already printed as part of the `use` injections
@@ -1809,7 +1853,7 @@ fn smart_resolve_path_fragment(
 
             Err(err) => {
                 if let Some(err) = report_errors_for_call(self, err) {
-                    self.r.report_error(err.span, err.node);
+                    self.report_error(err.span, err.node);
                 }
 
                 PartialRes::new(Res::Err)
@@ -1843,6 +1887,21 @@ fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool
         if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
     }
 
+    /// A wrapper around [`Resolver::report_error`].
+    ///
+    /// This doesn't emit errors for function bodies if this is rustdoc.
+    fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
+        if self.should_report_errs() {
+            self.r.report_error(span, resolution_error);
+        }
+    }
+
+    #[inline]
+    /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
+    fn should_report_errs(&self) -> bool {
+        !(self.r.session.opts.actually_rustdoc && self.in_func_body)
+    }
+
     // Resolve in alternative namespaces if resolution in the primary namespace fails.
     fn resolve_qpath_anywhere(
         &mut self,
index fc41ce5d5351114e4310fb90ef9b45b3d26b9337..9323c15a94109b9cdb6ad278051bcc451719cb8d 100644 (file)
@@ -480,10 +480,12 @@ fn smart_resolve_context_dependent_help(
 
         let mut bad_struct_syntax_suggestion = |def_id: DefId| {
             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(Some(
+                    parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
+                )) => {
+                    path_sep(err, &parent);
                 }
                 PathSource::Expr(None) if followed_by_brace => {
                     if let Some(sp) = closing_brace {
@@ -505,15 +507,56 @@ fn smart_resolve_context_dependent_help(
                             ),
                         );
                     }
-                    suggested = true;
                 }
-                _ => {}
-            }
-            if !suggested {
-                if let Some(span) = self.r.opt_span(def_id) {
-                    err.span_label(span, &format!("`{}` defined here", path_str));
+                PathSource::Expr(
+                    None | Some(Expr { kind: ExprKind::Call(..) | ExprKind::Path(..), .. }),
+                )
+                | PathSource::TupleStruct(_)
+                | PathSource::Pat => {
+                    let span = match &source {
+                        PathSource::Expr(Some(Expr {
+                            span, kind: ExprKind::Call(_, _), ..
+                        }))
+                        | PathSource::TupleStruct(span) => {
+                            // We want the main underline to cover the suggested code as well for
+                            // cleaner output.
+                            err.set_span(*span);
+                            *span
+                        }
+                        _ => span,
+                    };
+                    if let Some(span) = self.r.opt_span(def_id) {
+                        err.span_label(span, &format!("`{}` defined here", path_str));
+                    }
+                    let (tail, descr, applicability) = match source {
+                        PathSource::Pat | PathSource::TupleStruct(_) => {
+                            ("", "pattern", Applicability::MachineApplicable)
+                        }
+                        _ => (": val", "literal", Applicability::HasPlaceholders),
+                    };
+                    let (fields, applicability) = match self.r.field_names.get(&def_id) {
+                        Some(fields) => (
+                            fields
+                                .iter()
+                                .map(|f| format!("{}{}", f.node, tail))
+                                .collect::<Vec<String>>()
+                                .join(", "),
+                            applicability,
+                        ),
+                        None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
+                    };
+                    let pad = match self.r.field_names.get(&def_id) {
+                        Some(fields) if fields.is_empty() => "",
+                        _ => " ",
+                    };
+                    err.span_suggestion(
+                        span,
+                        &format!("use struct {} syntax instead", descr),
+                        format!("{} {{{pad}{}{pad}}}", path_str, fields, pad = pad),
+                        applicability,
+                    );
                 }
-                err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str));
+                _ => {}
             }
         };
 
@@ -546,7 +589,10 @@ fn smart_resolve_context_dependent_help(
                     return false;
                 }
             }
-            (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct | PathSource::Expr(..)) => {
+            (
+                Res::Def(DefKind::Enum, def_id),
+                PathSource::TupleStruct(_) | PathSource::Expr(..),
+            ) => {
                 if let Some(variants) = self.collect_enum_variants(def_id) {
                     if !variants.is_empty() {
                         let msg = if variants.len() == 1 {
@@ -714,10 +760,8 @@ fn lookup_typo_candidate(
                         if !module.no_implicit_prelude {
                             let extern_prelude = self.r.extern_prelude.clone();
                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
-                                self.r
-                                    .crate_loader
-                                    .maybe_process_path_extern(ident.name, ident.span)
-                                    .and_then(|crate_id| {
+                                self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
+                                    |crate_id| {
                                         let crate_mod = Res::Def(
                                             DefKind::Mod,
                                             DefId { krate: crate_id, index: CRATE_DEF_INDEX },
@@ -728,7 +772,8 @@ fn lookup_typo_candidate(
                                         } else {
                                             None
                                         }
-                                    })
+                                    },
+                                )
                             }));
 
                             if let Some(prelude) = self.r.prelude {
@@ -765,7 +810,7 @@ fn lookup_typo_candidate(
 
         match find_best_match_for_name(
             names.iter().map(|suggestion| &suggestion.candidate),
-            &name.as_str(),
+            name,
             None,
         ) {
             Some(found) if found != name => {
@@ -1008,7 +1053,7 @@ fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
             .filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
             .map(|(id, _)| &id.name);
 
-        find_best_match_for_name(names, &label.as_str(), None).map(|symbol| {
+        find_best_match_for_name(names, label.name, None).map(|symbol| {
             // Upon finding a similar name, get the ident that it was from - the span
             // contained within helps make a useful diagnostic. In addition, determine
             // whether this candidate is within scope.
index 1467bf537eb49169f8aa0274a35547d5570a3ea3..567db8edec9afe25b550f83e8be1e2df685c28b1 100644 (file)
@@ -2364,7 +2364,7 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>)
         if let Some(params) = error {
             // If there's no lifetime available, suggest `'static`.
             if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
-                lifetime_names.insert(Ident::from_str("'static"));
+                lifetime_names.insert(Ident::with_dummy_span(kw::StaticLifetime));
             }
         }
         self.add_missing_lifetime_specifiers_label(
index 0f1618031d034eb62d9f9ba580c83248adb46470..da39f79efcd3bc487d8889a90a4d4bab146e8b29 100644 (file)
@@ -193,11 +193,11 @@ enum ResolutionError<'a> {
     /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm.
     VariableBoundWithDifferentMode(Symbol, Span),
     /// Error E0415: identifier is bound more than once in this parameter list.
-    IdentifierBoundMoreThanOnceInParameterList(&'a str),
+    IdentifierBoundMoreThanOnceInParameterList(Symbol),
     /// Error E0416: identifier is bound more than once in the same pattern.
-    IdentifierBoundMoreThanOnceInSamePattern(&'a str),
+    IdentifierBoundMoreThanOnceInSamePattern(Symbol),
     /// Error E0426: use of undeclared label.
-    UndeclaredLabel { name: &'a str, suggestion: Option<LabelSuggestion> },
+    UndeclaredLabel { name: Symbol, suggestion: Option<LabelSuggestion> },
     /// Error E0429: `self` imports are only allowed within a `{ }` list.
     SelfImportsOnlyAllowedWithin { root: bool, span_with_rename: Span },
     /// Error E0430: `self` import can only appear once in the list.
@@ -211,13 +211,15 @@ enum ResolutionError<'a> {
     /// Error E0435: attempt to use a non-constant value in a constant.
     AttemptToUseNonConstantValueInConstant,
     /// Error E0530: `X` bindings cannot shadow `Y`s.
-    BindingShadowsSomethingUnacceptable(&'a str, Symbol, &'a NameBinding<'a>),
+    BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
     /// Error E0128: type parameters with a default cannot use forward-declared identifiers.
     ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
+    /// ERROR E0770: the type of const parameters must not depend on other generic parameters.
+    ParamInTyOfConstArg(Symbol),
     /// Error E0735: type parameters with a default cannot use `Self`
     SelfInTyParamDefault,
     /// Error E0767: use of unreachable label
-    UnreachableLabel { name: &'a str, definition_span: Span, suggestion: Option<LabelSuggestion> },
+    UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
 }
 
 enum VisResolutionError<'a> {
@@ -2480,6 +2482,12 @@ fn validate_res_from_ribs(
                             }
                             return Res::Err;
                         }
+                        ConstParamTyRibKind => {
+                            if record_used {
+                                self.report_error(span, ParamInTyOfConstArg(rib_ident.name));
+                            }
+                            return Res::Err;
+                        }
                     }
                 }
                 if let Some(res_err) = res_err {
@@ -2503,6 +2511,15 @@ fn validate_res_from_ribs(
                         // This was an attempt to use a type parameter outside its scope.
                         ItemRibKind(has_generic_params) => has_generic_params,
                         FnItemRibKind => HasGenericParams::Yes,
+                        ConstParamTyRibKind => {
+                            if record_used {
+                                self.report_error(
+                                    span,
+                                    ResolutionError::ParamInTyOfConstArg(rib_ident.name),
+                                );
+                            }
+                            return Res::Err;
+                        }
                     };
 
                     if record_used {
@@ -2527,9 +2544,24 @@ fn validate_res_from_ribs(
                 }
                 for rib in ribs {
                     let has_generic_params = match rib.kind {
+                        NormalRibKind
+                        | ClosureOrAsyncRibKind
+                        | AssocItemRibKind
+                        | ModuleRibKind(..)
+                        | MacroDefinition(..)
+                        | ForwardTyParamBanRibKind
+                        | ConstantItemRibKind => continue,
                         ItemRibKind(has_generic_params) => has_generic_params,
                         FnItemRibKind => HasGenericParams::Yes,
-                        _ => continue,
+                        ConstParamTyRibKind => {
+                            if record_used {
+                                self.report_error(
+                                    span,
+                                    ResolutionError::ParamInTyOfConstArg(rib_ident.name),
+                                );
+                            }
+                            return Res::Err;
+                        }
                     };
 
                     // This was an attempt to use a const parameter outside its scope.
@@ -2925,7 +2957,7 @@ fn extern_prelude_get(
                 let crate_id = if !speculative {
                     self.crate_loader.process_path_extern(ident.name, ident.span)
                 } else {
-                    self.crate_loader.maybe_process_path_extern(ident.name, ident.span)?
+                    self.crate_loader.maybe_process_path_extern(ident.name)?
                 };
                 let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
                 Some(
@@ -2946,7 +2978,7 @@ pub fn resolve_str_path_error(
         span: Span,
         path_str: &str,
         ns: Namespace,
-        module_id: LocalDefId,
+        module_id: DefId,
     ) -> Result<(ast::Path, Res), ()> {
         let path = if path_str.starts_with("::") {
             ast::Path {
@@ -2966,7 +2998,7 @@ pub fn resolve_str_path_error(
                     .collect(),
             }
         };
-        let module = self.module_map.get(&module_id).copied().unwrap_or(self.graph_root);
+        let module = self.get_module(module_id);
         let parent_scope = &ParentScope::module(module);
         let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
         Ok((path, res))
index bd3724449fabf1dc1ed78be7eecfa6e4bfa9182c..5aa676e3fce8eafb8a7663d97f124ea344440df6 100644 (file)
@@ -104,20 +104,20 @@ pub fn analysis(&self) -> &rls_data::Analysis {
         self.dumper.analysis()
     }
 
-    fn nest_tables<F>(&mut self, item_def_id: LocalDefId, f: F)
+    fn nest_typeck_results<F>(&mut self, item_def_id: LocalDefId, f: F)
     where
         F: FnOnce(&mut Self),
     {
-        let tables = if self.tcx.has_typeck_tables(item_def_id) {
-            Some(self.tcx.typeck_tables_of(item_def_id))
+        let typeck_results = if self.tcx.has_typeck_results(item_def_id) {
+            Some(self.tcx.typeck(item_def_id))
         } else {
             None
         };
 
-        let old_maybe_typeck_tables = self.save_ctxt.maybe_typeck_tables;
-        self.save_ctxt.maybe_typeck_tables = tables;
+        let old_maybe_typeck_results = self.save_ctxt.maybe_typeck_results;
+        self.save_ctxt.maybe_typeck_results = typeck_results;
         f(self);
-        self.save_ctxt.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.save_ctxt.maybe_typeck_results = old_maybe_typeck_results;
     }
 
     fn span_from_span(&self, span: Span) -> SpanData {
@@ -226,7 +226,7 @@ fn process_formals(&mut self, formals: &'tcx [hir::Param<'tcx>], qualname: &str)
             collector.visit_pat(&arg.pat);
 
             for (hir_id, ident, ..) in collector.collected_idents {
-                let typ = match self.save_ctxt.tables().node_type_opt(hir_id) {
+                let typ = match self.save_ctxt.typeck_results().node_type_opt(hir_id) {
                     Some(s) => s.to_string(),
                     None => continue,
                 };
@@ -269,7 +269,7 @@ fn process_method(
         debug!("process_method: {}:{}", hir_id, ident);
 
         let map = &self.tcx.hir();
-        self.nest_tables(map.local_def_id(hir_id), |v| {
+        self.nest_typeck_results(map.local_def_id(hir_id), |v| {
             if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) {
                 if let Some(body) = body {
                     v.process_formals(map.body(body).params, &method_data.qualname);
@@ -363,7 +363,7 @@ fn process_fn(
         body: hir::BodyId,
     ) {
         let map = &self.tcx.hir();
-        self.nest_tables(map.local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(map.local_def_id(item.hir_id), |v| {
             let body = map.body(body);
             if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(fn_data, DefData, item.span);
@@ -391,7 +391,7 @@ fn process_static_or_const_item(
         typ: &'tcx hir::Ty<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
     ) {
-        self.nest_tables(self.tcx.hir().local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(self.tcx.hir().local_def_id(item.hir_id), |v| {
             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(var_data, DefData, item.span);
                 v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id), var_data);
@@ -438,7 +438,7 @@ fn process_assoc_const(
         }
 
         // walk type and init value
-        self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
+        self.nest_typeck_results(self.tcx.hir().local_def_id(hir_id), |v| {
             v.visit_ty(typ);
             if let Some(expr) = expr {
                 v.visit_expr(expr);
@@ -508,7 +508,7 @@ fn process_struct(
             );
         }
 
-        self.nest_tables(self.tcx.hir().local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(self.tcx.hir().local_def_id(item.hir_id), |v| {
             for field in def.fields() {
                 v.process_struct_field_def(field, item.hir_id);
                 v.visit_ty(&field.ty);
@@ -641,7 +641,7 @@ fn process_impl(
         }
 
         let map = &self.tcx.hir();
-        self.nest_tables(map.local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(map.local_def_id(item.hir_id), |v| {
             v.visit_ty(&typ);
             if let &Some(ref trait_ref) = trait_ref {
                 v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path));
@@ -859,7 +859,7 @@ fn process_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
         match p.kind {
             hir::PatKind::Struct(ref _path, fields, _) => {
                 // FIXME do something with _path?
-                let adt = match self.save_ctxt.tables().node_type_opt(p.hir_id) {
+                let adt = match self.save_ctxt.typeck_results().node_type_opt(p.hir_id) {
                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
                     _ => {
                         intravisit::walk_pat(self, p);
@@ -900,7 +900,7 @@ fn process_var_decl(&mut self, pat: &'tcx hir::Pat<'tcx>) {
                 Res::Local(hir_id) => {
                     let typ = self
                         .save_ctxt
-                        .tables()
+                        .typeck_results()
                         .node_type_opt(hir_id)
                         .map(|t| t.to_string())
                         .unwrap_or_default();
@@ -1375,13 +1375,15 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
             hir::TyKind::Array(ref ty, ref anon_const) => {
                 self.visit_ty(ty);
                 let map = self.tcx.hir();
-                self.nest_tables(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
                     v.visit_expr(&map.body(anon_const.body).value)
                 });
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
                 let item = self.tcx.hir().item(item_id.id);
-                self.nest_tables(self.tcx.hir().local_def_id(item_id.id), |v| v.visit_item(item));
+                self.nest_typeck_results(self.tcx.hir().local_def_id(item_id.id), |v| {
+                    v.visit_item(item)
+                });
             }
             _ => intravisit::walk_ty(self, t),
         }
@@ -1393,7 +1395,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         match ex.kind {
             hir::ExprKind::Struct(ref path, ref fields, ref base) => {
                 let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.hir_id);
-                let adt = match self.save_ctxt.tables().expr_ty_opt(&hir_expr) {
+                let adt = match self.save_ctxt.typeck_results().expr_ty_opt(&hir_expr) {
                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
                     _ => {
                         intravisit::walk_expr(self, ex);
@@ -1430,7 +1432,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
 
                 // walk the body
                 let map = self.tcx.hir();
-                self.nest_tables(self.tcx.hir().local_def_id(ex.hir_id), |v| {
+                self.nest_typeck_results(self.tcx.hir().local_def_id(ex.hir_id), |v| {
                     let body = map.body(body);
                     v.process_formals(body.params, &id);
                     v.visit_expr(&body.value)
@@ -1439,7 +1441,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
             hir::ExprKind::Repeat(ref expr, ref anon_const) => {
                 self.visit_expr(expr);
                 let map = self.tcx.hir();
-                self.nest_tables(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
                     v.visit_expr(&map.body(anon_const.body).value)
                 });
             }
index 5ecb256719f1f6deb0b6cef86b57ef281320994b..22526fc61e6e0d7a6a0f4657a9d4b86c560f849c 100644 (file)
@@ -1,7 +1,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(nll)]
 #![feature(or_patterns)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![recursion_limit = "256"]
 
 mod dump_visitor;
@@ -50,7 +49,7 @@
 
 pub struct SaveContext<'tcx> {
     tcx: TyCtxt<'tcx>,
-    maybe_typeck_tables: Option<&'tcx ty::TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
     access_levels: &'tcx AccessLevels,
     span_utils: SpanUtils<'tcx>,
     config: Config,
@@ -65,12 +64,12 @@ pub enum Data {
 }
 
 impl<'tcx> SaveContext<'tcx> {
-    /// Gets the type-checking side-tables for the current body.
+    /// Gets the type-checking results for the current body.
     /// As this will ICE if called outside bodies, only call when working with
     /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
     #[track_caller]
-    fn tables(&self) -> &'tcx ty::TypeckTables<'tcx> {
-        self.maybe_typeck_tables.expect("`SaveContext::tables` called outside of body")
+    fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
+        self.maybe_typeck_results.expect("`SaveContext::typeck_results` called outside of body")
     }
 
     fn span_from_span(&self, span: Span) -> SpanData {
@@ -483,7 +482,7 @@ pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> O
                     None => {
                         debug!("could not find container for method {} at {:?}", hir_id, span);
                         // This is not necessarily a bug, if there was a compilation error,
-                        // the tables we need might not exist.
+                        // the typeck results we need might not exist.
                         return None;
                     }
                 },
@@ -524,13 +523,13 @@ pub fn get_trait_ref_data(&self, trait_ref: &hir::TraitRef<'_>) -> Option<Ref> {
     }
 
     pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
-        let ty = self.tables().expr_ty_adjusted_opt(expr)?;
+        let ty = self.typeck_results().expr_ty_adjusted_opt(expr)?;
         if matches!(ty.kind, ty::Error(_)) {
             return None;
         }
         match expr.kind {
             hir::ExprKind::Field(ref sub_ex, ident) => {
-                match self.tables().expr_ty_adjusted(&sub_ex).kind {
+                match self.typeck_results().expr_ty_adjusted(&sub_ex).kind {
                     ty::Adt(def, _) if !def.is_enum() => {
                         let variant = &def.non_enum_variant();
                         filter!(self.span_utils, ident.span);
@@ -575,7 +574,7 @@ pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
                 }
             }
             hir::ExprKind::MethodCall(ref seg, ..) => {
-                let method_id = match self.tables().type_dependent_def_id(expr.hir_id) {
+                let method_id = match self.typeck_results().type_dependent_def_id(expr.hir_id) {
                     Some(id) => id,
                     None => {
                         debug!("could not resolve method id for {:?}", expr);
@@ -624,7 +623,7 @@ pub fn get_path_res(&self, hir_id: hir::HirId) -> Res {
             },
 
             Node::Expr(&hir::Expr { kind: hir::ExprKind::Struct(ref qpath, ..), .. }) => {
-                self.tables().qpath_res(qpath, hir_id)
+                self.typeck_results().qpath_res(qpath, hir_id)
             }
 
             Node::Expr(&hir::Expr { kind: hir::ExprKind::Path(ref qpath), .. })
@@ -638,8 +637,8 @@ pub fn get_path_res(&self, hir_id: hir::HirId) -> Res {
             | Node::Ty(&hir::Ty { kind: hir::TyKind::Path(ref qpath), .. }) => match qpath {
                 hir::QPath::Resolved(_, path) => path.res,
                 hir::QPath::TypeRelative(..) => self
-                    .maybe_typeck_tables
-                    .map_or(Res::Err, |tables| tables.qpath_res(qpath, hir_id)),
+                    .maybe_typeck_results
+                    .map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)),
             },
 
             Node::Binding(&hir::Pat {
@@ -824,7 +823,7 @@ fn docs_for_attrs(&self, attrs: &[ast::Attribute]) -> String {
         for attr in attrs {
             if let Some(val) = attr.doc_str() {
                 if attr.is_doc_comment() {
-                    result.push_str(&strip_doc_comment_decoration(&val.as_str()));
+                    result.push_str(&strip_doc_comment_decoration(val));
                 } else {
                     result.push_str(&val.as_str());
                 }
@@ -1010,7 +1009,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
 
         let save_ctxt = SaveContext {
             tcx,
-            maybe_typeck_tables: None,
+            maybe_typeck_results: None,
             access_levels: &access_levels,
             span_utils: SpanUtils::new(&tcx.sess),
             config: find_config(config),
index 2f06ff95b1923a8eec4de3783c2fcc1b486255cc..ace233611223ce9b5a052a07f43f0d5754dbfe48 100644 (file)
@@ -4,7 +4,7 @@
 
 use log::debug;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use std::sync::{Arc, Mutex};
 
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
@@ -67,7 +67,7 @@ pub fn set_actual_reuse(&self, cgu_name: &str, kind: CguReuse) {
 
     pub fn set_expectation(
         &self,
-        cgu_name: &str,
+        cgu_name: Symbol,
         cgu_user_name: &str,
         error_span: Span,
         expected_reuse: CguReuse,
index c5a866817cb4a1930a5b085f22f32d11d50212c2..839ffa5785adacb372b7068475b3998ebe25e49f 100644 (file)
@@ -717,18 +717,20 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
     let mut ret = FxHashSet::default();
     ret.reserve(6); // the minimum number of insertions
     // Target bindings.
-    ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
+    ret.insert((sym::target_os, Some(Symbol::intern(os))));
     if let Some(ref fam) = sess.target.target.options.target_family {
-        ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
-        if fam == "windows" || fam == "unix" {
-            ret.insert((Symbol::intern(fam), None));
+        ret.insert((sym::target_family, Some(Symbol::intern(fam))));
+        if fam == "windows" {
+            ret.insert((sym::windows, None));
+        } else if fam == "unix" {
+            ret.insert((sym::unix, None));
         }
     }
-    ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
-    ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
-    ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
-    ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
-    ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
+    ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
+    ret.insert((sym::target_endian, Some(Symbol::intern(end))));
+    ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz))));
+    ret.insert((sym::target_env, Some(Symbol::intern(env))));
+    ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
     if sess.target.target.options.has_elf_tls {
         ret.insert((sym::target_thread_local, None));
     }
@@ -754,7 +756,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
     }
 
     if sess.opts.debug_assertions {
-        ret.insert((Symbol::intern("debug_assertions"), None));
+        ret.insert((sym::debug_assertions, None));
     }
     if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
         ret.insert((sym::proc_macro, None));
@@ -1705,6 +1707,31 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         );
     }
 
+    if debugging_opts.instrument_coverage {
+        if cg.profile_generate.enabled() || cg.profile_use.is_some() {
+            early_error(
+                error_format,
+                "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
+                or `-C profile-generate`",
+            );
+        }
+
+        // `-Z instrument-coverage` implies:
+        //   * `-Z symbol-mangling-version=v0` - to ensure consistent and reversable name mangling.
+        //     Note, LLVM coverage tools can analyze coverage over multiple runs, including some
+        //     changes to source code; so mangled names must be consistent across compilations.
+        //   * `-C link-dead-code` - so unexecuted code is still counted as zero, rather than be
+        //     optimized out. Note that instrumenting dead code can be explicitly disabled with:
+        //         `-Z instrument-coverage -C link-dead-code=no`.
+        debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
+        if cg.link_dead_code == None {
+            // FIXME(richkadel): Investigate if the `instrument-coverage` implementation can
+            // inject ["zero counters"](https://llvm.org/docs/CoverageMappingFormat.html#counter)
+            // in the coverage map when "dead code" is removed, rather than forcing `link-dead-code`.
+            cg.link_dead_code = Some(true);
+        }
+    }
+
     if !cg.embed_bitcode {
         match cg.lto {
             LtoCli::No | LtoCli::Unspecified => {}
index 2ad7d09cbf415ff4ebb3bc5c0a77f73bbe5b4388..8c1f6a77497407fe269b5ada524926ce56f37d0e 100644 (file)
@@ -715,7 +715,7 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "a single extra argument to append to the linker invocation (can be used several times)"),
     link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
         "extra arguments to append to the linker invocation (space separated)"),
-    link_dead_code: bool = (false, parse_bool, [UNTRACKED],
+    link_dead_code: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
         "keep dead code at link time (useful for code coverage) (default: no)"),
     linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
         "system linker to link outputs with"),
@@ -880,10 +880,12 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         (such as entering an empty infinite loop) by inserting llvm.sideeffect \
         (default: no)"),
     instrument_coverage: bool = (false, parse_bool, [TRACKED],
-        "instrument the generated code with LLVM code region counters to (in the \
-        future) generate coverage reports; disables/overrides some optimization \
-        options (note, the compiler build config must include `profiler = true`) \
-        (default: no)"),
+        "instrument the generated code to support LLVM source-based code coverage \
+        reports (note, the compiler build config must include `profiler = true`, \
+        and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \
+        implies `-C link-dead-code` (unless explicitly disabled)` and
+        `-Z symbol-mangling-version=v0`; and disables/overrides some optimization \
+        options (default: no)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
index fcd5dab94a6c25efe39d6c0f0a2ea23dabe3665a..4ad95e95e9a86a68fe5e30eebf489878e3067909 100644 (file)
@@ -1357,6 +1357,20 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         );
     }
 
+    // FIXME(richkadel): See `src/test/run-make-fulldeps/instrument-coverage/Makefile`. After
+    // compiling with `-Zinstrument-coverage`, the resulting binary generates a segfault during
+    // the program's exit process (likely while attempting to generate the coverage stats in
+    // the "*.profraw" file). An investigation to resolve the problem on Windows is ongoing,
+    // but until this is resolved, the option is disabled on Windows, and the test is skipped
+    // when targeting `MSVC`.
+    if sess.opts.debugging_opts.instrument_coverage && sess.target.target.options.is_like_msvc {
+        sess.warn(
+            "Rust source-based code coverage instrumentation (with `-Z instrument-coverage`) \
+            is not yet supported on Windows when targeting MSVC. The resulting binaries will \
+            still be instrumented for experimentation purposes, but may not execute correctly.",
+        );
+    }
+
     const ASAN_SUPPORTED_TARGETS: &[&str] = &[
         "aarch64-fuchsia",
         "aarch64-unknown-linux-gnu",
index 699871f1c61ce766cf2776ba8c2e65f5d631126c..666080028c10cfc0ab9c69b9d817eefc7e21cf1b 100644 (file)
@@ -6,7 +6,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(negative_impls)]
index 6b3dbd0bf7a059189df1fc5eb9eb8078ae699a7c..5d332ddf5f3df1ccecf1165219bd67d875fdd1b9 100644 (file)
@@ -19,6 +19,7 @@
 #[cfg(test)]
 mod tests;
 
+// The proc macro code for this is in `src/librustc_macros/src/symbols.rs`.
 symbols! {
     // After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
     // this should be rarely necessary though if the keywords are kept in alphabetic order.
         Union:              "union",
     }
 
-    // Symbols that can be referred to with rustc_span::sym::*. The symbol is
-    // the stringified identifier unless otherwise specified (e.g.
-    // `proc_dash_macro` represents "proc-macro").
+    // Pre-interned symbols that can be referred to with `rustc_span::sym::*`.
+    //
+    // The symbol is the stringified identifier unless otherwise specified, in
+    // which case the name should mention the non-identifier punctuation.
+    // E.g. `sym::proc_dash_macro` represents "proc-macro", and it shouldn't be
+    // called `sym::proc_macro` because then it's easy to mistakenly think it
+    // represents "proc_macro".
     //
     // As well as the symbols listed, there are symbols for the the strings
     // "0", "1", ..., "9", which are accessible via `sym::integer`.
+    //
+    // The proc macro will abort if symbols are not in alphabetical order (as
+    // defined by `impl Ord for str`) or if any symbols are duplicated. Vim
+    // users can sort the list by selecting it and executing the command
+    // `:'<,'>!LC_ALL=C sort`.
+    //
+    // There is currently no checking that all symbols are used; that would be
+    // nice to have.
     Symbols {
+        Alignment,
+        Arc,
+        Argument,
+        ArgumentV1,
+        Arguments,
+        C,
+        Center,
+        Clone,
+        Copy,
+        Count,
+        Debug,
+        Decodable,
+        Decoder,
+        Default,
+        Encodable,
+        Encoder,
+        Eq,
+        Equal,
+        Err,
+        Error,
+        FormatSpec,
+        Formatter,
+        From,
+        Future,
+        FxHashMap,
+        FxHashSet,
+        GlobalAlloc,
+        Hash,
+        HashMap,
+        HashSet,
+        Hasher,
+        Implied,
+        Input,
+        IntoIterator,
+        Is,
+        ItemContext,
+        Iterator,
+        Layout,
+        Left,
+        LintPass,
+        None,
+        Ok,
+        Option,
+        Ord,
+        Ordering,
+        Output,
+        Param,
+        PartialEq,
+        PartialOrd,
+        Pending,
+        Pin,
+        Poll,
+        ProcMacro,
+        ProcMacroHack,
+        ProceduralMasqueradeDummyType,
+        Range,
+        RangeFrom,
+        RangeFull,
+        RangeInclusive,
+        RangeTo,
+        RangeToInclusive,
+        Rc,
+        Ready,
+        Result,
+        Return,
+        Right,
+        RustcDecodable,
+        RustcEncodable,
+        Send,
+        Some,
+        StructuralEq,
+        StructuralPartialEq,
+        Sync,
+        Target,
+        Try,
+        Ty,
+        TyCtxt,
+        TyKind,
+        Unknown,
+        Vec,
+        Yield,
+        _DECLS,
+        _Self,
+        __D,
+        __H,
+        __S,
+        __next,
+        __try_var,
+        _d,
+        _e,
+        _task_context,
         aarch64_target_feature,
         abi,
         abi_amdgpu_kernel,
+        abi_avr_interrupt,
         abi_efiapi,
         abi_msp430_interrupt,
         abi_ptx,
         abi_unadjusted,
         abi_vectorcall,
         abi_x86_interrupt,
-        abi_avr_interrupt,
         abort,
         aborts,
-        address,
+        add,
+        add_assign,
         add_with_overflow,
+        address,
         advanced_slice_patterns,
         adx_target_feature,
         alias,
         align,
+        align_offset,
         alignstack,
         all,
+        alloc,
+        alloc_error_handler,
+        alloc_layout,
+        alloc_zeroed,
         allocator,
         allocator_internals,
-        alloc_error_handler,
         allow,
-        allowed,
         allow_fail,
         allow_internal_unsafe,
         allow_internal_unstable,
         allow_internal_unstable_backcompat_hack,
+        allowed,
         always,
         and,
+        and_then,
         any,
         arbitrary_enum_discriminant,
         arbitrary_self_types,
-        Arc,
-        Arguments,
-        ArgumentV1,
         arith_offset,
         arm_target_feature,
+        array,
+        as_str,
         asm,
         assert,
         assert_inhabited,
+        assert_receiver_is_total_eq,
         assert_uninit_valid,
         assert_zero_valid,
         associated_consts,
         async_await,
         async_closure,
         atomics,
+        att_syntax,
         attr,
-        attributes,
         attr_literals,
-        att_syntax,
+        attributes,
         augmented_assignments,
         automatically_derived,
         avx512_target_feature,
         await_macro,
+        bang,
         begin_panic,
         bench,
         bin,
         bind_by_move_pattern_guards,
         bindings_after_at,
+        bitand,
+        bitand_assign,
+        bitor,
+        bitor_assign,
+        bitreverse,
+        bitxor,
+        bitxor_assign,
         block,
         bool,
         borrowck_graphviz_format,
         borrowck_graphviz_postflow,
         borrowck_graphviz_preflow,
+        box_free,
         box_patterns,
         box_syntax,
         braced_empty_structs,
         breakpoint,
+        bridge,
         bswap,
-        bitreverse,
-        C,
+        c_variadic,
+        call,
+        call_mut,
+        call_once,
         caller_location,
         cdylib,
         ceilf32,
         cfg_target_vendor,
         cfg_version,
         char,
+        client,
         clippy,
         clone,
-        Clone,
         clone_closures,
         clone_from,
         closure_to_fn_coercion,
         cmp,
         cmpxchg16b_target_feature,
+        coerce_unsized,
         cold,
         column,
         compile_error,
         const_fn_union,
         const_generics,
         const_if_match,
-        const_indexing,
         const_in_array_repeat_expressions,
+        const_indexing,
         const_let,
         const_loop,
         const_mut_refs,
         const_panic,
         const_precise_live_drops,
+        const_ptr,
         const_raw_ptr_deref,
         const_raw_ptr_to_usize_cast,
-        const_transmute,
+        const_slice_ptr,
         const_trait_bound_opt_out,
         const_trait_impl,
+        const_transmute,
         contents,
         context,
         convert,
-        Copy,
-        copy_closures,
         copy,
+        copy_closures,
         copy_nonoverlapping,
         copysignf32,
         copysignf64,
         crate_name,
         crate_type,
         crate_visibility_modifier,
+        crt_dash_static: "crt-static",
+        ctlz,
+        ctlz_nonzero,
         ctpop,
         cttz,
         cttz_nonzero,
-        ctlz,
-        ctlz_nonzero,
         custom_attribute,
         custom_derive,
         custom_inner_attributes,
         custom_test_frameworks,
-        c_variadic,
+        d,
+        dead_code,
+        dealloc,
+        debug,
+        debug_assertions,
+        debug_struct,
         debug_trait,
-        declare_lint_pass,
+        debug_trait_builder,
+        debug_tuple,
         decl_macro,
-        debug,
-        Debug,
-        Decodable,
-        Default,
+        declare_lint_pass,
+        decode,
         default_lib_allocator,
         default_type_parameter_fallback,
         default_type_params,
         derive,
         diagnostic,
         direct,
+        discriminant_kind,
+        discriminant_type,
         discriminant_value,
+        dispatch_from_dyn,
+        div,
+        div_assign,
         doc,
         doc_alias,
         doc_cfg,
         doc_keyword,
         doc_masked,
+        doc_spotlight,
         doctest,
         document_private_items,
-        dotdoteq_in_patterns,
         dotdot_in_tuple_patterns,
+        dotdoteq_in_patterns,
+        double_braced_closure: "{{closure}}",
+        double_braced_constant: "{{constant}}",
+        double_braced_constructor: "{{constructor}}",
         double_braced_crate: "{{crate}}",
         double_braced_impl: "{{impl}}",
         double_braced_misc: "{{misc}}",
-        double_braced_closure: "{{closure}}",
-        double_braced_constructor: "{{constructor}}",
-        double_braced_constant: "{{constant}}",
         double_braced_opaque: "{{opaque}}",
+        drop,
+        drop_in_place,
+        drop_types_in_const,
         dropck_eyepatch,
         dropck_parametricity,
-        drop_types_in_const,
-        drop_in_place,
         dylib,
         dyn_trait,
+        eh_catch_typeinfo,
         eh_personality,
+        emit_enum,
+        emit_enum_variant,
+        emit_enum_variant_arg,
+        emit_struct,
+        emit_struct_field,
         enable,
-        Encodable,
+        enclosing_scope,
+        encode,
         env,
         eq,
         err,
-        Err,
-        Eq,
-        Equal,
-        enclosing_scope,
         exact_div,
         except,
+        exchange_malloc,
         exclusive_range_pattern,
         exhaustive_integer_patterns,
         exhaustive_patterns,
         existential_type,
-        expf32,
-        expf64,
         exp2f32,
         exp2f64,
         expected,
+        expf32,
+        expf64,
         export_name,
         expr,
         extern_absolute_paths,
-        external_doc,
         extern_crate_item_prelude,
         extern_crate_self,
         extern_in_paths,
         extern_prelude,
         extern_types,
+        external_doc,
+        f,
         f16c_target_feature,
         f32,
+        f32_runtime,
         f64,
-        fadd_fast,
+        f64_runtime,
         fabsf32,
         fabsf64,
+        fadd_fast,
         fdiv_fast,
         feature,
         ffi_const,
         field,
         field_init_shorthand,
         file,
+        fill,
+        finish,
+        flags,
         float_to_int_unchecked,
-        floorf64,
         floorf32,
+        floorf64,
         fmaf32,
         fmaf64,
         fmt,
         fmt_internals,
         fmul_fast,
         fn_must_use,
+        fn_mut,
+        fn_once,
+        fn_once_output,
         forbid,
         forget,
+        format,
         format_args,
-        format_args_nl,
         format_args_capture,
+        format_args_nl,
+        freeze,
         frem_fast,
         from,
-        From,
         from_desugaring,
         from_error,
         from_generator,
         from_method,
         from_ok,
-        from_usize,
+        from_size_align_unchecked,
         from_trait,
+        from_usize,
         fsub_fast,
         fundamental,
         future,
-        Future,
-        FxHashSet,
-        FxHashMap,
+        future_trait,
+        ge,
         gen_future,
         gen_kill,
+        generator,
+        generator_state,
         generators,
         generic_associated_types,
         generic_param_attrs,
         global_allocator,
         global_asm,
         globs,
+        gt,
         half_open_range_patterns,
         hash,
-        Hash,
-        HashSet,
-        HashMap,
         hexagon_target_feature,
         hidden,
         homogeneous_aggregate,
         html_no_source,
         html_playground_url,
         html_root_url,
+        i,
         i128,
         i128_type,
         i16,
         if_let,
         if_while_or_patterns,
         ignore,
-        inlateout,
-        inout,
         impl_header_lifetime_elision,
         impl_lint_pass,
         impl_trait_in_bindings,
         import_shadowing,
-        index,
-        index_mut,
         in_band_lifetimes,
         include,
         include_bytes,
         include_str,
         inclusive_range_syntax,
+        index,
+        index_mut,
         infer_outlives_requirements,
         infer_static_outlives_requirements,
+        inlateout,
         inline,
-        Input,
+        inout,
         intel,
         into_iter,
-        IntoIterator,
         into_result,
         intrinsics,
         irrefutable_let_patterns,
         issue_5723_bootstrap,
         issue_tracker_base_url,
         item,
-        item_context: "ItemContext",
         item_like_imports,
         iter,
-        Iterator,
         keyword,
         kind,
         label,
         label_break_value,
         lang,
         lang_items,
-        lazy_normalization_consts,
         lateout,
+        lazy_normalization_consts,
+        le,
         let_chains,
         lhs,
         lib,
+        libc,
         lifetime,
         likely,
         line,
         link,
-        linkage,
         link_args,
         link_cfg,
         link_llvm_intrinsics,
         link_name,
         link_ordinal,
         link_section,
-        LintPass,
+        linkage,
         lint_reasons,
         literal,
         llvm_asm,
         local_inner_macros,
-        log_syntax,
-        logf32,
-        logf64,
         log10f32,
         log10f64,
         log2f32,
         log2f64,
+        log_syntax,
+        logf32,
+        logf64,
         loop_break_value,
+        lt,
         macro_at_most_once_rep,
         macro_escape,
         macro_export,
         macro_lifetime_matcher,
         macro_literal_matcher,
         macro_reexport,
-        macros_in_extern,
         macro_use,
         macro_vis_matcher,
+        macros_in_extern,
         main,
         managed_boxes,
+        manually_drop,
+        map,
         marker,
         marker_trait_attr,
         masked,
         match_beginning_vert,
         match_default_bindings,
+        maxnumf32,
+        maxnumf64,
         may_dangle,
+        maybe_uninit,
         maybe_uninit_uninit,
         maybe_uninit_zeroed,
         mem_uninitialized,
         min_specialization,
         minnumf32,
         minnumf64,
-        maxnumf32,
-        maxnumf64,
         mips_target_feature,
         miri_start_panic,
         mmx_target_feature,
         module,
         module_path,
         more_struct_aliases,
+        movbe_target_feature,
         move_ref_pattern,
         move_val_init,
-        movbe_target_feature,
+        mul,
+        mul_assign,
         mul_with_overflow,
         must_use,
+        mut_ptr,
+        mut_slice_ptr,
         naked,
         naked_functions,
         name,
+        ne,
         nearbyintf32,
         nearbyintf64,
         needs_allocator,
         needs_drop,
         needs_panic_runtime,
+        neg,
         negate_unsigned,
         negative_impls,
         never,
         never_type_fallback,
         new,
         next,
-        __next,
         nll,
+        no,
         no_builtins,
         no_core,
         no_crate_inject,
         no_link,
         no_main,
         no_mangle,
+        no_niche,
+        no_sanitize,
+        no_stack_check,
+        no_start,
+        no_std,
         nomem,
         non_ascii_idents,
-        None,
         non_exhaustive,
         non_modrs_mods,
+        none_error,
         nontemporal_store,
-        nontrapping_fptoint: "nontrapping-fptoint",
+        nontrapping_dash_fptoint: "nontrapping-fptoint",
         noreturn,
-        no_niche,
-        no_sanitize,
         nostack,
-        no_stack_check,
-        no_start,
-        no_std,
         not,
         note,
         object_safe_for_dispatch,
         offset,
-        Ok,
         omit_gdb_pretty_printer_section,
         on,
         on_unimplemented,
         oom,
+        opaque,
         ops,
+        opt_out_copy,
         optimize,
         optimize_attribute,
         optin_builtin_traits,
         option,
-        Option,
         option_env,
+        option_type,
         options,
-        opt_out_copy,
         or,
         or_patterns,
-        Ord,
-        Ordering,
+        other,
         out,
-        Output,
         overlapping_marker_traits,
+        owned_box,
         packed,
         panic,
+        panic_abort,
+        panic_bounds_check,
         panic_handler,
         panic_impl,
         panic_implementation,
+        panic_info,
+        panic_location,
         panic_runtime,
+        panic_unwind,
+        param_attrs,
         parent_trait,
         partial_cmp,
-        param_attrs,
-        PartialEq,
-        PartialOrd,
+        partial_ord,
         passes,
         pat,
         path,
         pattern_parentheses,
-        Pending,
+        phantom_data,
         pin,
-        Pin,
         pinned,
         platform_intrinsics,
         plugin,
         plugin_registrar,
         plugins,
+        pointer,
         poll,
-        Poll,
+        position,
+        post_dash_lto: "post-lto",
         powerpc_target_feature,
         powf32,
         powf64,
         powif32,
         powif64,
+        pre_dash_lto: "pre-lto",
         precise_pointer_size_matching,
+        precision,
         pref_align_of,
         prefetch_read_data,
         prefetch_read_instruction,
         proc_macro_mod,
         proc_macro_non_items,
         proc_macro_path_invoc,
-        ProceduralMasqueradeDummyType,
-        ProcMacroHack,
         profiler_builtins,
         profiler_runtime,
         ptr_guaranteed_eq,
         quad_precision_float,
         question_mark,
         quote,
-        Range,
-        RangeFrom,
-        RangeFull,
-        RangeInclusive,
-        RangeTo,
-        RangeToInclusive,
         raw_dylib,
         raw_identifiers,
         raw_ref_op,
-        Rc,
+        re_rebalance_coherence,
+        read_enum,
+        read_enum_variant,
+        read_enum_variant_arg,
+        read_struct,
+        read_struct_field,
         readonly,
-        Ready,
+        realloc,
         reason,
+        receiver,
         recursion_limit,
         reexport_test_harness_main,
+        reference,
         reflect,
         register_attr,
         register_tool,
         relaxed_adts,
+        rem,
+        rem_assign,
         repr,
         repr128,
         repr_align,
         repr_packed,
         repr_simd,
         repr_transparent,
-        re_rebalance_coherence,
         result,
-        Result,
-        Return,
+        result_type,
         rhs,
         rintf32,
         rintf64,
         rust_2015_preview,
         rust_2018_preview,
         rust_begin_unwind,
+        rust_eh_personality,
+        rust_eh_register_frames,
+        rust_eh_unregister_frames,
+        rust_oom,
         rustc,
-        RustcDecodable,
-        RustcEncodable,
         rustc_allocator,
         rustc_allocator_nounwind,
         rustc_allow_const_fn_ptr,
         rustc_attrs,
         rustc_builtin_macro,
         rustc_clean,
-        rustc_const_unstable,
         rustc_const_stable,
+        rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_def_path,
         rustc_deprecated,
         rustc_partition_reused,
         rustc_peek,
         rustc_peek_definite_init,
+        rustc_peek_indirectly_mutable,
         rustc_peek_liveness,
         rustc_peek_maybe_init,
         rustc_peek_maybe_uninit,
-        rustc_peek_indirectly_mutable,
         rustc_private,
         rustc_proc_macro_decls,
         rustc_promotable,
         rustc_regions,
-        rustc_unsafe_specialization_marker,
+        rustc_reservation_impl,
+        rustc_serialize,
         rustc_specialization_trait,
         rustc_stable,
         rustc_std_internal_symbol,
         rustc_symbol_name,
         rustc_synthetic,
-        rustc_reservation_impl,
         rustc_test_marker,
         rustc_then_this_would_need,
+        rustc_unsafe_specialization_marker,
         rustc_variance,
         rustfmt,
-        rust_eh_personality,
-        rust_oom,
         rvalue_static_promotion,
         sanitize,
         sanitizer_runtime,
         saturating_add,
         saturating_sub,
-        _Self,
         self_in_typedefs,
         self_struct_ctor,
+        semitransparent,
         send_trait,
+        shl,
+        shl_assign,
         should_panic,
+        shr,
+        shr_assign,
         simd,
+        simd_add,
+        simd_and,
+        simd_bitmask,
+        simd_cast,
+        simd_ceil,
+        simd_div,
+        simd_eq,
         simd_extract,
+        simd_fabs,
+        simd_fcos,
+        simd_fexp,
+        simd_fexp2,
         simd_ffi,
+        simd_flog,
+        simd_flog10,
+        simd_flog2,
+        simd_floor,
+        simd_fma,
+        simd_fmax,
+        simd_fmin,
+        simd_fpow,
+        simd_fpowi,
+        simd_fsin,
+        simd_fsqrt,
+        simd_gather,
+        simd_ge,
+        simd_gt,
         simd_insert,
+        simd_le,
+        simd_lt,
+        simd_mul,
+        simd_ne,
+        simd_or,
+        simd_reduce_add_ordered,
+        simd_reduce_add_unordered,
+        simd_reduce_all,
+        simd_reduce_and,
+        simd_reduce_any,
+        simd_reduce_max,
+        simd_reduce_max_nanless,
+        simd_reduce_min,
+        simd_reduce_min_nanless,
+        simd_reduce_mul_ordered,
+        simd_reduce_mul_unordered,
+        simd_reduce_or,
+        simd_reduce_xor,
+        simd_rem,
+        simd_saturating_add,
+        simd_saturating_sub,
+        simd_scatter,
+        simd_select,
+        simd_select_bitmask,
+        simd_shl,
+        simd_shr,
+        simd_sub,
+        simd_xor,
         since,
         sinf32,
         sinf64,
         size,
         size_of,
         size_of_val,
+        sized,
+        slice,
+        slice_alloc,
         slice_patterns,
+        slice_u8,
+        slice_u8_alloc,
         slicing_syntax,
         soft,
-        Some,
         specialization,
         speed,
+        spotlight,
         sqrtf32,
         sqrtf64,
         sse4a_target_feature,
         stable,
         staged_api,
         start,
+        state,
         static_in_const,
-        staticlib,
         static_nobundle,
         static_recursion,
+        staticlib,
         std,
         std_inject,
-        str,
-        stringify,
         stmt,
         stmt_expr_attributes,
         stop_after_dataflow,
+        str,
+        str_alloc,
+        stringify,
         struct_field_attributes,
         struct_inherit,
-        structural_match,
         struct_variant,
+        structural_match,
+        structural_peq,
+        structural_teq,
         sty,
+        sub,
+        sub_assign,
         sub_with_overflow,
         suggestion,
         sym,
+        sync,
         sync_trait,
+        target_arch,
+        target_endian,
+        target_env,
+        target_family,
         target_feature,
         target_feature_11,
         target_has_atomic,
         target_has_atomic_load_store,
+        target_os,
+        target_pointer_width,
+        target_target_vendor,
         target_thread_local,
+        target_vendor,
         task,
-        _task_context,
         tbm_target_feature,
+        termination,
         termination_trait,
         termination_trait_test,
         test,
         trivial_bounds,
         truncf32,
         truncf64,
-        Try,
         try_blocks,
         try_trait,
         tt,
+        tuple,
         tuple_indexing,
         two_phase,
-        Ty,
         ty,
-        type_alias_impl_trait,
-        type_id,
-        type_name,
-        TyCtxt,
-        TyKind,
         type_alias_enum_variants,
+        type_alias_impl_trait,
         type_ascription,
+        type_id,
         type_length_limit,
         type_macros,
+        type_name,
         u128,
         u16,
         u32,
         underscore_imports,
         underscore_lifetimes,
         uniform_paths,
+        unit,
         universal_impl_trait,
+        unix,
         unlikely,
         unmarked_api,
+        unpin,
         unreachable,
         unreachable_code,
         unrestricted_attribute_tokens,
         unsafe_block_in_unsafe_fn,
+        unsafe_cell,
         unsafe_no_drop_flag,
+        unsize,
         unsized_locals,
         unsized_tuple_coercion,
         unstable,
         untagged_unions,
+        unused_qualifications,
         unwind,
         unwind_attributes,
         unwrap_or,
-        used,
         use_extern_macros,
         use_nested_groups,
+        used,
         usize,
         v1,
-        val,
-        var,
-        variant_count,
         va_arg,
         va_copy,
         va_end,
+        va_list,
         va_start,
+        val,
+        var,
+        variant_count,
         vec,
-        Vec,
+        vec_type,
         version,
         vis,
         visible_private_types,
         wasm_import_module,
         wasm_target_feature,
         while_let,
+        width,
         windows,
         windows_subsystem,
         wrapping_add,
-        wrapping_sub,
         wrapping_mul,
+        wrapping_sub,
         write_bytes,
-        Yield,
     }
 }
 
@@ -1419,7 +1665,7 @@ impl !Sync for SymbolStr {}
 
 /// This impl means that if `ss` is a `SymbolStr`:
 /// - `*ss` is a `str`;
-/// - `&*ss` is a `&str`;
+/// - `&*ss` is a `&str` (and `match &*ss { ... }` is a common pattern).
 /// - `&ss as &str` is a `&str`, which means that `&ss` can be passed to a
 ///   function expecting a `&str`.
 impl std::ops::Deref for SymbolStr {
index 012321026938e8643ccadd213890e59ee0b4e2dc..2579cf53d3d509bb71e062ef7115c9e154fe90d0 100644 (file)
 use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::config::SymbolManglingVersion;
 
-use rustc_span::symbol::Symbol;
-
 use log::debug;
 
 mod legacy;
@@ -133,7 +131,7 @@ pub fn provide(providers: &mut Providers) {
 // The `symbol_name` query provides the symbol name for calling a given
 // instance from the local crate. In particular, it will also look up the
 // correct symbol name of instances from upstream crates.
-fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
+fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName<'tcx> {
     let symbol_name = compute_symbol_name(tcx, instance, || {
         // This closure determines the instantiating crate for instances that
         // need an instantiating-crate-suffix for their symbol name, in order
@@ -149,7 +147,7 @@ fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::Symb
         }
     });
 
-    ty::SymbolName { name: Symbol::intern(&symbol_name) }
+    ty::SymbolName::new(tcx, &symbol_name)
 }
 
 /// Computes the symbol name for the given instance. This function will call
index 5175b692e17b69156872693f9257d2ec4c597a95..2f1c896ce2f1671f9d7442806f1bd0749f289993 100644 (file)
@@ -39,7 +39,7 @@ fn process_attrs(&mut self, hir_id: hir::HirId) {
                 let instance = Instance::mono(tcx, def_id.to_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.name.as_str()) {
+                if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
                     tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
                     tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
                 }
index ec6deb5b0595254f069d9c11441aaf35ad5714ee..1d0dc660ee616ec37d5178ebad623d64958c1a7c 100644 (file)
@@ -9,7 +9,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(bool_to_option)]
-#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(nll)]
index 201d6a0fff93b071c4333cff83ccbed2e5960b3b..6d929d1244789004f1512b4b3a89373be7fb7679 100644 (file)
@@ -17,7 +17,6 @@ pub fn opts() -> TargetOptions {
         needs_plt: true,
         relro_level: RelroLevel::Full,
         relocation_model: RelocModel::Static,
-        target_family: Some("unix".to_string()),
         pre_link_args,
 
         ..Default::default()
index 4a2dd8913185f421940fb139689bba38a9058b65..231ab1ea68ded7d538114a32e755a868f4183b18 100644 (file)
@@ -938,9 +938,6 @@ pub struct TargetOptions {
     /// for this target unconditionally.
     pub no_builtins: bool,
 
-    /// The codegen backend to use for this target, typically "llvm"
-    pub codegen_backend: String,
-
     /// The default visibility for symbols in this target should be "hidden"
     /// rather than "default"
     pub default_hidden_visibility: bool,
@@ -1068,7 +1065,6 @@ fn default() -> TargetOptions {
             requires_lto: false,
             singlethread: false,
             no_builtins: false,
-            codegen_backend: "llvm".to_string(),
             default_hidden_visibility: false,
             emit_debug_gdb_scripts: true,
             requires_uwtable: false,
@@ -1461,7 +1457,6 @@ macro_rules! key {
         key!(requires_lto, bool);
         key!(singlethread, bool);
         key!(no_builtins, bool);
-        key!(codegen_backend);
         key!(default_hidden_visibility, bool);
         key!(emit_debug_gdb_scripts, bool);
         key!(requires_uwtable, bool);
@@ -1699,7 +1694,6 @@ macro_rules! target_option_val {
         target_option_val!(requires_lto);
         target_option_val!(singlethread);
         target_option_val!(no_builtins);
-        target_option_val!(codegen_backend);
         target_option_val!(default_hidden_visibility);
         target_option_val!(emit_debug_gdb_scripts);
         target_option_val!(requires_uwtable);
index d542e16d83f10e58a32d39ce5b194624dfb36645..cc971440feac52a20fb3b4eea7cf4b96f07f5624 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc_middle::ty::{ToPredicate, TypeFoldable};
 use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
 #[derive(Copy, Clone, Debug)]
@@ -143,7 +143,11 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let normalized_ty = fulfillcx.normalize_projection_type(
             &self.infcx,
             self.param_env,
-            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
+            ty::ProjectionTy::from_ref_and_name(
+                tcx,
+                trait_ref,
+                Ident::with_dummy_span(sym::Target),
+            ),
             cause,
         );
         if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
index ad6e81ed3e8893610295f83885fcb680308f4312..112de6846608446dca9fccf999e6b41a3bdcaefd 100644 (file)
@@ -26,6 +26,7 @@
     TypeFoldable, WithConstness,
 };
 use rustc_session::DiagnosticMessageId;
+use rustc_span::symbol::{kw, sym};
 use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
@@ -283,8 +284,8 @@ fn report_selection_error(
                             .span_to_snippet(span)
                             .map(|s| &s == "?")
                             .unwrap_or(false);
-                        let is_from = format!("{}", trait_ref.print_only_trait_path())
-                            .starts_with("std::convert::From<");
+                        let is_from = self.tcx.get_diagnostic_item(sym::from_trait)
+                            == Some(trait_ref.def_id());
                         let is_unsize =
                             { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
                         let (message, note) = if is_try && is_from {
@@ -315,12 +316,15 @@ fn report_selection_error(
                             ))
                         );
 
-                        let should_convert_option_to_result =
-                            format!("{}", trait_ref.print_only_trait_path())
-                                .starts_with("std::convert::From<std::option::NoneError");
-                        let should_convert_result_to_option = format!("{}", trait_ref)
-                            .starts_with("<std::option::NoneError as std::convert::From<");
                         if is_try && is_from {
+                            let none_error = self
+                                .tcx
+                                .get_diagnostic_item(sym::none_error)
+                                .map(|def_id| tcx.type_of(def_id));
+                            let should_convert_option_to_result =
+                                Some(trait_ref.skip_binder().substs.type_at(1)) == none_error;
+                            let should_convert_result_to_option =
+                                Some(trait_ref.self_ty().skip_binder()) == none_error;
                             if should_convert_option_to_result {
                                 err.span_suggestion_verbose(
                                     span.shrink_to_lo(),
@@ -376,7 +380,12 @@ fn report_selection_error(
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
                             err.span_label(span, s.as_str());
-                            err.help(&explanation);
+                            if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) {
+                                // When the self type is a type param We don't need to "the trait
+                                // `std::marker::Sized` is not implemented for `T`" as we will point
+                                // at the type param with a label to suggest constraining it.
+                                err.help(&explanation);
+                            }
                         } else {
                             err.span_label(span, explanation);
                         }
@@ -403,7 +412,6 @@ fn report_selection_error(
                         }
 
                         self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg);
-                        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);
@@ -585,9 +593,9 @@ fn report_selection_error(
 
                         // Additional context information explaining why the closure only implements
                         // a particular trait.
-                        if let Some(tables) = self.in_progress_tables {
-                            let tables = tables.borrow();
-                            match (found_kind, tables.closure_kind_origins().get(hir_id)) {
+                        if let Some(typeck_results) = self.in_progress_typeck_results {
+                            let typeck_results = typeck_results.borrow();
+                            match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
                                 (ty::ClosureKind::FnOnce, Some((span, name))) => {
                                     err.span_label(
                                         *span,
@@ -1516,7 +1524,7 @@ fn maybe_report_ambiguity(
                     (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code)
                 {
                     let generics = self.tcx.generics_of(*def_id);
-                    if generics.params.iter().any(|p| p.name.as_str() != "Self")
+                    if generics.params.iter().any(|p| p.name != kw::SelfUpper)
                         && !snippet.ends_with('>')
                     {
                         // FIXME: To avoid spurious suggestions in functions where type arguments
index ec51dddc2c8102265469b2fb08cc6b842eafbbf3..d2b9f84af33ae3e100e2818cbffa13c3414ed1a8 100644 (file)
@@ -126,7 +126,7 @@ fn on_unimplemented_note(
 
         let mut flags = vec![];
         flags.push((
-            sym::item_context,
+            sym::ItemContext,
             self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
         ));
 
index d677d84b2ba1305910f3f4ed303720eb5b00e2ef..0a6fb72ca51eae890af70698ac34d8b50d788cf9 100644 (file)
@@ -18,7 +18,7 @@
     self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
     TyCtxt, TypeFoldable, WithConstness,
 };
-use rustc_middle::ty::{TypeAndMut, TypeckTables};
+use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
@@ -43,12 +43,6 @@ fn suggest_restricting_param_bound(
         body_id: hir::HirId,
     );
 
-    fn suggest_borrow_on_unsized_slice(
-        &self,
-        code: &ObligationCauseCode<'tcx>,
-        err: &mut DiagnosticBuilder<'_>,
-    );
-
     fn suggest_dereferences(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -151,7 +145,7 @@ fn note_obligation_cause_for_async_await(
         outer_generator: Option<DefId>,
         trait_ref: ty::TraitRef<'tcx>,
         target_ty: Ty<'tcx>,
-        tables: &ty::TypeckTables<'tcx>,
+        typeck_results: &ty::TypeckResults<'tcx>,
         obligation: &PredicateObligation<'tcx>,
         next_code: Option<&ObligationCauseCode<'tcx>>,
     );
@@ -515,32 +509,6 @@ fn suggest_dereferences(
         }
     }
 
-    /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
-    /// suggestion to borrow the initializer in order to use have a slice instead.
-    fn suggest_borrow_on_unsized_slice(
-        &self,
-        code: &ObligationCauseCode<'tcx>,
-        err: &mut DiagnosticBuilder<'_>,
-    ) {
-        if let &ObligationCauseCode::VariableType(hir_id) = code {
-            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.kind {
-                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
-                            err.span_suggestion(
-                                expr.span,
-                                "consider borrowing here",
-                                format!("&{}", snippet),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     /// Given a closure's `DefId`, return the given name of the closure.
     ///
     /// This doesn't account for reassignments, but it's only used for suggestions.
@@ -1000,12 +968,12 @@ fn suggest_impl_trait(
         let mut visitor = ReturnsVisitor::default();
         visitor.visit_body(&body);
 
-        let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
+        let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
 
         let mut ret_types = visitor
             .returns
             .iter()
-            .filter_map(|expr| tables.node_type_opt(expr.hir_id))
+            .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
             .map(|ty| self.resolve_vars_if_possible(&ty));
         let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
             (None, true, true),
@@ -1032,7 +1000,7 @@ fn suggest_impl_trait(
             },
         );
         let all_returns_conform_to_trait =
-            if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) {
+            if let Some(ty_ret_ty) = typeck_results.node_type_opt(ret_ty.hir_id) {
                 match ty_ret_ty.kind {
                     ty::Dynamic(predicates, _) => {
                         let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id);
@@ -1160,9 +1128,9 @@ fn point_at_returns_when_relevant(
             // Point at all the `return`s in the function as they have failed trait bounds.
             let mut visitor = ReturnsVisitor::default();
             visitor.visit_body(&body);
-            let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap();
+            let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
             for expr in &visitor.returns {
-                if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) {
+                if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
                     let ty = self.resolve_vars_if_possible(&returned_ty);
                     err.span_label(expr.span, &format!("this returned value is of type `{}`", ty));
                 }
@@ -1392,25 +1360,25 @@ fn maybe_note_obligation_cause_for_async_await(
             return false;
         }
 
-        // Get the tables from the infcx if the generator is the function we are
+        // Get the typeck results from the infcx if the generator is the function we are
         // currently type-checking; otherwise, get them by performing a query.
         // This is needed to avoid cycles.
-        let in_progress_tables = self.in_progress_tables.map(|t| t.borrow());
+        let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
         let generator_did_root = self.tcx.closure_base_def_id(generator_did);
         debug!(
             "maybe_note_obligation_cause_for_async_await: generator_did={:?} \
-             generator_did_root={:?} in_progress_tables.hir_owner={:?} span={:?}",
+             generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
             generator_did,
             generator_did_root,
-            in_progress_tables.as_ref().map(|t| t.hir_owner),
+            in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
             span
         );
-        let query_tables;
-        let tables: &TypeckTables<'tcx> = match &in_progress_tables {
+        let query_typeck_results;
+        let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
             Some(t) if t.hir_owner.to_def_id() == generator_did_root => t,
             _ => {
-                query_tables = self.tcx.typeck_tables_of(generator_did.expect_local());
-                &query_tables
+                query_typeck_results = self.tcx.typeck(generator_did.expect_local());
+                &query_typeck_results
             }
         };
 
@@ -1457,7 +1425,7 @@ fn maybe_note_obligation_cause_for_async_await(
 
         if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
             interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
-                let upvar_ty = tables.node_type(*upvar_id);
+                let upvar_ty = typeck_results.node_type(*upvar_id);
                 let upvar_ty = self.resolve_vars_if_possible(&upvar_ty);
                 if ty_matches(&upvar_ty) {
                     Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
@@ -1467,7 +1435,7 @@ fn maybe_note_obligation_cause_for_async_await(
             });
         };
 
-        tables
+        typeck_results
             .generator_interior_types
             .iter()
             .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty))
@@ -1478,7 +1446,7 @@ fn maybe_note_obligation_cause_for_async_await(
                     .into_iter()
                     .map(|id| hir.expect_expr(id))
                     .find(|await_expr| {
-                        let ty = tables.expr_ty_adjusted(&await_expr);
+                        let ty = typeck_results.expr_ty_adjusted(&await_expr);
                         debug!(
                             "maybe_note_obligation_cause_for_async_await: await_expr={:?}",
                             await_expr
@@ -1496,7 +1464,7 @@ fn maybe_note_obligation_cause_for_async_await(
         debug!(
             "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
                 generator_interior_types={:?}",
-            interior_or_upvar_span, tables.generator_interior_types
+            interior_or_upvar_span, typeck_results.generator_interior_types
         );
         if let Some(interior_or_upvar_span) = interior_or_upvar_span {
             self.note_obligation_cause_for_async_await(
@@ -1507,7 +1475,7 @@ fn maybe_note_obligation_cause_for_async_await(
                 outer_generator,
                 trait_ref,
                 target_ty,
-                tables,
+                typeck_results,
                 obligation,
                 next_code,
             );
@@ -1528,7 +1496,7 @@ fn note_obligation_cause_for_async_await(
         outer_generator: Option<DefId>,
         trait_ref: ty::TraitRef<'tcx>,
         target_ty: Ty<'tcx>,
-        tables: &ty::TypeckTables<'tcx>,
+        typeck_results: &ty::TypeckResults<'tcx>,
         obligation: &PredicateObligation<'tcx>,
         next_code: Option<&ObligationCauseCode<'tcx>>,
     ) {
@@ -1645,7 +1613,7 @@ fn note_obligation_cause_for_async_await(
                         // Look at the last interior type to get a span for the `.await`.
                         debug!(
                             "note_obligation_cause_for_async_await generator_interior_types: {:#?}",
-                            tables.generator_interior_types
+                            typeck_results.generator_interior_types
                         );
                         explain_yield(interior_span, yield_span, scope_span);
                     }
@@ -1666,7 +1634,7 @@ fn note_obligation_cause_for_async_await(
                             // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
                             // ```
                             //
-                            let is_region_borrow = tables
+                            let is_region_borrow = typeck_results
                                 .expr_adjustments(expr)
                                 .iter()
                                 .any(|adj| adj.is_region_borrow());
@@ -1683,7 +1651,7 @@ fn note_obligation_cause_for_async_await(
                                     _ => false,
                                 };
 
-                            if (tables.is_method_call(e) && is_region_borrow)
+                            if (typeck_results.is_method_call(e) && is_region_borrow)
                                 || is_raw_borrow_inside_fn_like_call
                             {
                                 err.span_help(
@@ -1817,15 +1785,56 @@ fn note_obligation_cause_code<T>(
                     }
                 }
             }
-            ObligationCauseCode::VariableType(_) => {
-                err.note("all local variables must have a statically known size");
+            ObligationCauseCode::VariableType(hir_id) => {
+                let parent_node = self.tcx.hir().get_parent_node(hir_id);
+                match self.tcx.hir().find(parent_node) {
+                    Some(Node::Local(hir::Local {
+                        init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }),
+                        ..
+                    })) => {
+                        // When encountering an assignment of an unsized trait, like
+                        // `let x = ""[..];`, provide a suggestion to borrow the initializer in
+                        // order to use have a slice instead.
+                        err.span_suggestion_verbose(
+                            span.shrink_to_lo(),
+                            "consider borrowing here",
+                            "&".to_owned(),
+                            Applicability::MachineApplicable,
+                        );
+                        err.note("all local variables must have a statically known size");
+                    }
+                    Some(Node::Param(param)) => {
+                        err.span_suggestion_verbose(
+                            param.ty_span.shrink_to_lo(),
+                            "function arguments must have a statically known size, borrowed types \
+                            always have a known size",
+                            "&".to_owned(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    _ => {
+                        err.note("all local variables must have a statically known size");
+                    }
+                }
                 if !self.tcx.features().unsized_locals {
                     err.help("unsized locals are gated as an unstable feature");
                 }
             }
-            ObligationCauseCode::SizedArgumentType => {
-                err.note("all function arguments must have a statically known size");
-                if !self.tcx.features().unsized_locals {
+            ObligationCauseCode::SizedArgumentType(sp) => {
+                if let Some(span) = sp {
+                    err.span_suggestion_verbose(
+                        span.shrink_to_lo(),
+                        "function arguments must have a statically known size, borrowed types \
+                         always have a known size",
+                        "&".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.note("all function arguments must have a statically known size");
+                }
+                if tcx.sess.opts.unstable_features.is_nightly_build()
+                    && !self.tcx.features().unsized_locals
+                {
                     err.help("unsized locals are gated as an unstable feature");
                 }
             }
@@ -1844,26 +1853,44 @@ fn note_obligation_cause_code<T>(
             ObligationCauseCode::StructInitializerSized => {
                 err.note("structs must have a statically known size to be initialized");
             }
-            ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item {
-                AdtKind::Struct => {
-                    if last {
-                        err.note(
-                            "the last field of a packed struct may only have a \
-                             dynamically sized type if it does not need drop to be run",
-                        );
-                    } else {
-                        err.note(
-                            "only the last field of a struct may have a dynamically sized type",
-                        );
+            ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => {
+                match *item {
+                    AdtKind::Struct => {
+                        if last {
+                            err.note(
+                                "the last field of a packed struct may only have a \
+                                dynamically sized type if it does not need drop to be run",
+                            );
+                        } else {
+                            err.note(
+                                "only the last field of a struct may have a dynamically sized type",
+                            );
+                        }
+                    }
+                    AdtKind::Union => {
+                        err.note("no field of a union may have a dynamically sized type");
+                    }
+                    AdtKind::Enum => {
+                        err.note("no field of an enum variant may have a dynamically sized type");
                     }
                 }
-                AdtKind::Union => {
-                    err.note("no field of a union may have a dynamically sized type");
-                }
-                AdtKind::Enum => {
-                    err.note("no field of an enum variant may have a dynamically sized type");
-                }
-            },
+                err.help("change the field's type to have a statically known size");
+                err.span_suggestion(
+                    span.shrink_to_lo(),
+                    "borrowed types always have a statically known size",
+                    "&".to_string(),
+                    Applicability::MachineApplicable,
+                );
+                err.multipart_suggestion(
+                    "the `Box` type always has a statically known size and allocates its contents \
+                     in the heap",
+                    vec![
+                        (span.shrink_to_lo(), "Box<".to_string()),
+                        (span.shrink_to_hi(), ">".to_string()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            }
             ObligationCauseCode::ConstSized => {
                 err.note("constant expressions must have a statically known size");
             }
index 800aef7284f9e3220fc7b69164f59acea2ed82ec..c6c76028f857c80fe9089d4b884e6723017c99c2 100644 (file)
@@ -524,10 +524,10 @@ fn process_obligation(
                 let stalled_on = &mut pending_obligation.stalled_on;
 
                 let mut evaluate = |c: &'tcx Const<'tcx>| {
-                    if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
+                    if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
                         match self.selcx.infcx().const_eval_resolve(
                             obligation.param_env,
-                            def_id,
+                            def,
                             substs,
                             promoted,
                             Some(obligation.cause.span),
index a1dfa838e7af3965702d69268238d6099258e353..deb33708681fa3ba8e9b1781f7d4100477fd54cf 100644 (file)
@@ -286,7 +286,7 @@ fn verify(
                     // `{from_desugaring}` is allowed
                     Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
                     // `{ItemContext}` is allowed
-                    Position::ArgumentNamed(s) if s == sym::item_context => (),
+                    Position::ArgumentNamed(s) if s == sym::ItemContext => (),
                     // So is `{A}` if A is a type parameter
                     Position::ArgumentNamed(s) => {
                         match generics.params.iter().find(|param| param.name == s) {
@@ -350,7 +350,7 @@ pub fn format(
 
         let s = self.0.as_str();
         let parser = Parser::new(&s, None, None, false, ParseMode::Format);
-        let item_context = (options.get(&sym::item_context)).unwrap_or(&empty_string);
+        let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
         parser
             .map(|p| match p {
                 Piece::String(s) => s,
@@ -364,7 +364,7 @@ pub fn format(
                             } else if s == sym::from_desugaring || s == sym::from_method {
                                 // don't break messages using these two arguments incorrectly
                                 &empty_string
-                            } else if s == sym::item_context {
+                            } else if s == sym::ItemContext {
                                 &item_context
                             } else {
                                 bug!(
index bd86109e5a4910f39883d29a491e11b36bdde737..c08198ec373b8114c22702872fe81a1e70a2504d 100644 (file)
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::{FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem};
+use rustc_hir::lang_items::{
+    DiscriminantTypeLangItem, FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem,
+};
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
@@ -1324,22 +1325,11 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
     let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
     let substs = tcx.mk_substs([self_ty.into()].iter());
 
-    let assoc_items = tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap());
-    // FIXME: emit an error if the trait definition is wrong
-    let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id;
-
-    let discriminant_ty = match self_ty.kind {
-        // Use the discriminant type for enums.
-        ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
-        // Default to `i32` for generators.
-        ty::Generator(..) => tcx.types.i32,
-        // Use `u8` for all other types.
-        _ => tcx.types.u8,
-    };
+    let discriminant_def_id = tcx.require_lang_item(DiscriminantTypeLangItem, None);
 
     let predicate = ty::ProjectionPredicate {
         projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
-        ty: discriminant_ty,
+        ty: self_ty.discriminant_ty(tcx),
     };
 
     confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
index ba5e60012da19616b0d4a9dfe9f5cd104a09f3c9..5dc5fb797ff6c1707de6344a34f2d5570dbc3afd 100644 (file)
@@ -507,11 +507,11 @@ fn evaluate_predicate_recursively<'o>(
                 debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
 
                 let evaluate = |c: &'tcx ty::Const<'tcx>| {
-                    if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
+                    if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
                         self.infcx
                             .const_eval_resolve(
                                 obligation.param_env,
-                                def_id,
+                                def,
                                 substs,
                                 promoted,
                                 Some(obligation.cause.span),
index ebff2dd9b23c1e3e46780d2933bce28348e97524..b8446fa0012abc9a05ec9c2c87c7c0008e906e61 100644 (file)
@@ -116,8 +116,8 @@ pub fn predicate_obligations<'a, 'tcx>(
             wf.compute(data.skip_binder().a.into()); // (*)
             wf.compute(data.skip_binder().b.into()); // (*)
         }
-        &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
-            let obligations = wf.nominal_obligations(def_id, substs);
+        &ty::PredicateKind::ConstEvaluatable(def, substs) => {
+            let obligations = wf.nominal_obligations(def.did, substs);
             wf.out.extend(obligations);
 
             for arg in substs.iter() {
@@ -359,13 +359,13 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
 
                 GenericArgKind::Const(constant) => {
                     match constant.val {
-                        ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
+                        ty::ConstKind::Unevaluated(def, substs, promoted) => {
                             assert!(promoted.is_none());
 
-                            let obligations = self.nominal_obligations(def_id, substs);
+                            let obligations = self.nominal_obligations(def.did, substs);
                             self.out.extend(obligations);
 
-                            let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs)
+                            let predicate = ty::PredicateKind::ConstEvaluatable(def, substs)
                                 .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::new(
index 9f5ab7f8e4a0233ae6acaafb9520a0a316a7c714..0bc6c4709786833e4b0ac3eeead6554635e9a579 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_errors::ErrorReported;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
@@ -14,15 +14,43 @@ fn resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
 ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
-    let (param_env, (def_id, substs)) = key.into_parts();
+    let (param_env, (did, substs)) = key.into_parts();
+    if let Some(did) = did.as_local() {
+        if let Some(param_did) = tcx.opt_const_param_of(did) {
+            return tcx.resolve_instance_of_const_arg(param_env.and((did, param_did, substs)));
+        }
+    }
+
+    inner_resolve_instance(tcx, param_env.and((ty::WithOptConstParam::unknown(did), substs)))
+}
+
+fn resolve_instance_of_const_arg<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>,
+) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+    let (param_env, (did, const_param_did, substs)) = key.into_parts();
+    inner_resolve_instance(
+        tcx,
+        param_env.and((
+            ty::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) },
+            substs,
+        )),
+    )
+}
+
+fn inner_resolve_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>,
+) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+    let (param_env, (def, substs)) = key.into_parts();
 
-    debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
-    let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
+    debug!("resolve(def={:?}, substs={:?})", def.did, substs);
+    let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
         debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
-        let item = tcx.associated_item(def_id);
+        let item = tcx.associated_item(def.did);
         resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
     } else {
-        let ty = tcx.type_of(def_id);
+        let ty = tcx.type_of(def.def_id_for_type_of());
         let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty);
 
         let def = match item_type.kind {
@@ -33,7 +61,7 @@ fn resolve_instance<'tcx>(
                 } =>
             {
                 debug!(" => intrinsic");
-                ty::InstanceDef::Intrinsic(def_id)
+                ty::InstanceDef::Intrinsic(def.did)
             }
             ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => {
                 let ty = substs.type_at(0);
@@ -53,12 +81,12 @@ fn resolve_instance<'tcx>(
             }
             _ => {
                 debug!(" => free item");
-                ty::InstanceDef::Item(def_id)
+                ty::InstanceDef::Item(def)
             }
         };
         Ok(Some(Instance { def, substs }))
     };
-    debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
+    debug!("resolve(def.did={:?}, substs={:?}) = {:?}", def.did, substs, result);
     result
 }
 
@@ -182,7 +210,9 @@ fn resolve_associated_item<'tcx>(
             Some(ty::Instance::new(leaf_def.item.def_id, substs))
         }
         traits::ImplSourceGenerator(generator_data) => Some(Instance {
-            def: ty::InstanceDef::Item(generator_data.generator_def_id),
+            def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
+                generator_data.generator_def_id,
+            )),
             substs: generator_data.substs,
         }),
         traits::ImplSourceClosure(closure_data) => {
@@ -244,5 +274,6 @@ fn resolve_associated_item<'tcx>(
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { resolve_instance, ..*providers };
+    *providers =
+        ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers };
 }
index 9329069c48dd1faaea58d771af81926ff15fe56a..93b503c976be4c8706ecee600cf78d08cfefe1f1 100644 (file)
@@ -18,6 +18,7 @@ rustc_attr = { path = "../librustc_attr" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_hir_pretty = { path = "../librustc_hir_pretty" }
 rustc_target = { path = "../librustc_target" }
 rustc_session = { path = "../librustc_session" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
index 5d1949626dd84e82a24bb0dc482b19993bacf35e..37f48f82ea6746176b0745a8f2691720caa34331 100644 (file)
@@ -886,8 +886,14 @@ fn create_substs_for_ast_path<'a>(
                     }
                 }
                 (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    let ct_def_id = tcx.hir().local_def_id(ct.value.hir_id);
-                    ty::Const::from_anon_const(tcx, ct_def_id).into()
+                    ty::Const::from_opt_const_arg_anon_const(
+                        tcx,
+                        ty::WithOptConstParam {
+                            did: tcx.hir().local_def_id(ct.value.hir_id),
+                            const_param_did: Some(param.def_id),
+                        },
+                    )
+                    .into()
                 }
                 _ => unreachable!(),
             },
@@ -1247,7 +1253,7 @@ fn complain_about_internal_fn_trait(
                             .generic_args()
                             .bindings
                             .iter()
-                            .find_map(|b| match (b.ident.as_str() == "Output", &b.kind) {
+                            .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
                                 (true, hir::TypeBindingKind::Equality { ty }) => {
                                     sess.source_map().span_to_snippet(ty.span).ok()
                                 }
@@ -2254,7 +2260,7 @@ fn complain_about_assoc_type_not_found<I>(
             .collect();
 
         if let (Some(suggested_name), true) = (
-            find_best_match_for_name(all_candidate_names.iter(), &assoc_name.as_str(), None),
+            find_best_match_for_name(all_candidate_names.iter(), assoc_name.name, None),
             assoc_name.span != DUMMY_SP,
         ) {
             err.span_suggestion(
@@ -2354,7 +2360,7 @@ pub fn associated_path_to_ty(
                     let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
                     if let Some(suggested_name) = find_best_match_for_name(
                         adt_def.variants.iter().map(|variant| &variant.ident.name),
-                        &assoc_ident.as_str(),
+                        assoc_ident.name,
                         None,
                     ) {
                         err.span_suggestion(
@@ -3049,14 +3055,14 @@ pub fn ty_of_fn(
         let bare_fn_ty =
             ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi));
 
-        if let (false, Some(ident_span)) = (self.allow_ty_infer(), ident_span) {
+        if !self.allow_ty_infer() {
             // We always collect the spans for placeholder types when evaluating `fn`s, but we
             // only want to emit an error complaining about them if infer types (`_`) are not
             // allowed. `allow_ty_infer` gates this behavior. We check for the presence of
             // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
             crate::collect::placeholder_type_error(
                 tcx,
-                ident_span.shrink_to_hi(),
+                ident_span.map(|sp| sp.shrink_to_hi()),
                 &generics.params[..],
                 visitor.0,
                 true,
index 308ed5d8402021864d830170422fc7f86a151430..4ba64035ca44ab78fea3260cb5022587403c98ed 100644 (file)
@@ -13,7 +13,7 @@
 };
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
 use rustc_trait_selection::autoderef::Autoderef;
@@ -192,9 +192,9 @@ fn try_overloaded_call_traits(
     ) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
         // Try the options that are least restrictive on the caller first.
         for &(opt_trait_def_id, method_name, borrow) in &[
-            (self.tcx.lang_items().fn_trait(), Ident::from_str("call"), true),
-            (self.tcx.lang_items().fn_mut_trait(), Ident::from_str("call_mut"), true),
-            (self.tcx.lang_items().fn_once_trait(), Ident::from_str("call_once"), false),
+            (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true),
+            (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
+            (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
         ] {
             let trait_def_id = match opt_trait_def_id {
                 Some(def_id) => def_id,
@@ -337,7 +337,7 @@ fn confirm_builtin_call(
                     let mut inner_callee_path = None;
                     let def = match callee.kind {
                         hir::ExprKind::Path(ref qpath) => {
-                            self.tables.borrow().qpath_res(qpath, callee.hir_id)
+                            self.typeck_results.borrow().qpath_res(qpath, callee.hir_id)
                         }
                         hir::ExprKind::Call(ref inner_callee, _) => {
                             // If the call spans more than one line and the callee kind is
@@ -355,7 +355,9 @@ fn confirm_builtin_call(
                             }
                             if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
                                 inner_callee_path = Some(inner_qpath);
-                                self.tables.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
+                                self.typeck_results
+                                    .borrow()
+                                    .qpath_res(inner_qpath, inner_callee.hir_id)
                             } else {
                                 Res::Err
                             }
index 1ea7bf25ef2ed67436f99a84f428ef3c200efe8a..a877df68326d6b61f5117bd6b34b274e3d034d36 100644 (file)
@@ -387,6 +387,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                             // Check for infer types because cases like `Option<{integer}>` would
                             // panic otherwise.
                             if !expr_ty.has_infer_types()
+                                && !ty.has_infer_types()
                                 && fcx.tcx.type_implements_trait((
                                     from_trait,
                                     ty,
@@ -565,7 +566,7 @@ pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
                 Ok(()) => {
                     self.trivial_cast_lint(fcx);
                     debug!(" -> CoercionCast");
-                    fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
+                    fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
                 }
                 Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
                     self.report_object_unsafe_cast(&fcx, did);
index fce2b18b782fb3a0794695f215d2d1d69ae18b45..8b18e759026b1bb1c6678c7c578506c612582af7 100644 (file)
@@ -416,7 +416,7 @@ fn sig_of_closure_with_expectation(
         // Up till this point, we have ignored the annotations that the user
         // gave. This function will check that they unify successfully.
         // Along the way, it also writes out entries for types that the user
-        // wrote into our tables, which are then later used by the privacy
+        // wrote into our typeck results, which are then later used by the privacy
         // check.
         match self.check_supplied_sig_against_expectation(expr_def_id, decl, body, &closure_sigs) {
             Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
@@ -588,7 +588,7 @@ fn supplied_sig_of_closure(
         debug!("supplied_sig_of_closure: result={:?}", result);
 
         let c_result = self.inh.infcx.canonicalize_response(&result);
-        self.tables.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
+        self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
 
         result
     }
index e6b3224050e9bc755fd70a299060f86fe99fb834..5cf2e2d64100c9957c55e01aabeba6e36c0cf5ac 100644 (file)
@@ -1000,7 +1000,7 @@ fn try_find_coercion_lub<E>(
         // First try to coerce the new expression to the type of the previous ones,
         // but only if the new expression has no coercion already applied to it.
         let mut first_error = None;
-        if !self.tables.borrow().adjustments().contains_key(new.hir_id) {
+        if !self.typeck_results.borrow().adjustments().contains_key(new.hir_id) {
             let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
             match result {
                 Ok(ok) => {
@@ -1021,7 +1021,7 @@ fn try_find_coercion_lub<E>(
         // previous expressions, other than noop reborrows (ignoring lifetimes).
         for expr in exprs {
             let expr = expr.as_coercion_site();
-            let noop = match self.tables.borrow().expr_adjustments(expr) {
+            let noop = match self.typeck_results.borrow().expr_adjustments(expr) {
                 &[Adjustment { kind: Adjust::Deref(_), .. }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }] =>
                 {
                     match self.node_ty(expr.hir_id).kind {
index 9a9630f09588698fc551517f3c8286641d016e27..be83ab259c2ecc0bcc96bd9484b099a70a593434 100644 (file)
@@ -320,14 +320,14 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
             _ => return None,
         };
 
-        let self_ty = self.tables.borrow().node_type(method_expr[0].hir_id);
+        let self_ty = self.typeck_results.borrow().node_type(method_expr[0].hir_id);
         let self_ty = format!("{:?}", self_ty);
-        let name = method_path.ident.as_str();
+        let name = method_path.ident.name;
         let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
             || self_ty.starts_with("&std::result::Result")
             || self_ty.starts_with("std::option::Option")
             || self_ty.starts_with("std::result::Result"))
-            && (name == "map" || name == "and_then");
+            && (name == sym::map || name == sym::and_then);
         match (is_as_ref_able, self.sess().source_map().span_to_snippet(*method_span)) {
             (true, Ok(src)) => {
                 let suggestion = format!("as_ref().{}", src);
@@ -466,10 +466,12 @@ pub fn check_ref(
                         let clone_trait = self.tcx.require_lang_item(CloneTraitLangItem, Some(sp));
                         if let ([arg], Some(true), sym::clone) = (
                             &args[..],
-                            self.tables.borrow().type_dependent_def_id(expr.hir_id).map(|did| {
-                                let ai = self.tcx.associated_item(did);
-                                ai.container == ty::TraitContainer(clone_trait)
-                            }),
+                            self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
+                                |did| {
+                                    let ai = self.tcx.associated_item(did);
+                                    ai.container == ty::TraitContainer(clone_trait)
+                                },
+                            ),
                             segment.ident.name,
                         ) {
                             // If this expression had a clone call when suggesting borrowing
index e6b51f4c2cd2a1bdd213f0b0dc9f13d4e6ee307e..63c100d5fad4f17bd399cdea8c571f6459621275 100644 (file)
@@ -68,7 +68,7 @@ fn check_expr_meets_expectation_or_error(
         // coercions from ! to `expected`.
         if ty.is_never() {
             assert!(
-                !self.tables.borrow().adjustments().contains_key(expr.hir_id),
+                !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id),
                 "expression with never type wound up being adjusted"
             );
             let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin {
@@ -430,7 +430,7 @@ fn check_named_place_expr(&self, oprnd: &'tcx hir::Expr<'tcx>) {
             // This is maybe too permissive, since it allows
             // `let u = &raw const Box::new((1,)).0`, which creates an
             // immediately dangling raw pointer.
-            self.tables.borrow().adjustments().get(base.hir_id).map_or(false, |x| {
+            self.typeck_results.borrow().adjustments().get(base.hir_id).map_or(false, |x| {
                 x.iter().any(|adj| if let Adjust::Deref(_) = adj.kind { true } else { false })
             })
         });
@@ -487,7 +487,7 @@ fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -
                     self.require_type_is_sized_deferred(
                         input,
                         expr.span,
-                        traits::SizedArgumentType,
+                        traits::SizedArgumentType(None),
                     );
                 }
             }
@@ -509,7 +509,7 @@ fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -
 
         // We always require that the type provided as the value for
         // a type parameter outlives the moment of instantiation.
-        let substs = self.tables.borrow().node_substs(expr.hir_id);
+        let substs = self.typeck_results.borrow().node_substs(expr.hir_id);
         self.add_wf_bounds(substs, expr);
 
         ty
@@ -1123,7 +1123,7 @@ fn check_expr_struct(
                             })
                             .collect();
 
-                        self.tables
+                        self.typeck_results
                             .borrow_mut()
                             .fru_field_types_mut()
                             .insert(expr.hir_id, fru_field_types);
@@ -1336,7 +1336,7 @@ fn report_unknown_field(
                 // prevent all specified fields from being suggested
                 let skip_fields = skip_fields.iter().map(|ref x| x.ident.name);
                 if let Some(field_name) =
-                    Self::suggest_field_name(variant, &field.ident.as_str(), skip_fields.collect())
+                    Self::suggest_field_name(variant, field.ident.name, skip_fields.collect())
                 {
                     err.span_suggestion(
                         field.ident.span,
@@ -1377,7 +1377,7 @@ fn report_unknown_field(
     // Return an hint about the closest match in field names
     fn suggest_field_name(
         variant: &'tcx ty::VariantDef,
-        field: &str,
+        field: Symbol,
         skip: Vec<Symbol>,
     ) -> Option<Symbol> {
         let names = variant.fields.iter().filter_map(|field| {
@@ -1621,7 +1621,7 @@ fn suggest_fields_on_recordish(
         field: Ident,
     ) {
         if let Some(suggested_field_name) =
-            Self::suggest_field_name(def.non_enum_variant(), &field.as_str(), vec![])
+            Self::suggest_field_name(def.non_enum_variant(), field.name, vec![])
         {
             err.span_suggestion(
                 field.span,
index ce376a08ea60486ddf2c8f60705e9e2ad3b16f64..c5004e4ce119b4ba75d46f94a3d438b51809e44b 100644 (file)
@@ -190,8 +190,8 @@ pub fn resolve_interior<'a, 'tcx>(
     let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
     let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list));
 
-    // Store the generator types and spans into the tables for this generator.
-    visitor.fcx.inh.tables.borrow_mut().generator_interior_types = type_causes;
+    // Store the generator types and spans into the typeck results for this generator.
+    visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = type_causes;
 
     debug!(
         "types in generator after region replacement {:?}, span = {:?}",
@@ -222,7 +222,7 @@ fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
 
         if let PatKind::Binding(..) = pat.kind {
             let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
-            let ty = self.fcx.tables.borrow().pat_ty(pat);
+            let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
             self.record(ty, Some(scope), None, pat.span);
         }
     }
@@ -231,7 +231,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         match &expr.kind {
             ExprKind::Call(callee, args) => match &callee.kind {
                 ExprKind::Path(qpath) => {
-                    let res = self.fcx.tables.borrow().qpath_res(qpath, callee.hir_id);
+                    let res = self.fcx.typeck_results.borrow().qpath_res(qpath, callee.hir_id);
                     match res {
                         // Direct calls never need to keep the callee `ty::FnDef`
                         // ZST in a temporary, so skip its type, just in case it
@@ -263,7 +263,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 
         // If there are adjustments, then record the final type --
         // this is the actual value that is being produced.
-        if let Some(adjusted_ty) = self.fcx.tables.borrow().expr_ty_adjusted_opt(expr) {
+        if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
             self.record(adjusted_ty, scope, Some(expr), expr.span);
         }
 
@@ -291,7 +291,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         //
         // The type table might not have information for this expression
         // if it is in a malformed scope. (#66387)
-        if let Some(ty) = self.fcx.tables.borrow().expr_ty_opt(expr) {
+        if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
             self.record(ty, scope, Some(expr), expr.span);
         } else {
             self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
index 9b3b4a67650a2ab74918a25a8b42ebce711d9697..a09edf575c8072b17370bd3461048b8eb58b1e99 100644 (file)
@@ -386,7 +386,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             }
 
             sym::count_code_region => {
-                (0, vec![tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
+                (0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
             }
 
             sym::coverage_counter_add | sym::coverage_counter_subtract => (
@@ -423,70 +423,81 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
     };
 
     let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id();
-    let name = it.ident.as_str();
+    let name = it.ident.name;
 
-    let (n_tps, inputs, output) = match &*name {
-        "simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => {
+    let (n_tps, inputs, output) = match name {
+        sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => {
             (2, vec![param(0), param(0)], param(1))
         }
-        "simd_add"
-        | "simd_sub"
-        | "simd_mul"
-        | "simd_rem"
-        | "simd_div"
-        | "simd_shl"
-        | "simd_shr"
-        | "simd_and"
-        | "simd_or"
-        | "simd_xor"
-        | "simd_fmin"
-        | "simd_fmax"
-        | "simd_fpow"
-        | "simd_saturating_add"
-        | "simd_saturating_sub" => (1, vec![param(0), param(0)], param(0)),
-        "simd_fsqrt" | "simd_fsin" | "simd_fcos" | "simd_fexp" | "simd_fexp2" | "simd_flog2"
-        | "simd_flog10" | "simd_flog" | "simd_fabs" | "simd_floor" | "simd_ceil" => {
-            (1, vec![param(0)], param(0))
+        sym::simd_add
+        | sym::simd_sub
+        | sym::simd_mul
+        | sym::simd_rem
+        | sym::simd_div
+        | sym::simd_shl
+        | sym::simd_shr
+        | sym::simd_and
+        | sym::simd_or
+        | sym::simd_xor
+        | sym::simd_fmin
+        | sym::simd_fmax
+        | sym::simd_fpow
+        | sym::simd_saturating_add
+        | sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)),
+        sym::simd_fsqrt
+        | sym::simd_fsin
+        | sym::simd_fcos
+        | sym::simd_fexp
+        | sym::simd_fexp2
+        | sym::simd_flog2
+        | sym::simd_flog10
+        | sym::simd_flog
+        | sym::simd_fabs
+        | sym::simd_floor
+        | sym::simd_ceil => (1, vec![param(0)], param(0)),
+        sym::simd_fpowi => (1, vec![param(0), tcx.types.i32], param(0)),
+        sym::simd_fma => (1, vec![param(0), param(0), param(0)], param(0)),
+        sym::simd_gather => (3, vec![param(0), param(1), param(2)], param(0)),
+        sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()),
+        sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
+        sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)),
+        sym::simd_cast => (2, vec![param(0)], param(1)),
+        sym::simd_bitmask => (2, vec![param(0)], param(1)),
+        sym::simd_select | sym::simd_select_bitmask => {
+            (2, vec![param(0), param(1), param(1)], param(1))
         }
-        "simd_fpowi" => (1, vec![param(0), tcx.types.i32], param(0)),
-        "simd_fma" => (1, vec![param(0), param(0), param(0)], param(0)),
-        "simd_gather" => (3, vec![param(0), param(1), param(2)], param(0)),
-        "simd_scatter" => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()),
-        "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
-        "simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)),
-        "simd_cast" => (2, vec![param(0)], param(1)),
-        "simd_bitmask" => (2, vec![param(0)], param(1)),
-        "simd_select" | "simd_select_bitmask" => (2, vec![param(0), param(1), param(1)], param(1)),
-        "simd_reduce_all" | "simd_reduce_any" => (1, vec![param(0)], tcx.types.bool),
-        "simd_reduce_add_ordered" | "simd_reduce_mul_ordered" => {
+        sym::simd_reduce_all | sym::simd_reduce_any => (1, vec![param(0)], tcx.types.bool),
+        sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => {
             (2, vec![param(0), param(1)], param(1))
         }
-        "simd_reduce_add_unordered"
-        | "simd_reduce_mul_unordered"
-        | "simd_reduce_and"
-        | "simd_reduce_or"
-        | "simd_reduce_xor"
-        | "simd_reduce_min"
-        | "simd_reduce_max"
-        | "simd_reduce_min_nanless"
-        | "simd_reduce_max_nanless" => (2, vec![param(0)], param(1)),
-        name if name.starts_with("simd_shuffle") => match name["simd_shuffle".len()..].parse() {
-            Ok(n) => {
-                let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)];
-                (2, params, param(1))
-            }
-            Err(_) => {
-                struct_span_err!(
-                    tcx.sess,
-                    it.span,
-                    E0439,
-                    "invalid `simd_shuffle`, needs length: `{}`",
-                    name
-                )
-                .emit();
-                return;
+        sym::simd_reduce_add_unordered
+        | sym::simd_reduce_mul_unordered
+        | sym::simd_reduce_and
+        | sym::simd_reduce_or
+        | sym::simd_reduce_xor
+        | sym::simd_reduce_min
+        | sym::simd_reduce_max
+        | sym::simd_reduce_min_nanless
+        | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)),
+        name if name.as_str().starts_with("simd_shuffle") => {
+            match name.as_str()["simd_shuffle".len()..].parse() {
+                Ok(n) => {
+                    let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)];
+                    (2, params, param(1))
+                }
+                Err(_) => {
+                    struct_span_err!(
+                        tcx.sess,
+                        it.span,
+                        E0439,
+                        "invalid `simd_shuffle`, needs length: `{}`",
+                        name
+                    )
+                    .emit();
+                    return;
+                }
             }
-        },
+        }
         _ => {
             let msg = format!("unrecognized platform-specific intrinsic function: `{}`", name);
             tcx.sess.struct_span_err(it.span, &msg).emit();
index 1c3d23a3a241f4bf751ad6490235491317ad26d2..96248e18aaf87a44fb6b9be380a14c112dfbd38d 100644 (file)
@@ -131,7 +131,7 @@ fn adjust_self_ty(
         pick: &probe::Pick<'tcx>,
     ) -> Ty<'tcx> {
         // Commit the autoderefs by calling `autoderef` again, but this
-        // time writing the results into the various tables.
+        // time writing the results into the various typeck results.
         let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
         let (_, n) = match autoderef.nth(pick.autoderefs) {
             Some(n) => n,
@@ -325,7 +325,7 @@ fn instantiate_method_substs(
                 }
                 (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(),
                 (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    self.to_const(&ct.value).into()
+                    self.const_arg_to_const(&ct.value, param.def_id).into()
                 }
                 _ => unreachable!(),
             },
index b1799c6eef3365cf5c5e20e8cb033cd44bbc0031..64dce3e1738e38115fd37a66536d3acc37a24fdc 100644 (file)
@@ -195,7 +195,7 @@ pub fn lookup_method(
 
         for import_id in &pick.import_ids {
             debug!("used_trait_import: {:?}", import_id);
-            Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
+            Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports)
                 .unwrap()
                 .insert(*import_id);
         }
@@ -456,8 +456,8 @@ pub fn resolve_ufcs(
         )?;
         debug!("resolve_ufcs: pick={:?}", pick);
         {
-            let mut tables = self.tables.borrow_mut();
-            let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap();
+            let mut typeck_results = self.typeck_results.borrow_mut();
+            let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap();
             for import_id in pick.import_ids {
                 debug!("resolve_ufcs: used_trait_import: {:?}", import_id);
                 used_trait_imports.insert(import_id);
index ba952df7e4e2861dc1b914c59d3e56f057cc1c9f..9c5e3cbc93844a338f77c3c6977b26e59a520e63 100644 (file)
@@ -1536,7 +1536,7 @@ fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodErr
             } else {
                 let best_name = {
                     let names = applicable_close_candidates.iter().map(|cand| &cand.ident.name);
-                    find_best_match_for_name(names, &self.method_name.unwrap().as_str(), None)
+                    find_best_match_for_name(names, self.method_name.unwrap().name, None)
                 }
                 .unwrap();
                 Ok(applicable_close_candidates
index 44ffabc4c266222617f11b17708e22c0330cf386..b9f1f8064c861062c253efc98188957f0e829fd9 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_middle::ty::{
     self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
-use rustc_span::symbol::{kw, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::Obligation;
@@ -729,7 +729,7 @@ trait bound{s}",
                     let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
                     if let Some(suggestion) = lev_distance::find_best_match_for_name(
                         adt_def.variants.iter().map(|s| &s.ident.name),
-                        &item_name.as_str(),
+                        item_name.name,
                         None,
                     ) {
                         err.span_suggestion(
@@ -743,7 +743,7 @@ trait bound{s}",
 
                 let mut fallback_span = true;
                 let msg = "remove this method call";
-                if item_name.as_str() == "as_str" && actual.peel_refs().is_str() {
+                if item_name.name == sym::as_str && actual.peel_refs().is_str() {
                     if let SelfSource::MethodCall(expr) = source {
                         let call_expr =
                             self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
@@ -937,6 +937,12 @@ fn suggest_traits_to_import<'b>(
         // legal to implement.
         let mut candidates = all_traits(self.tcx)
             .into_iter()
+            // Don't issue suggestions for unstable traits since they're
+            // unlikely to be implementable anyway
+            .filter(|info| match self.tcx.lookup_stability(info.def_id) {
+                Some(attr) => attr.level.is_stable(),
+                None => true,
+            })
             .filter(|info| {
                 // We approximate the coherence rules to only suggest
                 // traits that are legal to implement by requiring that
@@ -1037,7 +1043,9 @@ fn suggest_traits_to_import<'b>(
             };
             // Obtain the span for `param` and use it for a structured suggestion.
             let mut suggested = false;
-            if let (Some(ref param), Some(ref table)) = (param_type, self.in_progress_tables) {
+            if let (Some(ref param), Some(ref table)) =
+                (param_type, self.in_progress_typeck_results)
+            {
                 let table_owner = table.borrow().hir_owner;
                 let generics = self.tcx.generics_of(table_owner.to_def_id());
                 let type_param = generics.type_param(param, self.tcx);
index fa7360ce90051b36abb43327375ae195ffd67093..04e02704296defd79c3b2a8cbfc98eaee84c2eaf 100644 (file)
@@ -51,7 +51,7 @@
 nodes within the function.
 
 The types of top-level items, which never contain unbound type
-variables, are stored directly into the `tcx` tables.
+variables, are stored directly into the `tcx` typeck_results.
 
 N.B., a type variable is not the same thing as a type parameter.  A
 type variable is rather an "instance" of a type parameter: that is,
 use rustc_hir::lang_items::{
     FutureTraitLangItem, PinTypeLangItem, SizedTraitLangItem, VaListTypeLangItem,
 };
-use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath};
+use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_infer::infer;
@@ -182,24 +182,28 @@ pub struct LocalTy<'tcx> {
     revealed_ty: Ty<'tcx>,
 }
 
-/// A wrapper for `InferCtxt`'s `in_progress_tables` field.
+/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
 #[derive(Copy, Clone)]
 struct MaybeInProgressTables<'a, 'tcx> {
-    maybe_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>,
+    maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
 }
 
 impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
-    fn borrow(self) -> Ref<'a, ty::TypeckTables<'tcx>> {
-        match self.maybe_tables {
-            Some(tables) => tables.borrow(),
-            None => bug!("MaybeInProgressTables: inh/fcx.tables.borrow() with no tables"),
+    fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
+        match self.maybe_typeck_results {
+            Some(typeck_results) => typeck_results.borrow(),
+            None => bug!(
+                "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
+            ),
         }
     }
 
-    fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> {
-        match self.maybe_tables {
-            Some(tables) => tables.borrow_mut(),
-            None => bug!("MaybeInProgressTables: inh/fcx.tables.borrow_mut() with no tables"),
+    fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
+        match self.maybe_typeck_results {
+            Some(typeck_results) => typeck_results.borrow_mut(),
+            None => bug!(
+                "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
+            ),
         }
     }
 }
@@ -216,7 +220,7 @@ fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> {
 pub struct Inherited<'a, 'tcx> {
     infcx: InferCtxt<'a, 'tcx>,
 
-    tables: MaybeInProgressTables<'a, 'tcx>,
+    typeck_results: MaybeInProgressTables<'a, 'tcx>,
 
     locals: RefCell<HirIdMap<LocalTy<'tcx>>>,
 
@@ -645,7 +649,7 @@ pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
         let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
 
         InheritedBuilder {
-            infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(hir_owner),
+            infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner),
             def_id,
         }
     }
@@ -668,7 +672,9 @@ fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
         let body_id = tcx.hir().maybe_body_owned_by(item_id);
 
         Inherited {
-            tables: MaybeInProgressTables { maybe_tables: infcx.in_progress_tables },
+            typeck_results: MaybeInProgressTables {
+                maybe_typeck_results: infcx.in_progress_typeck_results,
+            },
             infcx,
             fulfillment_cx: RefCell::new(TraitEngine::new(tcx)),
             locals: RefCell::new(Default::default()),
@@ -744,7 +750,7 @@ fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
     debug_assert!(crate_num == LOCAL_CRATE);
     tcx.par_body_owners(|body_owner_def_id| {
-        tcx.ensure().typeck_tables_of(body_owner_def_id);
+        tcx.ensure().typeck(body_owner_def_id);
     });
 }
 
@@ -764,9 +770,10 @@ pub fn provide(providers: &mut Providers) {
     method::provide(providers);
     *providers = Providers {
         typeck_item_bodies,
-        typeck_tables_of,
-        diagnostic_only_typeck_tables_of,
-        has_typeck_tables,
+        typeck_const_arg,
+        typeck,
+        diagnostic_only_typeck,
+        has_typeck_results,
         adt_destructor,
         used_trait_imports,
         check_item_well_formed,
@@ -786,10 +793,10 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
 /// it's body-id, fn-header and fn-decl (if any). Otherwise,
 /// returns `None`.
 ///
-/// If this function returns `Some`, then `typeck_tables(def_id)` will
-/// succeed; if it returns `None`, then `typeck_tables(def_id)` may or
+/// If this function returns `Some`, then `typeck_results(def_id)` will
+/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
 /// may not succeed. In some cases where this function returns `None`
-/// (notably closures), `typeck_tables(def_id)` would wind up
+/// (notably closures), `typeck_results(def_id)` would wind up
 /// redirecting to the owning function.
 fn primary_body_of(
     tcx: TyCtxt<'_>,
@@ -824,12 +831,12 @@ fn primary_body_of(
     }
 }
 
-fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    // Closures' tables come from their outermost function,
+fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    // Closures' typeck results come from their outermost function,
     // as they are part of the same "inference environment".
     let outer_def_id = tcx.closure_base_def_id(def_id);
     if outer_def_id != def_id {
-        return tcx.has_typeck_tables(outer_def_id);
+        return tcx.has_typeck_results(outer_def_id);
     }
 
     if let Some(def_id) = def_id.as_local() {
@@ -841,7 +848,7 @@ fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 }
 
 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
-    &*tcx.typeck_tables_of(def_id).used_trait_imports
+    &*tcx.typeck(def_id).used_trait_imports
 }
 
 /// Inspects the substs of opaque types, replacing any inference variables
@@ -955,34 +962,43 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
     val.fold_with(&mut FixupFolder { tcx })
 }
 
-fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> {
-    let fallback = move || tcx.type_of(def_id.to_def_id());
-    typeck_tables_of_with_fallback(tcx, def_id, fallback)
+fn typeck_const_arg<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (did, param_did): (LocalDefId, DefId),
+) -> &ty::TypeckResults<'tcx> {
+    let fallback = move || tcx.type_of(param_did);
+    typeck_with_fallback(tcx, did, fallback)
 }
 
-/// Used only to get `TypeckTables` for type inference during error recovery.
+fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+    if let Some(param_did) = tcx.opt_const_param_of(def_id) {
+        tcx.typeck_const_arg((def_id, param_did))
+    } else {
+        let fallback = move || tcx.type_of(def_id.to_def_id());
+        typeck_with_fallback(tcx, def_id, fallback)
+    }
+}
+
+/// Used only to get `TypeckResults` for type inference during error recovery.
 /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
-fn diagnostic_only_typeck_tables_of<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> &ty::TypeckTables<'tcx> {
+fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
     let fallback = move || {
         let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id));
         tcx.ty_error_with_message(span, "diagnostic only typeck table used")
     };
-    typeck_tables_of_with_fallback(tcx, def_id, fallback)
+    typeck_with_fallback(tcx, def_id, fallback)
 }
 
-fn typeck_tables_of_with_fallback<'tcx>(
+fn typeck_with_fallback<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     fallback: impl Fn() -> Ty<'tcx> + 'tcx,
-) -> &'tcx ty::TypeckTables<'tcx> {
-    // Closures' tables come from their outermost function,
+) -> &'tcx ty::TypeckResults<'tcx> {
+    // Closures' typeck results come from their outermost function,
     // as they are part of the same "inference environment".
     let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
     if outer_def_id != def_id {
-        return tcx.typeck_tables_of(outer_def_id);
+        return tcx.typeck(outer_def_id);
     }
 
     let id = tcx.hir().as_local_hir_id(def_id);
@@ -994,7 +1010,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
     });
     let body = tcx.hir().body(body_id);
 
-    let tables = Inherited::build(tcx, def_id).enter(|inh| {
+    let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
         let param_env = tcx.param_env(def_id);
         let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) {
             let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
@@ -1124,11 +1140,11 @@ fn typeck_tables_of_with_fallback<'tcx>(
         fcx.resolve_type_vars_in_body(body)
     });
 
-    // Consistency check our TypeckTables instance can hold all ItemLocalIds
+    // Consistency check our TypeckResults instance can hold all ItemLocalIds
     // it will need to hold.
-    assert_eq!(tables.hir_owner, id.owner);
+    assert_eq!(typeck_results.hir_owner, id.owner);
 
-    tables
+    typeck_results
 }
 
 fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
@@ -1201,7 +1217,11 @@ fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
                     "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
                     ty.hir_id, o_ty, revealed_ty, c_ty
                 );
-                self.fcx.tables.borrow_mut().user_provided_types_mut().insert(ty.hir_id, c_ty);
+                self.fcx
+                    .typeck_results
+                    .borrow_mut()
+                    .user_provided_types_mut()
+                    .insert(ty.hir_id, c_ty);
 
                 Some(LocalTy { decl_ty: o_ty, revealed_ty })
             }
@@ -1342,20 +1362,21 @@ fn check_fn<'a, 'tcx>(
     let inputs_fn = fn_sig.inputs().iter().copied();
     for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
         // Check the pattern.
-        fcx.check_pat_top(&param.pat, param_ty, try { inputs_hir?.get(idx)?.span }, false);
+        let ty_span = try { inputs_hir?.get(idx)?.span };
+        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
 
         // Check that argument is Sized.
         // The check for a non-trivial pattern is a hack to avoid duplicate warnings
         // for simple cases like `fn foo(x: Trait)`,
         // where we would error once on the parameter as a whole, and once on the binding `x`.
         if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
-            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType);
+            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
         }
 
         fcx.write_ty(param.hir_id, param_ty);
     }
 
-    inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
 
     if let ty::Dynamic(..) = declared_ret_ty.kind {
         // FIXME: We need to verify that the return type is `Sized` after the return expression has
@@ -1744,17 +1765,17 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
 
     let mut label = false;
     if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
-        let tables = tcx.typeck_tables_of(tcx.hir().local_def_id(hir_id));
+        let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id));
         if visitor
             .returns
             .iter()
-            .filter_map(|expr| tables.node_type_opt(expr.hir_id))
+            .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
             .all(|ty| matches!(ty.kind, ty::Never))
         {
             let spans = visitor
                 .returns
                 .iter()
-                .filter(|expr| tables.node_type_opt(expr.hir_id).is_some())
+                .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some())
                 .map(|expr| expr.span)
                 .collect::<Vec<Span>>();
             let span_len = spans.len();
@@ -1777,7 +1798,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
             for (sp, ty) in visitor
                 .returns
                 .iter()
-                .filter_map(|e| tables.node_type_opt(e.hir_id).map(|t| (e.span, t)))
+                .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
                 .filter(|(_, ty)| !matches!(ty.kind, ty::Never))
             {
                 struct VisitTypes(Vec<DefId>);
@@ -1847,9 +1868,9 @@ fn binding_opaque_type_cycle_error(
                 ..
             }) => {
                 let hir_id = tcx.hir().as_local_hir_id(def_id);
-                let tables =
-                    tcx.typeck_tables_of(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id)));
-                if let Some(ty) = tables.node_type_opt(expr.hir_id) {
+                let typeck_results =
+                    tcx.typeck(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id)));
+                if let Some(ty) = typeck_results.node_type_opt(expr.hir_id) {
                     err.span_label(
                         expr.span,
                         &format!(
@@ -1917,11 +1938,11 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
         // Consts can play a role in type-checking, so they are included here.
         hir::ItemKind::Static(..) => {
             let def_id = tcx.hir().local_def_id(it.hir_id);
-            tcx.ensure().typeck_tables_of(def_id);
+            tcx.ensure().typeck(def_id);
             maybe_check_static_with_link_section(tcx, def_id, it.span);
         }
         hir::ItemKind::Const(..) => {
-            tcx.ensure().typeck_tables_of(tcx.hir().local_def_id(it.hir_id));
+            tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id));
         }
         hir::ItemKind::Enum(ref enum_definition, _) => {
             check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
@@ -2624,34 +2645,31 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
                     "packed type cannot transitively contain a `#[repr(align)]` type"
                 );
 
-                let hir = tcx.hir();
-                let hir_id = hir.as_local_hir_id(def_spans[0].0.expect_local());
-                if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
-                    err.span_note(
-                        tcx.def_span(def_spans[0].0),
-                        &format!("`{}` has a `#[repr(align)]` attribute", ident),
-                    );
-                }
+                err.span_note(
+                    tcx.def_span(def_spans[0].0),
+                    &format!(
+                        "`{}` has a `#[repr(align)]` attribute",
+                        tcx.item_name(def_spans[0].0)
+                    ),
+                );
 
                 if def_spans.len() > 2 {
                     let mut first = true;
                     for (adt_def, span) in def_spans.iter().skip(1).rev() {
-                        let hir_id = hir.as_local_hir_id(adt_def.expect_local());
-                        if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
-                            err.span_note(
-                                *span,
-                                &if first {
-                                    format!(
-                                        "`{}` contains a field of type `{}`",
-                                        tcx.type_of(def.did),
-                                        ident
-                                    )
-                                } else {
-                                    format!("...which contains a field of type `{}`", ident)
-                                },
-                            );
-                            first = false;
-                        }
+                        let ident = tcx.item_name(*adt_def);
+                        err.span_note(
+                            *span,
+                            &if first {
+                                format!(
+                                    "`{}` contains a field of type `{}`",
+                                    tcx.type_of(def.did),
+                                    ident
+                                )
+                            } else {
+                                format!("...which contains a field of type `{}`", ident)
+                            },
+                        );
+                        first = false;
                     }
                 }
 
@@ -2832,7 +2850,7 @@ pub fn check_enum<'tcx>(
 
     for v in vs {
         if let Some(ref e) = v.disr_expr {
-            tcx.ensure().typeck_tables_of(tcx.hir().local_def_id(e.hir_id));
+            tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
         }
     }
 
@@ -3201,7 +3219,7 @@ pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
             self.resolve_vars_if_possible(&ty),
             self.tag()
         );
-        self.tables.borrow_mut().node_types_mut().insert(id, ty);
+        self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
 
         if ty.references_error() {
             self.has_errors.set(true);
@@ -3210,11 +3228,11 @@ pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
     }
 
     pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
-        self.tables.borrow_mut().field_indices_mut().insert(hir_id, index);
+        self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
     }
 
     fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) {
-        self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
+        self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
     }
 
     pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
@@ -3268,7 +3286,7 @@ pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
         if !substs.is_noop() {
             debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
 
-            self.tables.borrow_mut().node_substs_mut().insert(node_id, substs);
+            self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
         }
     }
 
@@ -3319,7 +3337,7 @@ pub fn write_user_type_annotation(
         );
 
         if !canonical_user_type_annotation.is_identity() {
-            self.tables
+            self.typeck_results
                 .borrow_mut()
                 .user_provided_types_mut()
                 .insert(hir_id, canonical_user_type_annotation);
@@ -3342,7 +3360,7 @@ pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>
             })
         });
 
-        match self.tables.borrow_mut().adjustments_mut().entry(expr.hir_id) {
+        match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
             Entry::Vacant(entry) => {
                 entry.insert(adj);
             }
@@ -3527,7 +3545,7 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         if Self::can_contain_user_lifetime_bounds(ty) {
             let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
             debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
-            self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
+            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
         }
 
         ty
@@ -3544,6 +3562,24 @@ pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
         c
     }
 
+    pub fn const_arg_to_const(
+        &self,
+        ast_c: &hir::AnonConst,
+        param_def_id: DefId,
+    ) -> &'tcx ty::Const<'tcx> {
+        let const_def = ty::WithOptConstParam {
+            did: self.tcx.hir().local_def_id(ast_c.hir_id),
+            const_param_did: Some(param_def_id),
+        };
+        let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
     // If the type given by the user has free regions, save it for later, since
     // NLL would like to enforce those. Also pass in types that involve
     // projections, since those can resolve to `'static` bounds (modulo #54940,
@@ -3559,7 +3595,7 @@ fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
     }
 
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
-        match self.tables.borrow().node_types().get(id) {
+        match self.typeck_results.borrow().node_types().get(id) {
             Some(&t) => t,
             None if self.is_tainted_by_errors() => self.tcx.ty_error(),
             None => {
@@ -4498,7 +4534,8 @@ pub fn resolve_ty_and_res_ufcs<'b>(
             }
             QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
         };
-        if let Some(&cached_result) = self.tables.borrow().type_dependent_defs().get(hir_id) {
+        if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
+        {
             // Return directly on cache hit. This is useful to avoid doubly reporting
             // errors with default match binding modes. See #44614.
             let def =
@@ -4672,8 +4709,10 @@ fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
             let arm_spans: Vec<Span> = arms
                 .iter()
                 .filter_map(|arm| {
-                    self.in_progress_tables
-                        .and_then(|tables| tables.borrow().node_type_opt(arm.body.hir_id))
+                    self.in_progress_typeck_results
+                        .and_then(|typeck_results| {
+                            typeck_results.borrow().node_type_opt(arm.body.hir_id)
+                        })
                         .and_then(|arm_ty| {
                             if arm_ty.is_never() {
                                 None
@@ -5657,7 +5696,7 @@ pub fn instantiate_value_path(
                         self.to_ty(ty).into()
                     }
                     (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                        self.to_const(&ct.value).into()
+                        self.const_arg_to_const(&ct.value, param.def_id).into()
                     }
                     _ => unreachable!(),
                 },
index a1e060b97ad2815a6b527ba48b3541910f3f70d9..41aac3569d115f8e2e364eeb393e61db8f41add5 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_middle::ty::{
     self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor,
 };
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 
@@ -240,7 +240,7 @@ fn check_overloaded_binop(
                         // some cases applied on the RHS, on top of which we need
                         // to autoref, which is not allowed by apply_adjustments.
                         // self.apply_adjustments(rhs_expr, vec![autoref]);
-                        self.tables
+                        self.typeck_results
                             .borrow_mut()
                             .adjustments_mut()
                             .entry(rhs_expr.hir_id)
@@ -496,14 +496,14 @@ fn add_type_neq_err_label(
         err.span_label(span, ty.to_string());
         if let FnDef(def_id, _) = ty.kind {
             let source_map = self.tcx.sess.source_map();
-            if !self.tcx.has_typeck_tables(def_id) {
+            if !self.tcx.has_typeck_results(def_id) {
                 return false;
             }
             // We're emitting a suggestion, so we can just ignore regions
             let fn_sig = self.tcx.fn_sig(def_id).skip_binder();
 
             let other_ty = if let FnDef(def_id, _) = other_ty.kind {
-                if !self.tcx.has_typeck_tables(def_id) {
+                if !self.tcx.has_typeck_results(def_id) {
                     return false;
                 }
                 // We're emitting a suggestion, so we can just ignore regions
@@ -702,16 +702,16 @@ fn lookup_op_method(
         };
         let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op {
             match op.node {
-                hir::BinOpKind::Add => ("add_assign", lang.add_assign_trait()),
-                hir::BinOpKind::Sub => ("sub_assign", lang.sub_assign_trait()),
-                hir::BinOpKind::Mul => ("mul_assign", lang.mul_assign_trait()),
-                hir::BinOpKind::Div => ("div_assign", lang.div_assign_trait()),
-                hir::BinOpKind::Rem => ("rem_assign", lang.rem_assign_trait()),
-                hir::BinOpKind::BitXor => ("bitxor_assign", lang.bitxor_assign_trait()),
-                hir::BinOpKind::BitAnd => ("bitand_assign", lang.bitand_assign_trait()),
-                hir::BinOpKind::BitOr => ("bitor_assign", lang.bitor_assign_trait()),
-                hir::BinOpKind::Shl => ("shl_assign", lang.shl_assign_trait()),
-                hir::BinOpKind::Shr => ("shr_assign", lang.shr_assign_trait()),
+                hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()),
+                hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()),
+                hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()),
+                hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()),
+                hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()),
+                hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()),
+                hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()),
+                hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()),
+                hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()),
+                hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()),
                 hir::BinOpKind::Lt
                 | hir::BinOpKind::Le
                 | hir::BinOpKind::Ge
@@ -725,30 +725,30 @@ fn lookup_op_method(
             }
         } else if let Op::Binary(op, IsAssign::No) = op {
             match op.node {
-                hir::BinOpKind::Add => ("add", lang.add_trait()),
-                hir::BinOpKind::Sub => ("sub", lang.sub_trait()),
-                hir::BinOpKind::Mul => ("mul", lang.mul_trait()),
-                hir::BinOpKind::Div => ("div", lang.div_trait()),
-                hir::BinOpKind::Rem => ("rem", lang.rem_trait()),
-                hir::BinOpKind::BitXor => ("bitxor", lang.bitxor_trait()),
-                hir::BinOpKind::BitAnd => ("bitand", lang.bitand_trait()),
-                hir::BinOpKind::BitOr => ("bitor", lang.bitor_trait()),
-                hir::BinOpKind::Shl => ("shl", lang.shl_trait()),
-                hir::BinOpKind::Shr => ("shr", lang.shr_trait()),
-                hir::BinOpKind::Lt => ("lt", lang.partial_ord_trait()),
-                hir::BinOpKind::Le => ("le", lang.partial_ord_trait()),
-                hir::BinOpKind::Ge => ("ge", lang.partial_ord_trait()),
-                hir::BinOpKind::Gt => ("gt", lang.partial_ord_trait()),
-                hir::BinOpKind::Eq => ("eq", lang.eq_trait()),
-                hir::BinOpKind::Ne => ("ne", lang.eq_trait()),
+                hir::BinOpKind::Add => (sym::add, lang.add_trait()),
+                hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()),
+                hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()),
+                hir::BinOpKind::Div => (sym::div, lang.div_trait()),
+                hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()),
+                hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()),
+                hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()),
+                hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()),
+                hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()),
+                hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()),
+                hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()),
+                hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()),
+                hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
+                hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
+                hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()),
+                hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()),
                 hir::BinOpKind::And | hir::BinOpKind::Or => {
                     span_bug!(span, "&& and || are not overloadable")
                 }
             }
         } else if let Op::Unary(hir::UnOp::UnNot, _) = op {
-            ("not", lang.not_trait())
+            (sym::not, lang.not_trait())
         } else if let Op::Unary(hir::UnOp::UnNeg, _) = op {
-            ("neg", lang.neg_trait())
+            (sym::neg, lang.neg_trait())
         } else {
             bug!("lookup_op_method: op not supported: {:?}", op)
         };
@@ -759,7 +759,7 @@ fn lookup_op_method(
         );
 
         let method = trait_did.and_then(|trait_did| {
-            let opname = Ident::from_str(opname);
+            let opname = Ident::with_dummy_span(opname);
             self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys))
         });
 
index ea47ae68ce7d36c63220b15c2140602a7765cc14..42170bc199cbc3d9f0a281cc9842bcafc26645f7 100644 (file)
@@ -363,7 +363,11 @@ fn peel_off_references(
 
         if !pat_adjustments.is_empty() {
             debug!("default binding mode is now {:?}", def_bm);
-            self.inh.tables.borrow_mut().pat_adjustments_mut().insert(pat.hir_id, pat_adjustments);
+            self.inh
+                .typeck_results
+                .borrow_mut()
+                .pat_adjustments_mut()
+                .insert(pat.hir_id, pat_adjustments);
         }
 
         (expected, def_bm)
@@ -534,7 +538,7 @@ fn check_pat_ident(
             _ => BindingMode::convert(ba),
         };
         // ...and store it in a side table:
-        self.inh.tables.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
+        self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
 
         debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
 
@@ -1082,20 +1086,23 @@ fn check_struct_pat_fields(
             .filter(|ident| !used_fields.contains_key(&ident))
             .collect::<Vec<_>>();
 
-        if !inexistent_fields.is_empty() && !variant.recovered {
-            self.error_inexistent_fields(
+        let inexistent_fields_err = if !inexistent_fields.is_empty() && !variant.recovered {
+            Some(self.error_inexistent_fields(
                 adt.variant_descr(),
                 &inexistent_fields,
                 &mut unmentioned_fields,
                 variant,
-            );
-        }
+            ))
+        } else {
+            None
+        };
 
         // Require `..` if struct has non_exhaustive attribute.
         if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
             self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
         }
 
+        let mut unmentioned_err = None;
         // Report an error if incorrect number of the fields were specified.
         if adt.is_union() {
             if fields.len() != 1 {
@@ -1107,7 +1114,25 @@ fn check_struct_pat_fields(
                 tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
             }
         } else if !etc && !unmentioned_fields.is_empty() {
-            self.error_unmentioned_fields(pat.span, &unmentioned_fields, variant);
+            unmentioned_err = Some(self.error_unmentioned_fields(pat.span, &unmentioned_fields));
+        }
+        match (inexistent_fields_err, unmentioned_err) {
+            (Some(mut i), Some(mut u)) => {
+                if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) {
+                    // We don't want to show the inexistent fields error when this was
+                    // `Foo { a, b }` when it should have been `Foo(a, b)`.
+                    i.delay_as_bug();
+                    u.delay_as_bug();
+                    e.emit();
+                } else {
+                    i.emit();
+                    u.emit();
+                }
+            }
+            (None, Some(mut err)) | (Some(mut err), None) => {
+                err.emit();
+            }
+            (None, None) => {}
         }
         no_field_errors
     }
@@ -1154,7 +1179,7 @@ fn error_inexistent_fields(
         inexistent_fields: &[Ident],
         unmentioned_fields: &mut Vec<Ident>,
         variant: &ty::VariantDef,
-    ) {
+    ) -> DiagnosticBuilder<'tcx> {
         let tcx = self.tcx;
         let (field_names, t, plural) = if inexistent_fields.len() == 1 {
             (format!("a field named `{}`", inexistent_fields[0]), "this", "")
@@ -1195,7 +1220,7 @@ fn error_inexistent_fields(
             );
             if plural == "" {
                 let input = unmentioned_fields.iter().map(|field| &field.name);
-                let suggested_name = find_best_match_for_name(input, &ident.as_str(), None);
+                let suggested_name = find_best_match_for_name(input, ident.name, None);
                 if let Some(suggested_name) = suggested_name {
                     err.span_suggestion(
                         ident.span,
@@ -1221,15 +1246,62 @@ fn error_inexistent_fields(
                     it explicitly.",
             );
         }
-        err.emit();
+        err
+    }
+
+    fn error_tuple_variant_as_struct_pat(
+        &self,
+        pat: &Pat<'_>,
+        fields: &'tcx [hir::FieldPat<'tcx>],
+        variant: &ty::VariantDef,
+    ) -> Option<DiagnosticBuilder<'tcx>> {
+        if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) {
+            let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                s.print_qpath(qpath, false)
+            });
+            let mut err = struct_span_err!(
+                self.tcx.sess,
+                pat.span,
+                E0769,
+                "tuple variant `{}` written as struct variant",
+                path
+            );
+            let (sugg, appl) = if fields.len() == variant.fields.len() {
+                (
+                    fields
+                        .iter()
+                        .map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) {
+                            Ok(f) => f,
+                            Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                                s.print_pat(f.pat)
+                            }),
+                        })
+                        .collect::<Vec<String>>()
+                        .join(", "),
+                    Applicability::MachineApplicable,
+                )
+            } else {
+                (
+                    variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "),
+                    Applicability::MaybeIncorrect,
+                )
+            };
+            err.span_suggestion(
+                pat.span,
+                "use the tuple variant pattern syntax instead",
+                format!("{}({})", path, sugg),
+                appl,
+            );
+            return Some(err);
+        }
+        None
     }
 
     fn error_unmentioned_fields(
         &self,
         span: Span,
         unmentioned_fields: &[Ident],
-        variant: &ty::VariantDef,
-    ) {
+    ) -> DiagnosticBuilder<'tcx> {
         let field_names = if unmentioned_fields.len() == 1 {
             format!("field `{}`", unmentioned_fields[0])
         } else {
@@ -1248,9 +1320,6 @@ fn error_unmentioned_fields(
             field_names
         );
         diag.span_label(span, format!("missing {}", field_names));
-        if variant.ctor_kind == CtorKind::Fn {
-            diag.note("trying to match a tuple variant with a struct variant pattern");
-        }
         if self.tcx.sess.teach(&diag.get_code().unwrap()) {
             diag.note(
                 "This error indicates that a pattern for a struct fails to specify a \
@@ -1259,7 +1328,7 @@ fn error_unmentioned_fields(
                     ignore unwanted fields.",
             );
         }
-        diag.emit();
+        diag
     }
 
     fn check_pat_box(
index b7c8f310a1414763acb04b1b1b63becfe65704db..12468750923554ffc79b4db2ff62b9c50cfa706f 100644 (file)
@@ -221,9 +221,9 @@ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
             let mut source = self.node_ty(expr.hir_id);
             // Do not mutate adjustments in place, but rather take them,
             // and replace them after mutating them, to avoid having the
-            // tables borrowed during (`deref_mut`) method resolution.
+            // typeck results borrowed during (`deref_mut`) method resolution.
             let previous_adjustments =
-                self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
+                self.typeck_results.borrow_mut().adjustments_mut().remove(expr.hir_id);
             if let Some(mut adjustments) = previous_adjustments {
                 for adjustment in &mut adjustments {
                     if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
@@ -241,14 +241,14 @@ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
                     }
                     source = adjustment.target;
                 }
-                self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
+                self.typeck_results.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
             }
 
             match expr.kind {
                 hir::ExprKind::Index(ref base_expr, ref index_expr) => {
                     // We need to get the final type in case dereferences were needed for the trait
                     // to apply (#72002).
-                    let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
+                    let index_expr_ty = self.typeck_results.borrow().expr_ty_adjusted(index_expr);
                     self.convert_place_op_to_mutable(
                         PlaceOp::Index,
                         expr,
@@ -272,14 +272,14 @@ fn convert_place_op_to_mutable(
         arg_tys: &[Ty<'tcx>],
     ) {
         debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
-        if !self.tables.borrow().is_method_call(expr) {
+        if !self.typeck_results.borrow().is_method_call(expr) {
             debug!("convert_place_op_to_mutable - builtin, nothing to do");
             return;
         }
 
         // Need to deref because overloaded place ops take self by-reference.
         let base_ty = self
-            .tables
+            .typeck_results
             .borrow()
             .expr_ty_adjusted(base_expr)
             .builtin_deref(false)
@@ -306,7 +306,7 @@ fn convert_place_op_to_mutable(
         // region and mutability.
         let base_expr_ty = self.node_ty(base_expr.hir_id);
         if let Some(adjustments) =
-            self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
+            self.typeck_results.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
         {
             let mut source = base_expr_ty;
             for adjustment in &mut adjustments[..] {
index 199f49ca323e023c595d45a55509513119c46158..b72152d1911f7dc5851f627149f7d5d1205335aa 100644 (file)
@@ -82,6 +82,7 @@
 use rustc_hir::PatKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, RegionObligation, RegionckMode};
+use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
@@ -263,7 +264,7 @@ fn visit_fn_body(
         self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
 
         let fn_sig = {
-            match self.tables.borrow().liberated_fn_sigs().get(id) {
+            match self.typeck_results.borrow().liberated_fn_sigs().get(id) {
                 Some(f) => *f,
                 None => {
                     bug!("No fn-sig entry for id={:?}", id);
@@ -433,7 +434,7 @@ fn with_mc<F, R>(&self, f: F) -> R
             &self.infcx,
             self.outlives_environment.param_env,
             self.body_owner,
-            &self.tables.borrow(),
+            &self.typeck_results.borrow(),
         ))
     }
 
@@ -442,13 +443,13 @@ fn with_mc<F, R>(&self, f: F) -> R
     fn constrain_adjustments(
         &mut self,
         expr: &hir::Expr<'_>,
-    ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
+    ) -> mc::McResult<PlaceWithHirId<'tcx>> {
         debug!("constrain_adjustments(expr={:?})", expr);
 
         let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
 
-        let tables = self.tables.borrow();
-        let adjustments = tables.expr_adjustments(&expr);
+        let typeck_results = self.typeck_results.borrow();
+        let adjustments = typeck_results.expr_adjustments(&expr);
         if adjustments.is_empty() {
             return Ok(place);
         }
@@ -483,10 +484,10 @@ fn constrain_adjustments(
 
     fn check_safety_of_rvalue_destructor_if_necessary(
         &mut self,
-        place_with_id: &mc::PlaceWithHirId<'tcx>,
+        place_with_id: &PlaceWithHirId<'tcx>,
         span: Span,
     ) {
-        if let mc::PlaceBase::Rvalue = place_with_id.place.base {
+        if let PlaceBase::Rvalue = place_with_id.place.base {
             if place_with_id.place.projections.is_empty() {
                 let typ = self.resolve_type(place_with_id.place.ty());
                 let body_id = self.body_id;
@@ -573,14 +574,14 @@ fn link_fn_params(&self, params: &[hir::Param<'_>]) {
 
     /// Link lifetimes of any ref bindings in `root_pat` to the pointers found
     /// in the discriminant, if needed.
-    fn link_pattern(&self, discr_cmt: mc::PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
+    fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
         debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
         ignore_err!(self.with_mc(|mc| {
             mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| {
                 // `ref x` pattern
                 if let PatKind::Binding(..) = kind {
                     if let Some(ty::BindByReference(mutbl)) =
-                        mc.tables.extract_binding_mode(self.tcx.sess, *hir_id, *span)
+                        mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span)
                     {
                         self.link_region_from_node_type(*span, *hir_id, mutbl, &sub_cmt);
                     }
@@ -594,7 +595,7 @@ fn link_pattern(&self, discr_cmt: mc::PlaceWithHirId<'tcx>, root_pat: &hir::Pat<
     fn link_autoref(
         &self,
         expr: &hir::Expr<'_>,
-        expr_cmt: &mc::PlaceWithHirId<'tcx>,
+        expr_cmt: &PlaceWithHirId<'tcx>,
         autoref: &adjustment::AutoBorrow<'tcx>,
     ) {
         debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
@@ -615,7 +616,7 @@ fn link_region_from_node_type(
         span: Span,
         id: hir::HirId,
         mutbl: hir::Mutability,
-        cmt_borrowed: &mc::PlaceWithHirId<'tcx>,
+        cmt_borrowed: &PlaceWithHirId<'tcx>,
     ) {
         debug!(
             "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
@@ -638,7 +639,7 @@ fn link_region(
         span: Span,
         borrow_region: ty::Region<'tcx>,
         borrow_kind: ty::BorrowKind,
-        borrow_place: &mc::PlaceWithHirId<'tcx>,
+        borrow_place: &PlaceWithHirId<'tcx>,
     ) {
         let origin = infer::DataBorrowed(borrow_place.place.ty(), span);
         self.type_must_outlive(origin, borrow_place.place.ty(), borrow_region);
@@ -659,7 +660,7 @@ fn link_region(
                 _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty),
             }
         }
-        if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.place.base {
+        if let PlaceBase::Upvar(upvar_id) = borrow_place.place.base {
             self.link_upvar_region(span, borrow_region, upvar_id);
         }
     }
@@ -773,7 +774,7 @@ fn link_upvar_region(
         debug!("link_upvar_region(borrorw_region={:?}, upvar_id={:?}", borrow_region, upvar_id);
         // A by-reference upvar can't be borrowed for longer than the
         // upvar is borrowed from the environment.
-        match self.tables.borrow().upvar_capture(upvar_id) {
+        match self.typeck_results.borrow().upvar_capture(upvar_id) {
             ty::UpvarCapture::ByRef(upvar_borrow) => {
                 self.sub_regions(
                     infer::ReborrowUpvar(span, upvar_id),
index 0f3133e0695f10b5a35c7883a96c03ff46d80398..030c0ab668a8005db6a0a7bbf374697cbfabf06d 100644 (file)
 use super::FnCtxt;
 
 use crate::expr_use_visitor as euv;
-use crate::mem_categorization as mc;
-use crate::mem_categorization::PlaceBase;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::UpvarRegion;
+use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
 use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts};
 use rustc_span::{Span, Symbol};
 
@@ -135,13 +134,16 @@ fn analyze_closure(
                     }
                 };
 
-                self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
+                self.typeck_results.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind);
             }
             // Add the vector of upvars to the map keyed with the closure id.
             // This gives us an easier access to them without having to call
             // tcx.upvars again..
             if !closure_captures.is_empty() {
-                self.tables.borrow_mut().closure_captures.insert(closure_def_id, closure_captures);
+                self.typeck_results
+                    .borrow_mut()
+                    .closure_captures
+                    .insert(closure_def_id, closure_captures);
             }
         }
 
@@ -159,7 +161,7 @@ fn analyze_closure(
             &self.infcx,
             body_owner_def_id,
             self.param_env,
-            &self.tables.borrow(),
+            &self.typeck_results.borrow(),
         )
         .consume_body(body);
 
@@ -172,11 +174,14 @@ fn analyze_closure(
 
             // If we have an origin, store it.
             if let Some(origin) = delegate.current_origin {
-                self.tables.borrow_mut().closure_kind_origins_mut().insert(closure_hir_id, origin);
+                self.typeck_results
+                    .borrow_mut()
+                    .closure_kind_origins_mut()
+                    .insert(closure_hir_id, origin);
             }
         }
 
-        self.tables.borrow_mut().upvar_capture_map.extend(delegate.adjust_upvar_captures);
+        self.typeck_results.borrow_mut().upvar_capture_map.extend(delegate.adjust_upvar_captures);
 
         // Now that we've analyzed the closure, we know how each
         // variable is borrowed, and we know what traits the closure
@@ -227,7 +232,7 @@ fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec<Ty<'tcx>> {
                         var_path: ty::UpvarPath { hir_id: var_hir_id },
                         closure_expr_id: closure_def_id,
                     };
-                    let capture = self.tables.borrow().upvar_capture(upvar_id);
+                    let capture = self.typeck_results.borrow().upvar_capture(upvar_id);
 
                     debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture);
 
@@ -270,7 +275,7 @@ struct InferBorrowKind<'a, 'tcx> {
 impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
     fn adjust_upvar_borrow_kind_for_consume(
         &mut self,
-        place_with_id: &mc::PlaceWithHirId<'tcx>,
+        place_with_id: &PlaceWithHirId<'tcx>,
         mode: euv::ConsumeMode,
     ) {
         debug!(
@@ -309,7 +314,7 @@ fn adjust_upvar_borrow_kind_for_consume(
     /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
     /// to). If the place is based on a by-ref upvar, this implies that
     /// the upvar must be borrowed using an `&mut` borrow.
-    fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) {
+    fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &PlaceWithHirId<'tcx>) {
         debug!("adjust_upvar_borrow_kind_for_mut(place_with_id={:?})", place_with_id);
 
         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
@@ -334,7 +339,7 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &mc::PlaceWithHirI
         }
     }
 
-    fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) {
+    fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &PlaceWithHirId<'tcx>) {
         debug!("adjust_upvar_borrow_kind_for_unique(place_with_id={:?})", place_with_id);
 
         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
@@ -392,7 +397,7 @@ fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKi
             .adjust_upvar_captures
             .get(&upvar_id)
             .copied()
-            .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id));
+            .unwrap_or_else(|| self.fcx.typeck_results.borrow().upvar_capture(upvar_id));
         debug!(
             "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
             upvar_id, upvar_capture, kind
@@ -464,12 +469,12 @@ fn adjust_closure_kind(
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
-    fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) {
+    fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) {
         debug!("consume(place_with_id={:?},mode={:?})", place_with_id, mode);
         self.adjust_upvar_borrow_kind_for_consume(place_with_id, mode);
     }
 
-    fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
+    fn borrow(&mut self, place_with_id: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
         debug!("borrow(place_with_id={:?}, bk={:?})", place_with_id, bk);
 
         match bk {
@@ -483,7 +488,7 @@ fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKin
         }
     }
 
-    fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>) {
+    fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>) {
         debug!("mutate(assignee_place={:?})", assignee_place);
 
         self.adjust_upvar_borrow_kind_for_mut(assignee_place);
index d1a86a7ee89a8af5f7d3e8a6b3d54cf761bdcae6..845a4fcafc2241e31b0c4ab308eff591be9e1edc 100644 (file)
@@ -394,6 +394,7 @@ fn check_type_defn<'tcx, F>(
                                 Some(i) => i,
                                 None => bug!(),
                             },
+                            span: field.span,
                             last,
                         },
                     ),
@@ -422,8 +423,11 @@ fn check_type_defn<'tcx, F>(
                 fcx.register_predicate(traits::Obligation::new(
                     cause,
                     fcx.param_env,
-                    ty::PredicateKind::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs)
-                        .to_predicate(fcx.tcx),
+                    ty::PredicateKind::ConstEvaluatable(
+                        ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
+                        discr_substs,
+                    )
+                    .to_predicate(fcx.tcx),
                 ));
             }
         }
@@ -1326,10 +1330,10 @@ fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx
             .iter()
             .map(|field| {
                 let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
-                let field_ty = self.normalize_associated_types_in(field.span, &field_ty);
+                let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty);
                 let field_ty = self.resolve_vars_if_possible(&field_ty);
                 debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
-                AdtField { ty: field_ty, span: field.span }
+                AdtField { ty: field_ty, span: field.ty.span }
             })
             .collect();
         AdtVariant { fields, explicit_discr: None }
index fa17696e02b3021a226a4b8d406ebf2bdbb8dddb..82ee48f0b53461448e4565705e1a08999f6e9893 100644 (file)
 
 // During type inference, partially inferred types are
 // represented using Type variables (ty::Infer). These don't appear in
-// the final TypeckTables since all of the types should have been
-// inferred once typeck_tables_of is done.
+// the final TypeckResults since all of the types should have been
+// inferred once typeck is done.
 // When type inference is running however, having to update the typeck
-// tables every time a new type is inferred would be unreasonably slow,
+// typeck results every time a new type is inferred would be unreasonably slow,
 // so instead all of the replacement happens at the end in
 // resolve_type_vars_in_body, which creates a new TypeTables which
 // doesn't contain any inference types.
@@ -34,7 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn resolve_type_vars_in_body(
         &self,
         body: &'tcx hir::Body<'tcx>,
-    ) -> &'tcx ty::TypeckTables<'tcx> {
+    ) -> &'tcx ty::TypeckResults<'tcx> {
         let item_id = self.tcx.hir().body_owner(body.id());
         let item_def_id = self.tcx.hir().local_def_id(item_id);
 
@@ -65,36 +65,39 @@ pub fn resolve_type_vars_in_body(
         wbcx.visit_user_provided_sigs();
         wbcx.visit_generator_interior_types();
 
-        let used_trait_imports = mem::take(&mut self.tables.borrow_mut().used_trait_imports);
+        let used_trait_imports =
+            mem::take(&mut self.typeck_results.borrow_mut().used_trait_imports);
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
-        wbcx.tables.used_trait_imports = used_trait_imports;
+        wbcx.typeck_results.used_trait_imports = used_trait_imports;
 
-        wbcx.tables.closure_captures =
-            mem::replace(&mut self.tables.borrow_mut().closure_captures, Default::default());
+        wbcx.typeck_results.closure_captures = mem::replace(
+            &mut self.typeck_results.borrow_mut().closure_captures,
+            Default::default(),
+        );
 
         if self.is_tainted_by_errors() {
             // FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted.
-            wbcx.tables.tainted_by_errors = Some(ErrorReported);
+            wbcx.typeck_results.tainted_by_errors = Some(ErrorReported);
         }
 
-        debug!("writeback: tables for {:?} are {:#?}", item_def_id, wbcx.tables);
+        debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
 
-        self.tcx.arena.alloc(wbcx.tables)
+        self.tcx.arena.alloc(wbcx.typeck_results)
     }
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // The Writeback context. This visitor walks the AST, checking the
-// fn-specific tables to find references to types or regions. It
+// fn-specific typeck results to find references to types or regions. It
 // resolves those regions to remove inference variables and writes the
-// final result back into the master tables in the tcx. Here and
+// final result back into the master typeck results in the tcx. Here and
 // there, it applies a few ad-hoc checks that were not convenient to
 // do elsewhere.
 
 struct WritebackCx<'cx, 'tcx> {
     fcx: &'cx FnCtxt<'cx, 'tcx>,
 
-    tables: ty::TypeckTables<'tcx>,
+    typeck_results: ty::TypeckResults<'tcx>,
 
     body: &'tcx hir::Body<'tcx>,
 
@@ -109,17 +112,22 @@ fn new(
     ) -> WritebackCx<'cx, 'tcx> {
         let owner = body.id().hir_id.owner;
 
-        WritebackCx { fcx, tables: ty::TypeckTables::new(owner), body, rustc_dump_user_substs }
+        WritebackCx {
+            fcx,
+            typeck_results: ty::TypeckResults::new(owner),
+            body,
+            rustc_dump_user_substs,
+        }
     }
 
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.fcx.tcx
     }
 
-    fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
-        debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty);
+    fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
+        debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
         assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
-        self.tables.node_types_mut().insert(hir_id, ty);
+        self.typeck_results.node_types_mut().insert(hir_id, ty);
     }
 
     // Hacky hack: During type-checking, we treat *all* operators
@@ -133,9 +141,9 @@ fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
                 let inner_ty = self.fcx.resolve_vars_if_possible(&inner_ty);
 
                 if inner_ty.is_scalar() {
-                    let mut tables = self.fcx.tables.borrow_mut();
-                    tables.type_dependent_defs_mut().remove(e.hir_id);
-                    tables.node_substs_mut().remove(e.hir_id);
+                    let mut typeck_results = self.fcx.typeck_results.borrow_mut();
+                    typeck_results.type_dependent_defs_mut().remove(e.hir_id);
+                    typeck_results.node_substs_mut().remove(e.hir_id);
                 }
             }
             hir::ExprKind::Binary(ref op, ref lhs, ref rhs)
@@ -147,14 +155,14 @@ fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
                 let rhs_ty = self.fcx.resolve_vars_if_possible(&rhs_ty);
 
                 if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
-                    let mut tables = self.fcx.tables.borrow_mut();
-                    tables.type_dependent_defs_mut().remove(e.hir_id);
-                    tables.node_substs_mut().remove(e.hir_id);
+                    let mut typeck_results = self.fcx.typeck_results.borrow_mut();
+                    typeck_results.type_dependent_defs_mut().remove(e.hir_id);
+                    typeck_results.node_substs_mut().remove(e.hir_id);
 
                     match e.kind {
                         hir::ExprKind::Binary(..) => {
                             if !op.node.is_by_value() {
-                                let mut adjustments = tables.adjustments_mut();
+                                let mut adjustments = typeck_results.adjustments_mut();
                                 if let Some(a) = adjustments.get_mut(lhs.hir_id) {
                                     a.pop();
                                 }
@@ -164,7 +172,7 @@ fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
                             }
                         }
                         hir::ExprKind::AssignOp(..) => {
-                            if let Some(a) = tables.adjustments_mut().get_mut(lhs.hir_id) {
+                            if let Some(a) = typeck_results.adjustments_mut().get_mut(lhs.hir_id) {
                                 a.pop();
                             }
                         }
@@ -182,10 +190,10 @@ fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
     // usize-ish
     fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
         if let hir::ExprKind::Index(ref base, ref index) = e.kind {
-            let mut tables = self.fcx.tables.borrow_mut();
+            let mut typeck_results = self.fcx.typeck_results.borrow_mut();
 
             // 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);
+            let base_ty = typeck_results.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
@@ -193,7 +201,7 @@ fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
                 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(|| {
+                let index_ty = typeck_results.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
@@ -207,10 +215,10 @@ fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
 
                 if base_ty.builtin_index().is_some() && index_ty == self.fcx.tcx.types.usize {
                     // Remove the method call record
-                    tables.type_dependent_defs_mut().remove(e.hir_id);
-                    tables.node_substs_mut().remove(e.hir_id);
+                    typeck_results.type_dependent_defs_mut().remove(e.hir_id);
+                    typeck_results.node_substs_mut().remove(e.hir_id);
 
-                    if let Some(a) = tables.adjustments_mut().get_mut(base.hir_id) {
+                    if let Some(a) = typeck_results.adjustments_mut().get_mut(base.hir_id) {
                         // Discard the need for a mutable borrow
 
                         // Extra adjustment made when indexing causes a drop
@@ -237,7 +245,7 @@ fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
 // This is the master code which walks the AST. It delegates most of
 // the heavy lifting to the generic visit and resolve functions
 // below. In general, a function is made into a `visitor` if it must
-// traffic in node-ids or update tables in the type context etc.
+// traffic in node-ids or update typeck results in the type context etc.
 
 impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
     type Map = intravisit::ErasedMap<'tcx>;
@@ -283,9 +291,11 @@ fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
     fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
         match p.kind {
             hir::PatKind::Binding(..) => {
-                let tables = self.fcx.tables.borrow();
-                if let Some(bm) = tables.extract_binding_mode(self.tcx().sess, p.hir_id, p.span) {
-                    self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
+                let typeck_results = self.fcx.typeck_results.borrow();
+                if let Some(bm) =
+                    typeck_results.extract_binding_mode(self.tcx().sess, p.hir_id, p.span)
+                {
+                    self.typeck_results.pat_binding_modes_mut().insert(p.hir_id, bm);
                 }
             }
             hir::PatKind::Struct(_, fields, _) => {
@@ -306,20 +316,20 @@ fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
         intravisit::walk_local(self, l);
         let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty;
         let var_ty = self.resolve(&var_ty, &l.span);
-        self.write_ty_to_tables(l.hir_id, var_ty);
+        self.write_ty_to_typeck_results(l.hir_id, var_ty);
     }
 
     fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
         intravisit::walk_ty(self, hir_ty);
         let ty = self.fcx.node_ty(hir_ty.hir_id);
         let ty = self.resolve(&ty, &hir_ty.span);
-        self.write_ty_to_tables(hir_ty.hir_id, ty);
+        self.write_ty_to_typeck_results(hir_ty.hir_id, ty);
     }
 }
 
 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     fn visit_upvar_capture_map(&mut self) {
-        for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
+        for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() {
             let new_upvar_capture = match *upvar_capture {
                 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
                 ty::UpvarCapture::ByRef(ref upvar_borrow) => {
@@ -330,38 +340,38 @@ fn visit_upvar_capture_map(&mut self) {
                 }
             };
             debug!("Upvar capture for {:?} resolved to {:?}", upvar_id, new_upvar_capture);
-            self.tables.upvar_capture_map.insert(*upvar_id, new_upvar_capture);
+            self.typeck_results.upvar_capture_map.insert(*upvar_id, new_upvar_capture);
         }
     }
 
     fn visit_closures(&mut self) {
-        let fcx_tables = self.fcx.tables.borrow();
-        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
-        let common_hir_owner = fcx_tables.hir_owner;
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+        let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (&id, &origin) in fcx_tables.closure_kind_origins().iter() {
+        for (&id, &origin) in fcx_typeck_results.closure_kind_origins().iter() {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id: id };
-            self.tables.closure_kind_origins_mut().insert(hir_id, origin);
+            self.typeck_results.closure_kind_origins_mut().insert(hir_id, origin);
         }
     }
 
     fn visit_coercion_casts(&mut self) {
-        let fcx_tables = self.fcx.tables.borrow();
-        let fcx_coercion_casts = fcx_tables.coercion_casts();
-        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        let fcx_coercion_casts = fcx_typeck_results.coercion_casts();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
 
         for local_id in fcx_coercion_casts {
-            self.tables.set_coercion_cast(*local_id);
+            self.typeck_results.set_coercion_cast(*local_id);
         }
     }
 
     fn visit_user_provided_tys(&mut self) {
-        let fcx_tables = self.fcx.tables.borrow();
-        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
-        let common_hir_owner = fcx_tables.hir_owner;
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+        let common_hir_owner = fcx_typeck_results.hir_owner;
 
         let mut errors_buffer = Vec::new();
-        for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() {
+        for (&local_id, c_ty) in fcx_typeck_results.user_provided_types().iter() {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id };
 
             if cfg!(debug_assertions) && c_ty.needs_infer() {
@@ -372,7 +382,7 @@ fn visit_user_provided_tys(&mut self) {
                 );
             };
 
-            self.tables.user_provided_types_mut().insert(hir_id, *c_ty);
+            self.typeck_results.user_provided_types_mut().insert(hir_id, *c_ty);
 
             if let ty::UserType::TypeOf(_, user_substs) = c_ty.value {
                 if self.rustc_dump_user_substs {
@@ -398,10 +408,10 @@ fn visit_user_provided_tys(&mut self) {
     }
 
     fn visit_user_provided_sigs(&mut self) {
-        let fcx_tables = self.fcx.tables.borrow();
-        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
 
-        for (&def_id, c_sig) in fcx_tables.user_provided_sigs.iter() {
+        for (&def_id, c_sig) in fcx_typeck_results.user_provided_sigs.iter() {
             if cfg!(debug_assertions) && c_sig.needs_infer() {
                 span_bug!(
                     self.fcx.tcx.hir().span_if_local(def_id).unwrap(),
@@ -410,14 +420,15 @@ fn visit_user_provided_sigs(&mut self) {
                 );
             };
 
-            self.tables.user_provided_sigs.insert(def_id, *c_sig);
+            self.typeck_results.user_provided_sigs.insert(def_id, *c_sig);
         }
     }
 
     fn visit_generator_interior_types(&mut self) {
-        let fcx_tables = self.fcx.tables.borrow();
-        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
-        self.tables.generator_interior_types = fcx_tables.generator_interior_types.clone();
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+        self.typeck_results.generator_interior_types =
+            fcx_typeck_results.generator_interior_types.clone();
     }
 
     fn visit_opaque_types(&mut self, span: Span) {
@@ -472,7 +483,7 @@ fn visit_opaque_types(&mut self, span: Span) {
                         substs: opaque_defn.substs,
                     };
 
-                    let old = self.tables.concrete_opaque_types.insert(def_id, new);
+                    let old = self.typeck_results.concrete_opaque_types.insert(def_id, new);
                     if let Some(old) = old {
                         if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
                             span_bug!(
@@ -494,15 +505,18 @@ fn visit_opaque_types(&mut self, span: Span) {
     }
 
     fn visit_field_id(&mut self, hir_id: hir::HirId) {
-        if let Some(index) = self.fcx.tables.borrow_mut().field_indices_mut().remove(hir_id) {
-            self.tables.field_indices_mut().insert(hir_id, index);
+        if let Some(index) = self.fcx.typeck_results.borrow_mut().field_indices_mut().remove(hir_id)
+        {
+            self.typeck_results.field_indices_mut().insert(hir_id, index);
         }
     }
 
     fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) {
         // Export associated path extensions and method resolutions.
-        if let Some(def) = self.fcx.tables.borrow_mut().type_dependent_defs_mut().remove(hir_id) {
-            self.tables.type_dependent_defs_mut().insert(hir_id, def);
+        if let Some(def) =
+            self.fcx.typeck_results.borrow_mut().type_dependent_defs_mut().remove(hir_id)
+        {
+            self.typeck_results.type_dependent_defs_mut().insert(hir_id, def);
         }
 
         // Resolve any borrowings for the node with id `node_id`
@@ -511,20 +525,20 @@ fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) {
         // Resolve the type of the node with id `node_id`
         let n_ty = self.fcx.node_ty(hir_id);
         let n_ty = self.resolve(&n_ty, &span);
-        self.write_ty_to_tables(hir_id, n_ty);
+        self.write_ty_to_typeck_results(hir_id, n_ty);
         debug!("node {:?} has type {:?}", hir_id, n_ty);
 
         // Resolve any substitutions
-        if let Some(substs) = self.fcx.tables.borrow().node_substs_opt(hir_id) {
+        if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) {
             let substs = self.resolve(&substs, &span);
             debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs);
             assert!(!substs.needs_infer() && !substs.has_placeholders());
-            self.tables.node_substs_mut().insert(hir_id, substs);
+            self.typeck_results.node_substs_mut().insert(hir_id, substs);
         }
     }
 
     fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
-        let adjustment = self.fcx.tables.borrow_mut().adjustments_mut().remove(hir_id);
+        let adjustment = self.fcx.typeck_results.borrow_mut().adjustments_mut().remove(hir_id);
         match adjustment {
             None => {
                 debug!("no adjustments for node {:?}", hir_id);
@@ -533,13 +547,13 @@ fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
             Some(adjustment) => {
                 let resolved_adjustment = self.resolve(&adjustment, &span);
                 debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
-                self.tables.adjustments_mut().insert(hir_id, resolved_adjustment);
+                self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment);
             }
         }
     }
 
     fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
-        let adjustment = self.fcx.tables.borrow_mut().pat_adjustments_mut().remove(hir_id);
+        let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id);
         match adjustment {
             None => {
                 debug!("no pat_adjustments for node {:?}", hir_id);
@@ -548,32 +562,32 @@ fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
             Some(adjustment) => {
                 let resolved_adjustment = self.resolve(&adjustment, &span);
                 debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
-                self.tables.pat_adjustments_mut().insert(hir_id, resolved_adjustment);
+                self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment);
             }
         }
     }
 
     fn visit_liberated_fn_sigs(&mut self) {
-        let fcx_tables = self.fcx.tables.borrow();
-        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
-        let common_hir_owner = fcx_tables.hir_owner;
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+        let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs().iter() {
+        for (&local_id, fn_sig) in fcx_typeck_results.liberated_fn_sigs().iter() {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let fn_sig = self.resolve(fn_sig, &hir_id);
-            self.tables.liberated_fn_sigs_mut().insert(hir_id, fn_sig);
+            self.typeck_results.liberated_fn_sigs_mut().insert(hir_id, fn_sig);
         }
     }
 
     fn visit_fru_field_types(&mut self) {
-        let fcx_tables = self.fcx.tables.borrow();
-        assert_eq!(fcx_tables.hir_owner, self.tables.hir_owner);
-        let common_hir_owner = fcx_tables.hir_owner;
+        let fcx_typeck_results = self.fcx.typeck_results.borrow();
+        assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+        let common_hir_owner = fcx_typeck_results.hir_owner;
 
-        for (&local_id, ftys) in fcx_tables.fru_field_types().iter() {
+        for (&local_id, ftys) in fcx_typeck_results.fru_field_types().iter() {
             let hir_id = hir::HirId { owner: common_hir_owner, local_id };
             let ftys = self.resolve(ftys, &hir_id);
-            self.tables.fru_field_types_mut().insert(hir_id, ftys);
+            self.typeck_results.fru_field_types_mut().insert(hir_id, ftys);
         }
     }
 
@@ -588,11 +602,11 @@ fn resolve<T>(&mut self, x: &T, span: &dyn Locatable) -> T
         }
 
         // We may have introduced e.g. `ty::Error`, if inference failed, make sure
-        // to mark the `TypeckTables` as tainted in that case, so that downstream
-        // users of the tables don't produce extra errors, or worse, ICEs.
+        // to mark the `TypeckResults` as tainted in that case, so that downstream
+        // users of the typeck results don't produce extra errors, or worse, ICEs.
         if resolver.replaced_with_error {
             // FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted.
-            self.tables.tainted_by_errors = Some(ErrorReported);
+            self.typeck_results.tainted_by_errors = Some(ErrorReported);
         }
 
         x
index 15481660a52186d3ee67d37e133baefd6a04b1af..ec534aa925d4f2b58fd12463e33022440bff6de4 100644 (file)
@@ -29,7 +29,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, Node};
+use rustc_hir::{GenericParamKind, HirId, Node};
 use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -64,6 +64,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
+        opt_const_param_of: type_of::opt_const_param_of,
         type_of: type_of::type_of,
         generics_of,
         predicates_of,
@@ -129,7 +130,7 @@ struct CollectItemTypesVisitor<'tcx> {
 /// all already existing generic type parameters to avoid suggesting a name that is already in use.
 crate fn placeholder_type_error(
     tcx: TyCtxt<'tcx>,
-    span: Span,
+    span: Option<Span>,
     generics: &[hir::GenericParam<'_>],
     placeholder_types: Vec<Span>,
     suggest: bool,
@@ -137,12 +138,15 @@ struct CollectItemTypesVisitor<'tcx> {
     if placeholder_types.is_empty() {
         return;
     }
-    let type_name = generics.next_type_param_name(None);
 
+    let type_name = generics.next_type_param_name(None);
     let mut sugg: Vec<_> =
         placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
+
     if generics.is_empty() {
-        sugg.push((span, format!("<{}>", type_name)));
+        if let Some(span) = span {
+            sugg.push((span, format!("<{}>", type_name)));
+        }
     } else if let Some(arg) = generics.iter().find(|arg| match arg.name {
         hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
         _ => false,
@@ -158,6 +162,7 @@ struct CollectItemTypesVisitor<'tcx> {
             format!(", {}", type_name),
         ));
     }
+
     let mut err = bad_placeholder_type(tcx, placeholder_types);
     if suggest {
         err.multipart_suggestion(
@@ -186,7 +191,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
     let mut visitor = PlaceholderHirTyCollector::default();
     visitor.visit_item(item);
 
-    placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest);
+    placeholder_type_error(tcx, Some(generics.span), &generics.params[..], visitor.0, suggest);
 }
 
 impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -722,7 +727,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) {
             // Account for `const C: _;` and `type T = _;`.
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false);
+            placeholder_type_error(tcx, None, &[], visitor.0, false);
         }
 
         hir::TraitItemKind::Type(_, None) => {}
@@ -745,7 +750,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) {
             // Account for `type T = _;`
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_impl_item(impl_item);
-            placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false);
+            placeholder_type_error(tcx, None, &[], visitor.0, false);
         }
         hir::ImplItemKind::Const(..) => {}
     }
@@ -1150,6 +1155,35 @@ fn has_late_bound_regions<'tcx>(
     }
 }
 
+struct AnonConstInParamListDetector {
+    in_param_list: bool,
+    found_anon_const_in_list: bool,
+    ct: HirId,
+}
+
+impl<'v> Visitor<'v> for AnonConstInParamListDetector {
+    type Map = intravisit::ErasedMap<'v>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
+        let prev = self.in_param_list;
+        self.in_param_list = true;
+        intravisit::walk_generic_param(self, p);
+        self.in_param_list = prev;
+    }
+
+    fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
+        if self.in_param_list && self.ct == c.hir_id {
+            self.found_anon_const_in_list = true;
+        } else {
+            intravisit::walk_anon_const(self, c)
+        }
+    }
+}
+
 fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
     use rustc_hir::*;
 
@@ -1171,10 +1205,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             let parent_id = tcx.hir().get_parent_item(hir_id);
             let parent_def_id = tcx.hir().local_def_id(parent_id);
 
-            // HACK(eddyb) this provides the correct generics when
-            // `feature(const_generics)` is enabled, so that const expressions
-            // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
-            if tcx.lazy_normalization() {
+            let mut in_param_list = false;
+            for (_parent, node) in tcx.hir().parent_iter(hir_id) {
+                if let Some(generics) = node.generics() {
+                    let mut visitor = AnonConstInParamListDetector {
+                        in_param_list: false,
+                        found_anon_const_in_list: false,
+                        ct: hir_id,
+                    };
+
+                    visitor.visit_generics(generics);
+                    in_param_list = visitor.found_anon_const_in_list;
+                    break;
+                }
+            }
+
+            if in_param_list {
+                // We do not allow generic parameters in anon consts if we are inside
+                // of a param list.
+                //
+                // This affects both default type bindings, e.g. `struct<T, U = [u8; std::mem::size_of::<T>()]>(T, U)`,
+                // and the types of const parameters, e.g. `struct V<const N: usize, const M: [u8; N]>();`.
+                None
+            } else if tcx.lazy_normalization() {
+                // HACK(eddyb) this provides the correct generics when
+                // `feature(const_generics)` is enabled, so that const expressions
+                // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
                 Some(parent_def_id.to_def_id())
             } else {
                 let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
@@ -1459,7 +1515,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
         | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => {
             match get_infer_ret_ty(&sig.decl.output) {
                 Some(ty) => {
-                    let fn_sig = tcx.typeck_tables_of(def_id).liberated_fn_sigs()[hir_id];
+                    let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
                     let mut visitor = PlaceholderHirTyCollector::default();
                     visitor.visit_ty(ty);
                     let mut diag = bad_placeholder_type(tcx, visitor.0);
index 3dd9c9c5c39dbc4781a60c55d671057248371d4c..8c9cd50a17d6a63ba6b95102951e16b70d4e6b1f 100644 (file)
 use super::ItemCtxt;
 use super::{bad_placeholder_type, is_suggestable_infer_ty};
 
+/// Computes the relevant generic parameter for a potential generic const argument.
+///
+/// This should be called using the query `tcx.opt_const_param_of`.
+pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
+    use hir::*;
+
+    let hir_id = tcx.hir().as_local_hir_id(def_id);
+
+    if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
+        let parent_node_id = tcx.hir().get_parent_node(hir_id);
+        let parent_node = tcx.hir().get(parent_node_id);
+
+        match parent_node {
+            Node::Expr(&Expr {
+                kind:
+                    ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
+                ..
+            }) => {
+                let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+                let tables = tcx.typeck(body_owner);
+                // This may fail in case the method/path does not actually exist.
+                // As there is no relevant param for `def_id`, we simply return
+                // `None` here.
+                let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
+                let idx = segment
+                    .args
+                    .and_then(|args| {
+                        args.args
+                            .iter()
+                            .filter(|arg| arg.is_const())
+                            .position(|arg| arg.id() == hir_id)
+                    })
+                    .unwrap_or_else(|| {
+                        bug!("no arg matching AnonConst in segment");
+                    });
+
+                tcx.generics_of(type_dependent_def)
+                    .params
+                    .iter()
+                    .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const))
+                    .nth(idx)
+                    .map(|param| param.def_id)
+            }
+
+            Node::Ty(&Ty { kind: TyKind::Path(_), .. })
+            | Node::Expr(&Expr { kind: ExprKind::Struct(..), .. })
+            | Node::Expr(&Expr { kind: ExprKind::Path(_), .. })
+            | Node::TraitRef(..) => {
+                let path = match parent_node {
+                    Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
+                    | Node::TraitRef(&TraitRef { path, .. }) => &*path,
+                    Node::Expr(&Expr {
+                        kind:
+                            ExprKind::Path(QPath::Resolved(_, path))
+                            | ExprKind::Struct(&QPath::Resolved(_, path), ..),
+                        ..
+                    }) => {
+                        let body_owner =
+                            tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+                        let _tables = tcx.typeck(body_owner);
+                        &*path
+                    }
+                    _ => span_bug!(DUMMY_SP, "unexpected const parent path {:?}", parent_node),
+                };
+
+                // We've encountered an `AnonConst` in some path, so we need to
+                // figure out which generic parameter it corresponds to and return
+                // the relevant type.
+
+                let (arg_index, segment) = path
+                    .segments
+                    .iter()
+                    .filter_map(|seg| seg.args.map(|args| (args.args, seg)))
+                    .find_map(|(args, seg)| {
+                        args.iter()
+                            .filter(|arg| arg.is_const())
+                            .position(|arg| arg.id() == hir_id)
+                            .map(|index| (index, seg))
+                    })
+                    .unwrap_or_else(|| {
+                        bug!("no arg matching AnonConst in path");
+                    });
+
+                // Try to use the segment resolution if it is valid, otherwise we
+                // default to the path resolution.
+                let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
+                let generics = match res {
+                    Res::Def(DefKind::Ctor(..), def_id) => {
+                        tcx.generics_of(tcx.parent(def_id).unwrap())
+                    }
+                    Res::Def(_, def_id) => tcx.generics_of(def_id),
+                    Res::Err => {
+                        tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
+                        return None;
+                    }
+                    _ => span_bug!(
+                        DUMMY_SP,
+                        "unexpected anon const res {:?} in path: {:?}",
+                        res,
+                        path,
+                    ),
+                };
+
+                generics
+                    .params
+                    .iter()
+                    .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const))
+                    .nth(arg_index)
+                    .map(|param| param.def_id)
+            }
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
 pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
+    let def_id = def_id.expect_local();
     use rustc_hir::*;
 
-    let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
+    let hir_id = tcx.hir().as_local_hir_id(def_id);
 
-    let icx = ItemCtxt::new(tcx, def_id);
+    let icx = ItemCtxt::new(tcx, def_id.to_def_id());
 
     match tcx.hir().get(hir_id) {
         Node::TraitItem(item) => match item.kind {
             TraitItemKind::Fn(..) => {
-                let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                tcx.mk_fn_def(def_id, substs)
+                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
             TraitItemKind::Const(ref ty, body_id) => body_id
                 .and_then(|body_id| {
                     if is_suggestable_infer_ty(ty) {
-                        Some(infer_placeholder_type(
-                            tcx,
-                            def_id.expect_local(),
-                            body_id,
-                            ty.span,
-                            item.ident,
-                        ))
+                        Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
                     } else {
                         None
                     }
@@ -53,12 +165,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         Node::ImplItem(item) => match item.kind {
             ImplItemKind::Fn(..) => {
-                let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                tcx.mk_fn_def(def_id, substs)
+                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
             ImplItemKind::Const(ref ty, body_id) => {
                 if is_suggestable_infer_ty(ty) {
-                    infer_placeholder_type(tcx, def_id.expect_local(), body_id, ty.span, item.ident)
+                    infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
                 } else {
                     icx.to_ty(ty)
                 }
@@ -76,13 +188,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             match item.kind {
                 ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => {
                     if is_suggestable_infer_ty(ty) {
-                        infer_placeholder_type(
-                            tcx,
-                            def_id.expect_local(),
-                            body_id,
-                            ty.span,
-                            item.ident,
-                        )
+                        infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
                     } else {
                         icx.to_ty(ty)
                     }
@@ -91,37 +197,37 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     icx.to_ty(self_ty)
                 }
                 ItemKind::Fn(..) => {
-                    let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                    tcx.mk_fn_def(def_id, substs)
+                    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                    tcx.mk_fn_def(def_id.to_def_id(), substs)
                 }
                 ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
                     let def = tcx.adt_def(def_id);
-                    let substs = InternalSubsts::identity_for_item(tcx, def_id);
+                    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                     tcx.mk_adt(def, substs)
                 }
                 ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::Binding, .. }) => {
-                    let_position_impl_trait_type(tcx, def_id.expect_local())
+                    let_position_impl_trait_type(tcx, def_id)
                 }
                 ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => {
-                    find_opaque_ty_constraints(tcx, def_id.expect_local())
+                    find_opaque_ty_constraints(tcx, def_id)
                 }
                 // Opaque types desugared from `impl Trait`.
                 ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
                     let concrete_ty = tcx
                         .mir_borrowck(owner.expect_local())
                         .concrete_opaque_types
-                        .get(&def_id)
+                        .get(&def_id.to_def_id())
                         .map(|opaque| opaque.concrete_type)
                         .unwrap_or_else(|| {
                             tcx.sess.delay_span_bug(
                                 DUMMY_SP,
                                 &format!(
-                                    "owner {:?} has no opaque type for {:?} in its tables",
+                                    "owner {:?} has no opaque type for {:?} in its typeck results",
                                     owner, def_id,
                                 ),
                             );
                             if let Some(ErrorReported) =
-                                tcx.typeck_tables_of(owner.expect_local()).tainted_by_errors
+                                tcx.typeck(owner.expect_local()).tainted_by_errors
                             {
                                 // Some error in the
                                 // owner fn prevented us from populating
@@ -132,8 +238,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                                 // resolves to itself. Return the non-revealed
                                 // type, which should result in E0720.
                                 tcx.mk_opaque(
-                                    def_id,
-                                    InternalSubsts::identity_for_item(tcx, def_id),
+                                    def_id.to_def_id(),
+                                    InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
                                 )
                             }
                         });
@@ -158,11 +264,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         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)
+                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
             ForeignItemKind::Static(ref t, _) => icx.to_ty(t),
-            ForeignItemKind::Type => tcx.mk_foreign(def_id),
+            ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
         },
 
         Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
@@ -170,23 +276,29 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 tcx.type_of(tcx.hir().get_parent_did(hir_id).to_def_id())
             }
             VariantData::Tuple(..) => {
-                let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                tcx.mk_fn_def(def_id, substs)
+                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
         },
 
         Node::Field(field) => icx.to_ty(&field.ty),
 
         Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
-            let substs = InternalSubsts::identity_for_item(tcx, def_id);
+            let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
             if let Some(movability) = gen {
-                tcx.mk_generator(def_id, substs, movability)
+                tcx.mk_generator(def_id.to_def_id(), substs, movability)
             } else {
-                tcx.mk_closure(def_id, substs)
+                tcx.mk_closure(def_id.to_def_id(), substs)
             }
         }
 
         Node::AnonConst(_) => {
+            if let Some(param) = tcx.opt_const_param_of(def_id) {
+                // We defer to `type_of` of the corresponding parameter
+                // for generic arguments.
+                return tcx.type_of(param);
+            }
+
             let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
             match parent_node {
                 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
@@ -203,94 +315,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     .discr_type()
                     .to_ty(tcx),
 
-                Node::Ty(&Ty { kind: TyKind::Path(_), .. })
-                | Node::Expr(&Expr { kind: ExprKind::Struct(..) | ExprKind::Path(_), .. })
-                | Node::TraitRef(..) => {
-                    let path = match parent_node {
-                        Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
-                        | Node::Expr(&Expr {
-                            kind:
-                                ExprKind::Path(QPath::Resolved(_, path))
-                                | ExprKind::Struct(&QPath::Resolved(_, path), ..),
-                            ..
-                        })
-                        | Node::TraitRef(&TraitRef { path, .. }) => &*path,
-                        _ => {
-                            return tcx.ty_error_with_message(
-                                DUMMY_SP,
-                                &format!("unexpected const parent path {:?}", parent_node),
-                            );
-                        }
-                    };
-
-                    // We've encountered an `AnonConst` in some path, so we need to
-                    // figure out which generic parameter it corresponds to and return
-                    // the relevant type.
-
-                    let (arg_index, segment) = path
-                        .segments
-                        .iter()
-                        .filter_map(|seg| seg.args.as_ref().map(|args| (args.args, seg)))
-                        .find_map(|(args, seg)| {
-                            args.iter()
-                                .filter(|arg| arg.is_const())
-                                .enumerate()
-                                .filter(|(_, arg)| arg.id() == hir_id)
-                                .map(|(index, _)| (index, seg))
-                                .next()
-                        })
-                        .unwrap_or_else(|| {
-                            bug!("no arg matching AnonConst in path");
-                        });
-
-                    // Try to use the segment resolution if it is valid, otherwise we
-                    // default to the path resolution.
-                    let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
-                    let generics = match res {
-                        Res::Def(DefKind::Ctor(..), def_id) => {
-                            tcx.generics_of(tcx.parent(def_id).unwrap())
-                        }
-                        Res::Def(_, def_id) => tcx.generics_of(def_id),
-                        res => {
-                            return tcx.ty_error_with_message(
-                                DUMMY_SP,
-                                &format!(
-                                    "unexpected anon const res {:?} in path: {:?}",
-                                    res, path,
-                                ),
-                                );
-                        }
-                    };
-
-                    let ty = generics
-                        .params
-                        .iter()
-                        .filter(|param| {
-                            if let ty::GenericParamDefKind::Const = param.kind {
-                                true
-                            } else {
-                                false
-                            }
-                        })
-                        .nth(arg_index)
-                        .map(|param| tcx.type_of(param.def_id));
-
-                    if let Some(ty) = ty {
-                        ty
-                    } else {
-                        // This is no generic parameter associated with the arg. This is
-                        // probably from an extra arg where one is not needed.
-                        tcx.ty_error_with_message(
-                            DUMMY_SP,
-                            &format!(
-                                "missing generic parameter for `AnonConst`, \
-                                 parent: {:?}, res: {:?}",
-                                parent_node, res
-                            ),
-                        )
-                    }
-                }
-
                 x => tcx.ty_error_with_message(
                     DUMMY_SP,
                     &format!("unexpected const parent in type_of_def_id(): {:?}", x),
@@ -387,16 +411,16 @@ struct ConstraintLocator<'tcx> {
     impl ConstraintLocator<'_> {
         fn check(&mut self, def_id: LocalDefId) {
             // Don't try to check items that cannot possibly constrain the type.
-            if !self.tcx.has_typeck_tables(def_id) {
+            if !self.tcx.has_typeck_results(def_id) {
                 debug!(
-                    "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables",
+                    "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no typeck results",
                     self.def_id, def_id,
                 );
                 return;
             }
             // Calling `mir_borrowck` can lead to cycle errors through
             // const-checking, avoid calling it if we don't have to.
-            if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) {
+            if !self.tcx.typeck(def_id).concrete_opaque_types.contains_key(&self.def_id) {
                 debug!(
                     "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
                     self.def_id, def_id,
@@ -580,8 +604,8 @@ fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty
 
     let opaque_ty_def_id = opaque_ty_id.to_def_id();
 
-    let owner_tables = tcx.typeck_tables_of(scope_def_id);
-    let concrete_ty = owner_tables
+    let owner_typeck_results = tcx.typeck(scope_def_id);
+    let concrete_ty = owner_typeck_results
         .concrete_opaque_types
         .get(&opaque_ty_def_id)
         .map(|opaque| opaque.concrete_type)
@@ -589,11 +613,11 @@ fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty
             tcx.sess.delay_span_bug(
                 DUMMY_SP,
                 &format!(
-                    "owner {:?} has no opaque type for {:?} in its tables",
+                    "owner {:?} has no opaque type for {:?} in its typeck results",
                     scope_def_id, opaque_ty_id
                 ),
             );
-            if let Some(ErrorReported) = owner_tables.tainted_by_errors {
+            if let Some(ErrorReported) = owner_typeck_results.tainted_by_errors {
                 // Some error in the owner fn prevented us from populating the
                 // `concrete_opaque_types` table.
                 tcx.ty_error()
@@ -625,7 +649,7 @@ fn infer_placeholder_type(
     span: Span,
     item_ident: Ident,
 ) -> Ty<'_> {
-    let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id);
+    let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
 
     // If this came from a free `const` or `static mut?` item,
     // then the user may have written e.g. `const A = 42;`.
index 4e5ef4329c2c612bc68843cf0255d9e0188519f4..d1b386c9d4d47279ca3915cb5256f94a8b03d1be 100644 (file)
@@ -5,14 +5,17 @@
 pub use self::ConsumeMode::*;
 
 // Export these here so that Clippy can use them.
-pub use mc::{PlaceBase, PlaceWithHirId, Projection};
+pub use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId, Projection};
 
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::PatKind;
+use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
+use rustc_middle::hir::place::ProjectionKind;
 use rustc_middle::ty::{self, adjustment, TyCtxt};
+use rustc_target::abi::VariantIdx;
 
 use crate::mem_categorization as mc;
 use rustc_span::Span;
 pub trait Delegate<'tcx> {
     // The value found at `place` is either copied or moved, depending
     // on mode.
-    fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: ConsumeMode);
+    fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, mode: ConsumeMode);
 
     // The value found at `place` is being borrowed with kind `bk`.
-    fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind);
+    fn borrow(&mut self, place_with_id: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind);
 
     // The path at `place_with_id` is being assigned to.
-    fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>);
+    fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>);
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -80,16 +83,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
     ///
     /// - `delegate` -- who receives the callbacks
     /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
-    /// - `tables` --- typeck results for the code being analyzed
+    /// - `typeck_results` --- typeck results for the code being analyzed
     pub fn new(
         delegate: &'a mut (dyn Delegate<'tcx> + 'a),
         infcx: &'a InferCtxt<'a, 'tcx>,
         body_owner: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
-        tables: &'a ty::TypeckTables<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
     ) -> Self {
         ExprUseVisitor {
-            mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, tables),
+            mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, typeck_results),
             delegate,
         }
     }
@@ -294,7 +297,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) {
             }
 
             hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => {
-                if self.mc.tables.is_method_call(expr) {
+                if self.mc.typeck_results.is_method_call(expr) {
                     self.consume_expr(lhs);
                 } else {
                     self.mutate_expr(lhs);
@@ -388,14 +391,15 @@ fn walk_struct_expr(
             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() {
-                    let is_mentioned = fields
-                        .iter()
-                        .any(|f| self.tcx().field_index(f.hir_id, self.mc.tables) == f_index);
+                    let is_mentioned = fields.iter().any(|f| {
+                        self.tcx().field_index(f.hir_id, self.mc.typeck_results) == f_index
+                    });
                     if !is_mentioned {
                         let field_place = self.mc.cat_projection(
                             &*with_expr,
                             with_place.clone(),
                             with_field.ty(self.tcx(), substs),
+                            ProjectionKind::Field(f_index as u32, VariantIdx::new(0)),
                         );
                         self.delegate_consume(&field_place);
                     }
@@ -421,7 +425,7 @@ fn walk_struct_expr(
     // consumed or borrowed as part of the automatic adjustment
     // process.
     fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
-        let adjustments = self.mc.tables.expr_adjustments(expr);
+        let adjustments = self.mc.typeck_results.expr_adjustments(expr);
         let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
@@ -459,7 +463,7 @@ fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
     fn walk_autoref(
         &mut self,
         expr: &hir::Expr<'_>,
-        base_place: &mc::PlaceWithHirId<'tcx>,
+        base_place: &PlaceWithHirId<'tcx>,
         autoref: &adjustment::AutoBorrow<'tcx>,
     ) {
         debug!(
@@ -505,7 +509,9 @@ fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
         return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
             if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
                 debug!("walk_pat: binding place={:?} pat={:?}", place, pat,);
-                if let Some(bm) = mc.tables.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) {
+                if let Some(bm) =
+                    mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
+                {
                     debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
 
                     // pat_ty: the type of the binding being produced.
@@ -546,7 +552,7 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>, fn_decl_span: Span) {
                     var_path: ty::UpvarPath { hir_id: var_id },
                     closure_expr_id: closure_def_id,
                 };
-                let upvar_capture = self.mc.tables.upvar_capture(upvar_id);
+                let upvar_capture = self.mc.typeck_results.upvar_capture(upvar_id);
                 let captured_place = return_if_err!(self.cat_captured_var(
                     closure_expr.hir_id,
                     fn_decl_span,
@@ -570,7 +576,7 @@ fn cat_captured_var(
         closure_hir_id: hir::HirId,
         closure_span: Span,
         var_id: hir::HirId,
-    ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
+    ) -> mc::McResult<PlaceWithHirId<'tcx>> {
         // Create the place for the variable being borrowed, from the
         // perspective of the creator (parent) of the closure.
         let var_ty = self.mc.node_ty(var_id)?;
index ac42ce80689ec1a4cdbfafdecc15efd81b85eb41..afc7cb346eb428299fec3bb7093a749d2916e30c 100644 (file)
 //! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
 //! tied to `x`. The type of `x'` will be a borrowed pointer.
 
+use rustc_middle::hir::place::*;
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
+use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::PatKind;
+use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
 use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::infer::InferCtxtExt;
 
-#[derive(Clone, Debug)]
-pub enum PlaceBase {
-    /// A temporary variable
-    Rvalue,
-    /// A named `static` item
-    StaticItem,
-    /// A named local variable
-    Local(hir::HirId),
-    /// An upvar referenced by closure env
-    Upvar(ty::UpvarId),
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum ProjectionKind {
-    /// A dereference of a pointer, reference or `Box<T>` of the given type
-    Deref,
-    /// An index or a field
-    Other,
-}
-
-#[derive(Clone, Debug)]
-pub struct Projection<'tcx> {
-    // Type after the projection is being applied.
-    ty: Ty<'tcx>,
-
-    /// Defines the type of access
-    kind: ProjectionKind,
-}
-
-/// A `Place` represents how a value is located in memory.
-///
-/// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug)]
-pub struct Place<'tcx> {
-    /// The type of the `PlaceBase`
-    pub base_ty: Ty<'tcx>,
-    /// The "outermost" place that holds this value.
-    pub base: PlaceBase,
-    /// How this place is derived from the base place.
-    pub projections: Vec<Projection<'tcx>>,
-}
-
-/// A `PlaceWithHirId` represents how a value is located in memory.
-///
-/// This is an HIR version of `mir::Place`
-#[derive(Clone, Debug)]
-pub struct PlaceWithHirId<'tcx> {
-    /// `HirId` of the expression or pattern producing this value.
-    pub hir_id: hir::HirId,
-
-    /// Information about the `Place`
-    pub place: Place<'tcx>,
-}
-
-impl<'tcx> PlaceWithHirId<'tcx> {
-    crate fn new(
-        hir_id: hir::HirId,
-        base_ty: Ty<'tcx>,
-        base: PlaceBase,
-        projections: Vec<Projection<'tcx>>,
-    ) -> PlaceWithHirId<'tcx> {
-        PlaceWithHirId {
-            hir_id: hir_id,
-            place: Place { base_ty: base_ty, base: base, projections: projections },
-        }
-    }
-}
-
-impl<'tcx> Place<'tcx> {
-    /// Returns an iterator of the types that have to be dereferenced to access
-    /// the `Place`.
-    ///
-    /// The types are in the reverse order that they are applied. So if
-    /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
-    ///`*const u32` then `&*const u32`.
-    crate fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
-        self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
-            if ProjectionKind::Deref == proj.kind {
-                Some(self.ty_before_projection(index))
-            } else {
-                None
-            }
-        })
-    }
-
-    // Returns the type of this `Place` after all projections have been applied.
-    pub fn ty(&self) -> Ty<'tcx> {
-        self.projections.last().map_or_else(|| self.base_ty, |proj| proj.ty)
-    }
-
-    // Returns the type of this `Place` immediately before `projection_index`th projection
-    // is applied.
-    crate fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
-        assert!(projection_index < self.projections.len());
-        if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
-    }
-}
-
 crate trait HirNode {
     fn hir_id(&self) -> hir::HirId;
     fn span(&self) -> Span;
@@ -184,7 +90,7 @@ fn span(&self) -> Span {
 
 #[derive(Clone)]
 crate struct MemCategorizationContext<'a, 'tcx> {
-    crate tables: &'a ty::TypeckTables<'tcx>,
+    crate typeck_results: &'a ty::TypeckResults<'tcx>,
     infcx: &'a InferCtxt<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body_owner: LocalDefId,
@@ -199,10 +105,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         infcx: &'a InferCtxt<'a, 'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         body_owner: LocalDefId,
-        tables: &'a ty::TypeckTables<'tcx>,
+        typeck_results: &'a ty::TypeckResults<'tcx>,
     ) -> MemCategorizationContext<'a, 'tcx> {
         MemCategorizationContext {
-            tables,
+            typeck_results,
             infcx,
             param_env,
             body_owner,
@@ -257,15 +163,15 @@ fn resolve_type_vars_or_error(
     }
 
     crate fn node_ty(&self, hir_id: hir::HirId) -> McResult<Ty<'tcx>> {
-        self.resolve_type_vars_or_error(hir_id, self.tables.node_type_opt(hir_id))
+        self.resolve_type_vars_or_error(hir_id, self.typeck_results.node_type_opt(hir_id))
     }
 
     fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
-        self.resolve_type_vars_or_error(expr.hir_id, self.tables.expr_ty_opt(expr))
+        self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_opt(expr))
     }
 
     crate fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
-        self.resolve_type_vars_or_error(expr.hir_id, self.tables.expr_ty_adjusted_opt(expr))
+        self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_adjusted_opt(expr))
     }
 
     /// Returns the type of value that this pattern matches against.
@@ -283,7 +189,7 @@ fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
         // that these are never attached to binding patterns, so
         // actually this is somewhat "disjoint" from the code below
         // that aims to account for `ref x`.
-        if let Some(vec) = self.tables.pat_adjustments().get(pat.hir_id) {
+        if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) {
             if let Some(first_ty) = vec.first() {
                 debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
                 return Ok(first_ty);
@@ -302,8 +208,11 @@ fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
         // and if so, figures out what the type *being borrowed* is.
         let ret_ty = match pat.kind {
             PatKind::Binding(..) => {
-                let bm =
-                    *self.tables.pat_binding_modes().get(pat.hir_id).expect("missing binding mode");
+                let bm = *self
+                    .typeck_results
+                    .pat_binding_modes()
+                    .get(pat.hir_id)
+                    .expect("missing binding mode");
 
                 if let ty::BindByReference(_) = bm {
                     // a bind-by-ref means that the base_ty will be the type of the ident itself,
@@ -343,7 +252,7 @@ fn helper<'a, 'tcx>(
             }
         }
 
-        helper(self, expr, self.tables.expr_adjustments(expr))
+        helper(self, expr, self.typeck_results.expr_adjustments(expr))
     }
 
     crate fn cat_expr_adjusted(
@@ -395,7 +304,7 @@ fn cat_expr_adjusted_with<F>(
         let expr_ty = self.expr_ty(expr)?;
         match expr.kind {
             hir::ExprKind::Unary(hir::UnOp::UnDeref, ref e_base) => {
-                if self.tables.is_method_call(expr) {
+                if self.typeck_results.is_method_call(expr) {
                     self.cat_overloaded_place(expr, e_base)
                 } else {
                     let base = self.cat_expr(&e_base)?;
@@ -406,11 +315,24 @@ fn cat_expr_adjusted_with<F>(
             hir::ExprKind::Field(ref base, _) => {
                 let base = self.cat_expr(&base)?;
                 debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
-                Ok(self.cat_projection(expr, base, expr_ty))
+
+                let field_idx = self
+                    .typeck_results
+                    .field_indices()
+                    .get(expr.hir_id)
+                    .cloned()
+                    .expect("Field index not found");
+
+                Ok(self.cat_projection(
+                    expr,
+                    base,
+                    expr_ty,
+                    ProjectionKind::Field(field_idx as u32, VariantIdx::new(0)),
+                ))
             }
 
             hir::ExprKind::Index(ref base, _) => {
-                if self.tables.is_method_call(expr) {
+                if self.typeck_results.is_method_call(expr) {
                     // If this is an index implemented by a method call, then it
                     // will include an implicit deref of the result.
                     // The call to index() returns a `&T` value, which
@@ -419,12 +341,12 @@ fn cat_expr_adjusted_with<F>(
                     self.cat_overloaded_place(expr, base)
                 } else {
                     let base = self.cat_expr(&base)?;
-                    Ok(self.cat_projection(expr, base, expr_ty))
+                    Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index))
                 }
             }
 
             hir::ExprKind::Path(ref qpath) => {
-                let res = self.tables.qpath_res(qpath, expr.hir_id);
+                let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
                 self.cat_res(expr.hir_id, expr.span, expr_ty, res)
             }
 
@@ -533,9 +455,10 @@ fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWit
         node: &N,
         base_place: PlaceWithHirId<'tcx>,
         ty: Ty<'tcx>,
+        kind: ProjectionKind,
     ) -> PlaceWithHirId<'tcx> {
         let mut projections = base_place.place.projections;
-        projections.push(Projection { kind: ProjectionKind::Other, ty: ty });
+        projections.push(Projection { kind: kind, ty: ty });
         let ret = PlaceWithHirId::new(
             node.hir_id(),
             base_place.place.base_ty,
@@ -609,6 +532,75 @@ fn cat_deref(
         self.cat_pattern_(place, pat, &mut op)
     }
 
+    /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
+    /// Here `pat_hir_id` is the HirId of the pattern itself.
+    fn variant_index_for_adt(
+        &self,
+        qpath: &hir::QPath<'_>,
+        pat_hir_id: hir::HirId,
+        span: Span,
+    ) -> McResult<VariantIdx> {
+        let res = self.typeck_results.qpath_res(qpath, pat_hir_id);
+        let ty = self.typeck_results.node_type(pat_hir_id);
+        let adt_def = match ty.kind {
+            ty::Adt(adt_def, _) => adt_def,
+            _ => {
+                self.tcx()
+                    .sess
+                    .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
+                return Err(());
+            }
+        };
+
+        match res {
+            Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)),
+            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
+                Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
+            }
+            Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
+            | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            | Res::SelfCtor(..)
+            | Res::SelfTy(..) => {
+                // Structs and Unions have only have one variant.
+                Ok(VariantIdx::new(0))
+            }
+            _ => bug!("expected ADT path, found={:?}", res),
+        }
+    }
+
+    /// Returns the total number of fields in an ADT variant used within a pattern.
+    /// Here `pat_hir_id` is the HirId of the pattern itself.
+    fn total_fields_in_adt_variant(
+        &self,
+        pat_hir_id: hir::HirId,
+        variant_index: VariantIdx,
+        span: Span,
+    ) -> McResult<usize> {
+        let ty = self.typeck_results.node_type(pat_hir_id);
+        match ty.kind {
+            ty::Adt(adt_def, _) => Ok(adt_def.variants[variant_index].fields.len()),
+            _ => {
+                self.tcx()
+                    .sess
+                    .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
+                return Err(());
+            }
+        }
+    }
+
+    /// Returns the total number of fields in a tuple used within a Tuple pattern.
+    /// Here `pat_hir_id` is the HirId of the pattern itself.
+    fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult<usize> {
+        let ty = self.typeck_results.node_type(pat_hir_id);
+        match ty.kind {
+            ty::Tuple(substs) => Ok(substs.len()),
+            _ => {
+                self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple");
+                return Err(());
+            }
+        }
+    }
+
     // FIXME(#19596) This is a workaround, but there should be a better way to do this
     fn cat_pattern_<F>(
         &self,
@@ -660,7 +652,9 @@ fn cat_pattern_<F>(
         // Then we see that to get the same result, we must start with
         // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
         // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
-        for _ in 0..self.tables.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0) {
+        for _ in
+            0..self.typeck_results.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0)
+        {
             debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
             place_with_id = self.cat_deref(pat, place_with_id)?;
         }
@@ -679,20 +673,54 @@ fn cat_pattern_<F>(
         op(&place_with_id, pat);
 
         match pat.kind {
-            PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => {
-                // S(p1, ..., pN) or (p1, ..., pN)
-                for subpat in subpats.iter() {
+            PatKind::Tuple(ref subpats, dots_pos) => {
+                // (p1, ..., pN)
+                let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
+
+                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
                     let subpat_ty = self.pat_ty_adjusted(&subpat)?;
-                    let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty);
+                    let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0));
+                    let sub_place =
+                        self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
                     self.cat_pattern_(sub_place, &subpat, op)?;
                 }
             }
 
-            PatKind::Struct(_, field_pats, _) => {
+            PatKind::TupleStruct(ref qpath, ref subpats, dots_pos) => {
+                // S(p1, ..., pN)
+                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
+                let total_fields =
+                    self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
+
+                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
+                    let subpat_ty = self.pat_ty_adjusted(&subpat)?;
+                    let projection_kind = ProjectionKind::Field(i as u32, variant_index);
+                    let sub_place =
+                        self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
+                    self.cat_pattern_(sub_place, &subpat, op)?;
+                }
+            }
+
+            PatKind::Struct(ref qpath, field_pats, _) => {
                 // S { f1: p1, ..., fN: pN }
+
+                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
+
                 for fp in field_pats {
                     let field_ty = self.pat_ty_adjusted(&fp.pat)?;
-                    let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty);
+                    let field_index = self
+                        .typeck_results
+                        .field_indices()
+                        .get(fp.hir_id)
+                        .cloned()
+                        .expect("no index for a field");
+
+                    let field_place = self.cat_projection(
+                        pat,
+                        place_with_id.clone(),
+                        field_ty,
+                        ProjectionKind::Field(field_index as u32, variant_index),
+                    );
                     self.cat_pattern_(field_place, &fp.pat, op)?;
                 }
             }
@@ -723,13 +751,23 @@ fn cat_pattern_<F>(
                         return Err(());
                     }
                 };
-                let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty);
+                let elt_place = self.cat_projection(
+                    pat,
+                    place_with_id.clone(),
+                    element_ty,
+                    ProjectionKind::Index,
+                );
                 for before_pat in before {
                     self.cat_pattern_(elt_place.clone(), &before_pat, op)?;
                 }
                 if let Some(ref slice_pat) = *slice {
                     let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?;
-                    let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty);
+                    let slice_place = self.cat_projection(
+                        pat,
+                        place_with_id,
+                        slice_pat_ty,
+                        ProjectionKind::Subslice,
+                    );
                     self.cat_pattern_(slice_place, &slice_pat, op)?;
                 }
                 for after_pat in after {
index 57d499e38a77b83c15a82fc650dc62661222b055..53979d27052d3b34b51d697cdf505dd26c0fc4d8 100644 (file)
@@ -162,8 +162,8 @@ fn should_capitalize_first_letter(&self) -> bool {
             Cfg::Any(ref sub_cfgs) | Cfg::All(ref sub_cfgs) => {
                 sub_cfgs.first().map(Cfg::should_capitalize_first_letter).unwrap_or(false)
             }
-            Cfg::Cfg(name, _) => match &*name.as_str() {
-                "debug_assertions" | "target_endian" => true,
+            Cfg::Cfg(name, _) => match name {
+                sym::debug_assertions | sym::target_endian => true,
                 _ => false,
             },
         }
@@ -347,12 +347,11 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             Cfg::False => fmt.write_str("nowhere"),
 
             Cfg::Cfg(name, value) => {
-                let n = &*name.as_str();
-                let human_readable = match (n, value) {
-                    ("unix", None) => "Unix",
-                    ("windows", None) => "Windows",
-                    ("debug_assertions", None) => "debug-assertions enabled",
-                    ("target_os", Some(os)) => match &*os.as_str() {
+                let human_readable = match (name, value) {
+                    (sym::unix, None) => "Unix",
+                    (sym::windows, None) => "Windows",
+                    (sym::debug_assertions, None) => "debug-assertions enabled",
+                    (sym::target_os, Some(os)) => match &*os.as_str() {
                         "android" => "Android",
                         "dragonfly" => "DragonFly BSD",
                         "emscripten" => "Emscripten",
@@ -372,7 +371,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                         "windows" => "Windows",
                         _ => "",
                     },
-                    ("target_arch", Some(arch)) => match &*arch.as_str() {
+                    (sym::target_arch, Some(arch)) => match &*arch.as_str() {
                         "aarch64" => "AArch64",
                         "arm" => "ARM",
                         "asmjs" => "JavaScript",
@@ -388,7 +387,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                         "x86_64" => "x86-64",
                         _ => "",
                     },
-                    ("target_vendor", Some(vendor)) => match &*vendor.as_str() {
+                    (sym::target_vendor, Some(vendor)) => match &*vendor.as_str() {
                         "apple" => "Apple",
                         "pc" => "PC",
                         "rumprun" => "Rumprun",
@@ -396,7 +395,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                         "fortanix" => "Fortanix",
                         _ => "",
                     },
-                    ("target_env", Some(env)) => match &*env.as_str() {
+                    (sym::target_env, Some(env)) => match &*env.as_str() {
                         "gnu" => "GNU",
                         "msvc" => "MSVC",
                         "musl" => "musl",
@@ -405,9 +404,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                         "sgx" => "SGX",
                         _ => "",
                     },
-                    ("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian),
-                    ("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits),
-                    ("target_feature", Some(feat)) => {
+                    (sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian),
+                    (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits),
+                    (sym::target_feature, Some(feat)) => {
                         if self.1 {
                             return write!(fmt, "<code>{}</code>", feat);
                         } else {
@@ -419,9 +418,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                 if !human_readable.is_empty() {
                     fmt.write_str(human_readable)
                 } else if let Some(v) = value {
-                    write!(fmt, "<code>{}=\"{}\"</code>", Escape(n), Escape(&v.as_str()))
+                    write!(
+                        fmt,
+                        "<code>{}=\"{}\"</code>",
+                        Escape(&name.as_str()),
+                        Escape(&v.as_str())
+                    )
                 } else {
-                    write!(fmt, "<code>{}</code>", Escape(n))
+                    write!(fmt, "<code>{}</code>", Escape(&name.as_str()))
                 }
             }
         }
index 78628b198a3c3f73ab6740774273aecf31825f73..491daa80e5c859ddd0f8692fe4cf0e99c85f9a11 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_middle::ty;
 use rustc_mir::const_eval::is_min_const_fn;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
 use crate::clean::{self, GetDefId, ToSource, TypeKind};
@@ -194,6 +194,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
     let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
     let generics = filter_non_trait_generics(did, generics);
     let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
+    let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight);
     let is_auto = cx.tcx.trait_is_auto(did);
     clean::Trait {
         auto: auto_trait,
@@ -201,6 +202,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
         generics,
         items: trait_items,
         bounds: supertrait_bounds,
+        is_spotlight,
         is_auto,
     }
 }
@@ -339,6 +341,16 @@ pub fn build_impl(
                 return;
             }
         }
+
+        // Skip foreign unstable traits from lists of trait implementations and
+        // such. This helps prevent dependencies of the standard library, for
+        // example, from getting documented as "traits `u32` implements" which
+        // isn't really too helpful.
+        if let Some(stab) = cx.tcx.lookup_stability(did) {
+            if stab.level.is_unstable() {
+                return;
+            }
+        }
     }
 
     let for_ = if let Some(did) = did.as_local() {
index bfe8464347d2986b7982e7f7cd3ac7482ddbac72..8a4ee91df405fcb8b033ec6911e8916b71154aaf 100644 (file)
@@ -114,7 +114,7 @@ fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
                 for attr in attrs.lists(sym::doc) {
                     if let Some(v) = attr.value_str() {
                         if attr.check_name(sym::primitive) {
-                            prim = PrimitiveType::from_str(&v.as_str());
+                            prim = PrimitiveType::from_symbol(v);
                             if prim.is_some() {
                                 break;
                             }
@@ -1007,6 +1007,7 @@ fn clean(&self, cx: &DocContext<'_>) -> FnRetTy {
 impl Clean<Item> for doctree::Trait<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
         let attrs = self.attrs.clean(cx);
+        let is_spotlight = attrs.has_doc_flag(sym::spotlight);
         Item {
             name: Some(self.name.clean(cx)),
             attrs,
@@ -1021,6 +1022,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
                 items: self.items.iter().map(|ti| ti.clean(cx)).collect(),
                 generics: self.generics.clean(cx),
                 bounds: self.bounds.clean(cx),
+                is_spotlight,
                 is_auto: self.is_auto.clean(cx),
             }),
         }
index 34f91bfec5a88ee9bf9e505981c69fd0cf372e6b..6a03722cd0802786f31710bb146e981c3fecf13e 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_middle::middle::stability;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DUMMY_SP;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{self, FileName};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
@@ -486,33 +486,6 @@ pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> {
         })
     }
 
-    /// Enforce the format of attributes inside `#[doc(...)]`.
-    pub fn check_doc_attributes(
-        diagnostic: &::rustc_errors::Handler,
-        mi: &ast::MetaItem,
-    ) -> Option<(String, String)> {
-        mi.meta_item_list().and_then(|list| {
-            for meta in list {
-                if meta.check_name(sym::alias) {
-                    if !meta.is_value_str()
-                        || meta
-                            .value_str()
-                            .map(|s| s.to_string())
-                            .unwrap_or_else(String::new)
-                            .is_empty()
-                    {
-                        diagnostic.span_err(
-                            meta.span(),
-                            "doc alias attribute expects a string: #[doc(alias = \"0\")]",
-                        );
-                    }
-                }
-            }
-
-            None
-        })
-    }
-
     pub fn has_doc_flag(&self, flag: Symbol) -> bool {
         for attr in &self.other_attrs {
             if !attr.check_name(sym::doc) {
@@ -540,7 +513,7 @@ pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute])
             .filter_map(|attr| {
                 if let Some(value) = attr.doc_str() {
                     let (value, mk_fragment): (_, fn(_, _, _) -> _) = if attr.is_doc_comment() {
-                        (strip_doc_comment_decoration(&value.as_str()), DocFragment::SugaredDoc)
+                        (strip_doc_comment_decoration(value), DocFragment::SugaredDoc)
                     } else {
                         (value.to_string(), DocFragment::RawDoc)
                     };
@@ -556,7 +529,6 @@ pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute])
                 } else {
                     if attr.check_name(sym::doc) {
                         if let Some(mi) = attr.meta() {
-                            Attributes::check_doc_attributes(&diagnostic, &mi);
                             if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
                                 // Extracted #[doc(cfg(...))]
                                 match Cfg::parse(cfg_mi) {
@@ -995,6 +967,7 @@ pub struct Trait {
     pub items: Vec<Item>,
     pub generics: Generics,
     pub bounds: Vec<GenericBound>,
+    pub is_spotlight: bool,
     pub is_auto: bool,
 }
 
@@ -1230,33 +1203,33 @@ fn def_id(&self) -> Option<DefId> {
 }
 
 impl PrimitiveType {
-    pub fn from_str(s: &str) -> Option<PrimitiveType> {
+    pub fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
         match s {
-            "isize" => Some(PrimitiveType::Isize),
-            "i8" => Some(PrimitiveType::I8),
-            "i16" => Some(PrimitiveType::I16),
-            "i32" => Some(PrimitiveType::I32),
-            "i64" => Some(PrimitiveType::I64),
-            "i128" => Some(PrimitiveType::I128),
-            "usize" => Some(PrimitiveType::Usize),
-            "u8" => Some(PrimitiveType::U8),
-            "u16" => Some(PrimitiveType::U16),
-            "u32" => Some(PrimitiveType::U32),
-            "u64" => Some(PrimitiveType::U64),
-            "u128" => Some(PrimitiveType::U128),
-            "bool" => Some(PrimitiveType::Bool),
-            "char" => Some(PrimitiveType::Char),
-            "str" => Some(PrimitiveType::Str),
-            "f32" => Some(PrimitiveType::F32),
-            "f64" => Some(PrimitiveType::F64),
-            "array" => Some(PrimitiveType::Array),
-            "slice" => Some(PrimitiveType::Slice),
-            "tuple" => Some(PrimitiveType::Tuple),
-            "unit" => Some(PrimitiveType::Unit),
-            "pointer" => Some(PrimitiveType::RawPointer),
-            "reference" => Some(PrimitiveType::Reference),
-            "fn" => Some(PrimitiveType::Fn),
-            "never" => Some(PrimitiveType::Never),
+            sym::isize => Some(PrimitiveType::Isize),
+            sym::i8 => Some(PrimitiveType::I8),
+            sym::i16 => Some(PrimitiveType::I16),
+            sym::i32 => Some(PrimitiveType::I32),
+            sym::i64 => Some(PrimitiveType::I64),
+            sym::i128 => Some(PrimitiveType::I128),
+            sym::usize => Some(PrimitiveType::Usize),
+            sym::u8 => Some(PrimitiveType::U8),
+            sym::u16 => Some(PrimitiveType::U16),
+            sym::u32 => Some(PrimitiveType::U32),
+            sym::u64 => Some(PrimitiveType::U64),
+            sym::u128 => Some(PrimitiveType::U128),
+            sym::bool => Some(PrimitiveType::Bool),
+            sym::char => Some(PrimitiveType::Char),
+            sym::str => Some(PrimitiveType::Str),
+            sym::f32 => Some(PrimitiveType::F32),
+            sym::f64 => Some(PrimitiveType::F64),
+            sym::array => Some(PrimitiveType::Array),
+            sym::slice => Some(PrimitiveType::Slice),
+            sym::tuple => Some(PrimitiveType::Tuple),
+            sym::unit => Some(PrimitiveType::Unit),
+            sym::pointer => Some(PrimitiveType::RawPointer),
+            sym::reference => Some(PrimitiveType::Reference),
+            kw::Fn => Some(PrimitiveType::Fn),
+            sym::never => Some(PrimitiveType::Never),
             _ => None,
         }
     }
index 832b2420c238999fcf526f1f6158fca02c2b5b5b..52c306688268f51be4980e8e6e4ad0416672a573 100644 (file)
@@ -466,12 +466,12 @@ pub fn name_from_pat(p: &hir::Pat<'_>) -> String {
 
 pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String {
     match n.val {
-        ty::ConstKind::Unevaluated(def_id, _, promoted) => {
-            let mut s = if let Some(def_id) = def_id.as_local() {
-                let hir_id = cx.tcx.hir().as_local_hir_id(def_id);
+        ty::ConstKind::Unevaluated(def, _, promoted) => {
+            let mut s = if let Some(def) = def.as_local() {
+                let hir_id = cx.tcx.hir().as_local_hir_id(def.did);
                 print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
             } else {
-                inline::print_inlined_const(cx, def_id)
+                inline::print_inlined_const(cx, def.did)
             };
             if let Some(promoted) = promoted {
                 s.push_str(&format!("::{:?}", promoted))
index 14a6f3c89a3c9486560bb7da93af8f33caba8ea0..39e33da44964e00ebe77497a411172b2a30a4afc 100644 (file)
@@ -20,6 +20,7 @@
 use crate::externalfiles::ExternalHtml;
 use crate::html;
 use crate::html::markdown::IdMap;
+use crate::html::render::StylePath;
 use crate::html::static_files;
 use crate::opts;
 use crate::passes::{self, Condition, DefaultPassOption};
@@ -207,7 +208,7 @@ pub struct RenderOptions {
     pub sort_modules_alphabetically: bool,
     /// List of themes to extend the docs with. Original argument name is included to assist in
     /// displaying errors if it fails a theme check.
-    pub themes: Vec<PathBuf>,
+    pub themes: Vec<StylePath>,
     /// If present, CSS file that contains rules to add to the default CSS.
     pub extension_css: Option<PathBuf>,
     /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`.
@@ -410,7 +411,7 @@ fn println_condition(condition: Condition) {
                     ))
                     .emit();
                 }
-                themes.push(theme_file);
+                themes.push(StylePath { path: theme_file, disabled: true });
             }
         }
 
index a222920c7d292a2e09c89a387ebb1c76d829d57a..263909d5559d16bc93a04b354bb0888142f076e8 100644 (file)
@@ -5,10 +5,15 @@
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
-use rustc_hir::def::Namespace::TypeNS;
+use rustc_hir::def::{Namespace::TypeNS, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::HirId;
+use rustc_hir::{
+    intravisit::{self, NestedVisitorMap, Visitor},
+    Path,
+};
 use rustc_interface::interface;
+use rustc_middle::hir::map::Map;
 use rustc_middle::middle::cstore::CrateStore;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -315,7 +320,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
     let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name;
     let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
     let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name;
-    let invalid_codeblock_attribute_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
+    let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
 
     // In addition to those specific lints, we also need to allow those given through
     // command line, otherwise they'll get ignored and we don't want that.
@@ -325,12 +330,12 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         missing_doc_example.to_owned(),
         private_doc_tests.to_owned(),
         no_crate_level_docs.to_owned(),
-        invalid_codeblock_attribute_name.to_owned(),
+        invalid_codeblock_attributes_name.to_owned(),
     ];
 
     let (lint_opts, lint_caps) = init_lints(allowed_lints, lint_opts, |lint| {
         if lint.name == intra_link_resolution_failure_name
-            || lint.name == invalid_codeblock_attribute_name
+            || lint.name == invalid_codeblock_attributes_name
         {
             None
         } else {
@@ -372,7 +377,35 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         crate_name,
         lint_caps,
         register_lints: None,
-        override_queries: None,
+        override_queries: Some(|_sess, providers, _external_providers| {
+            // Most lints will require typechecking, so just don't run them.
+            providers.lint_mod = |_, _| {};
+            // Prevent `rustc_typeck::check_crate` from calling `typeck` on all bodies.
+            providers.typeck_item_bodies = |_, _| {};
+            // hack so that `used_trait_imports` won't try to call typeck
+            providers.used_trait_imports = |_, _| {
+                lazy_static! {
+                    static ref EMPTY_SET: FxHashSet<LocalDefId> = FxHashSet::default();
+                }
+                &EMPTY_SET
+            };
+            // In case typeck does end up being called, don't ICE in case there were name resolution errors
+            providers.typeck = move |tcx, def_id| {
+                // Closures' tables come from their outermost function,
+                // as they are part of the same "inference environment".
+                // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
+                let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
+                if outer_def_id != def_id {
+                    return tcx.typeck(outer_def_id);
+                }
+
+                let hir = tcx.hir();
+                let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id)));
+                debug!("visiting body for {:?}", def_id);
+                EmitIgnoredResolutionErrors::new(tcx).visit_body(body);
+                (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
+            };
+        }),
         registry: rustc_driver::diagnostics_registry(),
     };
 
@@ -397,7 +430,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                                 DUMMY_SP,
                                 extern_name,
                                 TypeNS,
-                                LocalDefId { local_def_index: CRATE_DEF_INDEX },
+                                LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
                             )
                             .unwrap_or_else(|()| {
                                 panic!("Unable to resolve external crate {}", extern_name)
@@ -416,10 +449,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
             let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
 
             global_ctxt.enter(|tcx| {
-                tcx.analysis(LOCAL_CRATE).ok();
-
-                // Abort if there were any errors so far
-                sess.abort_if_errors();
+                // Certain queries assume that some checks were run elsewhere
+                // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
+                // so type-check everything other than function bodies in this crate before running lints.
+                // NOTE: this does not call `tcx.analysis()` so that we won't
+                // typeck function bodies or run the default rustc lints.
+                // (see `override_queries` in the `config`)
+                let _ = rustc_typeck::check_crate(tcx);
+                tcx.sess.abort_if_errors();
+                sess.time("missing_docs", || {
+                    rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
+                });
 
                 let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
                 // Convert from a HirId set to a DefId set since we don't always have easy access
@@ -570,6 +610,62 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
     })
 }
 
+/// Due to https://github.com/rust-lang/rust/pull/73566,
+/// the name resolution pass may find errors that are never emitted.
+/// If typeck is called after this happens, then we'll get an ICE:
+/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
+struct EmitIgnoredResolutionErrors<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> EmitIgnoredResolutionErrors<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        // We need to recurse into nested closures,
+        // since those will fallback to the parent for type checking.
+        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    }
+
+    fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
+        debug!("visiting path {:?}", path);
+        if path.res == Res::Err {
+            // We have less context here than in rustc_resolve,
+            // so we can only emit the name and span.
+            // However we can give a hint that rustc_resolve will have more info.
+            let label = format!(
+                "could not resolve path `{}`",
+                path.segments
+                    .iter()
+                    .map(|segment| segment.ident.as_str().to_string())
+                    .collect::<Vec<_>>()
+                    .join("::")
+            );
+            let mut err = rustc_errors::struct_span_err!(
+                self.tcx.sess,
+                path.span,
+                E0433,
+                "failed to resolve: {}",
+                label
+            );
+            err.span_label(path.span, label);
+            err.note("this error was originally ignored because you are running `rustdoc`");
+            err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error");
+            err.emit();
+        }
+        // We could have an outer resolution that succeeded,
+        // but with generic parameters that failed.
+        // Recurse into the segments so we catch those too.
+        intravisit::walk_path(self, path);
+    }
+}
+
 /// `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)]
index 8b5a3a2ba61313cd209faf6862537882358d1bc2..c8121d39d0f8f5dc67c1bfaf4bae3f6da587ddd2 100644 (file)
@@ -37,14 +37,14 @@ pub fn load(
         let bc = format!(
             "{}{}",
             bc,
-            Markdown(&m_bc, &[], id_map, codes, edition, playground).to_string()
+            Markdown(&m_bc, &[], id_map, codes, edition, playground).into_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()
+            Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string()
         );
         Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
     }
index a453a8b3dcb2ae23cec835fe71c990c960740a9d..0d8284029afc72f87143d5367a6a8fd84e6bab08 100644 (file)
@@ -63,10 +63,22 @@ impl Buffer {
         Buffer { for_html: false, 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).
index c4bc73770a76b3981f2a8e0ed7225d8a1ccdad45..d4302d0cb546b8bf49ac5ca4e45e7c707d54ad32 100644 (file)
 use std::io::prelude::*;
 
 use rustc_ast::token::{self, Token};
+use rustc_data_structures::sync::Lrc;
 use rustc_parse::lexer;
 use rustc_session::parse::ParseSess;
+use rustc_span::hygiene::SyntaxContext;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym};
-use rustc_span::{FileName, Span};
+use rustc_span::{BytePos, FileName, SourceFile, Span};
 
 /// Highlights `src`, returning the HTML output.
 pub fn render_with_highlighting(
-    src: &str,
+    src: String,
     class: Option<&str>,
     playground_button: Option<&str>,
     tooltip: Option<(&str, &str)>,
@@ -38,12 +40,13 @@ pub fn render_with_highlighting(
     }
 
     let sess = ParseSess::with_silent_emitter();
-    let sf = sess
+    let source_file = sess
         .source_map()
-        .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned());
+        .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src);
+
+    let classifier_source_file = Lrc::clone(&source_file);
     let highlight_result = rustc_driver::catch_fatal_errors(|| {
-        let lexer = lexer::StringReader::new(&sess, sf, None);
-        let mut classifier = Classifier::new(lexer, sess.source_map());
+        let mut classifier = Classifier::new(&sess, classifier_source_file);
 
         let mut highlighted_source = vec![];
         if classifier.write_source(&mut highlighted_source).is_err() {
@@ -61,9 +64,17 @@ pub fn render_with_highlighting(
             write_footer(&mut out, playground_button).unwrap();
         }
         Err(()) => {
+            // Get the source back out of the source map to avoid a copy in the happy path.
+            let span =
+                Span::new(BytePos(0), BytePos(source_file.byte_length()), SyntaxContext::root());
+            let src = sess
+                .source_map()
+                .span_to_snippet(span)
+                .expect("could not retrieve snippet from artificial source file");
+
             // If errors are encountered while trying to highlight, just emit
             // the unhighlighted source.
-            write!(out, "<pre><code>{}</code></pre>", Escape(src)).unwrap();
+            write!(out, "<pre><code>{}</code></pre>", Escape(&src)).unwrap();
         }
     }
 
@@ -73,10 +84,10 @@ pub fn render_with_highlighting(
 /// Processes a program (nested in the internal `lexer`), classifying strings of
 /// text by highlighting category (`Class`). Calls out to a `Writer` to write
 /// each span of text in sequence.
-struct Classifier<'a> {
-    lexer: lexer::StringReader<'a>,
+struct Classifier<'sess> {
+    lexer: lexer::StringReader<'sess>,
     peek_token: Option<Token>,
-    source_map: &'a SourceMap,
+    source_map: &'sess SourceMap,
 
     // State of the classifier.
     in_attribute: bool,
@@ -154,6 +165,7 @@ fn exit_span(&mut self) -> io::Result<()> {
     }
 }
 
+#[derive(Debug)]
 enum HighlightError {
     LexError,
     IoError(io::Error),
@@ -165,12 +177,14 @@ fn from(err: io::Error) -> Self {
     }
 }
 
-impl<'a> Classifier<'a> {
-    fn new(lexer: lexer::StringReader<'a>, source_map: &'a SourceMap) -> Classifier<'a> {
+impl<'sess> Classifier<'sess> {
+    fn new(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Classifier<'_> {
+        let lexer = lexer::StringReader::new(sess, source_file, None);
+
         Classifier {
             lexer,
             peek_token: None,
-            source_map,
+            source_map: sess.source_map(),
             in_attribute: false,
             in_macro: false,
             in_macro_nonterminal: false,
@@ -209,11 +223,17 @@ fn peek(&mut self) -> Result<&Token, HighlightError> {
     /// source.
     fn write_source<W: Writer>(&mut self, out: &mut W) -> Result<(), HighlightError> {
         loop {
-            let next = self.try_next_token()?;
+            let mut next = self.try_next_token()?;
             if next == token::Eof {
                 break;
             }
 
+            // Glue any tokens that need to be glued.
+            if let Some(joint) = next.glue(self.peek()?) {
+                next = joint;
+                let _ = self.try_next_token()?;
+            }
+
             self.write_token(out, next)?;
         }
 
@@ -429,3 +449,6 @@ fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> {
 fn write_footer(out: &mut dyn Write, playground_button: Option<&str>) -> io::Result<()> {
     write!(out, "</pre>{}</div>\n", if let Some(button) = playground_button { button } else { "" })
 }
+
+#[cfg(test)]
+mod tests;
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
new file mode 100644 (file)
index 0000000..01b25fd
--- /dev/null
@@ -0,0 +1,82 @@
+use rustc_ast::attr::with_session_globals;
+use rustc_session::parse::ParseSess;
+use rustc_span::edition::Edition;
+use rustc_span::FileName;
+
+use super::Classifier;
+
+fn highlight(src: &str) -> String {
+    let mut out = vec![];
+
+    with_session_globals(Edition::Edition2018, || {
+        let sess = ParseSess::with_silent_emitter();
+        let source_file = sess.source_map().new_source_file(
+            FileName::Custom(String::from("rustdoc-highlighting")),
+            src.to_owned(),
+        );
+
+        let mut classifier = Classifier::new(&sess, source_file);
+        classifier.write_source(&mut out).unwrap();
+    });
+
+    String::from_utf8(out).unwrap()
+}
+
+#[test]
+fn function() {
+    assert_eq!(
+        highlight("fn main() {}"),
+        r#"<span class="kw">fn</span> <span class="ident">main</span>() {}"#,
+    );
+}
+
+#[test]
+fn statement() {
+    assert_eq!(
+        highlight("let foo = true;"),
+        concat!(
+            r#"<span class="kw">let</span> <span class="ident">foo</span> "#,
+            r#"<span class="op">=</span> <span class="bool-val">true</span>;"#,
+        ),
+    );
+}
+
+#[test]
+fn inner_attr() {
+    assert_eq!(
+        highlight(r##"#![crate_type = "lib"]"##),
+        concat!(
+            r##"<span class="attribute">#![<span class="ident">crate_type</span> "##,
+            r##"<span class="op">=</span> <span class="string">&quot;lib&quot;</span>]</span>"##,
+        ),
+    );
+}
+
+#[test]
+fn outer_attr() {
+    assert_eq!(
+        highlight(r##"#[cfg(target_os = "linux")]"##),
+        concat!(
+            r##"<span class="attribute">#[<span class="ident">cfg</span>("##,
+            r##"<span class="ident">target_os</span> <span class="op">=</span> "##,
+            r##"<span class="string">&quot;linux&quot;</span>)]</span>"##,
+        ),
+    );
+}
+
+#[test]
+fn mac() {
+    assert_eq!(
+        highlight("mac!(foo bar)"),
+        concat!(
+            r#"<span class="macro">mac</span><span class="macro">!</span>("#,
+            r#"<span class="ident">foo</span> <span class="ident">bar</span>)"#,
+        ),
+    );
+}
+
+// Regression test for #72684
+#[test]
+fn andand() {
+    assert_eq!(highlight("&&"), r#"<span class="op">&amp;&amp;</span>"#);
+}
index ea65b3905272e9c180ae75d081c5cca588d9d713..cc6b38ebcdb7fb26b929b7485724add16d254f3c 100644 (file)
@@ -3,7 +3,7 @@
 use crate::externalfiles::ExternalHtml;
 use crate::html::escape::Escape;
 use crate::html::format::{Buffer, Print};
-use crate::html::render::ensure_trailing_slash;
+use crate::html::render::{ensure_trailing_slash, StylePath};
 
 #[derive(Clone)]
 pub struct Layout {
@@ -36,7 +36,7 @@ pub fn render<T: Print, S: Print>(
     page: &Page<'_>,
     sidebar: S,
     t: T,
-    themes: &[PathBuf],
+    style_files: &[StylePath],
 ) -> String {
     let static_root_path = page.static_root_path.unwrap_or(page.root_path);
     format!(
@@ -52,10 +52,7 @@ pub fn render<T: Print, S: Print>(
     <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
     <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
           id=\"mainThemeStyle\">\
-    {themes}\
-    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}dark{suffix}.css\">\
-    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}light{suffix}.css\" \
-          id=\"themeStyle\">\
+    {style_files}\
     <script src=\"{static_root_path}storage{suffix}.js\"></script>\
     <noscript><link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\"></noscript>\
     {css_extension}\
@@ -172,13 +169,19 @@ pub fn render<T: Print, S: Print>(
         after_content = layout.external_html.after_content,
         sidebar = Buffer::html().to_display(sidebar),
         krate = layout.krate,
-        themes = themes
+        style_files = style_files
             .iter()
-            .filter_map(|t| t.file_stem())
-            .filter_map(|t| t.to_str())
+            .filter_map(|t| {
+                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
+            })
+            .filter_map(|t| {
+                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
+            })
             .map(|t| format!(
-                r#"<link rel="stylesheet" type="text/css" href="{}.css">"#,
-                Escape(&format!("{}{}{}", static_root_path, t, page.resource_suffix))
+                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
+                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
+                if t.1 { "disabled" } else { "" },
+                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
             ))
             .collect::<String>(),
         suffix = page.resource_suffix,
index a0f8eb04e2efb62206bbbfc3cc387b105480ec04..4cfd81ffbce9da6423f61167ecb6da85394241de 100644 (file)
@@ -13,7 +13,7 @@
 //! let s = "My *markdown* _text_";
 //! let mut id_map = IdMap::new();
 //! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None);
-//! let html = md.to_string();
+//! let html = md.into_string();
 //! // ... something using html
 //! ```
 
@@ -292,7 +292,7 @@ fn dont_escape(c: u8) -> bool {
 
         if let Some((s1, s2)) = tooltip {
             s.push_str(&highlight::render_with_highlighting(
-                &text,
+                text,
                 Some(&format!(
                     "rust-example-rendered{}",
                     if ignore != Ignore::None {
@@ -313,7 +313,7 @@ fn dont_escape(c: u8) -> bool {
             Some(Event::Html(s.into()))
         } else {
             s.push_str(&highlight::render_with_highlighting(
-                &text,
+                text,
                 Some(&format!(
                     "rust-example-rendered{}",
                     if ignore != Ignore::None {
@@ -848,7 +848,7 @@ fn parse(
 }
 
 impl Markdown<'_> {
-    pub fn to_string(self) -> String {
+    pub fn into_string(self) -> String {
         let Markdown(md, links, mut ids, codes, edition, playground) = self;
 
         // This is actually common enough to special-case
@@ -878,7 +878,7 @@ pub fn to_string(self) -> String {
 }
 
 impl MarkdownWithToc<'_> {
-    pub fn to_string(self) -> String {
+    pub fn into_string(self) -> String {
         let MarkdownWithToc(md, mut ids, codes, edition, playground) = self;
 
         let p = Parser::new_ext(md, opts());
@@ -899,7 +899,7 @@ pub fn to_string(self) -> String {
 }
 
 impl MarkdownHtml<'_> {
-    pub fn to_string(self) -> String {
+    pub fn into_string(self) -> String {
         let MarkdownHtml(md, mut ids, codes, edition, playground) = self;
 
         // This is actually common enough to special-case
@@ -926,7 +926,7 @@ pub fn to_string(self) -> String {
 }
 
 impl MarkdownSummaryLine<'_> {
-    pub fn to_string(self) -> String {
+    pub fn into_string(self) -> String {
         let MarkdownSummaryLine(md, links) = self;
         // This is actually common enough to special-case
         if md.is_empty() {
index bf0451a1d9d659c837f94ee124bba2c1db0c5874..783977d285dc466d0c9007b36a9f95330a25dbf4 100644 (file)
@@ -134,7 +134,7 @@ fn test_header() {
     fn t(input: &str, expect: &str) {
         let mut map = IdMap::new();
         let output =
-            Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
+            Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
         assert_eq!(output, expect, "original: {}", input);
     }
 
@@ -166,7 +166,8 @@ fn t(input: &str, expect: &str) {
 fn test_header_ids_multiple_blocks() {
     let mut map = IdMap::new();
     fn t(map: &mut IdMap, input: &str, expect: &str) {
-        let output = Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
+        let output =
+            Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
         assert_eq!(output, expect, "original: {}", input);
     }
 
@@ -228,7 +229,7 @@ fn test_markdown_html_escape() {
     fn t(input: &str, expect: &str) {
         let mut idmap = IdMap::new();
         let output =
-            MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
+            MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
         assert_eq!(output, expect, "original: {}", input);
     }
 
index 301896fd2c1ada0ae8aa85a9225f11f5d0de1401..f872ed7010c7537ad3aae0cdec855f2e6a771213 100644 (file)
@@ -188,8 +188,8 @@ struct Context {
     /// This flag indicates whether listings of modules (in the side bar and documentation itself)
     /// should be ordered alphabetically or in order of appearance (in the source code).
     pub sort_modules_alphabetically: bool,
-    /// Additional themes to be added to the generated docs.
-    pub themes: Vec<PathBuf>,
+    /// Additional CSS files to be added to the generated docs.
+    pub style_files: Vec<StylePath>,
     /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes
     /// "light-v2.css").
     pub resource_suffix: String,
@@ -418,6 +418,14 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     }
 }
 
+#[derive(Debug, Clone)]
+pub struct StylePath {
+    /// The path to the theme
+    pub path: PathBuf,
+    /// What the `disabled` attribute should be set to in the HTML tag
+    pub disabled: bool,
+}
+
 thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
 thread_local!(pub static CURRENT_DEPTH: Cell<usize> = Cell::new(0));
 
@@ -461,7 +469,7 @@ pub fn run(
         id_map,
         playground_url,
         sort_modules_alphabetically,
-        themes,
+        themes: style_files,
         extension_css,
         extern_html_root_urls,
         resource_suffix,
@@ -531,7 +539,7 @@ pub fn run(
         layout,
         created_dirs: Default::default(),
         sort_modules_alphabetically,
-        themes,
+        style_files,
         resource_suffix,
         static_root_path,
         fs: DocFS::new(&errors),
@@ -540,6 +548,19 @@ pub fn run(
         playground,
     };
 
+    // Add the default themes to the `Vec` of stylepaths
+    //
+    // Note that these must be added before `sources::render` is called
+    // so that the resulting source pages are styled
+    //
+    // `light.css` is not disabled because it is the stylesheet that stays loaded
+    // by the browser as the theme stylesheet. The theme system (hackily) works by
+    // changing the href to this stylesheet. All other themes are disabled to
+    // prevent rule conflicts
+    scx.style_files.push(StylePath { path: PathBuf::from("light.css"), disabled: false });
+    scx.style_files.push(StylePath { path: PathBuf::from("dark.css"), disabled: true });
+    scx.style_files.push(StylePath { path: PathBuf::from("ayu.css"), disabled: true });
+
     let dst = output;
     scx.ensure_dir(&dst)?;
     krate = sources::render(&dst, &mut scx, krate)?;
@@ -616,11 +637,40 @@ fn write_shared(
     // then we'll run over the "official" styles.
     let mut themes: FxHashSet<String> = FxHashSet::default();
 
-    for entry in &cx.shared.themes {
-        let content = try_err!(fs::read(&entry), &entry);
-        let theme = try_none!(try_none!(entry.file_stem(), &entry).to_str(), &entry);
-        let extension = try_none!(try_none!(entry.extension(), &entry).to_str(), &entry);
-        cx.shared.fs.write(cx.path(&format!("{}.{}", theme, extension)), content.as_slice())?;
+    for entry in &cx.shared.style_files {
+        let theme = try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path);
+        let extension =
+            try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
+
+        // Handle the official themes
+        match theme {
+            "light" => write_minify(
+                &cx.shared.fs,
+                cx.path("light.css"),
+                static_files::themes::LIGHT,
+                options.enable_minification,
+            )?,
+            "dark" => write_minify(
+                &cx.shared.fs,
+                cx.path("dark.css"),
+                static_files::themes::DARK,
+                options.enable_minification,
+            )?,
+            "ayu" => write_minify(
+                &cx.shared.fs,
+                cx.path("ayu.css"),
+                static_files::themes::AYU,
+                options.enable_minification,
+            )?,
+            _ => {
+                // Handle added third-party themes
+                let content = try_err!(fs::read(&entry.path), &entry.path);
+                cx.shared
+                    .fs
+                    .write(cx.path(&format!("{}.{}", theme, extension)), content.as_slice())?;
+            }
+        };
+
         themes.insert(theme.to_owned());
     }
 
@@ -634,20 +684,6 @@ fn write_shared(
     write(cx.path("brush.svg"), static_files::BRUSH_SVG)?;
     write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?;
     write(cx.path("down-arrow.svg"), static_files::DOWN_ARROW_SVG)?;
-    write_minify(
-        &cx.shared.fs,
-        cx.path("light.css"),
-        static_files::themes::LIGHT,
-        options.enable_minification,
-    )?;
-    themes.insert("light".to_owned());
-    write_minify(
-        &cx.shared.fs,
-        cx.path("dark.css"),
-        static_files::themes::DARK,
-        options.enable_minification,
-    )?;
-    themes.insert("dark".to_owned());
 
     let mut themes: Vec<&String> = themes.iter().collect();
     themes.sort();
@@ -958,7 +994,7 @@ fn to_json_string(&self) -> String {
                     })
                     .collect::<String>()
             );
-            let v = layout::render(&cx.shared.layout, &page, "", content, &cx.shared.themes);
+            let v = layout::render(&cx.shared.layout, &page, "", content, &cx.shared.style_files);
             cx.shared.fs.write(&dst, v.as_bytes())?;
         }
     }
@@ -1286,8 +1322,9 @@ fn settings(root_path: &str, suffix: &str) -> String {
             .into(),
         ("auto-hide-attributes", "Auto-hide item attributes.", true).into(),
         ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
-        ("auto-hide-trait-implementations", "Auto-hide trait implementations documentation", true)
+        ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", true)
             .into(),
+        ("auto-collapse-implementors", "Auto-hide implementors of a trait", true).into(),
         ("go-to-only-result", "Directly go to item in search if there is only one result", false)
             .into(),
         ("line-numbers", "Show line numbers on code examples", false).into(),
@@ -1376,7 +1413,7 @@ fn krate(self, mut krate: clean::Crate) -> Result<(), Error> {
             &page,
             sidebar,
             |buf: &mut Buffer| all.print(buf),
-            &self.shared.themes,
+            &self.shared.style_files,
         );
         self.shared.fs.write(&final_file, v.as_bytes())?;
 
@@ -1385,9 +1422,9 @@ fn krate(self, mut krate: clean::Crate) -> Result<(), Error> {
         page.description = "Settings of Rustdoc";
         page.root_path = "./";
 
-        let mut themes = self.shared.themes.clone();
+        let mut style_files = self.shared.style_files.clone();
         let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>";
-        themes.push(PathBuf::from("settings.css"));
+        style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false });
         let v = layout::render(
             &self.shared.layout,
             &page,
@@ -1396,7 +1433,7 @@ fn krate(self, mut krate: clean::Crate) -> Result<(), Error> {
                 self.shared.static_root_path.as_deref().unwrap_or("./"),
                 &self.shared.resource_suffix,
             ),
-            &themes,
+            &style_files,
         );
         self.shared.fs.write(&settings_file, v.as_bytes())?;
 
@@ -1458,7 +1495,7 @@ fn render_item(&self, it: &clean::Item, pushname: bool) -> String {
                 &page,
                 |buf: &mut _| print_sidebar(self, it, buf),
                 |buf: &mut _| print_item(self, it, buf),
-                &self.shared.themes,
+                &self.shared.style_files,
             )
         } else {
             let mut url = self.root_path();
@@ -1858,7 +1895,7 @@ fn render_markdown(
             cx.shared.edition,
             &cx.shared.playground
         )
-        .to_string()
+        .into_string()
     )
 }
 
@@ -2148,7 +2185,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                        </tr>",
                     name = *myitem.name.as_ref().unwrap(),
                     stab_tags = stability_tags(myitem),
-                    docs = MarkdownSummaryLine(doc_value, &myitem.links()).to_string(),
+                    docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(),
                     class = myitem.type_(),
                     add = add,
                     stab = stab.unwrap_or_else(String::new),
@@ -2193,12 +2230,15 @@ fn tag_html(class: &str, contents: &str) -> String {
         tags += &tag_html("deprecated", message);
     }
 
-    if let Some(stab) = item.stability.as_ref().filter(|s| s.level == stability::Unstable) {
-        if stab.feature.as_deref() == Some("rustc_private") {
-            tags += &tag_html("internal", "Internal");
-        } else {
-            tags += &tag_html("unstable", "Experimental");
-        }
+    // The "rustc_private" crates are permanently unstable so it makes no sense
+    // to render "unstable" everywhere.
+    if item
+        .stability
+        .as_ref()
+        .map(|s| s.level == stability::Unstable && s.feature.as_deref() != Some("rustc_private"))
+        == Some(true)
+    {
+        tags += &tag_html("unstable", "Experimental");
     }
 
     if let Some(ref cfg) = item.attrs.cfg {
@@ -2241,7 +2281,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
                 cx.shared.edition,
                 &cx.shared.playground,
             );
-            message.push_str(&format!(": {}", html.to_string()));
+            message.push_str(&format!(": {}", html.into_string()));
         }
         stability.push(format!(
             "<div class='stab deprecated'><span class='emoji'>👎</span> {}</div>",
@@ -2249,15 +2289,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
         ));
     }
 
-    if let Some(stab) = item.stability.as_ref().filter(|stab| stab.level == stability::Unstable) {
-        let is_rustc_private = stab.feature.as_deref() == Some("rustc_private");
-
-        let mut message = if is_rustc_private {
-            "<span class='emoji'>⚙️</span> This is an internal compiler API."
-        } else {
-            "<span class='emoji'>🔬</span> This is a nightly-only experimental API."
-        }
-        .to_owned();
+    // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
+    // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
+    if let Some(stab) = item.stability.as_ref().filter(|stab| {
+        stab.level == stability::Unstable && stab.feature.as_deref() != Some("rustc_private")
+    }) {
+        let mut message =
+            "<span class='emoji'>🔬</span> This is a nightly-only experimental API.".to_owned();
 
         if let Some(feature) = stab.feature.as_deref() {
             let mut feature = format!("<code>{}</code>", Escape(&feature));
@@ -2273,17 +2311,6 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
         }
 
         if let Some(unstable_reason) = &stab.unstable_reason {
-            // Provide a more informative message than the compiler help.
-            let unstable_reason = if is_rustc_private {
-                "This crate is being loaded from the sysroot, a permanently unstable location \
-                for private compiler dependencies. It is not intended for general use. Prefer \
-                using a public version of this crate from \
-                [crates.io](https://crates.io) via [`Cargo.toml`]\
-                (https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)."
-            } else {
-                unstable_reason
-            };
-
             let mut ids = cx.id_map.borrow_mut();
             message = format!(
                 "<details><summary>{}</summary>{}</details>",
@@ -2295,12 +2322,11 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
                     cx.shared.edition,
                     &cx.shared.playground,
                 )
-                .to_string()
+                .into_string()
             );
         }
 
-        let class = if is_rustc_private { "internal" } else { "unstable" };
-        stability.push(format!("<div class='stab {}'>{}</div>", class, message));
+        stability.push(format!("<div class='stab unstable'>{}</div>", message));
     }
 
     if let Some(ref cfg) = item.attrs.cfg {
@@ -2378,7 +2404,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
     write!(
         w,
         "{vis}{constness}{asyncness}{unsafety}{abi}fn \
-           {name}{generics}{decl}{where_clause}</pre>",
+           {name}{generics}{decl}{spotlight}{where_clause}</pre>",
         vis = it.visibility.print_with_space(),
         constness = f.header.constness.print_with_space(),
         asyncness = f.header.asyncness.print_with_space(),
@@ -2388,7 +2414,8 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
         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()
+            .print(),
+        spotlight = spotlight_decl(&f.decl),
     );
     document(w, cx, it)
 }
@@ -2575,7 +2602,7 @@ 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));
-        write!(w, "<h3 id='{id}' class='method'><code>", id = id);
+        write!(w, "<h3 id='{id}' class='method'><code>", id = id,);
         render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
         write!(w, "</code>");
         render_stability_since(w, m, t);
@@ -2889,7 +2916,7 @@ fn method(
         write!(
             w,
             "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
-                   {generics}{decl}{where_clause}",
+                   {generics}{decl}{spotlight}{where_clause}",
             if parent == ItemType::Trait { "    " } else { "" },
             meth.visibility.print_with_space(),
             header.constness.print_with_space(),
@@ -2901,6 +2928,7 @@ fn method(
             name = name,
             generics = g.print(),
             decl = Function { decl: d, header_len, indent, asyncness: header.asyncness }.print(),
+            spotlight = spotlight_decl(&d),
             where_clause = WhereClause { gens: g, indent, end_newline }
         )
     }
@@ -3522,6 +3550,62 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
     }
 }
 
+fn spotlight_decl(decl: &clean::FnDecl) -> String {
+    let mut out = Buffer::html();
+    let mut trait_ = String::new();
+
+    if let Some(did) = decl.output.def_id() {
+        let c = cache();
+        if let Some(impls) = c.impls.get(&did) {
+            for i in impls {
+                let impl_ = i.inner_impl();
+                if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) {
+                    if out.is_empty() {
+                        out.push_str(&format!(
+                            "<h3 class=\"important\">Important traits for {}</h3>\
+                                      <code class=\"content\">",
+                            impl_.for_.print()
+                        ));
+                        trait_.push_str(&impl_.for_.print().to_string());
+                    }
+
+                    //use the "where" class here to make it small
+                    out.push_str(&format!(
+                        "<span class=\"where fmt-newline\">{}</span>",
+                        impl_.print()
+                    ));
+                    let t_did = impl_.trait_.def_id().unwrap();
+                    for it in &impl_.items {
+                        if let clean::TypedefItem(ref tydef, _) = it.inner {
+                            out.push_str("<span class=\"where fmt-newline\">    ");
+                            assoc_type(
+                                &mut out,
+                                it,
+                                &[],
+                                Some(&tydef.type_),
+                                AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
+                                "",
+                            );
+                            out.push_str(";</span>");
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    if !out.is_empty() {
+        out.insert_str(
+            0,
+            "<span class=\"important-traits\"><span class=\"important-traits-tooltip\">ⓘ<div class='important-traits-tooltiptext'><span class=\"docblock\">"
+
+        );
+        out.push_str("</code></span></div></span></span>");
+    }
+
+    out.into_inner()
+}
+
 fn render_impl(
     w: &mut Buffer,
     cx: &Context,
@@ -3595,7 +3679,7 @@ fn render_impl(
                     cx.shared.edition,
                     &cx.shared.playground
                 )
-                .to_string()
+                .into_string()
             );
         }
     }
@@ -3633,7 +3717,8 @@ fn doc_impl_item(
                 // Only render when the method is not static or we allow static methods
                 if render_method_item {
                     let id = cx.derive_id(format!("{}.{}", item_type, name));
-                    write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class);
+                    write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class);
+                    write!(w, "<code>");
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
                     write!(w, "</code>");
                     render_stability_since_raw(w, item.stable_since(), outer_version);
@@ -4489,7 +4574,12 @@ fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) {
 
 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))
+        w.write_str(&highlight::render_with_highlighting(
+            t.source.clone(),
+            Some("macro"),
+            None,
+            None,
+        ))
     });
     document(w, cx, it)
 }
index f0900c34a4ba3dbcab473d92f4a3c8e25b85e986..e3215921f125c7bfe1b313c776ee1dac19b07e23 100644 (file)
@@ -75,7 +75,7 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
             return Ok(());
         }
 
-        let contents = match fs::read_to_string(&p) {
+        let mut contents = match fs::read_to_string(&p) {
             Ok(contents) => contents,
             Err(e) => {
                 return Err(Error::new(e, &p));
@@ -83,8 +83,9 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
         };
 
         // Remove the utf-8 BOM if any
-        let contents =
-            if contents.starts_with("\u{feff}") { &contents[3..] } else { &contents[..] };
+        if contents.starts_with("\u{feff}") {
+            contents.drain(..3);
+        }
 
         // Create the intermediate directories
         let mut cur = self.dst.clone();
@@ -122,8 +123,8 @@ fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
             &self.scx.layout,
             &page,
             "",
-            |buf: &mut _| print_src(buf, &contents),
-            &self.scx.themes,
+            |buf: &mut _| print_src(buf, contents),
+            &self.scx.style_files,
         );
         self.scx.fs.write(&cur, v.as_bytes())?;
         self.scx.local_sources.insert(p, href);
@@ -160,7 +161,7 @@ pub fn clean_path<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F)
 
 /// 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) {
+fn print_src(buf: &mut Buffer, s: String) {
     let lines = s.lines().count();
     let mut cols = 0;
     let mut tmp = lines;
index 69e2bacc21882e3d81fa18f1ca7838ed97ad7d8f..082f9cca064f133560460d5496d472223a2c2bcd 100644 (file)
@@ -2243,8 +2243,7 @@ function defocusSearchBar() {
                 relatedDoc = relatedDoc.nextElementSibling;
             }
 
-            if ((!relatedDoc && hasClass(docblock, "docblock") === false) ||
-                (pageId && document.getElementById(pageId))) {
+            if (!relatedDoc && hasClass(docblock, "docblock") === false) {
                 return;
             }
 
@@ -2364,6 +2363,7 @@ function defocusSearchBar() {
     (function() {
         var toggle = createSimpleToggle(false);
         var hideMethodDocs = getCurrentValue("rustdoc-auto-hide-method-docs") === "true";
+        var hideImplementors = getCurrentValue("rustdoc-auto-collapse-implementors") !== "false";
         var pageId = getPageId();
 
         var func = function(e) {
@@ -2393,7 +2393,13 @@ function defocusSearchBar() {
             if (hasClass(e, "impl") &&
                 (next.getElementsByClassName("method").length > 0 ||
                  next.getElementsByClassName("associatedconstant").length > 0)) {
-                insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]);
+                var newToggle = toggle.cloneNode(true);
+                insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
+                // In case the option "auto-collapse implementors" is not set to false, we collapse
+                // all implementors.
+                if (hideImplementors === true && e.parentNode.id === "implementors-list") {
+                    collapseDocs(newToggle, "hide", pageId);
+                }
             }
         };
 
@@ -2630,6 +2636,13 @@ function defocusSearchBar() {
         });
     }());
 
+    onEachLazy(document.getElementsByClassName("important-traits"), function(e) {
+        e.onclick = function() {
+            this.getElementsByClassName('important-traits-tooltiptext')[0]
+                .classList.toggle("force-tooltip");
+        };
+    });
+
     // In the search display, allows to switch between tabs.
     function printTab(nb) {
         if (nb === 0 || nb === 1 || nb === 2) {
index 2804c26a29662a3e32d668a072a778fa5efbbbee..0e0426279183f631fd297c1d4b4bb0c65b475457 100644 (file)
@@ -1 +1,2 @@
+/* ignore-tidy-linelength */
 /*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
index a3f4dc55fe757eb3fc9d6de8d70250afd21c9e85..38709b445efae9aa89649872aa167af0053942dd 100644 (file)
@@ -49,9 +49,9 @@
 }
 
 * {
-  -webkit-box-sizing: border-box;
-        -moz-box-sizing: border-box;
-                 box-sizing: border-box;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
 }
 
 /* This part handles the "default" theme being used depending on the system one. */
@@ -91,7 +91,8 @@ h2 {
 h3 {
        font-size: 1.3em;
 }
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.important), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.important),
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
        font-weight: 500;
        margin: 20px 0 15px 0;
        padding-bottom: 6px;
@@ -103,7 +104,8 @@ h1.fqn {
 h1.fqn > .in-band > a:hover {
        text-decoration: underline;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
        border-bottom: 1px solid;
 }
 h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
@@ -146,9 +148,12 @@ code, pre, a.test-arrow {
        border-radius: 3px;
        padding: 0 0.1em;
 }
-.docblock pre code, .docblock-short pre code {
+.docblock pre code, .docblock-short pre code, .docblock code.spotlight {
        padding: 0;
 }
+.docblock code.spotlight :last-child {
+       padding-bottom: 0.6em;
+}
 pre {
        padding: 14px;
 }
@@ -364,6 +369,7 @@ nav.sub {
 #results > table {
        width: 100%;
        table-layout: fixed;
+       margin-bottom: 40px;
 }
 
 .content pre.line-numbers {
@@ -522,7 +528,7 @@ h4 > code, h3 > code, .invisible > code {
        font-size: 0.8em;
 }
 
-.content .methods > div {
+.content .methods > div:not(.important-traits) {
        margin-left: 40px;
        margin-bottom: 15px;
 }
@@ -1078,10 +1084,6 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
        font-size: 16px;
 }
 
-.tooltip:hover .tooltiptext {
-       display: inline;
-}
-
 .tooltip .tooltiptext::after {
        content: " ";
        position: absolute;
@@ -1097,13 +1099,51 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
        font-size: 20px;
 }
 
-.tooltip .tooltiptext {
+.important-traits-tooltip {
+       display: inline-block;
+       cursor: pointer;
+}
+
+.important-traits:hover .important-traits-tooltiptext,
+.important-traits .important-traits-tooltiptext.force-tooltip {
+       display: inline-block;
+}
+
+.important-traits .important-traits-tooltiptext {
+       display: none;
+       padding: 5px 3px 3px 3px;
+       border-radius: 6px;
+       margin-left: 5px;
+       z-index: 10;
+       font-size: 16px;
+       cursor: default;
+       position: absolute;
        border: 1px solid;
-       font-weight: normal;
 }
 
-pre.rust {
+.important-traits-tooltip::after {
+       /* The margin on the tooltip does not capture hover events,
+          this extends the area of hover enough so that mouse hover is not
+          lost when moving the mouse to the tooltip */
+       content: "\00a0\00a0\00a0";
+}
+
+.important-traits .important, .important-traits .docblock {
+       margin: 0;
+}
+
+.important-traits .docblock code.content{
+       margin: 0;
+       padding: 0;
+       font-size: 20px;
+}
+
+/* Example code has the "Run" button that needs to be positioned relative to the pre */
+pre.rust.rust-example-rendered {
        position: relative;
+}
+
+pre.rust {
        tab-size: 4;
        -moz-tab-size: 4;
 }
@@ -1143,6 +1183,18 @@ pre.rust {
        font-size: 16px;
 }
 
+.important-traits {
+       cursor: pointer;
+       z-index: 2;
+       margin-left: 5px;
+}
+
+h4 > .important-traits {
+       position: absolute;
+       left: -44px;
+       top: 2px;
+}
+
 #all-types {
        text-align: center;
        border: 1px solid;
@@ -1369,6 +1421,12 @@ pre.rust {
                z-index: 1;
        }
 
+       h4 > .important-traits {
+               position: absolute;
+               left: -22px;
+               top: 24px;
+       }
+
        #titles > div > div.count {
                float: left;
                width: 100%;
index cfbfe6675f52bc62e58bf459e884d5c899d2cc6c..6805f2a266f0942e5e2e07a0ca58bbd499a295d7 100644 (file)
@@ -140,4 +140,9 @@ function createSourceSidebar() {
     });
 
     main.insertBefore(sidebar, main.firstChild);
+    // Focus on the current file in the source files sidebar.
+    var selected_elem = sidebar.getElementsByClassName("selected")[0];
+    if (typeof selected_elem !== "undefined") {
+        selected_elem.focus();
+    }
 }
diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css
new file mode 100644 (file)
index 0000000..e0ab717
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+Based off of the Ayu theme
+Original by Dempfi (https://github.com/dempfi/ayu)
+*/
+
+/* General structure and fonts */
+
+body {
+       background-color: #0f1419;
+       color: #c5c5c5;
+}
+
+h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
+h4:not(.method):not(.type):not(.tymethod) {
+       color: white;
+}
+h1.fqn {
+       border-bottom-color: #5c6773;
+}
+h1.fqn  a {
+       color: #fff;
+}
+h2, h3:not(.impl):not(.method):not(.type):not(.tymethod) {
+       border-bottom-color: #5c6773;
+}
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+       border: none;
+}
+
+.in-band {
+       background-color: #0f1419;
+}
+
+.invisible {
+       background: rgba(0, 0, 0, 0);
+}
+
+code {
+       color: #ffb454;
+}
+h3 > code, h4 > code, h5 > code {
+       color: #e6e1cf;
+}
+pre > code {
+       color: #e6e1cf;
+}
+span code {
+       color: #e6e1cf;
+}
+.docblock a > code {
+       color: #39AFD7 !important;
+}
+.docblock code, .docblock-short code {
+       background-color: #191f26;
+}
+pre {
+       color: #e6e1cf;
+       background-color: #191f26;
+}
+
+.sidebar {
+       background-color: #14191f;
+}
+
+/* Improve the scrollbar display on firefox */
+* {
+       scrollbar-color: #5c6773 transparent;
+}
+
+.sidebar {
+       scrollbar-color: #5c6773 transparent;
+}
+
+/* Improve the scrollbar display on webkit-based browsers */
+::-webkit-scrollbar-track {
+       background-color: transparent;
+}
+::-webkit-scrollbar-thumb {
+       background-color: #5c6773;
+}
+.sidebar::-webkit-scrollbar-track {
+       background-color: transparent;
+}
+.sidebar::-webkit-scrollbar-thumb {
+       background-color: #5c6773;
+}
+
+.sidebar .current {
+       background-color: transparent;
+       color: #ffb44c;
+}
+
+.source .sidebar {
+       background-color: #0f1419;
+}
+
+.sidebar .location {
+       border-color: #000;
+       background-color: #0f1419;
+       color: #fff;
+}
+
+.sidebar-elems .location {
+       color: #ff7733;
+}
+
+.sidebar-elems .location a {
+       color: #fff;
+}
+
+.sidebar .version {
+       border-bottom-color: #424c57;
+}
+
+.sidebar-title {
+       border-top-color: #5c6773;
+       border-bottom-color: #5c6773;
+}
+
+.block a:hover {
+       background: transparent;
+       color: #ffb44c;
+}
+
+.line-numbers span { color: #5c6773ab; }
+.line-numbers .line-highlighted {
+       background-color: rgba(255, 236, 164, 0.06) !important;
+       padding-right: 4px;
+       border-right: 1px solid #ffb44c;
+}
+
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
+       border-bottom-color: #5c6773;
+}
+
+.docblock table, .docblock table td, .docblock table th {
+       border-color: #5c6773;
+}
+
+.content .method .where,
+.content .fn .where,
+.content .where.fmt-newline {
+       color: #c5c5c5;
+}
+
+.content .highlighted {
+       color: #000 !important;
+       background-color: #c6afb3;
+}
+.content .highlighted a, .content .highlighted span { color: #000 !important; }
+.content .highlighted {
+       background-color: #c6afb3;
+}
+.search-results a {
+       color: #0096cf;
+}
+.search-results a span.desc {
+       color: #c5c5c5;
+}
+
+.content .stability::before { color: #ccc; }
+
+.content span.foreigntype, .content a.foreigntype { color: #ef57ff; }
+.content span.union, .content a.union { color: #98a01c; }
+.content span.constant, .content a.constant,
+.content span.static, .content a.static { color: #6380a0; }
+.content span.primitive, .content a.primitive { color: #32889b; }
+.content span.traitalias, .content a.traitalias { color: #57d399; }
+.content span.keyword, .content a.keyword { color: #de5249; }
+
+.content span.externcrate, .content span.mod, .content a.mod {
+       color: #acccf9;
+}
+.content span.struct, .content a.struct {
+       color: #ffa0a5;
+}
+.content span.enum, .content a.enum {
+       color: #99e0c9;
+}
+.content span.trait, .content a.trait {
+       color: #39AFD7;
+}
+.content span.type, .content a.type {
+       color: #cfbcf5;
+}
+.content span.fn, .content a.fn, .content span.method,
+.content a.method, .content span.tymethod,
+.content a.tymethod, .content .fnname {
+       color: #fdd687;
+}
+.content span.attr, .content a.attr, .content span.derive,
+.content a.derive, .content span.macro, .content a.macro {
+       color: #a37acc;
+}
+
+pre.rust .comment, pre.rust .doccomment {
+       color: #788797;
+       font-style: italic;
+}
+
+nav:not(.sidebar) {
+       border-bottom-color: #424c57;
+}
+nav.main .current {
+       border-top-color: #5c6773;
+       border-bottom-color: #5c6773;
+}
+nav.main .separator {
+       border: 1px solid #5c6773;
+}
+a {
+       color: #c5c5c5;
+}
+
+.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock-short a:not(.srclink):not(.test-arrow), .stability a {
+       color: #39AFD7;
+}
+
+.collapse-toggle {
+       color: #999;
+}
+
+#crate-search {
+       color: #c5c5c5;
+       background-color: #141920;
+       box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent;
+       border-color: #424c57;
+}
+
+.search-input {
+       color: #ffffff;
+       background-color: #141920;
+       box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent;
+       transition: box-shadow 150ms ease-in-out;
+}
+
+#crate-search+.search-input:focus {
+       box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
+       color: #ffffff;
+       background-color: #141920;
+       box-shadow: none;
+       transition: box-shadow 150ms ease-in-out;
+       border-radius: 4px;
+       margin-left: 8px;
+}
+
+#crate-search+.search-input:focus {
+       box-shadow: 0px 6px 20px 0px black;
+}
+
+.search-focus:disabled {
+       color: #929292;
+}
+
+.module-item .stab {
+       color: #000;
+}
+
+.stab.unstable,
+.stab.deprecated,
+.stab.portability {
+       color: #c5c5c5;
+       background: #314559 !important;
+       border-style: none !important;
+       border-radius: 4px;
+       padding: 3px 6px 3px 6px;
+}
+
+.stab.portability > code {
+       color: #e6e1cf;
+       background-color: transparent;
+}
+
+#help > div {
+       background: #14191f;
+       box-shadow: 0px 6px 20px 0px black;
+       border: none;
+       border-radius: 4px;
+}
+
+.since {
+       color: grey;
+}
+
+tr.result span.primitive::after, tr.result span.keyword::after {
+       color: #788797;
+}
+
+.line-numbers :target { background-color: transparent; }
+
+/* Code highlighting */
+pre.rust .number, pre.rust .string { color: #b8cc52; }
+pre.rust .kw, pre.rust .kw-2, pre.rust .prelude-ty,
+pre.rust .bool-val, pre.rust .prelude-val,
+pre.rust .op, pre.rust .lifetime { color: #ff7733; }
+pre.rust .macro, pre.rust .macro-nonterminal { color: #a37acc; }
+pre.rust .question-mark {
+       color: #ff9011;
+}
+pre.rust .self {
+       color: #36a3d9;
+       font-style: italic;
+}
+pre.rust .attribute {
+       color: #e6e1cf;
+}
+pre.rust .attribute .ident, pre.rust .attribute .op {
+       color: #e6e1cf;
+}
+
+.example-wrap > pre.line-number {
+       color: #5c67736e;
+       border: none;
+}
+
+a.test-arrow {
+       font-size: 100%;
+       color: #788797;
+       border-radius: 4px;
+       background-color: rgba(255, 255, 255, 0);
+}
+
+a.test-arrow:hover {
+       background-color: rgba(242, 151, 24, 0.05);
+       color: #ffb44c;
+}
+
+.toggle-label {
+       color: #999;
+}
+
+:target > code, :target > .in-band {
+       background: rgba(255, 236, 164, 0.06);
+       border-right: 3px solid #ffb44c;
+}
+
+pre.compile_fail {
+       border-left: 2px solid rgba(255,0,0,.4);
+}
+
+pre.compile_fail:hover, .information:hover + pre.compile_fail {
+       border-left: 2px solid #f00;
+}
+
+pre.should_panic {
+       border-left: 2px solid rgba(255,0,0,.4);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+       border-left: 2px solid #f00;
+}
+
+pre.ignore {
+       border-left: 2px solid rgba(255,142,0,.6);
+}
+
+pre.ignore:hover, .information:hover + pre.ignore {
+       border-left: 2px solid #ff9200;
+}
+
+.tooltip.compile_fail {
+       color: rgba(255,0,0,.5);
+}
+
+.information > .compile_fail:hover {
+       color: #f00;
+}
+
+.tooltip.should_panic {
+       color: rgba(255,0,0,.5);
+}
+
+.information > .should_panic:hover {
+       color: #f00;
+}
+
+.tooltip.ignore {
+       color: rgba(255,142,0,.6);
+}
+
+.information > .ignore:hover {
+       color: #ff9200;
+}
+
+.search-failed a {
+       color: #39AFD7;
+}
+
+.tooltip .tooltiptext {
+       background-color: #314559;
+       color: #c5c5c5;
+       border: 1px solid #5c6773;
+}
+
+.tooltip .tooltiptext::after {
+       border-color: transparent #314559 transparent transparent;
+}
+
+.important-traits-tooltiptext {
+       background-color: #314559;
+       border-color: #5c6773;
+}
+
+#titles > div.selected {
+       background-color: #141920 !important;
+       border-bottom: 1px solid #ffb44c !important;
+       border-top: none;
+}
+
+#titles > div:not(.selected) {
+       background-color: transparent !important;
+       border: none;
+}
+
+#titles > div:hover {
+       border-bottom: 1px solid rgba(242, 151, 24, 0.3);
+}
+
+#titles > div > div.count {
+       color: #888;
+}
+
+/* rules that this theme does not need to set, here to satisfy the rule checker */
+/* note that a lot of these are partially set in some way (meaning they are set
+individually rather than as a group) */
+/* FIXME: these rules should be at the bottom of the file but currently must be
+above the `@media (max-width: 700px)` rules due to a bug in the css checker */
+/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
+.content .highlighted.mod, .content .highlighted.externcrate {}
+.search-input:focus {}
+.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,
+.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {}
+.content .highlighted.trait {}
+.content span.struct,.content a.struct,.block a.current.struct {}
+#titles>div:hover,#titles>div.selected {}
+.content .highlighted.traitalias {}
+.content span.type,.content a.type,.block a.current.type {}
+.content span.union,.content a.union,.block a.current.union {}
+.content .highlighted.foreigntype {}
+pre.rust .lifetime {}
+.content .highlighted.primitive {}
+.content .highlighted.constant,.content .highlighted.static {}
+.stab.unstable {}
+.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod {}
+h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod) {}
+.content span.enum,.content a.enum,.block a.current.enum {}
+.content span.constant,.content a.constant,.block a.current.constant,.content span.static,
+.content a.static,.block a.current.static {}
+.content span.keyword,.content a.keyword,.block a.current.keyword {}
+pre.rust .comment {}
+.content .highlighted.enum {}
+.content .highlighted.struct {}
+.content .highlighted.keyword {}
+.content span.traitalias,.content a.traitalias,.block a.current.traitalias {}
+.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,
+.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,
+.content .fnname {}
+pre.rust .kw {}
+pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,
+pre.rust .attribute .ident {}
+.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype {}
+pre.rust .doccomment {}
+.stab.deprecated {}
+.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro {}
+.stab.portability {}
+.content .highlighted.union {}
+.content span.primitive,.content a.primitive,.block a.current.primitive {}
+.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod {}
+.content .highlighted.type {}
+pre.rust .kw-2,pre.rust .prelude-ty {}
+.content span.trait,.content a.trait,.block a.current.trait {}
+
+@media (max-width: 700px) {
+       .sidebar-menu {
+               background-color: #14191f;
+               border-bottom-color: #5c6773;
+               border-right-color: #5c6773;
+       }
+
+       .sidebar-elems {
+               background-color: #14191f;
+               border-right-color: #5c6773;
+       }
+
+       #sidebar-filler {
+               background-color: #14191f;
+               border-bottom-color: #5c6773;
+       }
+}
+
+kbd {
+       color: #c5c5c5;
+       background-color: #314559;
+       border-color: #5c6773;
+       border-bottom-color: #5c6773;
+       box-shadow-color: #c6cbd1;
+}
+
+#theme-picker, #settings-menu {
+       border-color: #5c6773;
+       background-color: #0f1419;
+}
+
+#theme-picker > img, #settings-menu > img {
+       filter: invert(100);
+}
+
+#theme-picker:hover, #theme-picker:focus,
+#settings-menu:hover, #settings-menu:focus {
+       border-color: #e0e0e0;
+}
+
+#theme-choices {
+       border-color: #5c6773;
+       background-color: #0f1419;
+}
+
+#theme-choices > button:not(:first-child) {
+       border-top-color: #c5c5c5;
+}
+
+#theme-choices > button:hover, #theme-choices > button:focus {
+       background-color: rgba(70, 70, 70, 0.33);
+}
+
+@media (max-width: 700px) {
+       #theme-picker {
+               background: #0f1419;
+       }
+}
+
+#all-types {
+       background-color: #14191f;
+}
+#all-types:hover {
+       background-color: rgba(70, 70, 70, 0.33);
+}
+
+.search-results td span.alias {
+       color: #c5c5c5;
+}
+.search-results td span.grey {
+       color: #999;
+}
+
+#sidebar-toggle {
+       background-color: #14191f;
+}
+#sidebar-toggle:hover {
+       background-color: rgba(70, 70, 70, 0.33);
+}
+#source-sidebar {
+       background-color: #14191f;
+}
+#source-sidebar > .title {
+       color: #fff;
+       border-bottom-color: #5c6773;
+}
+div.files > a:hover, div.name:hover {
+       background-color: #14191f;
+       color: #ffb44c;
+}
+div.files > .selected {
+       background-color: #14191f;
+       color: #ffb44c;
+}
+.setting-line > .title {
+       border-bottom-color: #5c6773;
+}
+input:checked + .slider {
+       background-color: #ffb454 !important;
+}
index 41dcb5c24507c6c38dfe99a66bd3f84ac20cde81..33c0f885fa95b4afe9f136c299f4db23e9c59b1b 100644 (file)
@@ -3,13 +3,15 @@ body {
        color: #ddd;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
+h4:not(.method):not(.type):not(.tymethod) {
        color: #ddd;
 }
 h1.fqn {
        border-bottom-color: #d2d2d2;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
+h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
+h4:not(.method):not(.type):not(.tymethod) {
        border-bottom-color: #d2d2d2;
 }
 
@@ -172,10 +174,6 @@ a {
        color: #D2991D;
 }
 
-.stab.internal a {
-       color: #304FFE;
-}
-
 a.test-arrow {
        color: #dedede;
 }
@@ -214,7 +212,6 @@ a.test-arrow {
 }
 
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.internal { background: #FFB9B3; border-color: #B71C1C; color: #2f2f2f; }
 .stab.deprecated { background: #F3DFFF; border-color: #7F0087; color: #2f2f2f; }
 .stab.portability { background: #C4ECFF; border-color: #7BA5DB; color: #2f2f2f; }
 
@@ -337,6 +334,11 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: transparent black transparent transparent;
 }
 
+.important-traits-tooltiptext {
+       background-color: #111;
+       border-color: #777;
+}
+
 #titles > div:not(.selected) {
        background-color: #252525;
        border-top-color: #252525;
index 386fe2398e63aec931bb665ea82dea7db5c0f0ef..569ce7da2091f07d79c2499d6f7fe4335de6bdd6 100644 (file)
@@ -5,13 +5,15 @@ body {
        color: black;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
+h4:not(.method):not(.type):not(.tymethod) {
        color: black;
 }
 h1.fqn {
        border-bottom-color: #D5D5D5;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
+h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
+h4:not(.method):not(.type):not(.tymethod) {
        border-bottom-color: #DDDDDD;
 }
 
@@ -173,10 +175,6 @@ a {
        color: #3873AD;
 }
 
-.stab.internal a {
-       color: #304FFE;
-}
-
 a.test-arrow {
        color: #f5f5f5;
 }
@@ -215,7 +213,6 @@ a.test-arrow {
 }
 
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-.stab.internal { background: #FFB9B3; border-color: #B71C1C; }
 .stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
 .stab.portability { background: #C4ECFF; border-color: #7BA5DB; }
 
@@ -331,6 +328,11 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: transparent black transparent transparent;
 }
 
+.important-traits-tooltiptext {
+       background-color: #eee;
+       border-color: #999;
+}
+
 #titles > div:not(.selected) {
        background-color: #e6e6e6;
        border-top-color: #e6e6e6;
index 6790f3bd5d0b19d2cf9cf573e5c0292ea4d965d9..6bd7e53cdfbe23acfc2e80fe7e41a72361b6e40b 100644 (file)
@@ -64,6 +64,9 @@ pub mod themes {
 
     /// The "dark" theme.
     pub static DARK: &str = include_str!("static/themes/dark.css");
+
+    /// The "ayu" theme.
+    pub static AYU: &str = include_str!("static/themes/ayu.css");
 }
 
 /// Files related to the Fira Sans font.
index 57151e2b200023ddcada5ed6ec7410a8f9fec42d..cbf53d52ef009d13661cbb2a681c6be5357a4955 100644 (file)
@@ -15,6 +15,8 @@
 #![recursion_limit = "256"]
 
 extern crate env_logger;
+#[macro_use]
+extern crate lazy_static;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr;
@@ -94,6 +96,7 @@ pub fn main() {
         32_000_000 // 32MB on other platforms
     };
     rustc_driver::set_sigpipe_handler();
+    rustc_driver::install_ice_hook();
     env_logger::init_from_env("RUSTDOC_LOG");
     let res = std::thread::Builder::new()
         .stack_size(thread_stack_size)
index e0753bcd70f29365c064b5d4a3da68bb53b5d637..89d184e35cb064a177c3a81a3961a97add895e12 100644 (file)
@@ -68,9 +68,9 @@ pub fn render<P: AsRef<Path>>(
     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, &mut ids, error_codes, edition, &playground).to_string()
+        MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string()
     } else {
-        Markdown(text, &[], &mut ids, error_codes, edition, &playground).to_string()
+        Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string()
     };
 
     let err = write!(
index f707c1a3e1a1086f8dd4de3430869a6927bb01cd..e187b9251f71e5194d002060dbca21f94b2211e7 100644 (file)
@@ -8,7 +8,7 @@
     Namespace::{self, *},
     PerNS, Res,
 };
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty;
 use rustc_resolve::ParentScope;
 use rustc_session::lint;
@@ -50,7 +50,8 @@ enum ErrorKind {
 
 struct LinkCollector<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
-    mod_ids: Vec<hir::HirId>,
+    // NOTE: this may not necessarily be a module in the current crate
+    mod_ids: Vec<DefId>,
 }
 
 impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
@@ -62,7 +63,7 @@ fn variant_field(
         &self,
         path_str: &str,
         current_item: &Option<String>,
-        module_id: LocalDefId,
+        module_id: DefId,
     ) -> Result<(Res, Option<String>), ErrorKind> {
         let cx = self.cx;
 
@@ -124,7 +125,7 @@ fn variant_field(
     }
 
     /// Resolves a string as a macro.
-    fn macro_resolve(&self, path_str: &str, parent_id: Option<hir::HirId>) -> Option<Res> {
+    fn macro_resolve(&self, path_str: &str, parent_id: Option<DefId>) -> Option<Res> {
         let cx = self.cx;
         let path = ast::Path::from_ident(Ident::from_str(path_str));
         cx.enter_resolver(|resolver| {
@@ -142,8 +143,7 @@ fn macro_resolve(&self, path_str: &str, parent_id: Option<hir::HirId>) -> Option
             if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
                 return Some(res.map_id(|_| panic!("unexpected id")));
             }
-            if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
-                let module_id = cx.tcx.hir().local_def_id(module_id);
+            if let Some(module_id) = parent_id {
                 if let Ok((_, res)) =
                     resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
                 {
@@ -167,15 +167,14 @@ fn resolve(
         disambiguator: Option<&str>,
         ns: Namespace,
         current_item: &Option<String>,
-        parent_id: Option<hir::HirId>,
+        parent_id: Option<DefId>,
         extra_fragment: &Option<String>,
         item_opt: Option<&Item>,
     ) -> Result<(Res, Option<String>), ErrorKind> {
         let cx = self.cx;
 
         // 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().local_def_id(module_id);
+        if let Some(module_id) = parent_id {
             let result = cx.enter_resolver(|resolver| {
                 resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
             });
@@ -445,40 +444,40 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Option<(Res, T)>>) -> bool {
 
 impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
     fn fold_item(&mut self, mut item: Item) -> Option<Item> {
-        let item_hir_id = if item.is_mod() {
-            if let Some(def_id) = item.def_id.as_local() {
-                Some(self.cx.tcx.hir().as_local_hir_id(def_id))
-            } else {
-                debug!("attempting to fold on a non-local item: {:?}", item);
-                return self.fold_item_recur(item);
-            }
-        } else {
-            None
-        };
+        use rustc_middle::ty::DefIdTree;
 
-        // FIXME: get the resolver to work with non-local resolve scopes.
-        let parent_node = self.cx.as_local_hir_id(item.def_id).and_then(|hir_id| {
-            // FIXME: this fails hard for impls in non-module scope, but is necessary for the
-            // current `resolve()` implementation.
-            match self.cx.as_local_hir_id(self.cx.tcx.parent_module(hir_id).to_def_id()).unwrap() {
-                id if id != hir_id => Some(id),
-                _ => None,
+        let parent_node = if item.is_fake() {
+            // FIXME: is this correct?
+            None
+        } else {
+            let mut current = item.def_id;
+            // The immediate parent might not always be a module.
+            // Find the first parent which is.
+            loop {
+                if let Some(parent) = self.cx.tcx.parent(current) {
+                    if self.cx.tcx.def_kind(parent) == DefKind::Mod {
+                        break Some(parent);
+                    }
+                    current = parent;
+                } else {
+                    break None;
+                }
             }
-        });
+        };
 
         if parent_node.is_some() {
-            debug!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
+            trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
         }
 
         let current_item = match item.inner {
             ModuleItem(..) => {
                 if item.attrs.inner_docs {
-                    if item_hir_id.unwrap() != hir::CRATE_HIR_ID { item.name.clone() } else { None }
+                    if item.def_id.is_top_level_module() { item.name.clone() } else { None }
                 } else {
-                    match parent_node.or(self.mod_ids.last().cloned()) {
-                        Some(parent) if parent != hir::CRATE_HIR_ID => {
+                    match parent_node.or(self.mod_ids.last().copied()) {
+                        Some(parent) if !parent.is_top_level_module() => {
                             // FIXME: can we pull the parent module's name from elsewhere?
-                            Some(self.cx.tcx.hir().name(parent).to_string())
+                            Some(self.cx.tcx.item_name(parent).to_string())
                         }
                         _ => None,
                     }
@@ -488,18 +487,22 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
                 for_.def_id().map(|did| self.cx.tcx.item_name(did).to_string())
             }
             // we don't display docs on `extern crate` items anyway, so don't process them.
-            ExternCrateItem(..) => return self.fold_item_recur(item),
+            ExternCrateItem(..) => {
+                debug!("ignoring extern crate item {:?}", item.def_id);
+                return self.fold_item_recur(item);
+            }
             ImportItem(Import::Simple(ref name, ..)) => Some(name.clone()),
             MacroItem(..) => None,
             _ => item.name.clone(),
         };
 
         if item.is_mod() && item.attrs.inner_docs {
-            self.mod_ids.push(item_hir_id.unwrap());
+            self.mod_ids.push(item.def_id);
         }
 
         let cx = self.cx;
         let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
+        trace!("got documentation '{}'", dox);
 
         look_for_tests(&cx, &dox, &item, true);
 
@@ -541,6 +544,8 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
         });
 
         for (ori_link, link_range) in markdown_links(&dox) {
+            trace!("considering link '{}'", ori_link);
+
             // Bail early for real links.
             if ori_link.contains('/') {
                 continue;
@@ -579,25 +584,18 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             let (res, fragment) = {
                 let mut kind = None;
                 let mut disambiguator = None;
-                path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"]
-                    .iter()
-                    .find(|p| link.starts_with(**p))
+                path_str = if let Some(prefix) =
+                    ["struct@", "enum@", "type@", "trait@", "union@", "module@", "mod@"]
+                        .iter()
+                        .find(|p| link.starts_with(**p))
                 {
                     kind = Some(TypeNS);
                     disambiguator = Some(&prefix[..prefix.len() - 1]);
                     link.trim_start_matches(prefix)
-                } else if let Some(prefix) = [
-                    "const@",
-                    "static@",
-                    "value@",
-                    "function@",
-                    "mod@",
-                    "fn@",
-                    "module@",
-                    "method@",
-                ]
-                .iter()
-                .find(|p| link.starts_with(**p))
+                } else if let Some(prefix) =
+                    ["const@", "static@", "value@", "function@", "fn@", "method@"]
+                        .iter()
+                        .find(|p| link.starts_with(**p))
                 {
                     kind = Some(ValueNS);
                     disambiguator = Some(&prefix[..prefix.len() - 1]);
@@ -641,8 +639,11 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
                 // we've already pushed this node onto the resolution stack but
                 // for outer comments we explicitly try and resolve against the
                 // parent_node first.
-                let base_node =
-                    if item.is_mod() && item.attrs.inner_docs { None } else { parent_node };
+                let base_node = if item.is_mod() && item.attrs.inner_docs {
+                    self.mod_ids.last().copied()
+                } else {
+                    parent_node
+                };
 
                 // replace `Self` with suitable item's parent name
                 if path_str.starts_with("Self::") {
@@ -826,7 +827,7 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
         }
 
         if item.is_mod() && !item.attrs.inner_docs {
-            self.mod_ids.push(item_hir_id.unwrap());
+            self.mod_ids.push(item.def_id);
         }
 
         if item.is_mod() {
@@ -864,6 +865,7 @@ fn build_diagnostic(
         Some(hir_id) => hir_id,
         None => {
             // If non-local, no need to check anything.
+            info!("ignoring warning from parent crate: {}", err_msg);
             return;
         }
     };
index c2d644bdd05f1894f28d3ecf34b57644ac8d9eb1..e8ea71997109ad31ec7c78047e201176b7775d5c 100644 (file)
@@ -45,14 +45,14 @@ pub struct TestOptions {
 pub fn run(options: Options) -> Result<(), String> {
     let input = config::Input::File(options.input.clone());
 
-    let invalid_codeblock_attribute_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
+    let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
 
     // In addition to those specific lints, we also need to allow those given through
     // command line, otherwise they'll get ignored and we don't want that.
-    let allowed_lints = vec![invalid_codeblock_attribute_name.to_owned()];
+    let allowed_lints = vec![invalid_codeblock_attributes_name.to_owned()];
 
     let (lint_opts, lint_caps) = init_lints(allowed_lints, options.lint_opts.clone(), |lint| {
-        if lint.name == invalid_codeblock_attribute_name {
+        if lint.name == invalid_codeblock_attributes_name {
             None
         } else {
             Some((lint.name_lower(), lint::Allow))
index c18f417e4f8e1173ab61fcb969df0bd53ef83e8f..735446d235c2e65154489af5826d637edf611ab9 100644 (file)
@@ -303,26 +303,22 @@ fn inherits_doc_hidden(cx: &core::DocContext<'_>, mut node: hir::HirId) -> bool
         if !res_did.is_local() && !is_no_inline {
             let attrs = clean::inline::load_attrs(self.cx, res_did);
             let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden);
-            match res {
-                Res::Def(
-                    DefKind::Trait
-                    | DefKind::Struct
-                    | DefKind::Union
-                    | DefKind::Enum
-                    | DefKind::ForeignTy
-                    | DefKind::TyAlias,
-                    did,
-                ) if !self_is_hidden => {
-                    self.cx.renderinfo.get_mut().access_levels.map.insert(did, AccessLevel::Public);
-                }
-                Res::Def(DefKind::Mod, did) => {
-                    if !self_is_hidden {
-                        crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did);
+            if !self_is_hidden {
+                if let Res::Def(kind, did) = res {
+                    if kind == DefKind::Mod {
+                        crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did)
+                    } else {
+                        // All items need to be handled here in case someone wishes to link
+                        // to them with intra-doc links
+                        self.cx
+                            .renderinfo
+                            .get_mut()
+                            .access_levels
+                            .map
+                            .insert(did, AccessLevel::Public);
                     }
                 }
-                _ => {}
             }
-
             return false;
         }
 
index 490afb5a0438f9088c545d4ede084e4b3797d927..136db6d5d3239d55211c9cf27a669b033d2d5428 100644 (file)
@@ -25,11 +25,15 @@ profiler_builtins = { path = "../libprofiler_builtins", optional = true }
 unwind = { path = "../libunwind" }
 hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] }
 
-[dependencies.backtrace_rs]
-package = "backtrace"
-version = "0.3.46"
-default-features = false # without the libstd `backtrace` feature, stub out everything
-features = [ "rustc-dep-of-std" ] # enable build support for integrating into libstd
+# Dependencies of the `backtrace` crate
+addr2line = { version = "0.13.0", optional = true, default-features = false }
+rustc-demangle = { version = "0.1.4", optional = true }
+miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
+[dependencies.object]
+version = "0.20"
+optional = true
+default-features = false
+features = ['read_core', 'elf', 'macho', 'pe']
 
 [dev-dependencies]
 rand = "0.7"
@@ -47,14 +51,14 @@ hermit-abi = { version = "0.1.14", features = ['rustc-dep-of-std'] }
 wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
 
 [features]
-default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
-
 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
+  "gimli-symbolize",
+  'addr2line/rustc-dep-of-std',
+  'object/rustc-dep-of-std',
+  'rustc-demangle/rustc-dep-of-std',
+  'miniz_oxide/rustc-dep-of-std',
 ]
+gimli-symbolize = []
 
 panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
index e10d466030f0b1abc135e1418373c8d08fc0ea40..e65775c1ced67909ad9d5e0954f946e78ffd55b5 100644 (file)
@@ -91,6 +91,7 @@
 // `Backtrace`, but that's a relatively small price to pay relative to capturing
 // a backtrace or actually symbolizing it.
 
+use crate::backtrace_rs::{self, BytesOrWideString};
 use crate::env;
 use crate::ffi::c_void;
 use crate::fmt;
@@ -98,8 +99,6 @@
 use crate::sync::Mutex;
 use crate::sys_common::backtrace::{lock, output_filename};
 use crate::vec::Vec;
-use backtrace::BytesOrWideString;
-use backtrace_rs as backtrace;
 
 /// A captured OS thread stack backtrace.
 ///
@@ -150,7 +149,7 @@ struct BacktraceFrame {
 }
 
 enum RawFrame {
-    Actual(backtrace::Frame),
+    Actual(backtrace_rs::Frame),
     #[cfg(test)]
     Fake,
 }
@@ -197,7 +196,7 @@ impl fmt::Debug for BacktraceSymbol {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(fmt, "{{ ")?;
 
-        if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
+        if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) {
             write!(fmt, "fn: \"{:#}\"", fn_name)?;
         } else {
             write!(fmt, "fn: <unknown>")?;
@@ -223,7 +222,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                 BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                 BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
             },
-            backtrace::PrintFmt::Short,
+            backtrace_rs::PrintFmt::Short,
             crate::env::current_dir().as_ref().ok(),
         )
     }
@@ -299,7 +298,7 @@ fn create(ip: usize) -> Backtrace {
         let mut frames = Vec::new();
         let mut actual_start = None;
         unsafe {
-            backtrace::trace_unsynchronized(|frame| {
+            backtrace_rs::trace_unsynchronized(|frame| {
                 frames.push(BacktraceFrame {
                     frame: RawFrame::Actual(frame.clone()),
                     symbols: Vec::new(),
@@ -350,9 +349,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 
         let full = fmt.alternate();
         let (frames, style) = if full {
-            (&capture.frames[..], backtrace::PrintFmt::Full)
+            (&capture.frames[..], backtrace_rs::PrintFmt::Full)
         } else {
-            (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
+            (&capture.frames[capture.actual_start..], backtrace_rs::PrintFmt::Short)
         };
 
         // When printing paths we try to strip the cwd if it exists, otherwise
@@ -364,7 +363,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
             output_filename(fmt, path, style, cwd.as_ref().ok())
         };
 
-        let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
+        let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path);
         f.add_context()?;
         for frame in frames {
             let mut f = f.frame();
@@ -374,7 +373,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                 for symbol in frame.symbols.iter() {
                     f.print_raw(
                         frame.frame.ip(),
-                        symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
+                        symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)),
                         symbol.filename.as_ref().map(|b| match b {
                             BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                             BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
@@ -409,7 +408,7 @@ fn resolve(&mut self) {
                 RawFrame::Fake => unimplemented!(),
             };
             unsafe {
-                backtrace::resolve_frame_unsynchronized(frame, |symbol| {
+                backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
                     symbols.push(BacktraceSymbol {
                         name: symbol.name().map(|m| m.as_bytes().to_vec()),
                         filename: symbol.filename_raw().map(|b| match b {
index 743a1778fbda339c4675ebe94fa663473f869ad7..58fb6fda19aabed41aafde057139836be1c69c2e 100644 (file)
@@ -62,5 +62,30 @@ fn main() {
         }
         println!("cargo:rustc-link-lib=c");
         println!("cargo:rustc-link-lib=compiler_rt");
+    } else if (target.contains("sgx") && target.contains("fortanix"))
+        || target.contains("hermit")
+        || target.contains("l4re")
+        || target.contains("redox")
+        || target.contains("haiku")
+        || target.contains("vxworks")
+        || target.contains("wasm32")
+        || target.contains("asmjs")
+    {
+        // These platforms don't have any special requirements.
+    } else {
+        // This is for Cargo's build-std support, to mark std as unstable for
+        // typically no_std platforms.
+        // This covers:
+        // - os=none ("bare metal" targets)
+        // - mipsel-sony-psp
+        // - nvptx64-nvidia-cuda
+        // - avr-unknown-unknown
+        // - tvos (aarch64-apple-tvos, x86_64-apple-tvos)
+        // - uefi (x86_64-unknown-uefi, i686-unknown-uefi)
+        // - JSON targets
+        // - Any new targets that have not been explicitly added above.
+        println!("cargo:rustc-cfg=feature=\"restricted-std\"");
     }
+    println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
+    println!("cargo:rustc-cfg=backtrace_in_libstd");
 }
index 97c20ca9459ef43d4953bcd19d0aa37547d0faa9..6489e0709cb91f8dec8d51f3a61d3709c1bfef87 100644 (file)
@@ -882,7 +882,7 @@ pub mod consts {
     /// - s390x
     /// - sparc64
     #[stable(feature = "env", since = "1.0.0")]
-    pub const ARCH: &str = super::arch::ARCH;
+    pub const ARCH: &str = env!("STD_ENV_ARCH");
 
     /// The family of the operating system. Example value is `unix`.
     ///
@@ -966,81 +966,6 @@ pub mod consts {
     pub const EXE_EXTENSION: &str = os::EXE_EXTENSION;
 }
 
-#[cfg(target_arch = "x86")]
-mod arch {
-    pub const ARCH: &str = "x86";
-}
-
-#[cfg(target_arch = "x86_64")]
-mod arch {
-    pub const ARCH: &str = "x86_64";
-}
-
-#[cfg(target_arch = "arm")]
-mod arch {
-    pub const ARCH: &str = "arm";
-}
-
-#[cfg(target_arch = "aarch64")]
-mod arch {
-    pub const ARCH: &str = "aarch64";
-}
-
-#[cfg(target_arch = "mips")]
-mod arch {
-    pub const ARCH: &str = "mips";
-}
-
-#[cfg(target_arch = "mips64")]
-mod arch {
-    pub const ARCH: &str = "mips64";
-}
-
-#[cfg(target_arch = "powerpc")]
-mod arch {
-    pub const ARCH: &str = "powerpc";
-}
-
-#[cfg(target_arch = "powerpc64")]
-mod arch {
-    pub const ARCH: &str = "powerpc64";
-}
-
-#[cfg(target_arch = "s390x")]
-mod arch {
-    pub const ARCH: &str = "s390x";
-}
-
-#[cfg(target_arch = "sparc64")]
-mod arch {
-    pub const ARCH: &str = "sparc64";
-}
-
-#[cfg(target_arch = "le32")]
-mod arch {
-    pub const ARCH: &str = "le32";
-}
-
-#[cfg(target_arch = "asmjs")]
-mod arch {
-    pub const ARCH: &str = "asmjs";
-}
-
-#[cfg(target_arch = "wasm32")]
-mod arch {
-    pub const ARCH: &str = "wasm32";
-}
-
-#[cfg(target_arch = "hexagon")]
-mod arch {
-    pub const ARCH: &'static str = "hexagon";
-}
-
-#[cfg(target_arch = "riscv64")]
-mod arch {
-    pub const ARCH: &'static str = "riscv64";
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
index dca1fdde4824295f72cd1539d5fa124ca96b3d9e..da25a0ede729d1fd3c66b1819fda6e91d17aa3bb 100644 (file)
@@ -1551,6 +1551,27 @@ fn index(&self, _index: ops::RangeFull) -> &CStr {
     }
 }
 
+#[stable(feature = "cstr_range_from", since = "1.47.0")]
+impl ops::Index<ops::RangeFrom<usize>> for CStr {
+    type Output = CStr;
+
+    fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
+        let bytes = self.to_bytes_with_nul();
+        // we need to manually check the starting index to account for the null
+        // byte, since otherwise we could get an empty string that doesn't end
+        // in a null.
+        if index.start < bytes.len() {
+            unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) }
+        } else {
+            panic!(
+                "index out of bounds: the len is {} but the index is {}",
+                bytes.len(),
+                index.start
+            );
+        }
+    }
+}
+
 #[stable(feature = "cstring_asref", since = "1.7.0")]
 impl AsRef<CStr> for CStr {
     #[inline]
@@ -1747,4 +1768,21 @@ fn cstr_const_constructor() {
 
         assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
     }
+
+    #[test]
+    fn cstr_index_from() {
+        let original = b"Hello, world!\0";
+        let cstr = CStr::from_bytes_with_nul(original).unwrap();
+        let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();
+
+        assert_eq!(&cstr[7..], result);
+    }
+
+    #[test]
+    #[should_panic]
+    fn cstr_index_from_empty() {
+        let original = b"Hello, world!\0";
+        let cstr = CStr::from_bytes_with_nul(original).unwrap();
+        let _ = &cstr[original.len()..];
+    }
 }
index 717d2868abf982295502b98b45e07b7454490a27..d5af4f25102d1de3c31bb63f3105a49278d36dc9 100644 (file)
@@ -499,6 +499,7 @@ pub(crate) fn default_write_vectored<F>(write: F, bufs: &[IoSlice<'_>]) -> Resul
 /// [`&str`]: ../../std/primitive.str.html
 /// [slice]: ../../std/primitive.slice.html
 #[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
 pub trait Read {
     /// Pull some bytes from this source into the specified buffer, returning
     /// how many bytes were read.
@@ -1261,6 +1262,7 @@ pub fn initialize(&self, buf: &mut [u8]) {
 ///
 /// [`write_all`]: #method.write_all
 #[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
 pub trait Write {
     /// Write a buffer into this writer, returning how many bytes were written.
     ///
index d6b7ad6254a8cba2cad3a43bfe8f5e3f7c5e0599..156f555be02d8d4ab0832a725cdcc861316062ca 100644 (file)
@@ -256,9 +256,23 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
 /// [`BufRead`]: trait.BufRead.html
 ///
 /// ### Note: Windows Portability Consideration
+///
 /// When operating in a console, the Windows implementation of this stream does not support
 /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
 /// an error.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::{self, Read};
+///
+/// fn main() -> io::Result<()> {
+///     let mut buffer = String::new();
+///     let mut stdin = io::stdin(); // We get `Stdin` here.
+///     stdin.read_to_string(&mut buffer)?;
+///     Ok(())
+/// }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Stdin {
     inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
@@ -274,9 +288,26 @@ pub struct Stdin {
 /// [`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
 /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
 /// an error.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::{self, Read};
+///
+/// fn main() -> io::Result<()> {
+///     let mut buffer = String::new();
+///     let stdin = io::stdin(); // We get `Stdin` here.
+///     {
+///         let mut stdin_lock = stdin.lock(); // We get `StdinLock` here.
+///         stdin_lock.read_to_string(&mut buffer)?;
+///     } // `StdinLock` is dropped here.
+///     Ok(())
+/// }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StdinLock<'a> {
     inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
index a53e7f5cf57aa15c2af6912db92921b7ceb91a5c..d985f10ccb486489fe65680c495e9127b851dbd7 100644 (file)
@@ -1497,11 +1497,188 @@ mod super_keyword {}
 
 #[doc(keyword = "trait")]
 //
-/// A common interface for a class of types.
+/// A common interface for a group of types.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// A `trait` is like an interface that data types can implement. When a type
+/// implements a trait it can be treated abstractly as that trait using generics
+/// or trait objects.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// Traits can be made up of three varieties of associated items:
+///
+/// - functions and methods
+/// - types
+/// - constants
+///
+/// Traits may also contain additional type parameters. Those type parameters
+/// or the trait itself can be constrained by other traits.
+///
+/// Traits can serve as markers or carry other logical semantics that
+/// aren't expressed through their items. When a type implements that
+/// trait it is promising to uphold its contract. [`Send`] and [`Sync`] are two
+/// such marker traits present in the standard library.
+///
+/// See the [Reference][Ref-Traits] for a lot more information on traits.
+///
+/// # Examples
+///
+/// Traits are declared using the `trait` keyword. Types can implement them
+/// using [`impl`] `Trait` [`for`] `Type`:
+///
+/// ```rust
+/// trait Zero {
+///     const ZERO: Self;
+///     fn is_zero(&self) -> bool;
+/// }
+///
+/// impl Zero for i32 {
+///     const ZERO: Self = 0;
+///
+///     fn is_zero(&self) -> bool {
+///         *self == Self::ZERO
+///     }
+/// }
+///
+/// assert_eq!(i32::ZERO, 0);
+/// assert!(i32::ZERO.is_zero());
+/// assert!(!4.is_zero());
+/// ```
+///
+/// With an associated type:
+///
+/// ```rust
+/// trait Builder {
+///     type Built;
+///
+///     fn build(&self) -> Self::Built;
+/// }
+/// ```
+///
+/// Traits can be generic, with constraints or without:
+///
+/// ```rust
+/// trait MaybeFrom<T> {
+///     fn maybe_from(value: T) -> Option<Self>
+///     where
+///         Self: Sized;
+/// }
+/// ```
+///
+/// Traits can build upon the requirements of other traits. In the example
+/// below `Iterator` is a **supertrait** and `ThreeIterator` is a **subtrait**:
+///
+/// ```rust
+/// trait ThreeIterator: std::iter::Iterator {
+///     fn next_three(&mut self) -> Option<[Self::Item; 3]>;
+/// }
+/// ```
+///
+/// Traits can be used in functions, as parameters:
+///
+/// ```rust
+/// # #![allow(dead_code)]
+/// fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug {
+///     for elem in it {
+///         println!("{:#?}", elem);
+///     }
+/// }
+///
+/// // u8_len_1, u8_len_2 and u8_len_3 are equivalent
+///
+/// fn u8_len_1(val: impl Into<Vec<u8>>) -> usize {
+///     val.into().len()
+/// }
+///
+/// fn u8_len_2<T: Into<Vec<u8>>>(val: T) -> usize {
+///     val.into().len()
+/// }
+///
+/// fn u8_len_3<T>(val: T) -> usize
+/// where
+///     T: Into<Vec<u8>>,
+/// {
+///     val.into().len()
+/// }
+/// ```
+///
+/// Or as return types:
+///
+/// ```rust
+/// # #![allow(dead_code)]
+/// fn from_zero_to(v: u8) -> impl Iterator<Item = u8> {
+///     (0..v).into_iter()
+/// }
+/// ```
+///
+/// The use of the [`impl`] keyword in this position allows the function writer
+/// to hide the concrete type as an implementation detail which can change
+/// without breaking user's code.
+///
+/// # Trait objects
+///
+/// A *trait object* is an opaque value of another type that implements a set of
+/// traits. A trait object implements all specified traits as well as their
+/// supertraits (if any).
+///
+/// The syntax is the following: `dyn BaseTrait + AutoTrait1 + ... AutoTraitN`.
+/// Only one `BaseTrait` can be used so this will not compile:
+///
+/// ```rust,compile_fail,E0225
+/// trait A {}
+/// trait B {}
+///
+/// let _: Box<dyn A + B>;
+/// ```
+///
+/// Neither will this, which is a syntax error:
+///
+/// ```rust,compile_fail
+/// trait A {}
+/// trait B {}
+///
+/// let _: Box<dyn A + dyn B>;
+/// ```
+///
+/// On the other hand, this is correct:
+///
+/// ```rust
+/// trait A {}
+///
+/// let _: Box<dyn A + Send + Sync>;
+/// ```
+///
+/// The [Reference][Ref-Trait-Objects] has more information about trait objects,
+/// their limitations and the differences between editions.
+///
+/// # Unsafe traits
+///
+/// Some traits may be unsafe to implement. Using the [`unsafe`] keyword in
+/// front of the trait's declaration is used to mark this:
+///
+/// ```rust
+/// unsafe trait UnsafeTrait {}
+///
+/// unsafe impl UnsafeTrait for i32 {}
+/// ```
+///
+/// # Differences between the 2015 and 2018 editions
+///
+/// In the 2015 edition parameters pattern where not needed for traits:
+///
+/// ```rust,edition2015
+/// trait Tr {
+///     fn f(i32);
+/// }
+/// ```
+///
+/// This behavior is no longer valid in edition 2018.
+///
+/// [`for`]: keyword.for.html
+/// [`impl`]: keyword.impl.html
+/// [`unsafe`]: keyword.unsafe.html
+/// [`Send`]: marker/trait.Send.html
+/// [`Sync`]: marker/trait.Sync.html
+/// [Ref-Traits]: ../reference/items/traits.html
+/// [Ref-Trait-Objects]: ../reference/types/trait-object.html
 mod trait_keyword {}
 
 #[doc(keyword = "true")]
diff --git a/src/libstd/lazy.rs b/src/libstd/lazy.rs
new file mode 100644 (file)
index 0000000..86e1cfa
--- /dev/null
@@ -0,0 +1,844 @@
+//! Lazy values and one-time initialization of static data.
+
+use crate::{
+    cell::{Cell, UnsafeCell},
+    fmt,
+    mem::{self, MaybeUninit},
+    ops::{Deref, Drop},
+    panic::{RefUnwindSafe, UnwindSafe},
+    sync::Once,
+};
+
+#[doc(inline)]
+#[unstable(feature = "once_cell", issue = "74465")]
+pub use core::lazy::*;
+
+/// A synchronization primitive which can be written to only once.
+///
+/// This type is a thread-safe `OnceCell`.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::lazy::SyncOnceCell;
+///
+/// static CELL: SyncOnceCell<String> = SyncOnceCell::new();
+/// assert!(CELL.get().is_none());
+///
+/// std::thread::spawn(|| {
+///     let value: &String = CELL.get_or_init(|| {
+///         "Hello, World!".to_string()
+///     });
+///     assert_eq!(value, "Hello, World!");
+/// }).join().unwrap();
+///
+/// let value: Option<&String> = CELL.get();
+/// assert!(value.is_some());
+/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct SyncOnceCell<T> {
+    once: Once,
+    // Whether or not the value is initialized is tracked by `state_and_queue`.
+    value: UnsafeCell<MaybeUninit<T>>,
+}
+
+// Why do we need `T: Send`?
+// Thread A creates a `SyncOnceCell` and shares it with
+// scoped thread B, which fills the cell, which is
+// then destroyed by A. That is, destructor observes
+// a sent value.
+#[unstable(feature = "once_cell", issue = "74465")]
+unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {}
+#[unstable(feature = "once_cell", issue = "74465")]
+unsafe impl<T: Send> Send for SyncOnceCell<T> {}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {}
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> Default for SyncOnceCell<T> {
+    fn default() -> SyncOnceCell<T> {
+        SyncOnceCell::new()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.get() {
+            Some(v) => f.debug_tuple("Once").field(v).finish(),
+            None => f.write_str("Once(Uninit)"),
+        }
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Clone> Clone for SyncOnceCell<T> {
+    fn clone(&self) -> SyncOnceCell<T> {
+        let cell = Self::new();
+        if let Some(value) = self.get() {
+            match cell.set(value.clone()) {
+                Ok(()) => (),
+                Err(_) => unreachable!(),
+            }
+        }
+        cell
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T> From<T> for SyncOnceCell<T> {
+    fn from(value: T) -> Self {
+        let cell = Self::new();
+        match cell.set(value) {
+            Ok(()) => cell,
+            Err(_) => unreachable!(),
+        }
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: PartialEq> PartialEq for SyncOnceCell<T> {
+    fn eq(&self, other: &SyncOnceCell<T>) -> bool {
+        self.get() == other.get()
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Eq> Eq for SyncOnceCell<T> {}
+
+impl<T> SyncOnceCell<T> {
+    /// Creates a new empty cell.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new() -> SyncOnceCell<T> {
+        SyncOnceCell { once: Once::new(), value: UnsafeCell::new(MaybeUninit::uninit()) }
+    }
+
+    /// Gets the reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty, or being initialized. This
+    /// method never blocks.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get(&self) -> Option<&T> {
+        if self.is_initialized() {
+            // Safe b/c checked is_initialized
+            Some(unsafe { self.get_unchecked() })
+        } else {
+            None
+        }
+    }
+
+    /// Gets the mutable reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty. This method never blocks.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_mut(&mut self) -> Option<&mut T> {
+        if self.is_initialized() {
+            // Safe b/c checked is_initialized and we have a unique access
+            Some(unsafe { self.get_unchecked_mut() })
+        } else {
+            None
+        }
+    }
+
+    /// Sets the contents of this cell to `value`.
+    ///
+    /// Returns `Ok(())` if the cell's value was updated.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new();
+    ///
+    /// fn main() {
+    ///     assert!(CELL.get().is_none());
+    ///
+    ///     std::thread::spawn(|| {
+    ///         assert_eq!(CELL.set(92), Ok(()));
+    ///     }).join().unwrap();
+    ///
+    ///     assert_eq!(CELL.set(62), Err(62));
+    ///     assert_eq!(CELL.get(), Some(&92));
+    /// }
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn set(&self, value: T) -> Result<(), T> {
+        let mut value = Some(value);
+        self.get_or_init(|| value.take().unwrap());
+        match value {
+            None => Ok(()),
+            Some(value) => Err(value),
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if the cell
+    /// was empty.
+    ///
+    /// Many threads may call `get_or_init` concurrently with different
+    /// initializing functions, but it is guaranteed that only one function
+    /// will be executed.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. The
+    /// exact outcome is unspecified. Current implementation deadlocks, but
+    /// this may be changed to a panic in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// let value = cell.get_or_init(|| 92);
+    /// assert_eq!(value, &92);
+    /// let value = cell.get_or_init(|| unreachable!());
+    /// assert_eq!(value, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_init<F>(&self, f: F) -> &T
+    where
+        F: FnOnce() -> T,
+    {
+        match self.get_or_try_init(|| Ok::<T, !>(f())) {
+            Ok(val) => val,
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if
+    /// the cell was empty. If the cell was empty and `f` failed, an
+    /// error is returned.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and
+    /// the cell remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`.
+    /// The exact outcome is unspecified. Current implementation
+    /// deadlocks, but this may be changed to a panic in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+    /// assert!(cell.get().is_none());
+    /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
+    ///     Ok(92)
+    /// });
+    /// assert_eq!(value, Ok(&92));
+    /// assert_eq!(cell.get(), Some(&92))
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        // Fast path check
+        // NOTE: We need to perform an acquire on the state in this method
+        // in order to correctly synchronize `SyncLazy::force`. This is
+        // currently done by calling `self.get()`, which in turn calls
+        // `self.is_initialized()`, which in turn performs the acquire.
+        if let Some(value) = self.get() {
+            return Ok(value);
+        }
+        self.initialize(f)?;
+
+        debug_assert!(self.is_initialized());
+
+        // Safety: The inner value has been initialized
+        Ok(unsafe { self.get_unchecked() })
+    }
+
+    /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns
+    /// `None` if the cell was empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell: SyncOnceCell<String> = SyncOnceCell::new();
+    /// assert_eq!(cell.into_inner(), None);
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn into_inner(mut self) -> Option<T> {
+        // Safety: Safe because we immediately free `self` without dropping
+        let inner = unsafe { self.take_inner() };
+
+        // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set
+        // the state to uninitialized.
+        mem::ManuallyDrop::new(self);
+        inner
+    }
+
+    /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
+    ///
+    /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized.
+    ///
+    /// Safety is guaranteed by requiring a mutable reference.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let mut cell: SyncOnceCell<String> = SyncOnceCell::new();
+    /// assert_eq!(cell.take(), None);
+    ///
+    /// let mut cell = SyncOnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.take(), Some("hello".to_string()));
+    /// assert_eq!(cell.get(), None);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn take(&mut self) -> Option<T> {
+        mem::take(self).into_inner()
+    }
+
+    /// Takes the wrapped value out of a `SyncOnceCell`.
+    /// Afterwards the cell is no longer initialized.
+    ///
+    /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell
+    /// are valid. Only used by `into_inner` and `drop`.
+    unsafe fn take_inner(&mut self) -> Option<T> {
+        // The mutable reference guarantees there are no other threads that can observe us
+        // taking out the wrapped value.
+        // Right after this function `self` is supposed to be freed, so it makes little sense
+        // to atomically set the state to uninitialized.
+        if self.is_initialized() {
+            let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit()));
+            Some(value.into_inner().assume_init())
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn is_initialized(&self) -> bool {
+        self.once.is_completed()
+    }
+
+    #[cold]
+    fn initialize<F, E>(&self, f: F) -> Result<(), E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        let mut res: Result<(), E> = Ok(());
+        let slot = &self.value;
+
+        // Ignore poisoning from other threads
+        // If another thread panics, then we'll be able to run our closure
+        self.once.call_once_force(|p| {
+            match f() {
+                Ok(value) => {
+                    unsafe { (&mut *slot.get()).write(value) };
+                }
+                Err(e) => {
+                    res = Err(e);
+
+                    // Treat the underlying `Once` as poisoned since we
+                    // failed to initialize our value. Calls
+                    p.poison();
+                }
+            }
+        });
+        res
+    }
+
+    /// Safety: The value must be initialized
+    unsafe fn get_unchecked(&self) -> &T {
+        debug_assert!(self.is_initialized());
+        (&*self.value.get()).get_ref()
+    }
+
+    /// Safety: The value must be initialized
+    unsafe fn get_unchecked_mut(&mut self) -> &mut T {
+        debug_assert!(self.is_initialized());
+        (&mut *self.value.get()).get_mut()
+    }
+}
+
+impl<T> Drop for SyncOnceCell<T> {
+    fn drop(&mut self) {
+        // Safety: The cell is being dropped, so it can't be accessed again
+        unsafe { self.take_inner() };
+    }
+}
+
+/// A value which is initialized on the first access.
+///
+/// This type is a thread-safe `Lazy`, and can be used in statics.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::collections::HashMap;
+///
+/// use std::lazy::SyncLazy;
+///
+/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| {
+///     println!("initializing");
+///     let mut m = HashMap::new();
+///     m.insert(13, "Spica".to_string());
+///     m.insert(74, "Hoyten".to_string());
+///     m
+/// });
+///
+/// fn main() {
+///     println!("ready");
+///     std::thread::spawn(|| {
+///         println!("{:?}", HASHMAP.get(&13));
+///     }).join().unwrap();
+///     println!("{:?}", HASHMAP.get(&74));
+///
+///     // Prints:
+///     //   ready
+///     //   initializing
+///     //   Some("Spica")
+///     //   Some("Hoyten")
+/// }
+/// ```
+#[unstable(feature = "once_cell", issue = "74465")]
+pub struct SyncLazy<T, F = fn() -> T> {
+    cell: SyncOnceCell<T>,
+    init: Cell<Option<F>>,
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
+    }
+}
+
+// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine
+// to not impl `Sync` for `F`
+// we do create a `&mut Option<F>` in `force`, but this is
+// properly synchronized, so it only happens once
+// so it also does not contribute to this impl.
+#[unstable(feature = "once_cell", issue = "74465")]
+unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
+// auto-derived `Send` impl is OK.
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T, F: RefUnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {}
+
+impl<T, F> SyncLazy<T, F> {
+    /// Creates a new lazy value with the given initializing
+    /// function.
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub const fn new(f: F) -> SyncLazy<T, F> {
+        SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) }
+    }
+}
+
+impl<T, F: FnOnce() -> T> SyncLazy<T, F> {
+    /// Forces the evaluation of this lazy value and
+    /// returns a reference to result. This is equivalent
+    /// to the `Deref` impl, but is explicit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncLazy;
+    ///
+    /// let lazy = SyncLazy::new(|| 92);
+    ///
+    /// assert_eq!(SyncLazy::force(&lazy), &92);
+    /// assert_eq!(&*lazy, &92);
+    /// ```
+    #[unstable(feature = "once_cell", issue = "74465")]
+    pub fn force(this: &SyncLazy<T, F>) -> &T {
+        this.cell.get_or_init(|| match this.init.take() {
+            Some(f) => f(),
+            None => panic!("Lazy instance has previously been poisoned"),
+        })
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        SyncLazy::force(self)
+    }
+}
+
+#[unstable(feature = "once_cell", issue = "74465")]
+impl<T: Default> Default for SyncLazy<T> {
+    /// Creates a new lazy value using `Default` as the initializing function.
+    fn default() -> SyncLazy<T> {
+        SyncLazy::new(T::default)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::{
+        lazy::{Lazy, SyncLazy, SyncOnceCell},
+        panic,
+        sync::{
+            atomic::{AtomicUsize, Ordering::SeqCst},
+            mpsc::channel,
+            Mutex,
+        },
+    };
+
+    #[test]
+    fn lazy_default() {
+        static CALLED: AtomicUsize = AtomicUsize::new(0);
+
+        struct Foo(u8);
+        impl Default for Foo {
+            fn default() -> Self {
+                CALLED.fetch_add(1, SeqCst);
+                Foo(42)
+            }
+        }
+
+        let lazy: Lazy<Mutex<Foo>> = <_>::default();
+
+        assert_eq!(CALLED.load(SeqCst), 0);
+
+        assert_eq!(lazy.lock().unwrap().0, 42);
+        assert_eq!(CALLED.load(SeqCst), 1);
+
+        lazy.lock().unwrap().0 = 21;
+
+        assert_eq!(lazy.lock().unwrap().0, 21);
+        assert_eq!(CALLED.load(SeqCst), 1);
+    }
+
+    #[test]
+    fn lazy_poisoning() {
+        let x: Lazy<String> = Lazy::new(|| panic!("kaboom"));
+        for _ in 0..2 {
+            let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len()));
+            assert!(res.is_err());
+        }
+    }
+
+    // miri doesn't support threads
+    #[cfg(not(miri))]
+    fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
+        crate::thread::spawn(f).join().unwrap()
+    }
+
+    #[cfg(not(miri))]
+    fn spawn(f: impl FnOnce() + Send + 'static) {
+        let _ = crate::thread::spawn(f);
+    }
+
+    // "stub threads" for Miri
+    #[cfg(miri)]
+    fn spawn_and_wait<R: Send + 'static>(f: impl FnOnce() -> R + Send + 'static) -> R {
+        f(())
+    }
+
+    #[cfg(miri)]
+    fn spawn(f: impl FnOnce() + Send + 'static) {
+        f(())
+    }
+
+    #[test]
+    fn sync_once_cell() {
+        static ONCE_CELL: SyncOnceCell<i32> = SyncOnceCell::new();
+
+        assert!(ONCE_CELL.get().is_none());
+
+        spawn_and_wait(|| {
+            ONCE_CELL.get_or_init(|| 92);
+            assert_eq!(ONCE_CELL.get(), Some(&92));
+        });
+
+        ONCE_CELL.get_or_init(|| panic!("Kabom!"));
+        assert_eq!(ONCE_CELL.get(), Some(&92));
+    }
+
+    #[test]
+    fn sync_once_cell_get_mut() {
+        let mut c = SyncOnceCell::new();
+        assert!(c.get_mut().is_none());
+        c.set(90).unwrap();
+        *c.get_mut().unwrap() += 2;
+        assert_eq!(c.get_mut(), Some(&mut 92));
+    }
+
+    #[test]
+    fn sync_once_cell_get_unchecked() {
+        let c = SyncOnceCell::new();
+        c.set(92).unwrap();
+        unsafe {
+            assert_eq!(c.get_unchecked(), &92);
+        }
+    }
+
+    #[test]
+    fn sync_once_cell_drop() {
+        static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
+        struct Dropper;
+        impl Drop for Dropper {
+            fn drop(&mut self) {
+                DROP_CNT.fetch_add(1, SeqCst);
+            }
+        }
+
+        let x = SyncOnceCell::new();
+        spawn_and_wait(move || {
+            x.get_or_init(|| Dropper);
+            assert_eq!(DROP_CNT.load(SeqCst), 0);
+            drop(x);
+        });
+
+        assert_eq!(DROP_CNT.load(SeqCst), 1);
+    }
+
+    #[test]
+    fn sync_once_cell_drop_empty() {
+        let x = SyncOnceCell::<String>::new();
+        drop(x);
+    }
+
+    #[test]
+    fn clone() {
+        let s = SyncOnceCell::new();
+        let c = s.clone();
+        assert!(c.get().is_none());
+
+        s.set("hello".to_string()).unwrap();
+        let c = s.clone();
+        assert_eq!(c.get().map(String::as_str), Some("hello"));
+    }
+
+    #[test]
+    fn get_or_try_init() {
+        let cell: SyncOnceCell<String> = SyncOnceCell::new();
+        assert!(cell.get().is_none());
+
+        let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() }));
+        assert!(res.is_err());
+        assert!(!cell.is_initialized());
+        assert!(cell.get().is_none());
+
+        assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+
+        assert_eq!(
+            cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())),
+            Ok(&"hello".to_string())
+        );
+        assert_eq!(cell.get(), Some(&"hello".to_string()));
+    }
+
+    #[test]
+    fn from_impl() {
+        assert_eq!(SyncOnceCell::from("value").get(), Some(&"value"));
+        assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar"));
+    }
+
+    #[test]
+    fn partialeq_impl() {
+        assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value"));
+        assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar"));
+
+        assert!(SyncOnceCell::<String>::new() == SyncOnceCell::new());
+        assert!(SyncOnceCell::<String>::new() != SyncOnceCell::from("value".to_owned()));
+    }
+
+    #[test]
+    fn into_inner() {
+        let cell: SyncOnceCell<String> = SyncOnceCell::new();
+        assert_eq!(cell.into_inner(), None);
+        let cell = SyncOnceCell::new();
+        cell.set("hello".to_string()).unwrap();
+        assert_eq!(cell.into_inner(), Some("hello".to_string()));
+    }
+
+    #[test]
+    fn sync_lazy_new() {
+        static CALLED: AtomicUsize = AtomicUsize::new(0);
+        static SYNC_LAZY: SyncLazy<i32> = SyncLazy::new(|| {
+            CALLED.fetch_add(1, SeqCst);
+            92
+        });
+
+        assert_eq!(CALLED.load(SeqCst), 0);
+
+        spawn_and_wait(|| {
+            let y = *SYNC_LAZY - 30;
+            assert_eq!(y, 62);
+            assert_eq!(CALLED.load(SeqCst), 1);
+        });
+
+        let y = *SYNC_LAZY - 30;
+        assert_eq!(y, 62);
+        assert_eq!(CALLED.load(SeqCst), 1);
+    }
+
+    #[test]
+    fn sync_lazy_default() {
+        static CALLED: AtomicUsize = AtomicUsize::new(0);
+
+        struct Foo(u8);
+        impl Default for Foo {
+            fn default() -> Self {
+                CALLED.fetch_add(1, SeqCst);
+                Foo(42)
+            }
+        }
+
+        let lazy: SyncLazy<Mutex<Foo>> = <_>::default();
+
+        assert_eq!(CALLED.load(SeqCst), 0);
+
+        assert_eq!(lazy.lock().unwrap().0, 42);
+        assert_eq!(CALLED.load(SeqCst), 1);
+
+        lazy.lock().unwrap().0 = 21;
+
+        assert_eq!(lazy.lock().unwrap().0, 21);
+        assert_eq!(CALLED.load(SeqCst), 1);
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // leaks memory
+    fn static_sync_lazy() {
+        static XS: SyncLazy<Vec<i32>> = SyncLazy::new(|| {
+            let mut xs = Vec::new();
+            xs.push(1);
+            xs.push(2);
+            xs.push(3);
+            xs
+        });
+
+        spawn_and_wait(|| {
+            assert_eq!(&*XS, &vec![1, 2, 3]);
+        });
+
+        assert_eq!(&*XS, &vec![1, 2, 3]);
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // leaks memory
+    fn static_sync_lazy_via_fn() {
+        fn xs() -> &'static Vec<i32> {
+            static XS: SyncOnceCell<Vec<i32>> = SyncOnceCell::new();
+            XS.get_or_init(|| {
+                let mut xs = Vec::new();
+                xs.push(1);
+                xs.push(2);
+                xs.push(3);
+                xs
+            })
+        }
+        assert_eq!(xs(), &vec![1, 2, 3]);
+    }
+
+    #[test]
+    fn sync_lazy_poisoning() {
+        let x: SyncLazy<String> = SyncLazy::new(|| panic!("kaboom"));
+        for _ in 0..2 {
+            let res = panic::catch_unwind(|| x.len());
+            assert!(res.is_err());
+        }
+    }
+
+    #[test]
+    fn is_sync_send() {
+        fn assert_traits<T: Send + Sync>() {}
+        assert_traits::<SyncOnceCell<String>>();
+        assert_traits::<SyncLazy<String>>();
+    }
+
+    #[test]
+    fn eval_once_macro() {
+        macro_rules! eval_once {
+            (|| -> $ty:ty {
+                $($body:tt)*
+            }) => {{
+                static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new();
+                fn init() -> $ty {
+                    $($body)*
+                }
+                ONCE_CELL.get_or_init(init)
+            }};
+        }
+
+        let fib: &'static Vec<i32> = eval_once! {
+            || -> Vec<i32> {
+                let mut res = vec![1, 1];
+                for i in 0..10 {
+                    let next = res[i] + res[i + 1];
+                    res.push(next);
+                }
+                res
+            }
+        };
+        assert_eq!(fib[5], 8)
+    }
+
+    #[test]
+    #[cfg_attr(miri, ignore)] // deadlocks without real threads
+    fn sync_once_cell_does_not_leak_partially_constructed_boxes() {
+        static ONCE_CELL: SyncOnceCell<String> = SyncOnceCell::new();
+
+        let n_readers = 10;
+        let n_writers = 3;
+        const MSG: &str = "Hello, World";
+
+        let (tx, rx) = channel();
+
+        for _ in 0..n_readers {
+            let tx = tx.clone();
+            spawn(move || {
+                loop {
+                    if let Some(msg) = ONCE_CELL.get() {
+                        tx.send(msg).unwrap();
+                        break;
+                    }
+                }
+            });
+        }
+        for _ in 0..n_writers {
+            spawn(move || {
+                let _ = ONCE_CELL.set(MSG.to_owned());
+            });
+        }
+
+        for _ in 0..n_readers {
+            let msg = rx.recv().unwrap();
+            assert_eq!(msg, MSG);
+        }
+    }
+}
index bd585d39c242fb226b21af7cfd37ea397d4c51cb..11b8f953be46008c0a8cd05c3e62da77e8a4ea03 100644 (file)
@@ -85,8 +85,9 @@
 //! # Contributing changes to the documentation
 //!
 //! Check out the rust contribution guidelines [here](
-//! https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md).
-//! The source for this documentation can be found on [Github](https://github.com/rust-lang).
+//! https://rustc-dev-guide.rust-lang.org/getting-started.html).
+//! The source for this documentation can be found on
+//! [GitHub](https://github.com/rust-lang/rust).
 //! To contribute changes, make sure you read the guidelines first, then submit
 //! pull-requests for your suggested changes.
 //!
 //! [primitive types]: ../book/ch03-02-data-types.html
 //! [rust-discord]: https://discord.gg/rust-lang
 
-#![stable(feature = "rust1", since = "1.0.0")]
+#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
+#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/",
 #![feature(atomic_mut_ptr)]
 #![feature(box_syntax)]
 #![feature(c_variadic)]
-#![feature(cfg_accessible)]
 #![feature(can_vector)]
+#![feature(cfg_accessible)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
 #![feature(doc_cfg)]
 #![feature(doc_keyword)]
 #![feature(doc_masked)]
+#![cfg_attr(not(bootstrap), feature(doc_spotlight))]
 #![feature(dropck_eyepatch)]
 #![feature(duration_constants)]
 #![feature(exact_size_is_empty)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
 #![feature(int_error_matching)]
-#![feature(into_future)]
 #![feature(integer_atomics)]
+#![feature(into_future)]
 #![feature(lang_items)]
 #![feature(libc)]
 #![feature(link_args)]
 #![feature(linkage)]
 #![feature(llvm_asm)]
 #![feature(log_syntax)]
+#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
+#![feature(min_specialization)]
 #![feature(needs_panic_runtime)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(nll)]
+#![feature(once_cell)]
 #![feature(optin_builtin_traits)]
 #![feature(or_patterns)]
 #![feature(panic_info_message)]
 #![feature(ptr_internals)]
 #![feature(raw)]
 #![feature(raw_ref_macros)]
+#![feature(ready_macro)]
 #![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
 #![feature(shrink_to)]
 #![feature(slice_concat_ext)]
 #![feature(slice_internals)]
-#![feature(min_specialization)]
+#![feature(slice_strip)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stdsimd)]
 #![feature(toowned_clone_into)]
 #![feature(total_cmp)]
 #![feature(trace_macros)]
-#![cfg_attr(bootstrap, feature(track_caller))]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
 #![feature(unsafe_block_in_unsafe_fn)]
 pub mod sync;
 pub mod time;
 
+#[unstable(feature = "once_cell", issue = "74465")]
+pub mod lazy;
+
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub mod task {
     //! Types and Traits for working with asynchronous tasks.
@@ -505,6 +514,10 @@ pub mod task {
 // compiler
 pub mod rt;
 
+#[path = "../backtrace/src/lib.rs"]
+#[allow(dead_code, unused_attributes)]
+mod backtrace_rs;
+
 // Pull in the `std_detect` crate directly into libstd. The contents of
 // `std_detect` are in a different repository: rust-lang/stdarch.
 //
@@ -551,3 +564,9 @@ pub mod task {
 // the rustdoc documentation for the existing keywords. Using `include!`
 // because rustdoc only looks for these modules at the crate level.
 include!("keyword_docs.rs");
+
+// This is required to avoid an unstable error when `restricted-std` is not
+// enabled. The use of #![feature(restricted_std)] in rustc-std-workspace-std
+// is unconditional, so the unstable feature needs to be defined somewhere.
+#[cfg_attr(not(feature = "restricted-std"), unstable(feature = "restricted_std", issue = "none"))]
+mod __restricted_std_workaround {}
index 9542e7209b4cf168347e18b00cc3253c349fb020..ab2a60103069d6571179c20c565f5e64800d6f0b 100644 (file)
@@ -171,7 +171,7 @@ fn default_hook(info: &PanicInfo<'_>) {
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
     let backtrace_env = if panic_count::get() >= 2 {
-        RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
+        RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full)
     } else {
         backtrace::rust_backtrace_env()
     };
index 2250c0d4203ef26a52d4fb2b7b0c442a82a1ba1a..9b90bfd68b50f3047ec1ee6e01245efe98311a11 100644 (file)
@@ -694,7 +694,6 @@ fn wait_while() {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_wait() {
         let m = Arc::new(Mutex::new(()));
         let c = Arc::new(Condvar::new());
@@ -714,7 +713,6 @@ fn wait_timeout_wait() {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_while_wait() {
         let m = Arc::new(Mutex::new(()));
         let c = Arc::new(Condvar::new());
@@ -739,7 +737,6 @@ fn wait_timeout_while_instant_satisfy() {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_while_wake() {
         let pair = Arc::new((Mutex::new(false), Condvar::new()));
         let pair_copy = pair.clone();
@@ -763,7 +760,6 @@ fn wait_timeout_while_wake() {
 
     #[test]
     #[cfg_attr(target_os = "emscripten", ignore)]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn wait_timeout_wake() {
         let m = Arc::new(Mutex::new(()));
         let c = Arc::new(Condvar::new());
index d6cc811154f11f667bd2abf47c1e1765061f517a..3ff50e9f213477716e1f39447a5d4451ca2cfc62 100644 (file)
@@ -2088,7 +2088,6 @@ fn recv(rx: Receiver<Box<i32>>, i: i32) {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn oneshot_single_thread_recv_timeout() {
         let (tx, rx) = channel();
         tx.send(()).unwrap();
@@ -2099,7 +2098,6 @@ fn oneshot_single_thread_recv_timeout() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_two_threads() {
         let (tx, rx) = channel();
         let stress = stress_factor() + 100;
@@ -2130,7 +2128,6 @@ fn stress_recv_timeout_two_threads() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn recv_timeout_upgrade() {
         let (tx, rx) = channel::<()>();
         let timeout = Duration::from_millis(1);
@@ -2142,7 +2139,6 @@ fn recv_timeout_upgrade() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_shared() {
         let (tx, rx) = channel();
         let stress = stress_factor() + 100;
@@ -2173,7 +2169,6 @@ fn stress_recv_timeout_shared() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn very_long_recv_timeout_wont_panic() {
         let (tx, rx) = channel::<()>();
         let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX)));
@@ -2195,7 +2190,6 @@ fn recv_a_lot() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn shared_recv_timeout() {
         let (tx, rx) = channel();
         let total = 5;
@@ -2425,7 +2419,6 @@ fn smoke_shared() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn recv_timeout() {
         let (tx, rx) = sync_channel::<i32>(1);
         assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
@@ -2517,7 +2510,6 @@ fn stress() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_two_threads() {
         let (tx, rx) = sync_channel::<i32>(0);
 
@@ -2543,7 +2535,6 @@ fn stress_recv_timeout_two_threads() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn stress_recv_timeout_shared() {
         const AMT: u32 = 1000;
         const NTHREADS: u32 = 8;
index 7dc822db3d0271fe7266a275e3854cf6391f5186..64260990824b86fdc9e51afeed8aeca6dea34ff9 100644 (file)
@@ -132,6 +132,7 @@ unsafe impl Send for Once {}
 #[derive(Debug)]
 pub struct OnceState {
     poisoned: bool,
+    set_state_on_drop_to: Cell<usize>,
 }
 
 /// Initialization value for static [`Once`] values.
@@ -321,7 +322,7 @@ pub fn call_once_force<F>(&self, f: F)
         }
 
         let mut f = Some(f);
-        self.call_inner(true, &mut |p| f.take().unwrap()(&OnceState { poisoned: p }));
+        self.call_inner(true, &mut |p| f.take().unwrap()(p));
     }
 
     /// Returns `true` if some `call_once` call has completed
@@ -385,7 +386,7 @@ pub fn is_completed(&self) -> bool {
     // currently no way to take an `FnOnce` and call it via virtual dispatch
     // without some allocation overhead.
     #[cold]
-    fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(bool)) {
+    fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) {
         let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
         loop {
             match state_and_queue {
@@ -413,8 +414,12 @@ fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(bool)) {
                     };
                     // Run the initialization function, letting it know if we're
                     // poisoned or not.
-                    init(state_and_queue == POISONED);
-                    waiter_queue.set_state_on_drop_to = COMPLETE;
+                    let init_state = OnceState {
+                        poisoned: state_and_queue == POISONED,
+                        set_state_on_drop_to: Cell::new(COMPLETE),
+                    };
+                    init(&init_state);
+                    waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get();
                     break;
                 }
                 _ => {
@@ -554,6 +559,14 @@ impl OnceState {
     pub fn poisoned(&self) -> bool {
         self.poisoned
     }
+
+    /// Poison the associated [`Once`] without explicitly panicking.
+    ///
+    /// [`Once`]: struct.Once.html
+    // NOTE: This is currently only exposed for the `lazy` module
+    pub(crate) fn poison(&self) {
+        self.set_state_on_drop_to.set(POISONED);
+    }
 }
 
 #[cfg(all(test, not(target_os = "emscripten")))]
index 8dbc31472d637247ba7409efcbf5f8eba3a10140..f7dd2c8d00fd220b1f2fb688e8ea18225d81d59a 100644 (file)
@@ -16,8 +16,8 @@
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-#[path = "../unix/thread_local.rs"]
-pub mod thread_local;
+#[path = "../unix/thread_local_key.rs"]
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/src/libstd/sys/hermit/fast_thread_local.rs b/src/libstd/sys/hermit/fast_thread_local.rs
deleted file mode 100644 (file)
index 9b683fc..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#![cfg(target_thread_local)]
-#![unstable(feature = "thread_local_internals", issue = "none")]
-
-// Simplify dtor registration by using a list of destructors.
-// The this solution works like the implementation of macOS and
-// doesn't additional OS support
-
-use crate::cell::Cell;
-use crate::ptr;
-
-#[thread_local]
-static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
-
-type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
-
-pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    if DTORS.get().is_null() {
-        let v: Box<List> = box Vec::new();
-        DTORS.set(Box::into_raw(v));
-    }
-
-    let list: &mut List = &mut *DTORS.get();
-    list.push((t, dtor));
-}
-
-// every thread call this function to run through all possible destructors
-pub unsafe fn run_dtors() {
-    let mut ptr = DTORS.replace(ptr::null_mut());
-    while !ptr.is_null() {
-        let list = Box::from_raw(ptr);
-        for (ptr, dtor) in list.into_iter() {
-            dtor(ptr);
-        }
-        ptr = DTORS.replace(ptr::null_mut());
-    }
-}
index 7bdc1be3b1702902c897196e16496692b93f64d2..675b82ceb775f7b0a35c116cc54b2c39d0c93b90 100644 (file)
@@ -22,7 +22,6 @@
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fd;
 pub mod fs;
 pub mod io;
@@ -37,7 +36,8 @@
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 
 use crate::io::ErrorKind;
diff --git a/src/libstd/sys/hermit/thread_local.rs b/src/libstd/sys/hermit/thread_local.rs
deleted file mode 100644 (file)
index f8be986..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-pub type Key = usize;
-
-#[inline]
-pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub unsafe fn set(_key: Key, _value: *mut u8) {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub unsafe fn get(_key: Key) -> *mut u8 {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub unsafe fn destroy(_key: Key) {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    panic!("should not be used on the wasm target");
-}
diff --git a/src/libstd/sys/hermit/thread_local_dtor.rs b/src/libstd/sys/hermit/thread_local_dtor.rs
new file mode 100644 (file)
index 0000000..9b683fc
--- /dev/null
@@ -0,0 +1,36 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "none")]
+
+// Simplify dtor registration by using a list of destructors.
+// The this solution works like the implementation of macOS and
+// doesn't additional OS support
+
+use crate::cell::Cell;
+use crate::ptr;
+
+#[thread_local]
+static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+
+type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    if DTORS.get().is_null() {
+        let v: Box<List> = box Vec::new();
+        DTORS.set(Box::into_raw(v));
+    }
+
+    let list: &mut List = &mut *DTORS.get();
+    list.push((t, dtor));
+}
+
+// every thread call this function to run through all possible destructors
+pub unsafe fn run_dtors() {
+    let mut ptr = DTORS.replace(ptr::null_mut());
+    while !ptr.is_null() {
+        let list = Box::from_raw(ptr);
+        for (ptr, dtor) in list.into_iter() {
+            dtor(ptr);
+        }
+        ptr = DTORS.replace(ptr::null_mut());
+    }
+}
diff --git a/src/libstd/sys/hermit/thread_local_key.rs b/src/libstd/sys/hermit/thread_local_key.rs
new file mode 100644 (file)
index 0000000..bf1b49e
--- /dev/null
@@ -0,0 +1,26 @@
+pub type Key = usize;
+
+#[inline]
+pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+    panic!("should not be used on the hermit target");
+}
+
+#[inline]
+pub unsafe fn set(_key: Key, _value: *mut u8) {
+    panic!("should not be used on the hermit target");
+}
+
+#[inline]
+pub unsafe fn get(_key: Key) -> *mut u8 {
+    panic!("should not be used on the hermit target");
+}
+
+#[inline]
+pub unsafe fn destroy(_key: Key) {
+    panic!("should not be used on the hermit target");
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    panic!("should not be used on the hermit target");
+}
index 875ff1af92013b5e03b2b829970c760b4839f4cd..7b5fac922d08a77151677b65d6118ccbb59f8881 100644 (file)
@@ -48,7 +48,8 @@
         mod sgx;
         pub use self::sgx::*;
     } else {
-        compile_error!("libstd doesn't compile for this platform yet");
+        mod unsupported;
+        pub use self::unsupported::*;
     }
 }
 
index 5ef26d4cc4dc65a52d3e4e2eb6d92f4990585c22..b0693b63a48fd19c3b863edd53daa79a7de9d438 100644 (file)
@@ -17,6 +17,9 @@
 #[cfg(not(test))]
 global_asm!(include_str!("entry.S"));
 
+#[repr(C)]
+struct EntryReturn(u64, u64);
+
 #[cfg(not(test))]
 #[no_mangle]
 unsafe extern "C" fn tcs_init(secondary: bool) {
@@ -56,8 +59,7 @@
 // able to specify this
 #[cfg(not(test))]
 #[no_mangle]
-#[allow(improper_ctypes_definitions)]
-extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
+extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
     // FIXME: how to support TLS in library mode?
     let tls = Box::new(tls::Tls::new());
     let _tls_guard = unsafe { tls.activate() };
@@ -65,7 +67,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
     if secondary {
         super::thread::Thread::entry();
 
-        (0, 0)
+        EntryReturn(0, 0)
     } else {
         extern "C" {
             fn main(argc: isize, argv: *const *const u8) -> isize;
index ae803ee47a6cb1717bd7439a6cc80322b28557ad..73f1b951e74304b0d406ba631e0f9c26896fac79 100644 (file)
@@ -1,6 +1,8 @@
 use crate::cmp;
-use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult};
-use crate::time::Duration;
+use crate::convert::TryFrom;
+use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
+use crate::sys::rand::rdrand64;
+use crate::time::{Duration, Instant};
 
 pub(crate) mod alloc;
 #[macro_use]
@@ -149,10 +151,94 @@ pub fn exit(panic: bool) -> ! {
 
 /// Usercall `wait`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
-pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
+pub fn wait(event_mask: u64, mut timeout: u64) -> IoResult<u64> {
+    if timeout != WAIT_NO && timeout != WAIT_INDEFINITE {
+        // We don't want people to rely on accuracy of timeouts to make
+        // security decisions in an SGX enclave. That's why we add a random
+        // amount not exceeding +/- 10% to the timeout value to discourage
+        // people from relying on accuracy of timeouts while providing a way
+        // to make things work in other cases. Note that in the SGX threat
+        // model the enclave runner which is serving the wait usercall is not
+        // trusted to ensure accurate timeouts.
+        if let Ok(timeout_signed) = i64::try_from(timeout) {
+            let tenth = timeout_signed / 10;
+            let deviation = (rdrand64() as i64).checked_rem(tenth).unwrap_or(0);
+            timeout = timeout_signed.saturating_add(deviation) as _;
+        }
+    }
     unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
 }
 
+/// This function makes an effort to wait for a non-spurious event at least as
+/// long as `duration`. Note that in general there is no guarantee about accuracy
+/// of time and timeouts in SGX model. The enclave runner serving usercalls may
+/// lie about current time and/or ignore timeout values.
+///
+/// Once the event is observed, `should_wake_up` will be used to determine
+/// whether or not the event was spurious.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn wait_timeout<F>(event_mask: u64, duration: Duration, should_wake_up: F)
+where
+    F: Fn() -> bool,
+{
+    // Calls the wait usercall and checks the result. Returns true if event was
+    // returned, and false if WouldBlock/TimedOut was returned.
+    // If duration is None, it will use WAIT_NO.
+    fn wait_checked(event_mask: u64, duration: Option<Duration>) -> bool {
+        let timeout = duration.map_or(raw::WAIT_NO, |duration| {
+            cmp::min((u64::MAX - 1) as u128, duration.as_nanos()) as u64
+        });
+        match wait(event_mask, timeout) {
+            Ok(eventset) => {
+                if event_mask == 0 {
+                    rtabort!("expected wait() to return Err, found Ok.");
+                }
+                rtassert!(eventset != 0 && eventset & !event_mask == 0);
+                true
+            }
+            Err(e) => {
+                rtassert!(e.kind() == ErrorKind::TimedOut || e.kind() == ErrorKind::WouldBlock);
+                false
+            }
+        }
+    }
+
+    match wait_checked(event_mask, Some(duration)) {
+        false => return,                    // timed out
+        true if should_wake_up() => return, // woken up
+        true => {}                          // spurious event
+    }
+
+    // Drain all cached events.
+    // Note that `event_mask != 0` is implied if we get here.
+    loop {
+        match wait_checked(event_mask, None) {
+            false => break,                     // no more cached events
+            true if should_wake_up() => return, // woken up
+            true => {}                          // spurious event
+        }
+    }
+
+    // Continue waiting, but take note of time spent waiting so we don't wait
+    // forever. We intentionally don't call `Instant::now()` before this point
+    // to avoid the cost of the `insecure_time` usercall in case there are no
+    // spurious wakeups.
+
+    let start = Instant::now();
+    let mut remaining = duration;
+    loop {
+        match wait_checked(event_mask, Some(remaining)) {
+            false => return,                    // timed out
+            true if should_wake_up() => return, // woken up
+            true => {}                          // spurious event
+        }
+        remaining = match duration.checked_sub(start.elapsed()) {
+            Some(remaining) => remaining,
+            None => break,
+        }
+    }
+}
+
 /// Usercall `send`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
index 9c5c086184d686bb94e261d56b7d85529ef8519b..ed6dbcf497147f68834e71a85bdad2165fc50f6c 100644 (file)
@@ -31,8 +31,10 @@ pub unsafe fn wait(&self, mutex: &Mutex) {
         mutex.lock()
     }
 
-    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
-        rtabort!("timeout not supported in SGX");
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock());
+        mutex.lock();
+        success
     }
 
     #[inline]
index 397dd496ae8afa468e788326d3547c782c6cac40..1d32eb25424345578d63d378ad1fa3c9d463f4db 100644 (file)
@@ -30,7 +30,7 @@
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
@@ -137,8 +137,8 @@ pub extern "C" fn __rust_abort() {
     abort_internal();
 }
 
-pub fn hashmap_random_keys() -> (u64, u64) {
-    fn rdrand64() -> u64 {
+pub mod rand {
+    pub fn rdrand64() -> u64 {
         unsafe {
             let mut ret: u64 = 0;
             for _ in 0..10 {
@@ -149,7 +149,10 @@ fn rdrand64() -> u64 {
             rtabort!("Failed to obtain random data");
         }
     }
-    (rdrand64(), rdrand64())
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (self::rand::rdrand64(), self::rand::rdrand64())
 }
 
 pub use crate::sys_common::{AsInner, FromInner, IntoInner};
index 9b515eb82de350bd5bc468d4cf626d8f0ca10c6b..5895f70436efa4a6f36547fd36e24fb0bffd048f 100644 (file)
@@ -73,8 +73,8 @@ pub fn set_name(_name: &CStr) {
         // FIXME: could store this pointer in TLS somewhere
     }
 
-    pub fn sleep(_dur: Duration) {
-        rtabort!("can't sleep"); // FIXME
+    pub fn sleep(dur: Duration) {
+        usercalls::wait_timeout(0, dur, || true);
     }
 
     pub fn join(self) {
diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local.rs
deleted file mode 100644 (file)
index b217844..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-use super::abi::tls::{Key as AbiKey, Tls};
-
-pub type Key = usize;
-
-#[inline]
-pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    Tls::create(dtor).as_usize()
-}
-
-#[inline]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    Tls::set(AbiKey::from_usize(key), value)
-}
-
-#[inline]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    Tls::get(AbiKey::from_usize(key))
-}
-
-#[inline]
-pub unsafe fn destroy(key: Key) {
-    Tls::destroy(AbiKey::from_usize(key))
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    false
-}
diff --git a/src/libstd/sys/sgx/thread_local_key.rs b/src/libstd/sys/sgx/thread_local_key.rs
new file mode 100644 (file)
index 0000000..b217844
--- /dev/null
@@ -0,0 +1,28 @@
+use super::abi::tls::{Key as AbiKey, Tls};
+
+pub type Key = usize;
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+    Tls::create(dtor).as_usize()
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    Tls::set(AbiKey::from_usize(key), value)
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    Tls::get(AbiKey::from_usize(key))
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+    Tls::destroy(AbiKey::from_usize(key))
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    false
+}
index 6e50f161b3b4191b2f664c97b389f967c8740212..070afa55f301927e3d5f7ac429a5fb930e3c595c 100644 (file)
@@ -1,16 +1,17 @@
+//! A simple queue implementation for synchronization primitives.
+//!
+//! This queue is used to implement condition variable and mutexes.
+//!
+//! Users of this API are expected to use the `WaitVariable<T>` type. Since
+//! that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
+//! allow shared access.
+//!
+//! Since userspace may send spurious wake-ups, the wakeup event state is
+//! recorded in the enclave. The wakeup event state is protected by a spinlock.
+//! The queue and associated wait state are stored in a `WaitVariable`.
 use crate::num::NonZeroUsize;
-/// A simple queue implementation for synchronization primitives.
-///
-/// This queue is used to implement condition variable and mutexes.
-///
-/// Users of this API are expected to use the `WaitVariable<T>` type. Since
-/// that type is not `Sync`, it needs to be protected by e.g., a `SpinMutex` to
-/// allow shared access.
-///
-/// Since userspace may send spurious wake-ups, the wakeup event state is
-/// recorded in the enclave. The wakeup event state is protected by a spinlock.
-/// The queue and associated wait state are stored in a `WaitVariable`.
 use crate::ops::{Deref, DerefMut};
+use crate::time::Duration;
 
 use super::abi::thread;
 use super::abi::usercalls;
@@ -158,6 +159,34 @@ pub fn wait<T, F: FnOnce()>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>, befo
         }
     }
 
+    /// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
+    /// until a wakeup event or timeout. If event was observed, returns true.
+    /// If not, it will remove the calling thread from the wait queue.
+    pub fn wait_timeout<T, F: FnOnce()>(
+        lock: &SpinMutex<WaitVariable<T>>,
+        timeout: Duration,
+        before_wait: F,
+    ) -> bool {
+        // very unsafe: check requirements of UnsafeList::push
+        unsafe {
+            let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
+                tcs: thread::current(),
+                wake: false,
+            }));
+            let entry_lock = lock.lock().queue.inner.push(&mut entry);
+            before_wait();
+            usercalls::wait_timeout(EV_UNPARK, timeout, || entry_lock.lock().wake);
+            // acquire the wait queue's lock first to avoid deadlock.
+            let mut guard = lock.lock();
+            let success = entry_lock.lock().wake;
+            if !success {
+                // nobody is waking us up, so remove our entry from the wait queue.
+                guard.queue.inner.remove(&mut entry);
+            }
+            success
+        }
+    }
+
     /// Either find the next waiter on the wait queue, or return the mutex
     /// guard unchanged.
     ///
@@ -325,6 +354,31 @@ pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
                 Some((*first.as_ptr()).value.as_ref().unwrap())
             }
         }
+
+        /// Removes an entry from the list.
+        ///
+        /// # Safety
+        ///
+        /// The caller must ensure that `entry` has been pushed onto `self`
+        /// prior to this call and has not moved since then.
+        pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry<T>) {
+            rtassert!(!self.is_empty());
+            // BEFORE:
+            //     /----\ next ---> /-----\ next ---> /----\
+            // ... |prev|           |entry|           |next| ...
+            //     \----/ <--- prev \-----/ <--- prev \----/
+            //
+            // AFTER:
+            //     /----\ next ---> /----\
+            // ... |prev|           |next| ...
+            //     \----/ <--- prev \----/
+            let mut prev = entry.prev;
+            let mut next = entry.next;
+            prev.as_mut().next = next;
+            next.as_mut().prev = prev;
+            entry.next = NonNull::dangling();
+            entry.prev = NonNull::dangling();
+        }
     }
 
     #[cfg(test)]
@@ -354,6 +408,51 @@ fn push_pop() {
             }
         }
 
+        #[test]
+        fn push_remove() {
+            unsafe {
+                let mut node = UnsafeListEntry::new(1234);
+                let mut list = UnsafeList::new();
+                assert_eq!(list.push(&mut node), &1234);
+                list.remove(&mut node);
+                assert_empty(&mut list);
+            }
+        }
+
+        #[test]
+        fn push_remove_pop() {
+            unsafe {
+                let mut node1 = UnsafeListEntry::new(11);
+                let mut node2 = UnsafeListEntry::new(12);
+                let mut node3 = UnsafeListEntry::new(13);
+                let mut node4 = UnsafeListEntry::new(14);
+                let mut node5 = UnsafeListEntry::new(15);
+                let mut list = UnsafeList::new();
+                assert_eq!(list.push(&mut node1), &11);
+                assert_eq!(list.push(&mut node2), &12);
+                assert_eq!(list.push(&mut node3), &13);
+                assert_eq!(list.push(&mut node4), &14);
+                assert_eq!(list.push(&mut node5), &15);
+
+                list.remove(&mut node1);
+                assert_eq!(list.pop().unwrap(), &12);
+                list.remove(&mut node3);
+                assert_eq!(list.pop().unwrap(), &14);
+                list.remove(&mut node5);
+                assert_empty(&mut list);
+
+                assert_eq!(list.push(&mut node1), &11);
+                assert_eq!(list.pop().unwrap(), &11);
+                assert_empty(&mut list);
+
+                assert_eq!(list.push(&mut node3), &13);
+                assert_eq!(list.push(&mut node4), &14);
+                list.remove(&mut node3);
+                list.remove(&mut node4);
+                assert_empty(&mut list);
+            }
+        }
+
         #[test]
         fn complex_pushes_pops() {
             unsafe {
@@ -474,7 +573,7 @@ mod tests {
         use super::*;
         use crate::sync::Arc;
         use crate::thread;
-        use crate::time::{Duration, SystemTime};
+        use crate::time::Duration;
 
         #[test]
         fn sleep() {
@@ -485,11 +584,7 @@ fn sleep() {
                 *mutex2.lock() = 1;
             });
 
-            // "sleep" for 50ms
-            // FIXME: https://github.com/fortanix/rust-sgx/issues/31
-            let start = SystemTime::now();
-            let max = Duration::from_millis(50);
-            while start.elapsed().unwrap() < max {}
+            thread::sleep(Duration::from_millis(50));
 
             assert_eq!(*guard, 0);
             drop(guard);
index 5b712e202423236757516b6d5b9359447e9b9f93..9bc44a59482a029899da659c64720f9b3e9f8e9f 100644 (file)
@@ -208,7 +208,7 @@ pub fn args() -> Args {
         #[cfg(target_arch = "aarch64")]
         extern "C" {
             fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
-            #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
+            #[allow(clashing_extern_declarations)]
             #[link_name = "objc_msgSend"]
             fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
         }
@@ -216,7 +216,7 @@ pub fn args() -> Args {
         #[cfg(not(target_arch = "aarch64"))]
         extern "C" {
             fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
-            #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
+            #[allow(clashing_extern_declarations)]
             #[link_name = "objc_msgSend"]
             fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
         }
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
deleted file mode 100644 (file)
index 8730b4d..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#![cfg(target_thread_local)]
-#![unstable(feature = "thread_local_internals", issue = "none")]
-
-// 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.
-#[cfg(any(
-    target_os = "linux",
-    target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "emscripten"
-))]
-pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    use crate::mem;
-    use crate::sys_common::thread_local::register_dtor_fallback;
-
-    extern "C" {
-        #[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 "C" fn(
-            dtor: unsafe extern "C" 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);
-}
-
-// This implementation is very similar to register_dtor_fallback in
-// sys_common/thread_local.rs. The main difference is that we want to hook into
-// macOS's analog of the above linux function, _tlv_atexit. OSX will run the
-// registered dtors before any TLS slots get freed, and when the main thread
-// exits.
-//
-// Unfortunately, calling _tlv_atexit while tls dtors are running is UB. The
-// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
-// thread. thread_local dtors are pushed to the DTOR list without calling
-// _tlv_atexit.
-#[cfg(target_os = "macos")]
-pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    use crate::cell::Cell;
-    use crate::ptr;
-
-    #[thread_local]
-    static REGISTERED: Cell<bool> = Cell::new(false);
-    if !REGISTERED.get() {
-        _tlv_atexit(run_dtors, ptr::null_mut());
-        REGISTERED.set(true);
-    }
-
-    type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
-
-    #[thread_local]
-    static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
-    if DTORS.get().is_null() {
-        let v: Box<List> = box Vec::new();
-        DTORS.set(Box::into_raw(v));
-    }
-
-    extern "C" {
-        fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
-    }
-
-    let list: &mut List = &mut *DTORS.get();
-    list.push((t, dtor));
-
-    unsafe extern "C" fn run_dtors(_: *mut u8) {
-        let mut ptr = DTORS.replace(ptr::null_mut());
-        while !ptr.is_null() {
-            let list = Box::from_raw(ptr);
-            for (ptr, dtor) in list.into_iter() {
-                dtor(ptr);
-            }
-            ptr = DTORS.replace(ptr::null_mut());
-        }
-    }
-}
index b1688e74173d71560ec45f5a45273f1e111c5e8e..eddf00d3979f509292f4cd5fe17a18fafc642918 100644 (file)
@@ -47,7 +47,6 @@
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fd;
 pub mod fs;
 pub mod io;
@@ -68,7 +67,8 @@
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
index f0bd1cdfed52f0a2c250aeffb44284d31dda32cc..6daf2885baed0768e010cbd8698521b655da6e7a 100644 (file)
@@ -246,6 +246,7 @@ pub fn signal(&self) -> Option<i32> {
     }
 }
 
+/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
 impl From<c_int> for ExitStatus {
     fn from(a: c_int) -> ExitStatus {
         ExitStatus(a as i64)
index f389c60615f244e28fa34a3694e6f567adae9433..371291b9f76ab0a529bbaaab35646ed66f2febe3 100644 (file)
@@ -1,3 +1,4 @@
+use crate::convert::TryInto;
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::ptr;
@@ -17,7 +18,7 @@ pub fn spawn(
         default: Stdio,
         needs_stdin: bool,
     ) -> io::Result<(Process, StdioPipes)> {
-        const CLOEXEC_MSG_FOOTER: &[u8] = b"NOEX";
+        const CLOEXEC_MSG_FOOTER: [u8; 4] = *b"NOEX";
 
         let envp = self.capture_env();
 
@@ -52,11 +53,12 @@ pub fn spawn(
                     drop(input);
                     let Err(err) = self.do_exec(theirs, envp.as_ref());
                     let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
+                    let errno = errno.to_be_bytes();
                     let bytes = [
-                        (errno >> 24) as u8,
-                        (errno >> 16) as u8,
-                        (errno >> 8) as u8,
-                        (errno >> 0) as u8,
+                        errno[0],
+                        errno[1],
+                        errno[2],
+                        errno[3],
                         CLOEXEC_MSG_FOOTER[0],
                         CLOEXEC_MSG_FOOTER[1],
                         CLOEXEC_MSG_FOOTER[2],
@@ -81,12 +83,13 @@ pub fn spawn(
             match input.read(&mut bytes) {
                 Ok(0) => return Ok((p, ours)),
                 Ok(8) => {
+                    let (errno, footer) = bytes.split_at(4);
                     assert!(
-                        combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4..8]),
+                        combine(CLOEXEC_MSG_FOOTER) == combine(footer.try_into().unwrap()),
                         "Validation on the CLOEXEC pipe failed: {:?}",
                         bytes
                     );
-                    let errno = combine(&bytes[0..4]);
+                    let errno = combine(errno.try_into().unwrap());
                     assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
                     return Err(Error::from_raw_os_error(errno));
                 }
@@ -103,13 +106,8 @@ pub fn spawn(
             }
         }
 
-        fn combine(arr: &[u8]) -> i32 {
-            let a = arr[0] as u32;
-            let b = arr[1] as u32;
-            let c = arr[2] as u32;
-            let d = arr[3] as u32;
-
-            ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
+        fn combine(arr: [u8; 4]) -> i32 {
+            i32::from_be_bytes(arr)
         }
     }
 
@@ -481,6 +479,7 @@ pub fn signal(&self) -> Option<i32> {
     }
 }
 
+/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
 impl From<c_int> for ExitStatus {
     fn from(a: c_int) -> ExitStatus {
         ExitStatus(a)
diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local.rs
deleted file mode 100644 (file)
index 2c5b94b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#![allow(dead_code)] // not used on all platforms
-
-use crate::mem;
-
-pub type Key = libc::pthread_key_t;
-
-#[inline]
-pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    let mut key = 0;
-    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
-    key
-}
-
-#[inline]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    let r = libc::pthread_setspecific(key, value as *mut _);
-    debug_assert_eq!(r, 0);
-}
-
-#[inline]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    libc::pthread_getspecific(key) as *mut u8
-}
-
-#[inline]
-pub unsafe fn destroy(key: Key) {
-    let r = libc::pthread_key_delete(key);
-    debug_assert_eq!(r, 0);
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    false
-}
diff --git a/src/libstd/sys/unix/thread_local_dtor.rs b/src/libstd/sys/unix/thread_local_dtor.rs
new file mode 100644 (file)
index 0000000..c3275eb
--- /dev/null
@@ -0,0 +1,94 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "none")]
+
+//! Provides thread-local destructors without an associated "key", which
+//! can be more efficient.
+
+// 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.
+#[cfg(any(
+    target_os = "linux",
+    target_os = "fuchsia",
+    target_os = "redox",
+    target_os = "emscripten"
+))]
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    use crate::mem;
+    use crate::sys_common::thread_local_dtor::register_dtor_fallback;
+
+    extern "C" {
+        #[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 "C" fn(
+            dtor: unsafe extern "C" 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);
+}
+
+// This implementation is very similar to register_dtor_fallback in
+// sys_common/thread_local.rs. The main difference is that we want to hook into
+// macOS's analog of the above linux function, _tlv_atexit. OSX will run the
+// registered dtors before any TLS slots get freed, and when the main thread
+// exits.
+//
+// Unfortunately, calling _tlv_atexit while tls dtors are running is UB. The
+// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
+// thread. thread_local dtors are pushed to the DTOR list without calling
+// _tlv_atexit.
+#[cfg(target_os = "macos")]
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    use crate::cell::Cell;
+    use crate::ptr;
+
+    #[thread_local]
+    static REGISTERED: Cell<bool> = Cell::new(false);
+    if !REGISTERED.get() {
+        _tlv_atexit(run_dtors, ptr::null_mut());
+        REGISTERED.set(true);
+    }
+
+    type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+
+    #[thread_local]
+    static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+    if DTORS.get().is_null() {
+        let v: Box<List> = box Vec::new();
+        DTORS.set(Box::into_raw(v));
+    }
+
+    extern "C" {
+        fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
+    }
+
+    let list: &mut List = &mut *DTORS.get();
+    list.push((t, dtor));
+
+    unsafe extern "C" fn run_dtors(_: *mut u8) {
+        let mut ptr = DTORS.replace(ptr::null_mut());
+        while !ptr.is_null() {
+            let list = Box::from_raw(ptr);
+            for (ptr, dtor) in list.into_iter() {
+                dtor(ptr);
+            }
+            ptr = DTORS.replace(ptr::null_mut());
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/thread_local_key.rs b/src/libstd/sys/unix/thread_local_key.rs
new file mode 100644 (file)
index 0000000..2c5b94b
--- /dev/null
@@ -0,0 +1,34 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::mem;
+
+pub type Key = libc::pthread_key_t;
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+    let mut key = 0;
+    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
+    key
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    let r = libc::pthread_setspecific(key, value as *mut _);
+    debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    libc::pthread_getspecific(key) as *mut u8
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+    let r = libc::pthread_key_delete(key);
+    debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    false
+}
diff --git a/src/libstd/sys/unsupported/alloc.rs b/src/libstd/sys/unsupported/alloc.rs
new file mode 100644 (file)
index 0000000..8d5d0a2
--- /dev/null
@@ -0,0 +1,22 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
+        0 as *mut u8
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 {
+        0 as *mut u8
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+
+    #[inline]
+    unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 {
+        0 as *mut u8
+    }
+}
diff --git a/src/libstd/sys/unsupported/args.rs b/src/libstd/sys/unsupported/args.rs
new file mode 100644 (file)
index 0000000..71d0c5f
--- /dev/null
@@ -0,0 +1,38 @@
+use crate::ffi::OsString;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+pub unsafe fn cleanup() {}
+
+pub struct Args {}
+
+pub fn args() -> Args {
+    Args {}
+}
+
+impl Args {
+    pub fn inner_debug(&self) -> &[OsString] {
+        &[]
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> {
+        None
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize {
+        0
+    }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> {
+        None
+    }
+}
diff --git a/src/libstd/sys/unsupported/cmath.rs b/src/libstd/sys/unsupported/cmath.rs
new file mode 100644 (file)
index 0000000..304cf90
--- /dev/null
@@ -0,0 +1,29 @@
+// These symbols are all defined in `compiler-builtins`
+extern "C" {
+    pub fn acos(n: f64) -> f64;
+    pub fn acosf(n: f32) -> f32;
+    pub fn asin(n: f64) -> f64;
+    pub fn asinf(n: f32) -> f32;
+    pub fn atan(n: f64) -> f64;
+    pub fn atan2(a: f64, b: f64) -> f64;
+    pub fn atan2f(a: f32, b: f32) -> f32;
+    pub fn atanf(n: f32) -> f32;
+    pub fn cbrt(n: f64) -> f64;
+    pub fn cbrtf(n: f32) -> f32;
+    pub fn cosh(n: f64) -> f64;
+    pub fn coshf(n: f32) -> f32;
+    pub fn expm1(n: f64) -> f64;
+    pub fn expm1f(n: f32) -> f32;
+    pub fn fdim(a: f64, b: f64) -> f64;
+    pub fn fdimf(a: f32, b: f32) -> f32;
+    pub fn hypot(x: f64, y: f64) -> f64;
+    pub fn hypotf(x: f32, y: f32) -> f32;
+    pub fn log1p(n: f64) -> f64;
+    pub fn log1pf(n: f32) -> f32;
+    pub fn sinh(n: f64) -> f64;
+    pub fn sinhf(n: f32) -> f32;
+    pub fn tan(n: f64) -> f64;
+    pub fn tanf(n: f32) -> f32;
+    pub fn tanh(n: f64) -> f64;
+    pub fn tanhf(n: f32) -> f32;
+}
diff --git a/src/libstd/sys/unsupported/common.rs b/src/libstd/sys/unsupported/common.rs
new file mode 100644 (file)
index 0000000..80311d2
--- /dev/null
@@ -0,0 +1,48 @@
+use crate::io as std_io;
+
+pub mod memchr {
+    pub use core::slice::memchr::{memchr, memrchr};
+}
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+// This is not necessarily correct. May want to consider making it part of the
+// spec definition?
+use crate::os::raw::c_char;
+
+#[cfg(not(test))]
+pub fn init() {}
+
+pub fn unsupported<T>() -> std_io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> std_io::Error {
+    std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on this platform")
+}
+
+pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
+    crate::io::ErrorKind::Other
+}
+
+pub fn abort_internal() -> ! {
+    core::intrinsics::abort();
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (1, 2)
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+    let mut n = 0;
+    while *s != 0 {
+        n += 1;
+        s = s.offset(1);
+    }
+    return n;
+}
diff --git a/src/libstd/sys/unsupported/condvar.rs b/src/libstd/sys/unsupported/condvar.rs
new file mode 100644 (file)
index 0000000..a578eee
--- /dev/null
@@ -0,0 +1,30 @@
+use crate::sys::mutex::Mutex;
+use crate::time::Duration;
+
+pub struct Condvar {}
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar {}
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {}
+
+    #[inline]
+    pub unsafe fn notify_one(&self) {}
+
+    #[inline]
+    pub unsafe fn notify_all(&self) {}
+
+    pub unsafe fn wait(&self, _mutex: &Mutex) {
+        panic!("condvar wait not supported")
+    }
+
+    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+        panic!("condvar wait not supported");
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/unsupported/env.rs b/src/libstd/sys/unsupported/env.rs
new file mode 100644 (file)
index 0000000..d2efec5
--- /dev/null
@@ -0,0 +1,9 @@
+pub mod os {
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = "";
+    pub const DLL_EXTENSION: &str = "";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/unsupported/fs.rs b/src/libstd/sys/unsupported/fs.rs
new file mode 100644 (file)
index 0000000..ecb5b51
--- /dev/null
@@ -0,0 +1,308 @@
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
+use crate::path::{Path, PathBuf};
+use crate::sys::time::SystemTime;
+use crate::sys::{unsupported, Void};
+
+pub struct File(Void);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {}
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder {}
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        match self.0 {}
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> FileType {
+        match self.0 {}
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileAttr {
+    fn clone(&self) -> FileAttr {
+        match self.0 {}
+    }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn set_readonly(&mut self, _readonly: bool) {
+        match self.0 {}
+    }
+}
+
+impl Clone for FilePermissions {
+    fn clone(&self) -> FilePermissions {
+        match self.0 {}
+    }
+}
+
+impl PartialEq for FilePermissions {
+    fn eq(&self, _other: &FilePermissions) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FilePermissions {}
+
+impl fmt::Debug for FilePermissions {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_file(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileType {
+    fn clone(&self) -> FileType {
+        match self.0 {}
+    }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+    fn eq(&self, _other: &FileType) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FileType {}
+
+impl Hash for FileType {
+    fn hash<H: Hasher>(&self, _h: &mut H) {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for FileType {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        match self.0 {}
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        match self.0 {}
+    }
+
+    pub fn file_name(&self) -> OsString {
+        match self.0 {}
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        match self.0 {}
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {}
+    }
+
+    pub fn read(&mut self, _read: bool) {}
+    pub fn write(&mut self, _write: bool) {}
+    pub fn append(&mut self, _append: bool) {}
+    pub fn truncate(&mut self, _truncate: bool) {}
+    pub fn create(&mut self, _create: bool) {}
+    pub fn create_new(&mut self, _create_new: bool) {}
+}
+
+impl File {
+    pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+        unsupported()
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        match self.0 {}
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn truncate(&self, _size: u64) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        match self.0 {}
+    }
+
+    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn diverge(&self) -> ! {
+        match self.0 {}
+    }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder {}
+    }
+
+    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+        unsupported()
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+    unsupported()
+}
+
+pub fn unlink(_p: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+    match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
+    unsupported()
+}
diff --git a/src/libstd/sys/unsupported/io.rs b/src/libstd/sys/unsupported/io.rs
new file mode 100644 (file)
index 0000000..d5f475b
--- /dev/null
@@ -0,0 +1,47 @@
+use crate::mem;
+
+#[derive(Copy, Clone)]
+pub struct IoSlice<'a>(&'a [u8]);
+
+impl<'a> IoSlice<'a> {
+    #[inline]
+    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+        IoSlice(buf)
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        self.0 = &self.0[n..]
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        self.0
+    }
+}
+
+pub struct IoSliceMut<'a>(&'a mut [u8]);
+
+impl<'a> IoSliceMut<'a> {
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+        IoSliceMut(buf)
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        let slice = mem::replace(&mut self.0, &mut []);
+        let (_, remaining) = slice.split_at_mut(n);
+        self.0 = remaining;
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        self.0
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [u8] {
+        self.0
+    }
+}
diff --git a/src/libstd/sys/unsupported/mod.rs b/src/libstd/sys/unsupported/mod.rs
new file mode 100644 (file)
index 0000000..87f655e
--- /dev/null
@@ -0,0 +1,24 @@
+pub mod alloc;
+pub mod args;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod fs;
+pub mod io;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod thread;
+#[cfg(target_thread_local)]
+pub mod thread_local_dtor;
+pub mod thread_local_key;
+pub mod time;
+
+mod common;
+pub use common::*;
diff --git a/src/libstd/sys/unsupported/mutex.rs b/src/libstd/sys/unsupported/mutex.rs
new file mode 100644 (file)
index 0000000..9ef8af5
--- /dev/null
@@ -0,0 +1,67 @@
+use crate::cell::UnsafeCell;
+
+pub struct Mutex {
+    locked: UnsafeCell<bool>,
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {} // no threads on this platform
+
+impl Mutex {
+    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
+    pub const fn new() -> Mutex {
+        Mutex { locked: UnsafeCell::new(false) }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {}
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let locked = self.locked.get();
+        assert!(!*locked, "cannot recursively acquire mutex");
+        *locked = true;
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        *self.locked.get() = false;
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        let locked = self.locked.get();
+        if *locked {
+            false
+        } else {
+            *locked = true;
+            true
+        }
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {}
+}
+
+// All empty stubs because this platform does not yet support threads, so lock
+// acquisition always succeeds.
+pub struct ReentrantMutex {}
+
+impl ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
+        ReentrantMutex {}
+    }
+
+    pub unsafe fn init(&self) {}
+
+    pub unsafe fn lock(&self) {}
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        true
+    }
+
+    pub unsafe fn unlock(&self) {}
+
+    pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/unsupported/net.rs b/src/libstd/sys/unsupported/net.rs
new file mode 100644 (file)
index 0000000..5c9f109
--- /dev/null
@@ -0,0 +1,361 @@
+use crate::convert::TryFrom;
+use crate::fmt;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::sys::{unsupported, Void};
+use crate::time::Duration;
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        match self.0 {}
+    }
+
+    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpListener {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+        unsupported()
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        match self.0 {}
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for UdpSocket {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct LookupHost(Void);
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        match self.0 {}
+    }
+}
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        match self.0 {}
+    }
+}
+
+impl TryFrom<&str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: &str) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+#[allow(nonstandard_style)]
+pub mod netc {
+    pub const AF_INET: u8 = 0;
+    pub const AF_INET6: u8 = 1;
+    pub type sa_family_t = u8;
+
+    #[derive(Copy, Clone)]
+    pub struct in_addr {
+        pub s_addr: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in {
+        pub sin_family: sa_family_t,
+        pub sin_port: u16,
+        pub sin_addr: in_addr,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct in6_addr {
+        pub s6_addr: [u8; 16],
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in6 {
+        pub sin6_family: sa_family_t,
+        pub sin6_port: u16,
+        pub sin6_addr: in6_addr,
+        pub sin6_flowinfo: u32,
+        pub sin6_scope_id: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr {}
+
+    pub type socklen_t = usize;
+}
diff --git a/src/libstd/sys/unsupported/os.rs b/src/libstd/sys/unsupported/os.rs
new file mode 100644 (file)
index 0000000..0615780
--- /dev/null
@@ -0,0 +1,104 @@
+use super::{unsupported, Void};
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::path::{self, PathBuf};
+
+pub fn errno() -> i32 {
+    0
+}
+
+pub fn error_string(_errno: i32) -> String {
+    "operation successful".to_string()
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        match *self.0 {}
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+    I: Iterator<Item = T>,
+    T: AsRef<OsStr>,
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "not supported on this platform yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "not supported on this platform yet"
+    }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub struct Env(Void);
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> {
+        match self.0 {}
+    }
+}
+
+pub fn env() -> Env {
+    panic!("not supported on this platform")
+}
+
+pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
+    Ok(None)
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+    Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on this platform"))
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+    Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on this platform"))
+}
+
+pub fn temp_dir() -> PathBuf {
+    panic!("no filesystem on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn exit(_code: i32) -> ! {
+    crate::intrinsics::abort()
+}
+
+pub fn getpid() -> u32 {
+    panic!("no pids on this platform")
+}
diff --git a/src/libstd/sys/unsupported/path.rs b/src/libstd/sys/unsupported/path.rs
new file mode 100644 (file)
index 0000000..840a7ae
--- /dev/null
@@ -0,0 +1,19 @@
+use crate::ffi::OsStr;
+use crate::path::Prefix;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+    None
+}
+
+pub const MAIN_SEP_STR: &str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/unsupported/pipe.rs b/src/libstd/sys/unsupported/pipe.rs
new file mode 100644 (file)
index 0000000..10d0925
--- /dev/null
@@ -0,0 +1,38 @@
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn diverge(&self) -> ! {
+        match self.0 {}
+    }
+}
+
+pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
+    match p1.0 {}
+}
diff --git a/src/libstd/sys/unsupported/process.rs b/src/libstd/sys/unsupported/process.rs
new file mode 100644 (file)
index 0000000..4702e5c
--- /dev/null
@@ -0,0 +1,149 @@
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::{unsupported, Void};
+use crate::sys_common::process::CommandEnv;
+
+pub use crate::ffi::OsString as EnvKey;
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+    env: CommandEnv,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+}
+
+impl Command {
+    pub fn new(_program: &OsStr) -> Command {
+        Command { env: Default::default() }
+    }
+
+    pub fn arg(&mut self, _arg: &OsStr) {}
+
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
+        &mut self.env
+    }
+
+    pub fn cwd(&mut self, _dir: &OsStr) {}
+
+    pub fn stdin(&mut self, _stdin: Stdio) {}
+
+    pub fn stdout(&mut self, _stdout: Stdio) {}
+
+    pub fn stderr(&mut self, _stderr: Stdio) {}
+
+    pub fn spawn(
+        &mut self,
+        _default: Stdio,
+        _needs_stdin: bool,
+    ) -> io::Result<(Process, StdioPipes)> {
+        unsupported()
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        pipe.diverge()
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(file: File) -> Stdio {
+        file.diverge()
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        Ok(())
+    }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+    pub fn success(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        match self.0 {}
+    }
+}
+
+impl Clone for ExitStatus {
+    fn clone(&self) -> ExitStatus {
+        match self.0 {}
+    }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+    fn eq(&self, _other: &ExitStatus) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for ExitStatus {}
+
+impl fmt::Debug for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(false);
+    pub const FAILURE: ExitCode = ExitCode(true);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
+pub struct Process(Void);
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        match self.0 {}
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        match self.0 {}
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        match self.0 {}
+    }
+}
diff --git a/src/libstd/sys/unsupported/rwlock.rs b/src/libstd/sys/unsupported/rwlock.rs
new file mode 100644 (file)
index 0000000..d37f34a
--- /dev/null
@@ -0,0 +1,69 @@
+use crate::cell::UnsafeCell;
+
+pub struct RWLock {
+    mode: UnsafeCell<isize>,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {} // no threads on this platform
+
+impl RWLock {
+    pub const fn new() -> RWLock {
+        RWLock { mode: UnsafeCell::new(0) }
+    }
+
+    #[inline]
+    pub unsafe fn read(&self) {
+        let mode = self.mode.get();
+        if *mode >= 0 {
+            *mode += 1;
+        } else {
+            rtabort!("rwlock locked for writing");
+        }
+    }
+
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool {
+        let mode = self.mode.get();
+        if *mode >= 0 {
+            *mode += 1;
+            true
+        } else {
+            false
+        }
+    }
+
+    #[inline]
+    pub unsafe fn write(&self) {
+        let mode = self.mode.get();
+        if *mode == 0 {
+            *mode = -1;
+        } else {
+            rtabort!("rwlock locked for reading")
+        }
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        let mode = self.mode.get();
+        if *mode == 0 {
+            *mode = -1;
+            true
+        } else {
+            false
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        *self.mode.get() -= 1;
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        *self.mode.get() += 1;
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/unsupported/stack_overflow.rs b/src/libstd/sys/unsupported/stack_overflow.rs
new file mode 100644 (file)
index 0000000..3255539
--- /dev/null
@@ -0,0 +1,3 @@
+pub unsafe fn init() {}
+
+pub unsafe fn cleanup() {}
diff --git a/src/libstd/sys/unsupported/stdio.rs b/src/libstd/sys/unsupported/stdio.rs
new file mode 100644 (file)
index 0000000..5a4e450
--- /dev/null
@@ -0,0 +1,59 @@
+use crate::io;
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+
+impl Stdin {
+    pub fn new() -> io::Result<Stdin> {
+        Ok(Stdin)
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+        Ok(0)
+    }
+}
+
+impl Stdout {
+    pub fn new() -> io::Result<Stdout> {
+        Ok(Stdout)
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub fn new() -> io::Result<Stderr> {
+        Ok(Stderr)
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    true
+}
+
+pub fn panic_output() -> Option<Vec<u8>> {
+    None
+}
diff --git a/src/libstd/sys/unsupported/thread.rs b/src/libstd/sys/unsupported/thread.rs
new file mode 100644 (file)
index 0000000..20ae309
--- /dev/null
@@ -0,0 +1,41 @@
+use super::{unsupported, Void};
+use crate::ffi::CStr;
+use crate::io;
+use crate::time::Duration;
+
+pub struct Thread(Void);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+impl Thread {
+    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+    pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+        unsupported()
+    }
+
+    pub fn yield_now() {
+        // do nothing
+    }
+
+    pub fn set_name(_name: &CStr) {
+        // nope
+    }
+
+    pub fn sleep(_dur: Duration) {
+        panic!("can't sleep");
+    }
+
+    pub fn join(self) {
+        match self.0 {}
+    }
+}
+
+pub mod guard {
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> {
+        None
+    }
+    pub unsafe fn init() -> Option<Guard> {
+        None
+    }
+}
diff --git a/src/libstd/sys/unsupported/thread_local_dtor.rs b/src/libstd/sys/unsupported/thread_local_dtor.rs
new file mode 100644 (file)
index 0000000..85d6609
--- /dev/null
@@ -0,0 +1,9 @@
+#![unstable(feature = "thread_local_internals", issue = "none")]
+
+pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern "C" fn(*mut u8)) {
+    // FIXME: right now there is no concept of "thread exit", but this is likely
+    // going to show up at some point in the form of an exported symbol that the
+    // wasm runtime is going to be expected to call. For now we basically just
+    // ignore the arguments, but if such a function starts to exist it will
+    // likely look like the OSX implementation in `unix/fast_thread_local.rs`
+}
diff --git a/src/libstd/sys/unsupported/thread_local_key.rs b/src/libstd/sys/unsupported/thread_local_key.rs
new file mode 100644 (file)
index 0000000..c31b61c
--- /dev/null
@@ -0,0 +1,26 @@
+pub type Key = usize;
+
+#[inline]
+pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+    panic!("should not be used on this target");
+}
+
+#[inline]
+pub unsafe fn set(_key: Key, _value: *mut u8) {
+    panic!("should not be used on this target");
+}
+
+#[inline]
+pub unsafe fn get(_key: Key) -> *mut u8 {
+    panic!("should not be used on this target");
+}
+
+#[inline]
+pub unsafe fn destroy(_key: Key) {
+    panic!("should not be used on this target");
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    panic!("should not be used on this target");
+}
diff --git a/src/libstd/sys/unsupported/time.rs b/src/libstd/sys/unsupported/time.rs
new file mode 100644 (file)
index 0000000..8aaf177
--- /dev/null
@@ -0,0 +1,53 @@
+use crate::time::Duration;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+
+impl Instant {
+    pub fn now() -> Instant {
+        panic!("time not implemented on this platform")
+    }
+
+    pub const fn zero() -> Instant {
+        Instant(Duration::from_secs(0))
+    }
+
+    pub fn actually_monotonic() -> bool {
+        false
+    }
+
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.0.checked_sub(other.0)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_add(*other)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant(self.0.checked_sub(*other)?))
+    }
+}
+
+impl SystemTime {
+    pub fn now() -> SystemTime {
+        panic!("time not implemented on this platform")
+    }
+
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime(self.0.checked_add(*other)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime(self.0.checked_sub(*other)?))
+    }
+}
diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/fast_thread_local.rs
deleted file mode 100644 (file)
index 098668c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![cfg(target_thread_local)]
-#![unstable(feature = "thread_local_internals", issue = "none")]
-
-pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    use crate::sys_common::thread_local::register_dtor_fallback;
-    register_dtor_fallback(t, dtor);
-}
-
-pub fn requires_move_before_drop() -> bool {
-    false
-}
index 0787e7098988ccef4060718d842aa2bdbb6e6d7f..1132a849e2f18b34965d8fe11a12c6bad83c2e71 100644 (file)
@@ -13,7 +13,6 @@
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fd;
 pub mod fs;
 pub mod io;
@@ -29,7 +28,8 @@
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
index 78b6e9a4db7853617fb5f58f0e4bbe966b24ca7d..bbbd5eda7731411ee6a7ddf39aeebe35ac927426 100644 (file)
@@ -376,6 +376,7 @@ pub fn signal(&self) -> Option<i32> {
     }
 }
 
+/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
 impl From<c_int> for ExitStatus {
     fn from(a: c_int) -> ExitStatus {
         ExitStatus(a)
diff --git a/src/libstd/sys/vxworks/thread_local.rs b/src/libstd/sys/vxworks/thread_local.rs
deleted file mode 100644 (file)
index 2c5b94b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#![allow(dead_code)] // not used on all platforms
-
-use crate::mem;
-
-pub type Key = libc::pthread_key_t;
-
-#[inline]
-pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    let mut key = 0;
-    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
-    key
-}
-
-#[inline]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    let r = libc::pthread_setspecific(key, value as *mut _);
-    debug_assert_eq!(r, 0);
-}
-
-#[inline]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    libc::pthread_getspecific(key) as *mut u8
-}
-
-#[inline]
-pub unsafe fn destroy(key: Key) {
-    let r = libc::pthread_key_delete(key);
-    debug_assert_eq!(r, 0);
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    false
-}
diff --git a/src/libstd/sys/vxworks/thread_local_dtor.rs b/src/libstd/sys/vxworks/thread_local_dtor.rs
new file mode 100644 (file)
index 0000000..3f73f6c
--- /dev/null
@@ -0,0 +1,7 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "none")]
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    use crate::sys_common::thread_local::register_dtor_fallback;
+    register_dtor_fallback(t, dtor);
+}
diff --git a/src/libstd/sys/vxworks/thread_local_key.rs b/src/libstd/sys/vxworks/thread_local_key.rs
new file mode 100644 (file)
index 0000000..2c5b94b
--- /dev/null
@@ -0,0 +1,34 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::mem;
+
+pub type Key = libc::pthread_key_t;
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+    let mut key = 0;
+    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
+    key
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    let r = libc::pthread_setspecific(key, value as *mut _);
+    debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    libc::pthread_getspecific(key) as *mut u8
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+    let r = libc::pthread_key_delete(key);
+    debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    false
+}
index 4fe9661421b03fca32be286f33909156a1ef9ca5..2704ff484f9911c920329e86ebdb21dbeaf9372e 100644 (file)
 
 use crate::io as std_io;
 use crate::mem;
-use crate::os::raw::c_char;
 
 pub mod alloc;
 pub mod args;
-#[path = "../wasm/cmath.rs"]
+#[path = "../unsupported/cmath.rs"]
 pub mod cmath;
-#[path = "../wasm/condvar.rs"]
+#[path = "../unsupported/condvar.rs"]
 pub mod condvar;
 pub mod env;
 pub mod fd;
 pub mod fs;
 pub mod io;
-#[path = "../wasm/memchr.rs"]
-pub mod memchr;
-#[path = "../wasm/mutex.rs"]
+#[path = "../unsupported/mutex.rs"]
 pub mod mutex;
 pub mod net;
 pub mod os;
 pub use crate::sys_common::os_str_bytes as os_str;
 pub mod ext;
-#[path = "../wasm/fast_thread_local.rs"]
-pub mod fast_thread_local;
 pub mod path;
 pub mod pipe;
 pub mod process;
-#[path = "../wasm/rwlock.rs"]
+#[path = "../unsupported/rwlock.rs"]
 pub mod rwlock;
-#[path = "../wasm/stack_overflow.rs"]
+#[path = "../unsupported/stack_overflow.rs"]
 pub mod stack_overflow;
 pub mod stdio;
 pub mod thread;
-#[path = "../wasm/thread_local.rs"]
-pub mod thread_local;
+#[path = "../unsupported/thread_local_dtor.rs"]
+pub mod thread_local_dtor;
+#[path = "../unsupported/thread_local_key.rs"]
+pub mod thread_local_key;
 pub mod time;
 
-#[cfg(not(test))]
-pub fn init() {}
-
-pub fn unsupported<T>() -> std_io::Result<T> {
-    Err(unsupported_err())
-}
-
-pub fn unsupported_err() -> std_io::Error {
-    std_io::Error::new(std_io::ErrorKind::Other, "operation not supported on wasm yet")
-}
+#[path = "../unsupported/common.rs"]
+#[allow(unused)]
+mod common;
+pub use common::*;
 
 pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     use std_io::ErrorKind::*;
@@ -86,20 +77,6 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     }
 }
 
-// This enum is used as the storage for a bunch of types which can't actually
-// exist.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub enum Void {}
-
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
-    }
-    return n;
-}
-
 pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/wasm/cmath.rs
deleted file mode 100644 (file)
index 304cf90..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// These symbols are all defined in `compiler-builtins`
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-}
diff --git a/src/libstd/sys/wasm/condvar.rs b/src/libstd/sys/wasm/condvar.rs
deleted file mode 100644 (file)
index 9fd781c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-use crate::sys::mutex::Mutex;
-use crate::time::Duration;
-
-pub struct Condvar {}
-
-impl Condvar {
-    pub const fn new() -> Condvar {
-        Condvar {}
-    }
-
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
-    pub unsafe fn notify_one(&self) {}
-
-    #[inline]
-    pub unsafe fn notify_all(&self) {}
-
-    pub unsafe fn wait(&self, _mutex: &Mutex) {
-        panic!("can't block with web assembly")
-    }
-
-    pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
-        panic!("can't block with web assembly");
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-}
diff --git a/src/libstd/sys/wasm/fast_thread_local.rs b/src/libstd/sys/wasm/fast_thread_local.rs
deleted file mode 100644 (file)
index 85d6609..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#![unstable(feature = "thread_local_internals", issue = "none")]
-
-pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern "C" fn(*mut u8)) {
-    // FIXME: right now there is no concept of "thread exit", but this is likely
-    // going to show up at some point in the form of an exported symbol that the
-    // wasm runtime is going to be expected to call. For now we basically just
-    // ignore the arguments, but if such a function starts to exist it will
-    // likely look like the OSX implementation in `unix/fast_thread_local.rs`
-}
diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs
deleted file mode 100644 (file)
index ecb5b51..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::hash::{Hash, Hasher};
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
-use crate::path::{Path, PathBuf};
-use crate::sys::time::SystemTime;
-use crate::sys::{unsupported, Void};
-
-pub struct File(Void);
-
-pub struct FileAttr(Void);
-
-pub struct ReadDir(Void);
-
-pub struct DirEntry(Void);
-
-#[derive(Clone, Debug)]
-pub struct OpenOptions {}
-
-pub struct FilePermissions(Void);
-
-pub struct FileType(Void);
-
-#[derive(Debug)]
-pub struct DirBuilder {}
-
-impl FileAttr {
-    pub fn size(&self) -> u64 {
-        match self.0 {}
-    }
-
-    pub fn perm(&self) -> FilePermissions {
-        match self.0 {}
-    }
-
-    pub fn file_type(&self) -> FileType {
-        match self.0 {}
-    }
-
-    pub fn modified(&self) -> io::Result<SystemTime> {
-        match self.0 {}
-    }
-
-    pub fn accessed(&self) -> io::Result<SystemTime> {
-        match self.0 {}
-    }
-
-    pub fn created(&self) -> io::Result<SystemTime> {
-        match self.0 {}
-    }
-}
-
-impl Clone for FileAttr {
-    fn clone(&self) -> FileAttr {
-        match self.0 {}
-    }
-}
-
-impl FilePermissions {
-    pub fn readonly(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn set_readonly(&mut self, _readonly: bool) {
-        match self.0 {}
-    }
-}
-
-impl Clone for FilePermissions {
-    fn clone(&self) -> FilePermissions {
-        match self.0 {}
-    }
-}
-
-impl PartialEq for FilePermissions {
-    fn eq(&self, _other: &FilePermissions) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for FilePermissions {}
-
-impl fmt::Debug for FilePermissions {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl FileType {
-    pub fn is_dir(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn is_file(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn is_symlink(&self) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Clone for FileType {
-    fn clone(&self) -> FileType {
-        match self.0 {}
-    }
-}
-
-impl Copy for FileType {}
-
-impl PartialEq for FileType {
-    fn eq(&self, _other: &FileType) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for FileType {}
-
-impl Hash for FileType {
-    fn hash<H: Hasher>(&self, _h: &mut H) {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for FileType {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for ReadDir {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl Iterator for ReadDir {
-    type Item = io::Result<DirEntry>;
-
-    fn next(&mut self) -> Option<io::Result<DirEntry>> {
-        match self.0 {}
-    }
-}
-
-impl DirEntry {
-    pub fn path(&self) -> PathBuf {
-        match self.0 {}
-    }
-
-    pub fn file_name(&self) -> OsString {
-        match self.0 {}
-    }
-
-    pub fn metadata(&self) -> io::Result<FileAttr> {
-        match self.0 {}
-    }
-
-    pub fn file_type(&self) -> io::Result<FileType> {
-        match self.0 {}
-    }
-}
-
-impl OpenOptions {
-    pub fn new() -> OpenOptions {
-        OpenOptions {}
-    }
-
-    pub fn read(&mut self, _read: bool) {}
-    pub fn write(&mut self, _write: bool) {}
-    pub fn append(&mut self, _append: bool) {}
-    pub fn truncate(&mut self, _truncate: bool) {}
-    pub fn create(&mut self, _create: bool) {}
-    pub fn create_new(&mut self, _create_new: bool) {}
-}
-
-impl File {
-    pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
-        unsupported()
-    }
-
-    pub fn file_attr(&self) -> io::Result<FileAttr> {
-        match self.0 {}
-    }
-
-    pub fn fsync(&self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn datasync(&self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn truncate(&self, _size: u64) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_read_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_write_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn flush(&self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
-        match self.0 {}
-    }
-
-    pub fn duplicate(&self) -> io::Result<File> {
-        match self.0 {}
-    }
-
-    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn diverge(&self) -> ! {
-        match self.0 {}
-    }
-}
-
-impl DirBuilder {
-    pub fn new() -> DirBuilder {
-        DirBuilder {}
-    }
-
-    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
-        unsupported()
-    }
-}
-
-impl fmt::Debug for File {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
-    unsupported()
-}
-
-pub fn unlink(_p: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
-    match perm.0 {}
-}
-
-pub fn rmdir(_p: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
-    unsupported()
-}
-
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
-    unsupported()
-}
-
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
-    unsupported()
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
-    unsupported()
-}
-
-pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
-    unsupported()
-}
diff --git a/src/libstd/sys/wasm/io.rs b/src/libstd/sys/wasm/io.rs
deleted file mode 100644 (file)
index d5f475b..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-use crate::mem;
-
-#[derive(Copy, Clone)]
-pub struct IoSlice<'a>(&'a [u8]);
-
-impl<'a> IoSlice<'a> {
-    #[inline]
-    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
-        IoSlice(buf)
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        self.0 = &self.0[n..]
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        self.0
-    }
-}
-
-pub struct IoSliceMut<'a>(&'a mut [u8]);
-
-impl<'a> IoSliceMut<'a> {
-    #[inline]
-    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
-        IoSliceMut(buf)
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        let slice = mem::replace(&mut self.0, &mut []);
-        let (_, remaining) = slice.split_at_mut(n);
-        self.0 = remaining;
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        self.0
-    }
-
-    #[inline]
-    pub fn as_mut_slice(&mut self) -> &mut [u8] {
-        self.0
-    }
-}
diff --git a/src/libstd/sys/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs
deleted file mode 100644 (file)
index 9967482..0000000
+++ /dev/null
@@ -1 +0,0 @@
-pub use core::slice::memchr::{memchr, memrchr};
index 050e8099af4badf7de0778abf9899ee9a8d1cbaa..3de58904043573d4d4020021156e98c8d0383c12 100644 (file)
 //! compiling for wasm. That way it's a compile time error for something that's
 //! guaranteed to be a runtime error!
 
-use crate::os::raw::c_char;
-
 pub mod alloc;
 pub mod args;
+#[path = "../unsupported/cmath.rs"]
 pub mod cmath;
 pub mod env;
-pub mod fast_thread_local;
+#[path = "../unsupported/fs.rs"]
 pub mod fs;
+#[path = "../unsupported/io.rs"]
 pub mod io;
-pub mod memchr;
+#[path = "../unsupported/net.rs"]
 pub mod net;
+#[path = "../unsupported/os.rs"]
 pub mod os;
+#[path = "../unsupported/path.rs"]
 pub mod path;
+#[path = "../unsupported/pipe.rs"]
 pub mod pipe;
+#[path = "../unsupported/process.rs"]
 pub mod process;
+#[path = "../unsupported/stack_overflow.rs"]
 pub mod stack_overflow;
+#[path = "../unsupported/stdio.rs"]
 pub mod stdio;
 pub mod thread;
-pub mod thread_local;
+#[path = "../unsupported/thread_local_dtor.rs"]
+pub mod thread_local_dtor;
+#[path = "../unsupported/thread_local_key.rs"]
+pub mod thread_local_key;
+#[path = "../unsupported/time.rs"]
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
         #[path = "rwlock_atomics.rs"]
         pub mod rwlock;
     } else {
+        #[path = "../unsupported/condvar.rs"]
         pub mod condvar;
+        #[path = "../unsupported/mutex.rs"]
         pub mod mutex;
+        #[path = "../unsupported/rwlock.rs"]
         pub mod rwlock;
     }
 }
 
-#[cfg(not(test))]
-pub fn init() {}
-
-pub fn unsupported<T>() -> crate::io::Result<T> {
-    Err(unsupported_err())
-}
-
-pub fn unsupported_err() -> crate::io::Error {
-    crate::io::Error::new(crate::io::ErrorKind::Other, "operation not supported on wasm yet")
-}
-
-pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
-    crate::io::ErrorKind::Other
-}
-
-// This enum is used as the storage for a bunch of types which can't actually
-// exist.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub enum Void {}
-
-pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
-    }
-    return n;
-}
-
-pub fn abort_internal() -> ! {
-    unsafe { crate::arch::wasm32::unreachable() }
-}
-
-// We don't have randomness yet, but I totally used a random number generator to
-// generate these numbers.
-//
-// More seriously though this is just for DOS protection in hash maps. It's ok
-// if we don't do that on wasm just yet.
-pub fn hashmap_random_keys() -> (u64, u64) {
-    (1, 2)
-}
+#[path = "../unsupported/common.rs"]
+mod common;
+pub use common::*;
diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/wasm/mutex.rs
deleted file mode 100644 (file)
index 7aaf1b3..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-use crate::cell::UnsafeCell;
-
-pub struct Mutex {
-    locked: UnsafeCell<bool>,
-}
-
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {} // no threads on wasm
-
-impl Mutex {
-    pub const fn new() -> Mutex {
-        Mutex { locked: UnsafeCell::new(false) }
-    }
-
-    #[inline]
-    pub unsafe fn init(&mut self) {}
-
-    #[inline]
-    pub unsafe fn lock(&self) {
-        let locked = self.locked.get();
-        assert!(!*locked, "cannot recursively acquire mutex");
-        *locked = true;
-    }
-
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        *self.locked.get() = false;
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let locked = self.locked.get();
-        if *locked {
-            false
-        } else {
-            *locked = true;
-            true
-        }
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-}
-
-// All empty stubs because wasm has no threads yet, so lock acquisition always
-// succeeds.
-pub struct ReentrantMutex {}
-
-impl ReentrantMutex {
-    pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex {}
-    }
-
-    pub unsafe fn init(&self) {}
-
-    pub unsafe fn lock(&self) {}
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        true
-    }
-
-    pub unsafe fn unlock(&self) {}
-
-    pub unsafe fn destroy(&self) {}
-}
diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs
deleted file mode 100644 (file)
index 5c9f109..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-use crate::convert::TryFrom;
-use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::sys::{unsupported, Void};
-use crate::time::Duration;
-
-pub struct TcpStream(Void);
-
-impl TcpStream {
-    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
-        unsupported()
-    }
-
-    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
-        unsupported()
-    }
-
-    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        match self.0 {}
-    }
-
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        match self.0 {}
-    }
-
-    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_read_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_write_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
-    }
-
-    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn duplicate(&self) -> io::Result<TcpStream> {
-        match self.0 {}
-    }
-
-    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn nodelay(&self) -> io::Result<bool> {
-        match self.0 {}
-    }
-
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        match self.0 {}
-    }
-
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        match self.0 {}
-    }
-
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for TcpStream {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-pub struct TcpListener(Void);
-
-impl TcpListener {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
-        unsupported()
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
-    }
-
-    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
-        match self.0 {}
-    }
-
-    pub fn duplicate(&self) -> io::Result<TcpListener> {
-        match self.0 {}
-    }
-
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        match self.0 {}
-    }
-
-    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn only_v6(&self) -> io::Result<bool> {
-        match self.0 {}
-    }
-
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        match self.0 {}
-    }
-
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for TcpListener {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-pub struct UdpSocket(Void);
-
-impl UdpSocket {
-    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
-        unsupported()
-    }
-
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
-    }
-
-    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
-        match self.0 {}
-    }
-
-    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        match self.0 {}
-    }
-
-    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        match self.0 {}
-    }
-
-    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn duplicate(&self) -> io::Result<UdpSocket> {
-        match self.0 {}
-    }
-
-    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        match self.0 {}
-    }
-
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        match self.0 {}
-    }
-
-    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn broadcast(&self) -> io::Result<bool> {
-        match self.0 {}
-    }
-
-    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
-        match self.0 {}
-    }
-
-    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
-        match self.0 {}
-    }
-
-    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
-        match self.0 {}
-    }
-
-    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn ttl(&self) -> io::Result<u32> {
-        match self.0 {}
-    }
-
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        match self.0 {}
-    }
-
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
-        match self.0 {}
-    }
-}
-
-impl fmt::Debug for UdpSocket {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-pub struct LookupHost(Void);
-
-impl LookupHost {
-    pub fn port(&self) -> u16 {
-        match self.0 {}
-    }
-}
-
-impl Iterator for LookupHost {
-    type Item = SocketAddr;
-    fn next(&mut self) -> Option<SocketAddr> {
-        match self.0 {}
-    }
-}
-
-impl TryFrom<&str> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: &str) -> io::Result<LookupHost> {
-        unsupported()
-    }
-}
-
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
-    type Error = io::Error;
-
-    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
-        unsupported()
-    }
-}
-
-#[allow(nonstandard_style)]
-pub mod netc {
-    pub const AF_INET: u8 = 0;
-    pub const AF_INET6: u8 = 1;
-    pub type sa_family_t = u8;
-
-    #[derive(Copy, Clone)]
-    pub struct in_addr {
-        pub s_addr: u32,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr_in {
-        pub sin_family: sa_family_t,
-        pub sin_port: u16,
-        pub sin_addr: in_addr,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct in6_addr {
-        pub s6_addr: [u8; 16],
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr_in6 {
-        pub sin6_family: sa_family_t,
-        pub sin6_port: u16,
-        pub sin6_addr: in6_addr,
-        pub sin6_flowinfo: u32,
-        pub sin6_scope_id: u32,
-    }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr {}
-
-    pub type socklen_t = usize;
-}
diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs
deleted file mode 100644 (file)
index 91afdc8..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-use crate::error::Error as StdError;
-use crate::ffi::{OsStr, OsString};
-use crate::fmt;
-use crate::io;
-use crate::path::{self, PathBuf};
-use crate::str;
-use crate::sys::{unsupported, Void};
-
-pub fn errno() -> i32 {
-    0
-}
-
-pub fn error_string(_errno: i32) -> String {
-    "operation successful".to_string()
-}
-
-pub fn getcwd() -> io::Result<PathBuf> {
-    unsupported()
-}
-
-pub fn chdir(_: &path::Path) -> io::Result<()> {
-    unsupported()
-}
-
-pub struct SplitPaths<'a>(&'a Void);
-
-pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
-    panic!("unsupported")
-}
-
-impl<'a> Iterator for SplitPaths<'a> {
-    type Item = PathBuf;
-    fn next(&mut self) -> Option<PathBuf> {
-        match *self.0 {}
-    }
-}
-
-#[derive(Debug)]
-pub struct JoinPathsError;
-
-pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
-where
-    I: Iterator<Item = T>,
-    T: AsRef<OsStr>,
-{
-    Err(JoinPathsError)
-}
-
-impl fmt::Display for JoinPathsError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        "not supported on wasm yet".fmt(f)
-    }
-}
-
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on wasm yet"
-    }
-}
-
-pub fn current_exe() -> io::Result<PathBuf> {
-    unsupported()
-}
-
-pub struct Env(Void);
-
-impl Iterator for Env {
-    type Item = (OsString, OsString);
-    fn next(&mut self) -> Option<(OsString, OsString)> {
-        match self.0 {}
-    }
-}
-
-pub fn env() -> Env {
-    panic!("not supported on web assembly")
-}
-
-pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
-    Ok(None)
-}
-
-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(_: &OsStr) -> io::Result<()> {
-    Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown"))
-}
-
-pub fn temp_dir() -> PathBuf {
-    panic!("no filesystem on wasm")
-}
-
-pub fn home_dir() -> Option<PathBuf> {
-    None
-}
-
-pub fn exit(_code: i32) -> ! {
-    unsafe {
-        crate::arch::wasm32::unreachable();
-    }
-}
-
-pub fn getpid() -> u32 {
-    panic!("no pids on wasm")
-}
diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/wasm/path.rs
deleted file mode 100644 (file)
index 840a7ae..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-use crate::ffi::OsStr;
-use crate::path::Prefix;
-
-#[inline]
-pub fn is_sep_byte(b: u8) -> bool {
-    b == b'/'
-}
-
-#[inline]
-pub fn is_verbatim_sep(b: u8) -> bool {
-    b == b'/'
-}
-
-pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
-    None
-}
-
-pub const MAIN_SEP_STR: &str = "/";
-pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs
deleted file mode 100644 (file)
index 10d0925..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
-    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_read_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        match self.0 {}
-    }
-
-    pub fn is_write_vectored(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn diverge(&self) -> ! {
-        match self.0 {}
-    }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
-    match p1.0 {}
-}
diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs
deleted file mode 100644 (file)
index 4702e5c..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
-    env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-}
-
-impl Command {
-    pub fn new(_program: &OsStr) -> Command {
-        Command { env: Default::default() }
-    }
-
-    pub fn arg(&mut self, _arg: &OsStr) {}
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn cwd(&mut self, _dir: &OsStr) {}
-
-    pub fn stdin(&mut self, _stdin: Stdio) {}
-
-    pub fn stdout(&mut self, _stdout: Stdio) {}
-
-    pub fn stderr(&mut self, _stderr: Stdio) {}
-
-    pub fn spawn(
-        &mut self,
-        _default: Stdio,
-        _needs_stdin: bool,
-    ) -> io::Result<(Process, StdioPipes)> {
-        unsupported()
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        pipe.diverge()
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        file.diverge()
-    }
-}
-
-impl fmt::Debug for Command {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
-    }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
-    pub fn success(&self) -> bool {
-        match self.0 {}
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        match self.0 {}
-    }
-}
-
-impl Clone for ExitStatus {
-    fn clone(&self) -> ExitStatus {
-        match self.0 {}
-    }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
-    fn eq(&self, _other: &ExitStatus) -> bool {
-        match self.0 {}
-    }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.0 {}
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(false);
-    pub const FAILURE: ExitCode = ExitCode(true);
-
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
-
-pub struct Process(Void);
-
-impl Process {
-    pub fn id(&self) -> u32 {
-        match self.0 {}
-    }
-
-    pub fn kill(&mut self) -> io::Result<()> {
-        match self.0 {}
-    }
-
-    pub fn wait(&mut self) -> io::Result<ExitStatus> {
-        match self.0 {}
-    }
-
-    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
-        match self.0 {}
-    }
-}
diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs
deleted file mode 100644 (file)
index a599444..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-use crate::cell::UnsafeCell;
-
-pub struct RWLock {
-    mode: UnsafeCell<isize>,
-}
-
-unsafe impl Send for RWLock {}
-unsafe impl Sync for RWLock {} // no threads on wasm
-
-impl RWLock {
-    pub const fn new() -> RWLock {
-        RWLock { mode: UnsafeCell::new(0) }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        let mode = self.mode.get();
-        if *mode >= 0 {
-            *mode += 1;
-        } else {
-            rtabort!("rwlock locked for writing");
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        let mode = self.mode.get();
-        if *mode >= 0 {
-            *mode += 1;
-            true
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        let mode = self.mode.get();
-        if *mode == 0 {
-            *mode = -1;
-        } else {
-            rtabort!("rwlock locked for reading")
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        let mode = self.mode.get();
-        if *mode == 0 {
-            *mode = -1;
-            true
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        *self.mode.get() -= 1;
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        *self.mode.get() += 1;
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-}
diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/wasm/stack_overflow.rs
deleted file mode 100644 (file)
index 3255539..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-pub unsafe fn init() {}
-
-pub unsafe fn cleanup() {}
diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs
deleted file mode 100644 (file)
index 5a4e450..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-use crate::io;
-
-pub struct Stdin;
-pub struct Stdout;
-pub struct Stderr;
-
-impl Stdin {
-    pub fn new() -> io::Result<Stdin> {
-        Ok(Stdin)
-    }
-}
-
-impl io::Read for Stdin {
-    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
-        Ok(0)
-    }
-}
-
-impl Stdout {
-    pub fn new() -> io::Result<Stdout> {
-        Ok(Stdout)
-    }
-}
-
-impl io::Write for Stdout {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        Ok(buf.len())
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-impl Stderr {
-    pub fn new() -> io::Result<Stderr> {
-        Ok(Stderr)
-    }
-}
-
-impl io::Write for Stderr {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        Ok(buf.len())
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-pub const STDIN_BUF_SIZE: usize = 0;
-
-pub fn is_ebadf(_err: &io::Error) -> bool {
-    true
-}
-
-pub fn panic_output() -> Option<Vec<u8>> {
-    None
-}
diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/wasm/thread_local.rs
deleted file mode 100644 (file)
index f8be986..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-pub type Key = usize;
-
-#[inline]
-pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub unsafe fn set(_key: Key, _value: *mut u8) {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub unsafe fn get(_key: Key) -> *mut u8 {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub unsafe fn destroy(_key: Key) {
-    panic!("should not be used on the wasm target");
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    panic!("should not be used on the wasm target");
-}
diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs
deleted file mode 100644 (file)
index d9edc7f..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-use crate::time::Duration;
-
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant(Duration);
-
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct SystemTime(Duration);
-
-pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
-
-impl Instant {
-    pub fn now() -> Instant {
-        panic!("time not implemented on wasm32-unknown-unknown")
-    }
-
-    pub const fn zero() -> Instant {
-        Instant(Duration::from_secs(0))
-    }
-
-    pub fn actually_monotonic() -> bool {
-        false
-    }
-
-    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
-        self.0.checked_sub(other.0)
-    }
-
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
-        Some(Instant(self.0.checked_add(*other)?))
-    }
-
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-        Some(Instant(self.0.checked_sub(*other)?))
-    }
-}
-
-impl SystemTime {
-    pub fn now() -> SystemTime {
-        panic!("time not implemented on wasm32-unknown-unknown")
-    }
-
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
-    }
-
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_add(*other)?))
-    }
-
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_sub(*other)?))
-    }
-}
diff --git a/src/libstd/sys/windows/fast_thread_local.rs b/src/libstd/sys/windows/fast_thread_local.rs
deleted file mode 100644 (file)
index 191fa07..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#![unstable(feature = "thread_local_internals", issue = "none")]
-#![cfg(target_thread_local)]
-
-pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
index 193ab5b47ef1332cf6c9d26e631acd5a28907d77..9a52371280e159ffb2e0115f8af19086eb90570d 100644 (file)
@@ -20,7 +20,6 @@
 pub mod condvar;
 pub mod env;
 pub mod ext;
-pub mod fast_thread_local;
 pub mod fs;
 pub mod handle;
 pub mod io;
@@ -35,7 +34,8 @@
 pub mod rand;
 pub mod rwlock;
 pub mod thread;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod time;
 cfg_if::cfg_if! {
     if #[cfg(not(target_vendor = "uwp"))] {
index 524f21f889bc2c492fe69c92e35b8b56f26a79c7..dda3ed68cfc95aac651c2d65f27ecf6abf77a68f 100644 (file)
@@ -2,6 +2,16 @@
 use crate::mem;
 use crate::path::Prefix;
 
+#[cfg(test)]
+mod tests;
+
+pub const MAIN_SEP_STR: &str = "\\";
+pub const MAIN_SEP: char = '\\';
+
+// The unsafety here stems from converting between `&OsStr` and `&[u8]`
+// and back. This is safe to do because (1) we only look at ASCII
+// contents of the encoding and (2) new &OsStr values are produced
+// only from ASCII-bounded slices of existing &OsStr values.
 fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
     unsafe { mem::transmute(s) }
 }
@@ -19,76 +29,79 @@ pub fn is_verbatim_sep(b: u8) -> bool {
     b == b'\\'
 }
 
+// In most DOS systems, it is not possible to have more than 26 drive letters.
+// See <https://en.wikipedia.org/wiki/Drive_letter_assignment#Common_assignments>.
+pub fn is_valid_drive_letter(disk: u8) -> bool {
+    disk.is_ascii_alphabetic()
+}
+
 pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
-    use crate::path::Prefix::*;
-    unsafe {
-        // The unsafety here stems from converting between &OsStr and &[u8]
-        // and back. This is safe to do because (1) we only look at ASCII
-        // contents of the encoding and (2) new &OsStr values are produced
-        // only from ASCII-bounded slices of existing &OsStr values.
-        let mut path = os_str_as_u8_slice(path);
+    use Prefix::{DeviceNS, Disk, Verbatim, VerbatimDisk, VerbatimUNC, UNC};
+
+    let path = os_str_as_u8_slice(path);
 
-        if path.starts_with(br"\\") {
-            // \\
-            path = &path[2..];
-            if path.starts_with(br"?\") {
-                // \\?\
-                path = &path[2..];
-                if path.starts_with(br"UNC\") {
-                    // \\?\UNC\server\share
-                    path = &path[4..];
-                    let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
-                        Some((server, share)) => {
-                            (u8_slice_as_os_str(server), u8_slice_as_os_str(share))
-                        }
-                        None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])),
-                    };
-                    return Some(VerbatimUNC(server, share));
-                } else {
-                    // \\?\path
-                    let idx = path.iter().position(|&b| b == b'\\');
-                    if idx == Some(2) && path[1] == b':' {
-                        let c = path[0];
-                        if c.is_ascii() && (c as char).is_alphabetic() {
-                            // \\?\C:\ path
-                            return Some(VerbatimDisk(c.to_ascii_uppercase()));
-                        }
+    // \\
+    if let Some(path) = path.strip_prefix(br"\\") {
+        // \\?\
+        if let Some(path) = path.strip_prefix(br"?\") {
+            // \\?\UNC\server\share
+            if let Some(path) = path.strip_prefix(br"UNC\") {
+                let (server, share) = match get_first_two_components(path, is_verbatim_sep) {
+                    Some((server, share)) => unsafe {
+                        (u8_slice_as_os_str(server), u8_slice_as_os_str(share))
+                    },
+                    None => (unsafe { u8_slice_as_os_str(path) }, OsStr::new("")),
+                };
+                return Some(VerbatimUNC(server, share));
+            } else {
+                // \\?\path
+                match path {
+                    // \\?\C:\path
+                    [c, b':', b'\\', ..] if is_valid_drive_letter(*c) => {
+                        return Some(VerbatimDisk(c.to_ascii_uppercase()));
+                    }
+                    // \\?\cat_pics
+                    _ => {
+                        let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len());
+                        let slice = &path[..idx];
+                        return Some(Verbatim(unsafe { u8_slice_as_os_str(slice) }));
                     }
-                    let slice = &path[..idx.unwrap_or(path.len())];
-                    return Some(Verbatim(u8_slice_as_os_str(slice)));
-                }
-            } else if path.starts_with(b".\\") {
-                // \\.\path
-                path = &path[2..];
-                let pos = path.iter().position(|&b| b == b'\\');
-                let slice = &path[..pos.unwrap_or(path.len())];
-                return Some(DeviceNS(u8_slice_as_os_str(slice)));
-            }
-            match parse_two_comps(path, is_sep_byte) {
-                Some((server, share)) if !server.is_empty() && !share.is_empty() => {
-                    // \\server\share
-                    return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)));
                 }
-                _ => (),
             }
-        } else if path.get(1) == Some(&b':') {
-            // C:
-            let c = path[0];
-            if c.is_ascii() && (c as char).is_alphabetic() {
-                return Some(Disk(c.to_ascii_uppercase()));
+        } else if let Some(path) = path.strip_prefix(b".\\") {
+            // \\.\COM42
+            let idx = path.iter().position(|&b| b == b'\\').unwrap_or(path.len());
+            let slice = &path[..idx];
+            return Some(DeviceNS(unsafe { u8_slice_as_os_str(slice) }));
+        }
+        match get_first_two_components(path, is_sep_byte) {
+            Some((server, share)) if !server.is_empty() && !share.is_empty() => {
+                // \\server\share
+                return Some(unsafe { UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share)) });
             }
+            _ => {}
+        }
+    } else if let [c, b':', ..] = path {
+        // C:
+        if is_valid_drive_letter(*c) {
+            return Some(Disk(c.to_ascii_uppercase()));
         }
-        return None;
-    }
-
-    fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
-        let first = &path[..path.iter().position(|x| f(*x))?];
-        path = &path[(first.len() + 1)..];
-        let idx = path.iter().position(|x| f(*x));
-        let second = &path[..idx.unwrap_or(path.len())];
-        Some((first, second))
     }
+    None
 }
 
-pub const MAIN_SEP_STR: &str = "\\";
-pub const MAIN_SEP: char = '\\';
+/// Returns the first two path components with predicate `f`.
+///
+/// The two components returned will be use by caller
+/// to construct `VerbatimUNC` or `UNC` Windows path prefix.
+///
+/// Returns [`None`] if there are no separators in path.
+fn get_first_two_components(path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
+    let idx = path.iter().position(|&x| f(x))?;
+    // Panic safe
+    // The max `idx+1` is `path.len()` and `path[path.len()..]` is a valid index.
+    let (first, path) = (&path[..idx], &path[idx + 1..]);
+    let idx = path.iter().position(|&x| f(x)).unwrap_or(path.len());
+    let second = &path[..idx];
+    Some((first, second))
+}
diff --git a/src/libstd/sys/windows/path/tests.rs b/src/libstd/sys/windows/path/tests.rs
new file mode 100644 (file)
index 0000000..fbac1dc
--- /dev/null
@@ -0,0 +1,21 @@
+use super::*;
+
+#[test]
+fn test_get_first_two_components() {
+    assert_eq!(
+        get_first_two_components(br"server\share", is_verbatim_sep),
+        Some((&b"server"[..], &b"share"[..])),
+    );
+
+    assert_eq!(
+        get_first_two_components(br"server\", is_verbatim_sep),
+        Some((&b"server"[..], &b""[..]))
+    );
+
+    assert_eq!(
+        get_first_two_components(br"\server\", is_verbatim_sep),
+        Some((&b""[..], &b"server"[..]))
+    );
+
+    assert_eq!(get_first_two_components(br"there are no separators here", is_verbatim_sep), None,);
+}
index 77f9a5c9dc7b9c9378c292c50c6e713cdb3c4d66..7d6d4775eec8a87b588d94c2603f90ab4bb87915 100644 (file)
@@ -378,6 +378,7 @@ pub fn code(&self) -> Option<i32> {
     }
 }
 
+/// Converts a raw `c::DWORD` to a type-safe `ExitStatus` by wrapping it without copying.
 impl From<c::DWORD> for ExitStatus {
     fn from(u: c::DWORD) -> ExitStatus {
         ExitStatus(u)
diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs
deleted file mode 100644 (file)
index e0bb102..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-use crate::mem;
-use crate::ptr;
-use crate::sync::atomic::AtomicPtr;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sys::c;
-
-pub type Key = c::DWORD;
-pub type Dtor = unsafe extern "C" fn(*mut u8);
-
-// Turns out, like pretty much everything, Windows is pretty close the
-// functionality that Unix provides, but slightly different! In the case of
-// TLS, Windows does not provide an API to provide a destructor for a TLS
-// variable. This ends up being pretty crucial to this implementation, so we
-// need a way around this.
-//
-// The solution here ended up being a little obscure, but fear not, the
-// internet has informed me [1][2] that this solution is not unique (no way
-// I could have thought of it as well!). The key idea is to insert some hook
-// somewhere to run arbitrary code on thread termination. With this in place
-// we'll be able to run anything we like, including all TLS destructors!
-//
-// To accomplish this feat, we perform a number of threads, all contained
-// within this module:
-//
-// * All TLS destructors are tracked by *us*, not the windows runtime. This
-//   means that we have a global list of destructors for each TLS key that
-//   we know about.
-// * When a thread exits, we run over the entire list and run dtors for all
-//   non-null keys. This attempts to match Unix semantics in this regard.
-//
-// This ends up having the overhead of using a global list, having some
-// locks here and there, and in general just adding some more code bloat. We
-// attempt to optimize runtime by forgetting keys that don't have
-// destructors, but this only gets us so far.
-//
-// For more details and nitty-gritty, see the code sections below!
-//
-// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
-// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
-//                        /threading/thread_local_storage_win.cc#L42
-
-// -------------------------------------------------------------------------
-// Native bindings
-//
-// This section is just raw bindings to the native functions that Windows
-// provides, There's a few extra calls to deal with destructors.
-
-#[inline]
-pub unsafe fn create(dtor: Option<Dtor>) -> Key {
-    let key = c::TlsAlloc();
-    assert!(key != c::TLS_OUT_OF_INDEXES);
-    if let Some(f) = dtor {
-        register_dtor(key, f);
-    }
-    key
-}
-
-#[inline]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    let r = c::TlsSetValue(key, value as c::LPVOID);
-    debug_assert!(r != 0);
-}
-
-#[inline]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    c::TlsGetValue(key) as *mut u8
-}
-
-#[inline]
-pub unsafe fn destroy(_key: Key) {
-    rtabort!("can't destroy tls keys on windows")
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    true
-}
-
-// -------------------------------------------------------------------------
-// Dtor registration
-//
-// Windows has no native support for running destructors so we manage our own
-// list of destructors to keep track of how to destroy keys. We then install a
-// callback later to get invoked whenever a thread exits, running all
-// appropriate destructors.
-//
-// Currently unregistration from this list is not supported. A destructor can be
-// registered but cannot be unregistered. There's various simplifying reasons
-// for doing this, the big ones being:
-//
-// 1. Currently we don't even support deallocating TLS keys, so normal operation
-//    doesn't need to deallocate a destructor.
-// 2. There is no point in time where we know we can unregister a destructor
-//    because it could always be getting run by some remote thread.
-//
-// Typically processes have a statically known set of TLS keys which is pretty
-// small, and we'd want to keep this memory alive for the whole process anyway
-// really.
-//
-// Perhaps one day we can fold the `Box` here into a static allocation,
-// expanding the `StaticKey` structure to contain not only a slot for the TLS
-// key but also a slot for the destructor queue on windows. An optimization for
-// another day!
-
-static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
-
-struct Node {
-    dtor: Dtor,
-    key: Key,
-    next: *mut Node,
-}
-
-unsafe fn register_dtor(key: Key, dtor: Dtor) {
-    let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() });
-
-    let mut head = DTORS.load(SeqCst);
-    loop {
-        node.next = head;
-        match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
-            Ok(_) => return mem::forget(node),
-            Err(cur) => head = cur,
-        }
-    }
-}
-
-// -------------------------------------------------------------------------
-// Where the Magic (TM) Happens
-//
-// If you're looking at this code, and wondering "what is this doing?",
-// you're not alone! I'll try to break this down step by step:
-//
-// # What's up with CRT$XLB?
-//
-// For anything about TLS destructors to work on Windows, we have to be able
-// to run *something* when a thread exits. To do so, we place a very special
-// static in a very special location. If this is encoded in just the right
-// way, the kernel's loader is apparently nice enough to run some function
-// of ours whenever a thread exits! How nice of the kernel!
-//
-// Lots of detailed information can be found in source [1] above, but the
-// gist of it is that this is leveraging a feature of Microsoft's PE format
-// (executable format) which is not actually used by any compilers today.
-// This apparently translates to any callbacks in the ".CRT$XLB" section
-// being run on certain events.
-//
-// So after all that, we use the compiler's #[link_section] feature to place
-// a callback pointer into the magic section so it ends up being called.
-//
-// # What's up with this callback?
-//
-// The callback specified receives a number of parameters from... someone!
-// (the kernel? the runtime? I'm not quite sure!) There are a few events that
-// this gets invoked for, but we're currently only interested on when a
-// thread or a process "detaches" (exits). The process part happens for the
-// last thread and the thread part happens for any normal thread.
-//
-// # Ok, what's up with running all these destructors?
-//
-// This will likely need to be improved over time, but this function
-// attempts a "poor man's" destructor callback system. Once we've got a list
-// of what to run, we iterate over all keys, check their values, and then run
-// destructors if the values turn out to be non null (setting them to null just
-// beforehand). We do this a few times in a loop to basically match Unix
-// semantics. If we don't reach a fixed point after a short while then we just
-// inevitably leak something most likely.
-//
-// # The article mentions weird stuff about "/INCLUDE"?
-//
-// It sure does! Specifically we're talking about this quote:
-//
-//      The Microsoft run-time library facilitates this process by defining a
-//      memory image of the TLS Directory and giving it the special name
-//      “__tls_used” (Intel x86 platforms) or “_tls_used” (other platforms). The
-//      linker looks for this memory image and uses the data there to create the
-//      TLS Directory. Other compilers that support TLS and work with the
-//      Microsoft linker must use this same technique.
-//
-// Basically what this means is that if we want support for our TLS
-// destructors/our hook being called then we need to make sure the linker does
-// not omit this symbol. Otherwise it will omit it and our callback won't be
-// wired up.
-//
-// We don't actually use the `/INCLUDE` linker flag here like the article
-// mentions because the Rust compiler doesn't propagate linker flags, but
-// instead we use a shim function which performs a volatile 1-byte load from
-// the address of the symbol to ensure it sticks around.
-
-#[link_section = ".CRT$XLB"]
-#[allow(dead_code, unused_variables)]
-#[used] // we don't want LLVM eliminating this symbol for any reason, and
-// when the symbol makes it to the linker the linker will take over
-pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) =
-    on_tls_callback;
-
-#[allow(dead_code, unused_variables)]
-unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
-    if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
-        run_dtors();
-    }
-
-    // See comments above for what this is doing. Note that we don't need this
-    // trickery on GNU windows, just on MSVC.
-    reference_tls_used();
-    #[cfg(target_env = "msvc")]
-    unsafe fn reference_tls_used() {
-        extern "C" {
-            static _tls_used: u8;
-        }
-        crate::intrinsics::volatile_load(&_tls_used);
-    }
-    #[cfg(not(target_env = "msvc"))]
-    unsafe fn reference_tls_used() {}
-}
-
-#[allow(dead_code)] // actually called above
-unsafe fn run_dtors() {
-    let mut any_run = true;
-    for _ in 0..5 {
-        if !any_run {
-            break;
-        }
-        any_run = false;
-        let mut cur = DTORS.load(SeqCst);
-        while !cur.is_null() {
-            let ptr = c::TlsGetValue((*cur).key);
-
-            if !ptr.is_null() {
-                c::TlsSetValue((*cur).key, ptr::null_mut());
-                ((*cur).dtor)(ptr as *mut _);
-                any_run = true;
-            }
-
-            cur = (*cur).next;
-        }
-    }
-}
diff --git a/src/libstd/sys/windows/thread_local_dtor.rs b/src/libstd/sys/windows/thread_local_dtor.rs
new file mode 100644 (file)
index 0000000..7be13bc
--- /dev/null
@@ -0,0 +1,4 @@
+#![unstable(feature = "thread_local_internals", issue = "none")]
+#![cfg(target_thread_local)]
+
+pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
diff --git a/src/libstd/sys/windows/thread_local_key.rs b/src/libstd/sys/windows/thread_local_key.rs
new file mode 100644 (file)
index 0000000..e0bb102
--- /dev/null
@@ -0,0 +1,236 @@
+use crate::mem;
+use crate::ptr;
+use crate::sync::atomic::AtomicPtr;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sys::c;
+
+pub type Key = c::DWORD;
+pub type Dtor = unsafe extern "C" fn(*mut u8);
+
+// Turns out, like pretty much everything, Windows is pretty close the
+// functionality that Unix provides, but slightly different! In the case of
+// TLS, Windows does not provide an API to provide a destructor for a TLS
+// variable. This ends up being pretty crucial to this implementation, so we
+// need a way around this.
+//
+// The solution here ended up being a little obscure, but fear not, the
+// internet has informed me [1][2] that this solution is not unique (no way
+// I could have thought of it as well!). The key idea is to insert some hook
+// somewhere to run arbitrary code on thread termination. With this in place
+// we'll be able to run anything we like, including all TLS destructors!
+//
+// To accomplish this feat, we perform a number of threads, all contained
+// within this module:
+//
+// * All TLS destructors are tracked by *us*, not the windows runtime. This
+//   means that we have a global list of destructors for each TLS key that
+//   we know about.
+// * When a thread exits, we run over the entire list and run dtors for all
+//   non-null keys. This attempts to match Unix semantics in this regard.
+//
+// This ends up having the overhead of using a global list, having some
+// locks here and there, and in general just adding some more code bloat. We
+// attempt to optimize runtime by forgetting keys that don't have
+// destructors, but this only gets us so far.
+//
+// For more details and nitty-gritty, see the code sections below!
+//
+// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
+// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
+//                        /threading/thread_local_storage_win.cc#L42
+
+// -------------------------------------------------------------------------
+// Native bindings
+//
+// This section is just raw bindings to the native functions that Windows
+// provides, There's a few extra calls to deal with destructors.
+
+#[inline]
+pub unsafe fn create(dtor: Option<Dtor>) -> Key {
+    let key = c::TlsAlloc();
+    assert!(key != c::TLS_OUT_OF_INDEXES);
+    if let Some(f) = dtor {
+        register_dtor(key, f);
+    }
+    key
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    let r = c::TlsSetValue(key, value as c::LPVOID);
+    debug_assert!(r != 0);
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    c::TlsGetValue(key) as *mut u8
+}
+
+#[inline]
+pub unsafe fn destroy(_key: Key) {
+    rtabort!("can't destroy tls keys on windows")
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    true
+}
+
+// -------------------------------------------------------------------------
+// Dtor registration
+//
+// Windows has no native support for running destructors so we manage our own
+// list of destructors to keep track of how to destroy keys. We then install a
+// callback later to get invoked whenever a thread exits, running all
+// appropriate destructors.
+//
+// Currently unregistration from this list is not supported. A destructor can be
+// registered but cannot be unregistered. There's various simplifying reasons
+// for doing this, the big ones being:
+//
+// 1. Currently we don't even support deallocating TLS keys, so normal operation
+//    doesn't need to deallocate a destructor.
+// 2. There is no point in time where we know we can unregister a destructor
+//    because it could always be getting run by some remote thread.
+//
+// Typically processes have a statically known set of TLS keys which is pretty
+// small, and we'd want to keep this memory alive for the whole process anyway
+// really.
+//
+// Perhaps one day we can fold the `Box` here into a static allocation,
+// expanding the `StaticKey` structure to contain not only a slot for the TLS
+// key but also a slot for the destructor queue on windows. An optimization for
+// another day!
+
+static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
+
+struct Node {
+    dtor: Dtor,
+    key: Key,
+    next: *mut Node,
+}
+
+unsafe fn register_dtor(key: Key, dtor: Dtor) {
+    let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() });
+
+    let mut head = DTORS.load(SeqCst);
+    loop {
+        node.next = head;
+        match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
+            Ok(_) => return mem::forget(node),
+            Err(cur) => head = cur,
+        }
+    }
+}
+
+// -------------------------------------------------------------------------
+// Where the Magic (TM) Happens
+//
+// If you're looking at this code, and wondering "what is this doing?",
+// you're not alone! I'll try to break this down step by step:
+//
+// # What's up with CRT$XLB?
+//
+// For anything about TLS destructors to work on Windows, we have to be able
+// to run *something* when a thread exits. To do so, we place a very special
+// static in a very special location. If this is encoded in just the right
+// way, the kernel's loader is apparently nice enough to run some function
+// of ours whenever a thread exits! How nice of the kernel!
+//
+// Lots of detailed information can be found in source [1] above, but the
+// gist of it is that this is leveraging a feature of Microsoft's PE format
+// (executable format) which is not actually used by any compilers today.
+// This apparently translates to any callbacks in the ".CRT$XLB" section
+// being run on certain events.
+//
+// So after all that, we use the compiler's #[link_section] feature to place
+// a callback pointer into the magic section so it ends up being called.
+//
+// # What's up with this callback?
+//
+// The callback specified receives a number of parameters from... someone!
+// (the kernel? the runtime? I'm not quite sure!) There are a few events that
+// this gets invoked for, but we're currently only interested on when a
+// thread or a process "detaches" (exits). The process part happens for the
+// last thread and the thread part happens for any normal thread.
+//
+// # Ok, what's up with running all these destructors?
+//
+// This will likely need to be improved over time, but this function
+// attempts a "poor man's" destructor callback system. Once we've got a list
+// of what to run, we iterate over all keys, check their values, and then run
+// destructors if the values turn out to be non null (setting them to null just
+// beforehand). We do this a few times in a loop to basically match Unix
+// semantics. If we don't reach a fixed point after a short while then we just
+// inevitably leak something most likely.
+//
+// # The article mentions weird stuff about "/INCLUDE"?
+//
+// It sure does! Specifically we're talking about this quote:
+//
+//      The Microsoft run-time library facilitates this process by defining a
+//      memory image of the TLS Directory and giving it the special name
+//      “__tls_used” (Intel x86 platforms) or “_tls_used” (other platforms). The
+//      linker looks for this memory image and uses the data there to create the
+//      TLS Directory. Other compilers that support TLS and work with the
+//      Microsoft linker must use this same technique.
+//
+// Basically what this means is that if we want support for our TLS
+// destructors/our hook being called then we need to make sure the linker does
+// not omit this symbol. Otherwise it will omit it and our callback won't be
+// wired up.
+//
+// We don't actually use the `/INCLUDE` linker flag here like the article
+// mentions because the Rust compiler doesn't propagate linker flags, but
+// instead we use a shim function which performs a volatile 1-byte load from
+// the address of the symbol to ensure it sticks around.
+
+#[link_section = ".CRT$XLB"]
+#[allow(dead_code, unused_variables)]
+#[used] // we don't want LLVM eliminating this symbol for any reason, and
+// when the symbol makes it to the linker the linker will take over
+pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) =
+    on_tls_callback;
+
+#[allow(dead_code, unused_variables)]
+unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
+    if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
+        run_dtors();
+    }
+
+    // See comments above for what this is doing. Note that we don't need this
+    // trickery on GNU windows, just on MSVC.
+    reference_tls_used();
+    #[cfg(target_env = "msvc")]
+    unsafe fn reference_tls_used() {
+        extern "C" {
+            static _tls_used: u8;
+        }
+        crate::intrinsics::volatile_load(&_tls_used);
+    }
+    #[cfg(not(target_env = "msvc"))]
+    unsafe fn reference_tls_used() {}
+}
+
+#[allow(dead_code)] // actually called above
+unsafe fn run_dtors() {
+    let mut any_run = true;
+    for _ in 0..5 {
+        if !any_run {
+            break;
+        }
+        any_run = false;
+        let mut cur = DTORS.load(SeqCst);
+        while !cur.is_null() {
+            let ptr = c::TlsGetValue((*cur).key);
+
+            if !ptr.is_null() {
+                c::TlsSetValue((*cur).key, ptr::null_mut());
+                ((*cur).dtor)(ptr as *mut _);
+                any_run = true;
+            }
+
+            cur = (*cur).next;
+        }
+    }
+}
index e9b1e86d7ae49ed8e66a6f5a995be65ceb8ef4d5..d386a656e4ffdc896aa93fdceb53060d1c75a71c 100644 (file)
@@ -1,3 +1,4 @@
+use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
 use crate::borrow::Cow;
 /// Common code for printing the backtrace in the same way across the different
 /// supported platforms.
@@ -9,8 +10,6 @@
 use crate::sync::atomic::{self, Ordering};
 use crate::sys::mutex::Mutex;
 
-use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt};
-
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
 
index e03e0fc83454be6e39e2bf642a18f48c63c0e09c..840f9093e00f15dd2ece0c6f81526db752e82ec1 100644 (file)
@@ -51,13 +51,9 @@ macro_rules! rtunwrap {
 pub mod fs;
 pub mod io;
 pub mod mutex;
-#[cfg(any(doc, // see `mod os`, docs are generated for multiple platforms
-          unix,
-          target_os = "redox",
-          target_os = "cloudabi",
-          target_os = "hermit",
-          target_arch = "wasm32",
-          all(target_vendor = "fortanix", target_env = "sgx")))]
+// `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows
+// when generating documentation.
+#[cfg(any(doc, not(windows)))]
 pub mod os_str_bytes;
 pub mod poison;
 pub mod process;
@@ -65,7 +61,8 @@ macro_rules! rtunwrap {
 pub mod rwlock;
 pub mod thread;
 pub mod thread_info;
-pub mod thread_local;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
 pub mod util;
 pub mod wtf8;
 
@@ -73,6 +70,7 @@ macro_rules! rtunwrap {
     if #[cfg(any(target_os = "cloudabi",
                  target_os = "l4re",
                  target_os = "hermit",
+                 feature = "restricted-std",
                  all(target_arch = "wasm32", not(target_os = "emscripten")),
                  all(target_vendor = "fortanix", target_env = "sgx")))] {
         pub use crate::sys::net;
index 899fc6a72353042107e81f5626c96b49dac41c38..e66d8994147e13fc1ea4030fecc78966bd1b09d4 100644 (file)
@@ -17,6 +17,7 @@ impl Mutex {
     /// Also, until `init` is called, behavior is undefined if this
     /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
     /// are called by the thread currently holding the lock.
+    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Mutex {
         Mutex(imp::Mutex::new())
     }
diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs
deleted file mode 100644 (file)
index 756b8d0..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-//! OS-based thread local storage
-//!
-//! This module provides an implementation of OS-based thread local storage,
-//! using the native OS-provided facilities (think `TlsAlloc` or
-//! `pthread_setspecific`). The interface of this differs from the other types
-//! of thread-local-storage provided in this crate in that OS-based TLS can only
-//! get/set pointers,
-//!
-//! This module also provides two flavors of TLS. One is intended for static
-//! initialization, and does not contain a `Drop` implementation to deallocate
-//! the OS-TLS key. The other is a type which does implement `Drop` and hence
-//! has a safe interface.
-//!
-//! # Usage
-//!
-//! This module should likely not be used directly unless other primitives are
-//! being built on. types such as `thread_local::spawn::Key` are likely much
-//! more useful in practice than this OS-based version which likely requires
-//! unsafe code to interoperate with.
-//!
-//! # Examples
-//!
-//! Using a dynamically allocated TLS key. Note that this key can be shared
-//! among many threads via an `Arc`.
-//!
-//! ```ignore (cannot-doctest-private-modules)
-//! let key = Key::new(None);
-//! assert!(key.get().is_null());
-//! key.set(1 as *mut u8);
-//! assert!(!key.get().is_null());
-//!
-//! drop(key); // deallocate this TLS slot.
-//! ```
-//!
-//! Sometimes a statically allocated key is either required or easier to work
-//! with, however.
-//!
-//! ```ignore (cannot-doctest-private-modules)
-//! static KEY: StaticKey = INIT;
-//!
-//! unsafe {
-//!     assert!(KEY.get().is_null());
-//!     KEY.set(1 as *mut u8);
-//! }
-//! ```
-
-#![allow(non_camel_case_types)]
-#![unstable(feature = "thread_local_internals", issue = "none")]
-#![allow(dead_code)] // sys isn't exported yet
-
-use crate::ptr;
-use crate::sync::atomic::{self, AtomicUsize, Ordering};
-use crate::sys::thread_local as imp;
-use crate::sys_common::mutex::Mutex;
-
-/// A type for TLS keys that are statically allocated.
-///
-/// This type is entirely `unsafe` to use as it does not protect against
-/// use-after-deallocation or use-during-deallocation.
-///
-/// The actual OS-TLS key is lazily allocated when this is used for the first
-/// time. The key is also deallocated when the Rust runtime exits or `destroy`
-/// is called, whichever comes first.
-///
-/// # Examples
-///
-/// ```ignore (cannot-doctest-private-modules)
-/// use tls::os::{StaticKey, INIT};
-///
-/// static KEY: StaticKey = INIT;
-///
-/// unsafe {
-///     assert!(KEY.get().is_null());
-///     KEY.set(1 as *mut u8);
-/// }
-/// ```
-pub struct StaticKey {
-    /// Inner static TLS key (internals).
-    key: AtomicUsize,
-    /// Destructor for the TLS value.
-    ///
-    /// See `Key::new` for information about when the destructor runs and how
-    /// it runs.
-    dtor: Option<unsafe extern "C" fn(*mut u8)>,
-}
-
-/// A type for a safely managed OS-based TLS slot.
-///
-/// This type allocates an OS TLS key when it is initialized and will deallocate
-/// the key when it falls out of scope. When compared with `StaticKey`, this
-/// type is entirely safe to use.
-///
-/// Implementations will likely, however, contain unsafe code as this type only
-/// operates on `*mut u8`, a raw pointer.
-///
-/// # Examples
-///
-/// ```ignore (cannot-doctest-private-modules)
-/// use tls::os::Key;
-///
-/// let key = Key::new(None);
-/// assert!(key.get().is_null());
-/// key.set(1 as *mut u8);
-/// assert!(!key.get().is_null());
-///
-/// drop(key); // deallocate this TLS slot.
-/// ```
-pub struct Key {
-    key: imp::Key,
-}
-
-/// Constant initialization value for static TLS keys.
-///
-/// This value specifies no destructor by default.
-pub const INIT: StaticKey = StaticKey::new(None);
-
-impl StaticKey {
-    pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
-        StaticKey { key: atomic::AtomicUsize::new(0), dtor }
-    }
-
-    /// Gets the value associated with this TLS key
-    ///
-    /// This will lazily allocate a TLS key from the OS if one has not already
-    /// been allocated.
-    #[inline]
-    pub unsafe fn get(&self) -> *mut u8 {
-        imp::get(self.key())
-    }
-
-    /// Sets this TLS key to a new value.
-    ///
-    /// This will lazily allocate a TLS key from the OS if one has not already
-    /// been allocated.
-    #[inline]
-    pub unsafe fn set(&self, val: *mut u8) {
-        imp::set(self.key(), val)
-    }
-
-    #[inline]
-    unsafe fn key(&self) -> imp::Key {
-        match self.key.load(Ordering::Relaxed) {
-            0 => self.lazy_init() as imp::Key,
-            n => n as imp::Key,
-        }
-    }
-
-    unsafe fn lazy_init(&self) -> usize {
-        // Currently the Windows implementation of TLS is pretty hairy, and
-        // it greatly simplifies creation if we just synchronize everything.
-        //
-        // Additionally a 0-index of a tls key hasn't been seen on windows, so
-        // we just simplify the whole branch.
-        if imp::requires_synchronized_create() {
-            // We never call `INIT_LOCK.init()`, so it is UB to attempt to
-            // acquire this mutex reentrantly!
-            static INIT_LOCK: Mutex = Mutex::new();
-            let _guard = INIT_LOCK.lock();
-            let mut key = self.key.load(Ordering::SeqCst);
-            if key == 0 {
-                key = imp::create(self.dtor) as usize;
-                self.key.store(key, Ordering::SeqCst);
-            }
-            rtassert!(key != 0);
-            return key;
-        }
-
-        // POSIX allows the key created here to be 0, but the compare_and_swap
-        // below relies on using 0 as a sentinel value to check who won the
-        // race to set the shared TLS key. As far as I know, there is no
-        // guaranteed value that cannot be returned as a posix_key_create key,
-        // so there is no value we can initialize the inner key with to
-        // prove that it has not yet been set. As such, we'll continue using a
-        // value of 0, but with some gyrations to make sure we have a non-0
-        // value returned from the creation routine.
-        // FIXME: this is clearly a hack, and should be cleaned up.
-        let key1 = imp::create(self.dtor);
-        let key = if key1 != 0 {
-            key1
-        } else {
-            let key2 = imp::create(self.dtor);
-            imp::destroy(key1);
-            key2
-        };
-        rtassert!(key != 0);
-        match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
-            // The CAS succeeded, so we've created the actual key
-            0 => key as usize,
-            // If someone beat us to the punch, use their key instead
-            n => {
-                imp::destroy(key);
-                n
-            }
-        }
-    }
-}
-
-impl Key {
-    /// Creates a new managed OS TLS key.
-    ///
-    /// This key will be deallocated when the key falls out of scope.
-    ///
-    /// The argument provided is an optionally-specified destructor for the
-    /// value of this TLS key. When a thread exits and the value for this key
-    /// is non-null the destructor will be invoked. The TLS value will be reset
-    /// to null before the destructor is invoked.
-    ///
-    /// Note that the destructor will not be run when the `Key` goes out of
-    /// scope.
-    #[inline]
-    pub fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-        Key { key: unsafe { imp::create(dtor) } }
-    }
-
-    /// See StaticKey::get
-    #[inline]
-    pub fn get(&self) -> *mut u8 {
-        unsafe { imp::get(self.key) }
-    }
-
-    /// See StaticKey::set
-    #[inline]
-    pub fn set(&self, val: *mut u8) {
-        unsafe { imp::set(self.key, val) }
-    }
-}
-
-impl Drop for Key {
-    fn drop(&mut self) {
-        // Right now Windows doesn't support TLS key destruction, but this also
-        // isn't used anywhere other than tests, so just leak the TLS key.
-        // unsafe { imp::destroy(self.key) }
-    }
-}
-
-pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
-    // The fallback implementation uses a vanilla OS-based TLS key to track
-    // the list of destructors that need to be run for this thread. The key
-    // then has its own destructor which runs all the other destructors.
-    //
-    // The destructor for DTORS is a little special in that it has a `while`
-    // loop to continuously drain the list of registered destructors. It
-    // *should* be the case that this loop always terminates because we
-    // provide the guarantee that a TLS key cannot be set after it is
-    // flagged for destruction.
-
-    static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
-    type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
-    if DTORS.get().is_null() {
-        let v: Box<List> = box Vec::new();
-        DTORS.set(Box::into_raw(v) as *mut u8);
-    }
-    let list: &mut List = &mut *(DTORS.get() as *mut List);
-    list.push((t, dtor));
-
-    unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
-        while !ptr.is_null() {
-            let list: Box<List> = Box::from_raw(ptr as *mut List);
-            for (ptr, dtor) in list.into_iter() {
-                dtor(ptr);
-            }
-            ptr = DTORS.get();
-            DTORS.set(ptr::null_mut());
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{Key, StaticKey};
-
-    fn assert_sync<T: Sync>() {}
-    fn assert_send<T: Send>() {}
-
-    #[test]
-    fn smoke() {
-        assert_sync::<Key>();
-        assert_send::<Key>();
-
-        let k1 = Key::new(None);
-        let k2 = Key::new(None);
-        assert!(k1.get().is_null());
-        assert!(k2.get().is_null());
-        k1.set(1 as *mut _);
-        k2.set(2 as *mut _);
-        assert_eq!(k1.get() as usize, 1);
-        assert_eq!(k2.get() as usize, 2);
-    }
-
-    #[test]
-    fn statik() {
-        static K1: StaticKey = StaticKey::new(None);
-        static K2: StaticKey = StaticKey::new(None);
-
-        unsafe {
-            assert!(K1.get().is_null());
-            assert!(K2.get().is_null());
-            K1.set(1 as *mut _);
-            K2.set(2 as *mut _);
-            assert_eq!(K1.get() as usize, 1);
-            assert_eq!(K2.get() as usize, 2);
-        }
-    }
-}
diff --git a/src/libstd/sys_common/thread_local_dtor.rs b/src/libstd/sys_common/thread_local_dtor.rs
new file mode 100644 (file)
index 0000000..6f5ebf4
--- /dev/null
@@ -0,0 +1,49 @@
+//! Thread-local destructor
+//!
+//! Besides thread-local "keys" (pointer-sized non-adressable thread-local store
+//! with an associated destructor), many platforms also provide thread-local
+//! destructors that are not associated with any particular data. These are
+//! often more efficient.
+//!
+//! This module provides a fallback implementation for that interface, based
+//! on the less efficient thread-local "keys". Each platform provides
+//! a `thread_local_dtor` module which will either re-export the fallback,
+//! or implement something more efficient.
+
+#![unstable(feature = "thread_local_internals", issue = "none")]
+#![allow(dead_code)] // sys isn't exported yet
+
+use crate::ptr;
+use crate::sys_common::thread_local_key::StaticKey;
+
+pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    // The fallback implementation uses a vanilla OS-based TLS key to track
+    // the list of destructors that need to be run for this thread. The key
+    // then has its own destructor which runs all the other destructors.
+    //
+    // The destructor for DTORS is a little special in that it has a `while`
+    // loop to continuously drain the list of registered destructors. It
+    // *should* be the case that this loop always terminates because we
+    // provide the guarantee that a TLS key cannot be set after it is
+    // flagged for destruction.
+
+    static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
+    type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+    if DTORS.get().is_null() {
+        let v: Box<List> = box Vec::new();
+        DTORS.set(Box::into_raw(v) as *mut u8);
+    }
+    let list: &mut List = &mut *(DTORS.get() as *mut List);
+    list.push((t, dtor));
+
+    unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
+        while !ptr.is_null() {
+            let list: Box<List> = Box::from_raw(ptr as *mut List);
+            for (ptr, dtor) in list.into_iter() {
+                dtor(ptr);
+            }
+            ptr = DTORS.get();
+            DTORS.set(ptr::null_mut());
+        }
+    }
+}
diff --git a/src/libstd/sys_common/thread_local_key.rs b/src/libstd/sys_common/thread_local_key.rs
new file mode 100644 (file)
index 0000000..ac5b128
--- /dev/null
@@ -0,0 +1,271 @@
+//! OS-based thread local storage
+//!
+//! This module provides an implementation of OS-based thread local storage,
+//! using the native OS-provided facilities (think `TlsAlloc` or
+//! `pthread_setspecific`). The interface of this differs from the other types
+//! of thread-local-storage provided in this crate in that OS-based TLS can only
+//! get/set pointer-sized data, possibly with an associated destructor.
+//!
+//! This module also provides two flavors of TLS. One is intended for static
+//! initialization, and does not contain a `Drop` implementation to deallocate
+//! the OS-TLS key. The other is a type which does implement `Drop` and hence
+//! has a safe interface.
+//!
+//! # Usage
+//!
+//! This module should likely not be used directly unless other primitives are
+//! being built on. Types such as `thread_local::spawn::Key` are likely much
+//! more useful in practice than this OS-based version which likely requires
+//! unsafe code to interoperate with.
+//!
+//! # Examples
+//!
+//! Using a dynamically allocated TLS key. Note that this key can be shared
+//! among many threads via an `Arc`.
+//!
+//! ```ignore (cannot-doctest-private-modules)
+//! let key = Key::new(None);
+//! assert!(key.get().is_null());
+//! key.set(1 as *mut u8);
+//! assert!(!key.get().is_null());
+//!
+//! drop(key); // deallocate this TLS slot.
+//! ```
+//!
+//! Sometimes a statically allocated key is either required or easier to work
+//! with, however.
+//!
+//! ```ignore (cannot-doctest-private-modules)
+//! static KEY: StaticKey = INIT;
+//!
+//! unsafe {
+//!     assert!(KEY.get().is_null());
+//!     KEY.set(1 as *mut u8);
+//! }
+//! ```
+
+#![allow(non_camel_case_types)]
+#![unstable(feature = "thread_local_internals", issue = "none")]
+#![allow(dead_code)] // sys isn't exported yet
+
+use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::sys::thread_local_key as imp;
+use crate::sys_common::mutex::Mutex;
+
+/// A type for TLS keys that are statically allocated.
+///
+/// This type is entirely `unsafe` to use as it does not protect against
+/// use-after-deallocation or use-during-deallocation.
+///
+/// The actual OS-TLS key is lazily allocated when this is used for the first
+/// time. The key is also deallocated when the Rust runtime exits or `destroy`
+/// is called, whichever comes first.
+///
+/// # Examples
+///
+/// ```ignore (cannot-doctest-private-modules)
+/// use tls::os::{StaticKey, INIT};
+///
+/// static KEY: StaticKey = INIT;
+///
+/// unsafe {
+///     assert!(KEY.get().is_null());
+///     KEY.set(1 as *mut u8);
+/// }
+/// ```
+pub struct StaticKey {
+    /// Inner static TLS key (internals).
+    key: AtomicUsize,
+    /// Destructor for the TLS value.
+    ///
+    /// See `Key::new` for information about when the destructor runs and how
+    /// it runs.
+    dtor: Option<unsafe extern "C" fn(*mut u8)>,
+}
+
+/// A type for a safely managed OS-based TLS slot.
+///
+/// This type allocates an OS TLS key when it is initialized and will deallocate
+/// the key when it falls out of scope. When compared with `StaticKey`, this
+/// type is entirely safe to use.
+///
+/// Implementations will likely, however, contain unsafe code as this type only
+/// operates on `*mut u8`, a raw pointer.
+///
+/// # Examples
+///
+/// ```ignore (cannot-doctest-private-modules)
+/// use tls::os::Key;
+///
+/// let key = Key::new(None);
+/// assert!(key.get().is_null());
+/// key.set(1 as *mut u8);
+/// assert!(!key.get().is_null());
+///
+/// drop(key); // deallocate this TLS slot.
+/// ```
+pub struct Key {
+    key: imp::Key,
+}
+
+/// Constant initialization value for static TLS keys.
+///
+/// This value specifies no destructor by default.
+pub const INIT: StaticKey = StaticKey::new(None);
+
+impl StaticKey {
+    pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
+        StaticKey { key: atomic::AtomicUsize::new(0), dtor }
+    }
+
+    /// Gets the value associated with this TLS key
+    ///
+    /// This will lazily allocate a TLS key from the OS if one has not already
+    /// been allocated.
+    #[inline]
+    pub unsafe fn get(&self) -> *mut u8 {
+        imp::get(self.key())
+    }
+
+    /// Sets this TLS key to a new value.
+    ///
+    /// This will lazily allocate a TLS key from the OS if one has not already
+    /// been allocated.
+    #[inline]
+    pub unsafe fn set(&self, val: *mut u8) {
+        imp::set(self.key(), val)
+    }
+
+    #[inline]
+    unsafe fn key(&self) -> imp::Key {
+        match self.key.load(Ordering::Relaxed) {
+            0 => self.lazy_init() as imp::Key,
+            n => n as imp::Key,
+        }
+    }
+
+    unsafe fn lazy_init(&self) -> usize {
+        // Currently the Windows implementation of TLS is pretty hairy, and
+        // it greatly simplifies creation if we just synchronize everything.
+        //
+        // Additionally a 0-index of a tls key hasn't been seen on windows, so
+        // we just simplify the whole branch.
+        if imp::requires_synchronized_create() {
+            // We never call `INIT_LOCK.init()`, so it is UB to attempt to
+            // acquire this mutex reentrantly!
+            static INIT_LOCK: Mutex = Mutex::new();
+            let _guard = INIT_LOCK.lock();
+            let mut key = self.key.load(Ordering::SeqCst);
+            if key == 0 {
+                key = imp::create(self.dtor) as usize;
+                self.key.store(key, Ordering::SeqCst);
+            }
+            rtassert!(key != 0);
+            return key;
+        }
+
+        // POSIX allows the key created here to be 0, but the compare_and_swap
+        // below relies on using 0 as a sentinel value to check who won the
+        // race to set the shared TLS key. As far as I know, there is no
+        // guaranteed value that cannot be returned as a posix_key_create key,
+        // so there is no value we can initialize the inner key with to
+        // prove that it has not yet been set. As such, we'll continue using a
+        // value of 0, but with some gyrations to make sure we have a non-0
+        // value returned from the creation routine.
+        // FIXME: this is clearly a hack, and should be cleaned up.
+        let key1 = imp::create(self.dtor);
+        let key = if key1 != 0 {
+            key1
+        } else {
+            let key2 = imp::create(self.dtor);
+            imp::destroy(key1);
+            key2
+        };
+        rtassert!(key != 0);
+        match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
+            // The CAS succeeded, so we've created the actual key
+            0 => key as usize,
+            // If someone beat us to the punch, use their key instead
+            n => {
+                imp::destroy(key);
+                n
+            }
+        }
+    }
+}
+
+impl Key {
+    /// Creates a new managed OS TLS key.
+    ///
+    /// This key will be deallocated when the key falls out of scope.
+    ///
+    /// The argument provided is an optionally-specified destructor for the
+    /// value of this TLS key. When a thread exits and the value for this key
+    /// is non-null the destructor will be invoked. The TLS value will be reset
+    /// to null before the destructor is invoked.
+    ///
+    /// Note that the destructor will not be run when the `Key` goes out of
+    /// scope.
+    #[inline]
+    pub fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+        Key { key: unsafe { imp::create(dtor) } }
+    }
+
+    /// See StaticKey::get
+    #[inline]
+    pub fn get(&self) -> *mut u8 {
+        unsafe { imp::get(self.key) }
+    }
+
+    /// See StaticKey::set
+    #[inline]
+    pub fn set(&self, val: *mut u8) {
+        unsafe { imp::set(self.key, val) }
+    }
+}
+
+impl Drop for Key {
+    fn drop(&mut self) {
+        // Right now Windows doesn't support TLS key destruction, but this also
+        // isn't used anywhere other than tests, so just leak the TLS key.
+        // unsafe { imp::destroy(self.key) }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{Key, StaticKey};
+
+    fn assert_sync<T: Sync>() {}
+    fn assert_send<T: Send>() {}
+
+    #[test]
+    fn smoke() {
+        assert_sync::<Key>();
+        assert_send::<Key>();
+
+        let k1 = Key::new(None);
+        let k2 = Key::new(None);
+        assert!(k1.get().is_null());
+        assert!(k2.get().is_null());
+        k1.set(1 as *mut _);
+        k2.set(2 as *mut _);
+        assert_eq!(k1.get() as usize, 1);
+        assert_eq!(k2.get() as usize, 2);
+    }
+
+    #[test]
+    fn statik() {
+        static K1: StaticKey = StaticKey::new(None);
+        static K2: StaticKey = StaticKey::new(None);
+
+        unsafe {
+            assert!(K1.get().is_null());
+            assert!(K2.get().is_null());
+            K1.set(1 as *mut _);
+            K2.set(2 as *mut _);
+            assert_eq!(K1.get() as usize, 1);
+            assert_eq!(K2.get() as usize, 2);
+        }
+    }
+}
index 094c468a6770e25f5d2bcc37e530d42b0cd08d3a..ecd6fbc6b9395aaa7dfdc6f8dfa4713856b8acc2 100644 (file)
@@ -363,7 +363,7 @@ pub mod fast {
     use crate::cell::Cell;
     use crate::fmt;
     use crate::mem;
-    use crate::sys::fast_thread_local::register_dtor;
+    use crate::sys::thread_local_dtor::register_dtor;
 
     #[derive(Copy, Clone)]
     enum DtorState {
@@ -468,7 +468,7 @@ pub mod os {
     use crate::fmt;
     use crate::marker;
     use crate::ptr;
-    use crate::sys_common::thread_local::StaticKey as OsStaticKey;
+    use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
 
     pub struct Key<T> {
         // OS-TLS key that we'll use to key off.
index d435ca6842518bcd47b05abbd6f15d9e5e0c2c87..202867258f1e403006c53b07932a67e2dfb9915f 100644 (file)
@@ -641,9 +641,8 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn current() -> Thread {
     thread_info::current_thread().expect(
-        "use of std::thread::current() is not \
-                                          possible after the thread's local \
-                                          data has been destroyed",
+        "use of std::thread::current() is not possible \
+         after the thread's local data has been destroyed",
     )
 }
 
@@ -1742,7 +1741,6 @@ fn test_park_timeout_unpark_before() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn test_park_timeout_unpark_not_called() {
         for _ in 0..10 {
             thread::park_timeout(Duration::from_millis(10));
@@ -1750,7 +1748,6 @@ fn test_park_timeout_unpark_not_called() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn test_park_timeout_unpark_called_other_thread() {
         for _ in 0..10 {
             let th = thread::current();
@@ -1765,7 +1762,6 @@ fn test_park_timeout_unpark_called_other_thread() {
     }
 
     #[test]
-    #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     fn sleep_ms_smoke() {
         thread::sleep(Duration::from_millis(2));
     }
index 170fbb984cf9b5aa7bfed063c320f24e8fe178a1..a4748c5a46628d46727435a31a91e1e9169631bb 100644 (file)
@@ -10,6 +10,7 @@ path = "lib.rs"
 crate-type = ["dylib", "rlib"]
 
 [dependencies]
+cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
 term = { path = "../libterm" }
 std = { path = "../libstd" }
@@ -23,9 +24,12 @@ proc_macro = { path = "../libproc_macro" }
 
 # Forward features to the `std` crate as necessary
 [features]
+default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
 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"]
+std_detect_file_io = ["std/std_detect_file_io"]
+std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
index e8f3820558a6d7936db86ff2bbb018eb0830e8db..2fe87247e3acfc0951bb5c751d5f73f76dbb9194 100644 (file)
@@ -14,61 +14,36 @@ pub fn get_concurrency() -> usize {
         }
         Err(..) => num_cpus(),
     };
+}
 
-    #[cfg(windows)]
-    #[allow(nonstandard_style)]
-    fn num_cpus() -> usize {
-        #[repr(C)]
-        struct SYSTEM_INFO {
-            wProcessorArchitecture: u16,
-            wReserved: u16,
-            dwPageSize: u32,
-            lpMinimumApplicationAddress: *mut u8,
-            lpMaximumApplicationAddress: *mut u8,
-            dwActiveProcessorMask: *mut u8,
-            dwNumberOfProcessors: u32,
-            dwProcessorType: u32,
-            dwAllocationGranularity: u32,
-            wProcessorLevel: u16,
-            wProcessorRevision: u16,
-        }
-        extern "system" {
-            fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
-        }
-        unsafe {
-            let mut sysinfo = std::mem::zeroed();
-            GetSystemInfo(&mut sysinfo);
-            sysinfo.dwNumberOfProcessors as usize
+cfg_if::cfg_if! {
+    if #[cfg(windows)] {
+        #[allow(nonstandard_style)]
+        fn num_cpus() -> usize {
+            #[repr(C)]
+            struct SYSTEM_INFO {
+                wProcessorArchitecture: u16,
+                wReserved: u16,
+                dwPageSize: u32,
+                lpMinimumApplicationAddress: *mut u8,
+                lpMaximumApplicationAddress: *mut u8,
+                dwActiveProcessorMask: *mut u8,
+                dwNumberOfProcessors: u32,
+                dwProcessorType: u32,
+                dwAllocationGranularity: u32,
+                wProcessorLevel: u16,
+                wProcessorRevision: u16,
+            }
+            extern "system" {
+                fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
+            }
+            unsafe {
+                let mut sysinfo = std::mem::zeroed();
+                GetSystemInfo(&mut sysinfo);
+                sysinfo.dwNumberOfProcessors as usize
+            }
         }
-    }
-
-    #[cfg(target_os = "vxworks")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on vxWorks
-        1
-    }
-
-    #[cfg(target_os = "redox")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on Redox
-        1
-    }
-
-    #[cfg(target_os = "hermit")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on HermitCore
-        1
-    }
-
-    #[cfg(any(
-        all(target_arch = "wasm32", not(target_os = "emscripten")),
-        all(target_vendor = "fortanix", target_env = "sgx")
-    ))]
-    fn num_cpus() -> usize {
-        1
-    }
-
-    #[cfg(any(
+    } else if #[cfg(any(
         target_os = "android",
         target_os = "cloudabi",
         target_os = "emscripten",
@@ -78,23 +53,46 @@ fn num_cpus() -> usize {
         target_os = "macos",
         target_os = "solaris",
         target_os = "illumos",
-    ))]
-    fn num_cpus() -> usize {
-        unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
-    }
-
-    #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))]
-    fn num_cpus() -> usize {
-        use std::ptr;
+    ))] {
+        fn num_cpus() -> usize {
+            unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
+        }
+    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
+        fn num_cpus() -> usize {
+            use std::ptr;
 
-        let mut cpus: libc::c_uint = 0;
-        let mut cpus_size = std::mem::size_of_val(&cpus);
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = std::mem::size_of_val(&cpus);
 
-        unsafe {
-            cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+            unsafe {
+                cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+            }
+            if cpus < 1 {
+                let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+                unsafe {
+                    libc::sysctl(
+                        mib.as_mut_ptr(),
+                        2,
+                        &mut cpus as *mut _ as *mut _,
+                        &mut cpus_size as *mut _ as *mut _,
+                        ptr::null_mut(),
+                        0,
+                    );
+                }
+                if cpus < 1 {
+                    cpus = 1;
+                }
+            }
+            cpus as usize
         }
-        if cpus < 1 {
+    } else if #[cfg(target_os = "openbsd")] {
+        fn num_cpus() -> usize {
+            use std::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = std::mem::size_of_val(&cpus);
             let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
             unsafe {
                 libc::sysctl(
                     mib.as_mut_ptr(),
@@ -108,43 +106,12 @@ fn num_cpus() -> usize {
             if cpus < 1 {
                 cpus = 1;
             }
+            cpus as usize
         }
-        cpus as usize
-    }
-
-    #[cfg(target_os = "openbsd")]
-    fn num_cpus() -> usize {
-        use std::ptr;
-
-        let mut cpus: libc::c_uint = 0;
-        let mut cpus_size = std::mem::size_of_val(&cpus);
-        let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-
-        unsafe {
-            libc::sysctl(
-                mib.as_mut_ptr(),
-                2,
-                &mut cpus as *mut _ as *mut _,
-                &mut cpus_size as *mut _ as *mut _,
-                ptr::null_mut(),
-                0,
-            );
-        }
-        if cpus < 1 {
-            cpus = 1;
+    } else {
+        // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
+        fn num_cpus() -> usize {
+            1
         }
-        cpus as usize
-    }
-
-    #[cfg(target_os = "haiku")]
-    fn num_cpus() -> usize {
-        // FIXME: implement
-        1
-    }
-
-    #[cfg(target_os = "l4re")]
-    fn num_cpus() -> usize {
-        // FIXME: implement
-        1
     }
 }
index 831094f7545c103e8ddf93825a5a68a02769d27a..874ecc3764572b8f328a81f368a0f98cd567e7ae 100644 (file)
@@ -1,34 +1,32 @@
 //! Helper module which provides a function to test
 //! if stdout is a tty.
 
-#[cfg(any(
-    target_os = "cloudabi",
-    target_os = "hermit",
-    all(target_arch = "wasm32", not(target_os = "emscripten")),
-    all(target_vendor = "fortanix", target_env = "sgx")
-))]
-pub fn stdout_isatty() -> bool {
-    // FIXME: Implement isatty on SGX
-    false
-}
-#[cfg(unix)]
-pub fn stdout_isatty() -> bool {
-    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
-}
-#[cfg(windows)]
-pub fn stdout_isatty() -> bool {
-    type DWORD = u32;
-    type BOOL = i32;
-    type HANDLE = *mut u8;
-    type LPDWORD = *mut u32;
-    const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
-    extern "system" {
-        fn GetStdHandle(which: DWORD) -> HANDLE;
-        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
-    }
-    unsafe {
-        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
+cfg_if::cfg_if! {
+    if #[cfg(unix)] {
+        pub fn stdout_isatty() -> bool {
+            unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
+        }
+    } else if #[cfg(windows)] {
+        pub fn stdout_isatty() -> bool {
+            type DWORD = u32;
+            type BOOL = i32;
+            type HANDLE = *mut u8;
+            type LPDWORD = *mut u32;
+            const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+            extern "system" {
+                fn GetStdHandle(which: DWORD) -> HANDLE;
+                fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
+            }
+            unsafe {
+                let handle = GetStdHandle(STD_OUTPUT_HANDLE);
+                let mut out = 0;
+                GetConsoleMode(handle, &mut out) != 0
+            }
+        }
+    } else {
+        // FIXME: Implement isatty on SGX
+        pub fn stdout_isatty() -> bool {
+            false
+        }
     }
 }
index cc025da1af5557d7a74cee57ddbfb1f35a04c888..c4d10ab177be9534659df7ae4b69fe9355f47c07 100644 (file)
@@ -9,12 +9,31 @@
 
 cfg_if::cfg_if! {
     if #[cfg(target_env = "msvc")] {
-        // no extra unwinder support needed
-    } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
-        // no unwinder on the system!
-    } else {
+        // Windows MSVC no extra unwinder support needed
+    } else if #[cfg(any(
+        target_os = "l4re",
+        target_os = "none",
+    ))] {
+        // These "unix" family members do not have unwinder.
+        // Note this also matches x86_64-linux-kernel.
+    } else if #[cfg(any(
+        unix,
+        windows,
+        target_os = "cloudabi",
+        all(target_vendor = "fortanix", target_env = "sgx"),
+    ))] {
         mod libunwind;
         pub use libunwind::*;
+    } else {
+        // no unwinder on the system!
+        // - wasm32 (not emscripten, which is "unix" family)
+        // - os=none ("bare metal" targets)
+        // - os=hermit
+        // - os=uefi
+        // - os=cuda
+        // - nvptx64-nvidia-cuda
+        // - mipsel-sony-psp
+        // - Any new targets not listed above.
     }
 }
 
index d134a53927fa033ae7e0f3e8ee872ff2dc71468d..86b120e6f302d39cd6973b6391fb299d7bc22122 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d134a53927fa033ae7e0f3e8ee872ff2dc71468d
+Subproject commit 86b120e6f302d39cd6973b6391fb299d7bc22122
diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/src/rustllvm/CoverageMappingWrapper.cpp
new file mode 100644 (file)
index 0000000..c6c4cdb
--- /dev/null
@@ -0,0 +1,115 @@
+#include "rustllvm.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
+#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ADT/ArrayRef.h"
+
+#include <iostream>
+
+using namespace llvm;
+
+extern "C" SmallVectorTemplateBase<coverage::CounterExpression>
+    *LLVMRustCoverageSmallVectorCounterExpressionCreate() {
+  return new SmallVector<coverage::CounterExpression, 32>();
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterExpressionDispose(
+    SmallVectorTemplateBase<coverage::CounterExpression> *Vector) {
+  delete Vector;
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterExpressionAdd(
+    SmallVectorTemplateBase<coverage::CounterExpression> *Expressions,
+    coverage::CounterExpression::ExprKind Kind,
+    unsigned LeftIndex,
+    unsigned RightIndex) {
+  auto LHS = coverage::Counter::getCounter(LeftIndex);
+  auto RHS = coverage::Counter::getCounter(RightIndex);
+  Expressions->push_back(coverage::CounterExpression { Kind, LHS, RHS });
+}
+
+extern "C" SmallVectorTemplateBase<coverage::CounterMappingRegion>
+    *LLVMRustCoverageSmallVectorCounterMappingRegionCreate() {
+  return new SmallVector<coverage::CounterMappingRegion, 32>();
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterMappingRegionDispose(
+    SmallVectorTemplateBase<coverage::CounterMappingRegion> *Vector) {
+  delete Vector;
+}
+
+extern "C" void LLVMRustCoverageSmallVectorCounterMappingRegionAdd(
+    SmallVectorTemplateBase<coverage::CounterMappingRegion> *MappingRegions,
+    unsigned Index,
+    unsigned FileID,
+    unsigned LineStart,
+    unsigned ColumnStart,
+    unsigned LineEnd,
+    unsigned ColumnEnd) {
+  auto Counter = coverage::Counter::getCounter(Index);
+  MappingRegions->push_back(coverage::CounterMappingRegion::makeRegion(
+           Counter, FileID, LineStart,
+           ColumnStart, LineEnd, ColumnEnd));
+
+  // FIXME(richkadel): As applicable, implement additional CounterMappingRegion types using the
+  // static method alternatives to `coverage::CounterMappingRegion::makeRegion`:
+  //
+  //   makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart,
+  //                 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
+  //   makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart,
+  //               unsigned LineEnd, unsigned ColumnEnd) {
+  //   makeGapRegion(Counter Count, unsigned FileID, unsigned LineStart,
+  //                 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
+}
+
+extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
+    const char* const Filenames[],
+    size_t FilenamesLen,
+    RustStringRef BufferOut) {
+  SmallVector<StringRef,32> FilenameRefs;
+  for (size_t i = 0; i < FilenamesLen; i++) {
+    FilenameRefs.push_back(StringRef(Filenames[i]));
+  }
+  auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter(
+    makeArrayRef(FilenameRefs));
+  RawRustStringOstream OS(BufferOut);
+  FilenamesWriter.write(OS);
+}
+
+extern "C" void LLVMRustCoverageWriteMappingToBuffer(
+    const unsigned *VirtualFileMappingIDs,
+    unsigned NumVirtualFileMappingIDs,
+    const SmallVectorImpl<coverage::CounterExpression> *Expressions,
+    SmallVectorImpl<coverage::CounterMappingRegion> *MappingRegions,
+    RustStringRef BufferOut) {
+  auto CoverageMappingWriter = coverage::CoverageMappingWriter(
+    makeArrayRef(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
+    makeArrayRef(*Expressions),
+    MutableArrayRef<coverage::CounterMappingRegion> { *MappingRegions });
+  RawRustStringOstream OS(BufferOut);
+  CoverageMappingWriter.write(OS);
+}
+
+extern "C" uint64_t LLVMRustCoverageComputeHash(const char *Name) {
+  StringRef NameRef(Name);
+  return IndexedInstrProf::ComputeHash(NameRef);
+}
+
+extern "C" void LLVMRustCoverageWriteSectionNameToString(LLVMModuleRef M,
+                                                         RustStringRef Str) {
+  Triple TargetTriple(unwrap(M)->getTargetTriple());
+  auto name = getInstrProfSectionName(IPSK_covmap,
+                                      TargetTriple.getObjectFormat());
+  RawRustStringOstream OS(Str);
+  OS << name;
+}
+
+extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
+  auto name = getCoverageMappingVarName();
+  RawRustStringOstream OS(Str);
+  OS << name;
+}
+
+extern "C" uint32_t LLVMRustCoverageMappingVersion() {
+  return coverage::CovMapVersion::CurrentVersion;
+}
index c92cf65f98af7fc1909f483a118c23c920791a95..667bf4a2ded37e7931df99735435f05eef8cbda0 100644 (file)
@@ -1395,7 +1395,7 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
       FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles));
 }
 
-extern "C" LLVMValueRef LLVMRustGetInstrprofIncrementIntrinsic(LLVMModuleRef M) {
+extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
   return wrap(llvm::Intrinsic::getDeclaration(unwrap(M),
               (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment));
 }
index da48048113bc218f6fb7464e9bd190be589aa1fc..57b8664d3b6058d1050790354cb0a5fc89cc16ca 100644 (file)
@@ -3,6 +3,7 @@
 #include "llvm-c/Object.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/Lint.h"
 #include "llvm/Analysis/Passes.h"
index 769ec669bdc8da412687430df97beaad07ea0490..4234ce4bac07dd84a56c8ef32ce2d17ec0ed8fb0 100644 (file)
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.(x+1).0` for Cargo where they were released on `date`.
 
-date: 2020-06-16
+date: 2020-07-16
 rustc: beta
 cargo: beta
 
@@ -20,7 +20,7 @@ cargo: beta
 # bootstrapping issues with use of new syntax in this repo. If you're looking at
 # the beta/stable branch, this key should be omitted, as we don't want to depend
 # on rustfmt from nightly there.
-rustfmt: nightly-2020-04-22
+rustfmt: nightly-2020-07-12
 
 # When making a stable release the process currently looks like:
 #
diff --git a/src/test/codegen/atomic-operations.rs b/src/test/codegen/atomic-operations.rs
new file mode 100644 (file)
index 0000000..ff94ac8
--- /dev/null
@@ -0,0 +1,60 @@
+// Code generation of atomic operations.
+//
+// compile-flags: -O
+#![crate_type = "lib"]
+
+use std::sync::atomic::{AtomicI32, Ordering::*};
+
+// CHECK-LABEL: @compare_exchange
+#[no_mangle]
+pub fn compare_exchange(a: &AtomicI32) {
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 10 monotonic monotonic
+    let _ = a.compare_exchange(0, 10, Relaxed, Relaxed);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 20 release monotonic
+    let _ = a.compare_exchange(0, 20, Release, Relaxed);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 30 acquire monotonic
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 31 acquire acquire
+    let _ = a.compare_exchange(0, 30, Acquire, Relaxed);
+    let _ = a.compare_exchange(0, 31, Acquire, Acquire);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 41 acq_rel acquire
+    let _ = a.compare_exchange(0, 40, AcqRel, Relaxed);
+    let _ = a.compare_exchange(0, 41, AcqRel, Acquire);
+
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 51 seq_cst acquire
+    // CHECK: cmpxchg i32* %{{.*}}, i32 0, i32 52 seq_cst seq_cst
+    let _ = a.compare_exchange(0, 50, SeqCst, Relaxed);
+    let _ = a.compare_exchange(0, 51, SeqCst, Acquire);
+    let _ = a.compare_exchange(0, 52, SeqCst, SeqCst);
+}
+
+// CHECK-LABEL: @compare_exchange_weak
+#[no_mangle]
+pub fn compare_exchange_weak(w: &AtomicI32) {
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 10 monotonic monotonic
+    let _ = w.compare_exchange_weak(1, 10, Relaxed, Relaxed);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 20 release monotonic
+    let _ = w.compare_exchange_weak(1, 20, Release, Relaxed);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 30 acquire monotonic
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 31 acquire acquire
+    let _ = w.compare_exchange_weak(1, 30, Acquire, Relaxed);
+    let _ = w.compare_exchange_weak(1, 31, Acquire, Acquire);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 40 acq_rel monotonic
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 41 acq_rel acquire
+    let _ = w.compare_exchange_weak(1, 40, AcqRel, Relaxed);
+    let _ = w.compare_exchange_weak(1, 41, AcqRel, Acquire);
+
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 50 seq_cst monotonic
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 51 seq_cst acquire
+    // CHECK: cmpxchg weak i32* %{{.*}}, i32 1, i32 52 seq_cst seq_cst
+    let _ = w.compare_exchange_weak(1, 50, SeqCst, Relaxed);
+    let _ = w.compare_exchange_weak(1, 51, SeqCst, Acquire);
+    let _ = w.compare_exchange_weak(1, 52, SeqCst, SeqCst);
+}
index eee59be629bb66ef1e909a47a94bb010aec11d6f..2270eca5014286a68b82537b059052b9b31c2d90 100644 (file)
@@ -6,12 +6,13 @@
 #![crate_type = "rlib"]
 #![feature(thread_local)]
 
-// CHECK: @STATIC_VAR_1 = thread_local local_unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
+// local_unnamed_addr does not appear when std is built with debug assertions.
+// CHECK: @STATIC_VAR_1 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
 #[no_mangle]
 #[thread_local]
 static mut STATIC_VAR_1: [u32; 8] = [0; 8];
 
-// CHECK: @STATIC_VAR_2 = thread_local local_unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
+// CHECK: @STATIC_VAR_2 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
 #[no_mangle]
 #[thread_local]
 static mut STATIC_VAR_2: [u32; 8] = [4; 8];
index c23c57c8c590097d8a5656364cd7b34a1beb83c2..59f29e756fc9a1541058925b3cd269d198968a4c 100644 (file)
@@ -3,6 +3,7 @@
 
 // min-system-llvm-version: 9.0
 // ignore-arm
+// ignore-aarch64
 // ignore-mips
 // ignore-mips64
 // ignore-powerpc
index c9415aed930d5ad85290ff8a96a74e3f59b1d1f2..5b8690c3b98ce8fb00524f802fa76998a0400ee6 100644 (file)
@@ -1,5 +1,3 @@
-// WONTFIX(#20184) Needs landing pads (not present in stage1) or the compiler hangs.
-// ignore-stage1
 // compile-flags: -C codegen-units=2
 // ignore-emscripten
 
index ae28fcad903be648871df818a2c1b370e3e57461..d3cb5aaaeba89095fed6fbae4ac5cdfc7427d8ac 100644 (file)
@@ -1,4 +1,4 @@
 // compile-flags: --extern std=
-// error-pattern: can't find crate for `std`
+// error-pattern: extern location for std does not exist
 
 fn main() {}
index 34f30548c5a8157f7ee2ea0e3362888ff1ee8677..2af72f0e98764838b2241b6c6537ed2267e70a87 100644 (file)
@@ -24,7 +24,7 @@
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -35,7 +35,7 @@ pub fn check() {
 pub mod fn_calls_free_fn {
     use point::{self, Point};
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         point::distance_squared(&x);
@@ -46,7 +46,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -56,7 +56,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -66,7 +66,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index b49731b26e78f6664f6180b11eb60b98c7ec0cb1..0245374007985c3f2bab1dd5855585a1608d3f45 100644 (file)
@@ -6,12 +6,12 @@
 
 extern crate a;
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn call_function0() {
     a::function0(77);
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn call_function1() {
     a::function1(77);
 }
index 662aa5353313401f99dabd3b79546c7b2529d9b0..89699bce209f0e8cfae4d5fcebeb2890b6b67df9 100644 (file)
@@ -70,7 +70,7 @@ pub fn x(&self) -> f32 {
 pub mod fn_with_type_in_sig {
     use point::Point;
 
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn boop(p: Option<&Point>) -> f32 {
         p.map(|p| p.total()).unwrap_or(0.0)
     }
@@ -86,7 +86,7 @@ pub fn boop(p: Option<&Point>) -> f32 {
 pub mod call_fn_with_type_in_sig {
     use fn_with_type_in_sig;
 
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn bip() -> f32 {
         fn_with_type_in_sig::boop(None)
     }
@@ -102,7 +102,7 @@ pub fn bip() -> f32 {
 pub mod fn_with_type_in_body {
     use point::Point;
 
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn boop() -> f32 {
         Point::origin().total()
     }
@@ -115,7 +115,7 @@ pub fn boop() -> f32 {
 pub mod call_fn_with_type_in_body {
     use fn_with_type_in_body;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn bip() -> f32 {
         fn_with_type_in_body::boop()
     }
@@ -125,7 +125,7 @@ pub fn bip() -> f32 {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn make_origin(p: Point) -> Point {
         Point { ..p }
     }
@@ -135,7 +135,7 @@ pub fn make_origin(p: Point) -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -145,7 +145,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index c167cf6e035d6b505152cb588ff4356c62159e97..7448b54dd079c4870172f4b3ad874d13520caac5 100644 (file)
@@ -18,7 +18,7 @@
 use a::A;
 use b::B;
 
-//? #[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+//? #[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn main() {
     A + B;
 }
index 722e62ef11ded4ca086da662105f52c372828d3f..ba4bf4e7b7d20a2126554045777b33000649ed23 100644 (file)
@@ -51,7 +51,7 @@ pub fn translate(&mut self, x: f32, y: f32) {
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -62,7 +62,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -73,7 +73,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -83,7 +83,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -93,7 +93,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 384441d6d0c71e510f4cb46f16f864906b01d21b..5072ef609e2cc951e947dad39d1c6787c64dc61d 100644 (file)
@@ -23,7 +23,7 @@
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -34,7 +34,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -45,7 +45,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -55,7 +55,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -65,7 +65,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index ec5899f3119d86b7e8e8c92a865a221a5fd8cabc..5c024ed91a3bfb1717938bec35a1130b57ed72ff 100644 (file)
@@ -51,7 +51,7 @@ pub fn translate(&mut self, x: f32, y: f32) {
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -62,7 +62,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -73,7 +73,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -83,7 +83,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -93,7 +93,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index f0e78f8d0a48341a32814fe882e7b3fb123576a6..2aeecfc89d5c099875349be8c0dc7e73836653cd 100644 (file)
@@ -24,7 +24,7 @@
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -35,7 +35,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn dirty() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -46,7 +46,7 @@ pub fn dirty() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -56,7 +56,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -66,7 +66,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 641d20ed6cc8ab86ff01d2ce606cb656d1745197..c944901e34542ecdcbbc81702f41b45e69c434a7 100644 (file)
@@ -42,7 +42,7 @@ pub fn x(&self) -> f32 {
 pub mod fn_calls_changed_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.distance_from_origin();
@@ -53,7 +53,7 @@ pub fn check() {
 pub mod fn_calls_another_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.x();
@@ -64,7 +64,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -74,7 +74,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -84,7 +84,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 9b8f9517bf149783e8fa87c0984bccaee764c2b9..4a5aac682f5aaa173f3b4e63f73467c2deef25df 100644 (file)
@@ -52,7 +52,7 @@ pub fn x(&self) -> f32 {
 pub mod fn_calls_changed_method {
     use point::Point;
 
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.distance_from_point(None);
@@ -63,7 +63,7 @@ pub fn check() {
 pub mod fn_calls_another_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.x();
@@ -74,7 +74,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -84,7 +84,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -94,7 +94,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index b9a1846b37d44ba93e948f08f0f68b33e1ec30da..2a1056df4cecacb99ed020dc81accb6029398383 100644 (file)
@@ -25,16 +25,16 @@ pub fn x() -> u32 {
 mod y {
     use x;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     pub fn y() {
-        //[cfail2]~^ ERROR `typeck_tables_of(y::y)` should be clean but is not
+        //[cfail2]~^ ERROR `typeck(y::y)` should be clean but is not
         x::x();
     }
 }
 
 mod z {
-    #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_dirty(label="typeck", cfg="cfail2")]
     pub fn z() {
-        //[cfail2]~^ ERROR `typeck_tables_of(z::z)` should be dirty but is not
+        //[cfail2]~^ ERROR `typeck(z::z)` should be dirty but is not
     }
 }
index 3706ab4a0207593aefa95313bf0ca47799094dcb..d4511cee75bb9740d43c3d6f218ffbf545492896 100644 (file)
@@ -25,7 +25,7 @@ pub fn change_callee_function() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_callee_function() {
     callee2(1, 2)
@@ -40,7 +40,7 @@ pub fn change_argument_function() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_argument_function() {
     callee1(1, 3)
@@ -81,7 +81,7 @@ pub fn change_callee_method() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_callee_method() {
     let s = Struct;
@@ -98,7 +98,7 @@ pub fn change_argument_method() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_argument_method() {
     let s = Struct;
@@ -115,7 +115,7 @@ pub fn change_ufcs_callee_method() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_ufcs_callee_method() {
     let s = Struct;
@@ -132,7 +132,7 @@ pub fn change_argument_method_ufcs() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_argument_method_ufcs() {
     let s = Struct;
@@ -149,7 +149,7 @@ pub fn change_to_ufcs() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 // One might think this would be expanded in the hir_owner_nodes/Mir, but it actually
 // results in slightly different hir_owner/Mir.
@@ -171,7 +171,7 @@ pub mod change_ufcs_callee_indirectly {
     #[cfg(not(cfail1))]
     use super::Struct2 as Struct;
 
-    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
     #[rustc_clean(cfg="cfail3")]
 
 
index b1e9ed678c4c55ec7d12e5982fac401be4e86ac4..7372cbc9156086d21c16f31073eb315e7f89c3e2 100644 (file)
@@ -37,7 +37,7 @@ pub fn add_parameter() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_parameter() {
     let x = 0u32;
@@ -53,7 +53,7 @@ pub fn change_parameter_pattern() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_parameter_pattern() {
     let _ = |(x,): (u32,)| x;
@@ -84,7 +84,7 @@ pub fn add_type_ascription_to_parameter() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck_tables_of")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner_nodes, typeck")]
 #[rustc_clean(cfg = "cfail3")]
 pub fn add_type_ascription_to_parameter() {
     let closure = |x: u32| x + 1u32;
@@ -101,7 +101,7 @@ pub fn change_parameter_type() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_parameter_type() {
     let closure = |x: u16| (x as u64) + 1;
index 2c07cbcb2054b711f55bd91f8e0f7c337aa0183f..4161c6a6bfcded44ab9d24b3472c72303b941d20 100644 (file)
@@ -34,7 +34,7 @@ pub fn change_field_value_struct_like() -> Enum {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_field_value_struct_like() -> Enum {
     Enum::Struct {
@@ -57,7 +57,7 @@ pub fn change_field_order_struct_like() -> Enum {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
 // FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it
 // would if it were not all constants
@@ -96,7 +96,7 @@ pub fn change_constructor_path_struct_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_path_struct_like() {
     let _ = Enum2::Struct {
@@ -119,7 +119,7 @@ pub fn change_constructor_variant_struct_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_variant_struct_like() {
     let _ = Enum2::Struct2 {
@@ -139,8 +139,8 @@ pub mod change_constructor_path_indirectly_struct_like {
 
     #[rustc_clean(
         cfg="cfail2",
-        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,mir_built,\
-                typeck_tables_of"
+        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\
+                typeck"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> TheEnum {
@@ -161,7 +161,7 @@ pub mod change_constructor_variant_indirectly_struct_like {
     #[cfg(not(cfail1))]
     use super::Enum2::Struct2 as Variant;
 
-    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> Enum2 {
         Variant {
@@ -180,7 +180,7 @@ pub fn change_field_value_tuple_like() -> Enum {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_field_value_tuple_like() -> Enum {
     Enum::Tuple(0, 1, 3)
@@ -197,7 +197,7 @@ pub fn change_constructor_path_tuple_like() {
 #[cfg(not(cfail1))]
 #[rustc_clean(
     cfg="cfail2",
-    except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of"
+    except="hir_owner_nodes,optimized_mir,typeck"
 )]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_path_tuple_like() {
@@ -215,7 +215,7 @@ pub fn change_constructor_variant_tuple_like() {
 #[cfg(not(cfail1))]
 #[rustc_clean(
     cfg="cfail2",
-    except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of"
+    except="hir_owner_nodes,optimized_mir,typeck"
 )]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_variant_tuple_like() {
@@ -232,8 +232,8 @@ pub mod change_constructor_path_indirectly_tuple_like {
 
     #[rustc_clean(
         cfg="cfail2",
-        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,mir_built,\
-                typeck_tables_of"
+        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\
+                typeck"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> TheEnum {
@@ -251,7 +251,7 @@ pub mod change_constructor_variant_indirectly_tuple_like {
     #[cfg(not(cfail1))]
     use super::Enum2::Tuple2 as Variant;
 
-    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> Enum2 {
         Variant(0, 1, 2)
@@ -278,7 +278,7 @@ pub fn change_constructor_path_c_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_path_c_like() {
     let _x = Clike2::B;
@@ -293,7 +293,7 @@ pub fn change_constructor_variant_c_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_variant_c_like() {
     let _x = Clike::C;
@@ -309,8 +309,8 @@ pub mod change_constructor_path_indirectly_c_like {
 
     #[rustc_clean(
         cfg="cfail2",
-        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,mir_built,\
-                typeck_tables_of"
+        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,\
+                typeck"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> TheEnum {
@@ -328,7 +328,7 @@ pub mod change_constructor_variant_indirectly_c_like {
     #[cfg(not(cfail1))]
     use super::Clike::B as Variant;
 
-    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> Clike {
         Variant
index 4ea58705017ee5c79fc72dfad2a228216b6a518e..40b6925bc72769ff8ded2221e620314fa212c5da 100644 (file)
@@ -16,7 +16,7 @@ pub fn body_not_exported_to_metadata() -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn body_not_exported_to_metadata() -> u32 {
     2
@@ -35,7 +35,7 @@ pub fn body_exported_to_metadata_because_of_inline() -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[inline]
 pub fn body_exported_to_metadata_because_of_inline() -> u32 {
@@ -55,7 +55,7 @@ pub fn body_exported_to_metadata_because_of_generic() -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[inline]
 pub fn body_exported_to_metadata_because_of_generic() -> u32 {
index d3d5a69c171f9550d82bad05e735f3efb83c47bc..e1460503d2d9424d0a0adf515ef7cf1e40342c72 100644 (file)
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
@@ -48,7 +48,7 @@ pub fn change_iteration_variable_name() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_iteration_variable_name() {
     let mut _x = 0;
@@ -71,7 +71,7 @@ pub fn change_iteration_variable_pattern() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_iteration_variable_pattern() {
     let mut _x = 0;
@@ -94,7 +94,7 @@ pub fn change_iterable() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, promoted_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_iterable() {
     let mut _x = 0;
@@ -116,7 +116,7 @@ pub fn add_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_break() {
     let mut _x = 0;
@@ -187,7 +187,7 @@ pub fn change_break_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_break_label() {
     let mut _x = 0;
@@ -237,7 +237,7 @@ pub fn change_continue_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_label() {
     let mut _x = 0;
@@ -262,7 +262,7 @@ pub fn change_continue_to_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_to_break() {
     let mut _x = 0;
index a6b936fcbcf895665e2003fd315b38ffcc7fb7d2..706cbcf4caf34da5b54aebd6f53f98fa7f29a35b 100644 (file)
@@ -22,7 +22,7 @@ pub fn add_parameter() {}
 #[cfg(not(cfail1))]
 #[rustc_clean(
     cfg = "cfail2",
-    except = "hir_owner, hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of, fn_sig"
+    except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail3")]
 pub fn add_parameter(p: i32) {}
@@ -45,7 +45,7 @@ pub fn type_of_parameter(p: i32) {}
 #[cfg(not(cfail1))]
 #[rustc_clean(
     cfg = "cfail2",
-    except = "hir_owner, hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of, fn_sig"
+    except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail3")]
 pub fn type_of_parameter(p: i64) {}
@@ -58,7 +58,7 @@ pub fn type_of_parameter_ref(p: &i32) {}
 #[cfg(not(cfail1))]
 #[rustc_clean(
     cfg = "cfail2",
-    except = "hir_owner, hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of, fn_sig"
+    except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail3")]
 pub fn type_of_parameter_ref(p: &mut i32) {}
@@ -71,7 +71,7 @@ pub fn order_of_parameters(p1: i32, p2: i64) {}
 #[cfg(not(cfail1))]
 #[rustc_clean(
     cfg = "cfail2",
-    except = "hir_owner, hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of, fn_sig"
+    except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail3")]
 pub fn order_of_parameters(p2: i64, p1: i32) {}
@@ -84,7 +84,7 @@ pub fn make_unsafe() {}
 #[cfg(not(cfail1))]
 #[rustc_clean(
     cfg = "cfail2",
-    except = "hir_owner, hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of, fn_sig"
+    except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig"
 )]
 #[rustc_clean(cfg = "cfail3")]
 pub unsafe fn make_unsafe() {}
@@ -95,7 +95,7 @@ pub unsafe fn make_unsafe() {}
 pub fn make_extern() {}
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck_tables_of, fn_sig")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")]
 #[rustc_clean(cfg = "cfail3")]
 pub extern "C" fn make_extern() {}
 
@@ -241,7 +241,7 @@ pub fn return_impl_trait() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck_tables_of, fn_sig")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")]
 #[rustc_clean(cfg = "cfail3")]
 pub fn return_impl_trait() -> impl Clone {
     0
@@ -274,7 +274,7 @@ pub mod change_return_type_indirectly {
 
     #[rustc_clean(
         cfg = "cfail2",
-        except = "hir_owner, hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of, fn_sig"
+        except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig"
     )]
     #[rustc_clean(cfg = "cfail3")]
     pub fn indirect_return_type() -> ReturnType {
@@ -292,7 +292,7 @@ pub mod change_parameter_type_indirectly {
 
     #[rustc_clean(
         cfg = "cfail2",
-        except = "hir_owner, hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of, fn_sig"
+        except = "hir_owner, hir_owner_nodes, optimized_mir, typeck, fn_sig"
     )]
     #[rustc_clean(cfg = "cfail3")]
     pub fn indirect_parameter_type(p: ParameterType) {}
index 29b3f1f5b1d832f64e588a87873987f810a40e81..59af1fc09c2de5097aa4db459dee89ae2612c6b6 100644 (file)
@@ -25,7 +25,7 @@ pub fn change_condition(x: bool) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_condition(x: bool) -> u32 {
     if !x {
@@ -46,7 +46,7 @@ pub fn change_then_branch(x: bool) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_then_branch(x: bool) -> u32 {
     if x {
@@ -69,7 +69,7 @@ pub fn change_else_branch(x: bool) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_else_branch(x: bool) -> u32 {
     if x {
@@ -120,7 +120,7 @@ pub fn change_condition_if_let(x: Option<u32>) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_condition_if_let(x: Option<u32>) -> u32 {
     if let Some(_) = x {
@@ -143,7 +143,7 @@ pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
     if let Some(x) = x {
@@ -166,7 +166,7 @@ pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
     if let Some(x) = x {
index a9c8457f7f260a0651904f0bf698c7af5caa3bc3..fcd12ad30ebc92955adf0e61c5b7467c6248ce8a 100644 (file)
@@ -44,7 +44,7 @@ pub fn method_body() { }
 impl Foo {
     #[rustc_clean(
         cfg="cfail2",
-        except="hir_owner_nodes,optimized_mir,promoted_mir,mir_built,typeck_tables_of"
+        except="hir_owner_nodes,optimized_mir,promoted_mir,typeck"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn method_body() {
@@ -68,7 +68,7 @@ pub fn method_body_inlined() { }
 impl Foo {
     #[rustc_clean(
         cfg="cfail2",
-        except="hir_owner_nodes,optimized_mir,promoted_mir,mir_built,typeck_tables_of"
+        except="hir_owner_nodes,optimized_mir,promoted_mir,typeck"
     )]
     #[rustc_clean(cfg="cfail3")]
     #[inline]
@@ -120,7 +120,7 @@ pub fn method_selfmutness(&self) { }
 impl Foo {
     #[rustc_clean(
         cfg="cfail2",
-        except="hir_owner,hir_owner_nodes,fn_sig,typeck_tables_of,optimized_mir,mir_built"
+        except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn method_selfmutness(&mut self) { }
@@ -160,7 +160,7 @@ pub fn add_method_parameter(&self) { }
 impl Foo {
     #[rustc_clean(
         cfg="cfail2",
-        except="hir_owner,hir_owner_nodes,fn_sig,typeck_tables_of,optimized_mir,mir_built"
+        except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn add_method_parameter(&self, _: i32) { }
@@ -178,7 +178,7 @@ pub fn change_method_parameter_name(&self, a: i64) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
     #[rustc_clean(cfg="cfail3")]
     pub fn change_method_parameter_name(&self, b: i64) { }
 }
@@ -197,7 +197,7 @@ pub fn change_method_return_type(&self) -> u16 { 0 }
 impl Foo {
     #[rustc_clean(
         cfg="cfail2",
-        except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,mir_built,typeck_tables_of")]
+        except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")]
     #[rustc_clean(cfg="cfail3")]
     pub fn change_method_return_type(&self) -> u8 { 0 }
 }
@@ -232,7 +232,7 @@ pub fn change_method_parameter_order(&self, a: i64, b: i64) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
     #[rustc_clean(cfg="cfail3")]
     pub fn change_method_parameter_order(&self, b: i64, a: i64) { }
 }
@@ -251,7 +251,7 @@ pub fn make_method_unsafe(&self) { }
 impl Foo {
     #[rustc_clean(
         cfg="cfail2",
-        except="hir_owner,hir_owner_nodes,fn_sig,typeck_tables_of,optimized_mir,mir_built"
+        except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub unsafe fn make_method_unsafe(&self) { }
@@ -269,7 +269,7 @@ pub fn make_method_extern(&self) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck_tables_of")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")]
     #[rustc_clean(cfg="cfail3")]
     pub extern fn make_method_extern(&self) { }
 }
@@ -286,7 +286,7 @@ pub extern "C" fn change_method_calling_convention(&self) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck_tables_of")]
+    #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")]
     #[rustc_clean(cfg="cfail3")]
     pub extern "system" fn change_method_calling_convention(&self) { }
 }
@@ -303,15 +303,15 @@ pub fn add_lifetime_parameter_to_method(&self) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    // Warning: Note that `typeck_tables_of` are coming up clean here.
+    // Warning: Note that `typeck` are coming up clean here.
     // The addition or removal of lifetime parameters that don't
     // appear in the arguments or fn body in any way does not, in
-    // fact, affect the `typeck_tables_of` in any semantic way (at least
+    // fact, affect the `typeck` in any semantic way (at least
     // as of this writing). **However,** altering the order of
-    // lowering **can** cause it appear to affect the `typeck_tables_of`:
+    // lowering **can** cause it appear to affect the `typeck`:
     // if we lower generics before the body, then the `HirId` for
     // things in the body will be affected. So if you start to see
-    // `typeck_tables_of` appear dirty, that might be the cause. -nmatsakis
+    // `typeck` appear dirty, that might be the cause. -nmatsakis
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
     #[rustc_clean(cfg="cfail3")]
     pub fn add_lifetime_parameter_to_method<'a>(&self) { }
@@ -329,14 +329,14 @@ pub fn add_type_parameter_to_method(&self) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    // Warning: Note that `typeck_tables_of` are coming up clean here.
+    // Warning: Note that `typeck` are coming up clean here.
     // The addition or removal of type parameters that don't appear in
     // the arguments or fn body in any way does not, in fact, affect
-    // the `typeck_tables_of` in any semantic way (at least as of this
+    // the `typeck` in any semantic way (at least as of this
     // writing). **However,** altering the order of lowering **can**
-    // cause it appear to affect the `typeck_tables_of`: if we lower
+    // cause it appear to affect the `typeck`: if we lower
     // generics before the body, then the `HirId` for things in the
-    // body will be affected. So if you start to see `typeck_tables_of`
+    // body will be affected. So if you start to see `typeck`
     // appear dirty, that might be the cause. -nmatsakis
     #[rustc_clean(
         cfg="cfail2",
@@ -378,14 +378,14 @@ pub fn add_lifetime_bound_to_type_param_of_method<'a, T>(&self) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    // Warning: Note that `typeck_tables_of` are coming up clean here.
+    // Warning: Note that `typeck` are coming up clean here.
     // The addition or removal of bounds that don't appear in the
     // arguments or fn body in any way does not, in fact, affect the
-    // `typeck_tables_of` in any semantic way (at least as of this
+    // `typeck` in any semantic way (at least as of this
     // writing). **However,** altering the order of lowering **can**
-    // cause it appear to affect the `typeck_tables_of`: if we lower
+    // cause it appear to affect the `typeck`: if we lower
     // generics before the body, then the `HirId` for things in the
-    // body will be affected. So if you start to see `typeck_tables_of`
+    // body will be affected. So if you start to see `typeck`
     // appear dirty, that might be the cause. -nmatsakis
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,\
                                         type_of")]
@@ -405,14 +405,14 @@ pub fn add_trait_bound_to_type_param_of_method<T>(&self) { }
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    // Warning: Note that `typeck_tables_of` are coming up clean here.
+    // Warning: Note that `typeck` are coming up clean here.
     // The addition or removal of bounds that don't appear in the
     // arguments or fn body in any way does not, in fact, affect the
-    // `typeck_tables_of` in any semantic way (at least as of this
+    // `typeck` in any semantic way (at least as of this
     // writing). **However,** altering the order of lowering **can**
-    // cause it appear to affect the `typeck_tables_of`: if we lower
+    // cause it appear to affect the `typeck`: if we lower
     // generics before the body, then the `HirId` for things in the
-    // body will be affected. So if you start to see `typeck_tables_of`
+    // body will be affected. So if you start to see `typeck`
     // appear dirty, that might be the cause. -nmatsakis
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
     #[rustc_clean(cfg="cfail3")]
@@ -453,7 +453,7 @@ pub fn add_type_parameter_to_impl(&self) { }
 impl<T> Bar<T> {
     #[rustc_clean(
         cfg="cfail2",
-        except="generics_of,fn_sig,typeck_tables_of,type_of,optimized_mir,mir_built"
+        except="generics_of,fn_sig,typeck,type_of,optimized_mir"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn add_type_parameter_to_impl(&self) { }
@@ -471,7 +471,7 @@ pub fn change_impl_self_type(&self) { }
 #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 impl Bar<u64> {
-    #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,mir_built,typeck_tables_of")]
+    #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")]
     #[rustc_clean(cfg="cfail3")]
     pub fn change_impl_self_type(&self) { }
 }
index 3eaffc440615f73cf1d490f460f32a371404111f..7fd9975bc22a93366d1840596c2977a598ea060c 100644 (file)
@@ -33,7 +33,7 @@ pub fn change_template(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 pub fn change_template(a: i32) -> i32 {
@@ -69,7 +69,7 @@ pub fn change_output(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 pub fn change_output(a: i32) -> i32 {
@@ -105,7 +105,7 @@ pub fn change_input(_a: i32, _b: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 pub fn change_input(_a: i32, _b: i32) -> i32 {
@@ -140,7 +140,7 @@ pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
@@ -175,7 +175,7 @@ pub fn change_clobber(_a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 pub fn change_clobber(_a: i32) -> i32 {
@@ -210,7 +210,7 @@ pub fn change_options(_a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 pub fn change_options(_a: i32) -> i32 {
index 846bfc6d0e4dbb3e64b1efbddf429246a4f997ba..918e72582d6978289c736000f5d769463f933372 100644 (file)
@@ -22,7 +22,7 @@ pub fn change_name() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir")]
+    except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_name() {
     let _y = 2u64;
@@ -38,7 +38,7 @@ pub fn add_type() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built")]
+    except="hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_type() {
     let _x: u32 = 2u32;
@@ -54,7 +54,7 @@ pub fn change_type() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_type() {
     let _x: u8 = 2;
@@ -70,7 +70,7 @@ pub fn change_mutability_of_reference_type() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_mutability_of_reference_type() {
     let _x: &mut u64;
@@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_mutability_of_slot() {
     let _x: u64 = 0;
@@ -102,7 +102,7 @@ pub fn change_simple_binding_to_pattern() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_simple_binding_to_pattern() {
     let (_a, _b) = (0u8, 'x');
@@ -118,7 +118,7 @@ pub fn change_name_in_pattern() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir")]
+    except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_name_in_pattern() {
     let (_a, _c) = (1u8, 'y');
@@ -134,7 +134,7 @@ pub fn add_ref_in_pattern() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_ref_in_pattern() {
     let (ref _a, _b) = (1u8, 'y');
@@ -150,7 +150,7 @@ pub fn add_amp_in_pattern() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_amp_in_pattern() {
     let (&_a, _b) = (&1u8, 'y');
@@ -166,7 +166,7 @@ pub fn change_mutability_of_binding_in_pattern() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_mutability_of_binding_in_pattern() {
     let (mut _a, _b) = (99u8, 'q');
@@ -182,7 +182,7 @@ pub fn add_initializer() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")]
+    except="hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_initializer() {
     let _x: i16 = 3i16;
@@ -198,7 +198,7 @@ pub fn change_initializer() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir")]
+    except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_initializer() {
     let _x = 5u16;
index 65db89eb976cf916671ccc6e84c37b0f90997d4b..178def016a25f0ed607100204add86289fa9f475 100644 (file)
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
@@ -47,7 +47,7 @@ pub fn add_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_break() {
     let mut _x = 0;
@@ -118,7 +118,7 @@ pub fn change_break_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_break_label() {
     let mut _x = 0;
@@ -168,7 +168,7 @@ pub fn change_continue_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_label() {
     let mut _x = 0;
@@ -193,7 +193,7 @@ pub fn change_continue_to_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_to_break() {
     let mut _x = 0;
index 033723a4c77963b9c8840c580657160e574eb57b..969f930f57bdfb2f675b978fc199befd240a69fa 100644 (file)
@@ -26,7 +26,7 @@ pub fn add_arm(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_arm(x: u32) -> u32 {
     match x {
@@ -51,7 +51,7 @@ pub fn change_order_of_arms(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir")]
+    except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_order_of_arms(x: u32) -> u32 {
     match x {
@@ -75,7 +75,7 @@ pub fn add_guard_clause(x: u32, y: bool) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_guard_clause(x: u32, y: bool) -> u32 {
     match x {
@@ -99,7 +99,7 @@ pub fn change_guard_clause(x: u32, y: bool) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_guard_clause(x: u32, y: bool) -> u32 {
     match x {
@@ -123,7 +123,7 @@ pub fn add_at_binding(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_at_binding(x: u32) -> u32 {
     match x {
@@ -147,7 +147,7 @@ pub fn change_name_of_at_binding(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir")]
+    except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_name_of_at_binding(x: u32) -> u32 {
     match x {
@@ -170,7 +170,7 @@ pub fn change_simple_name_to_pattern(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_simple_name_to_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -193,7 +193,7 @@ pub fn change_name_in_pattern(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir")]
+    except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_name_in_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -216,7 +216,7 @@ pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -238,7 +238,7 @@ pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -260,7 +260,7 @@ pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
     match (&x, x & 1) {
@@ -283,7 +283,7 @@ pub fn change_rhs_of_arm(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir")]
+    except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_rhs_of_arm(x: u32) -> u32 {
     match x {
@@ -307,7 +307,7 @@ pub fn add_alternative_to_arm(x: u32) -> u32 {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="hir_owner_nodes,mir_built,optimized_mir,typeck_tables_of")]
+    except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_alternative_to_arm(x: u32) -> u32 {
     match x {
index 9de2aaa1bfd117e31759128bb33c75a9359a452c..cc0bd45a4b4c14cc948390057cf44919da717904 100644 (file)
@@ -18,7 +18,7 @@
 
 
 // Indexing expression
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn indexing(slice: &[u8]) -> u8 {
     #[cfg(cfail1)]
@@ -33,7 +33,7 @@ pub fn indexing(slice: &[u8]) -> u8 {
 
 
 // Arithmetic overflow plus
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_plus(val: i32) -> i32 {
     #[cfg(cfail1)]
@@ -48,7 +48,7 @@ pub fn arithmetic_overflow_plus(val: i32) -> i32 {
 
 
 // Arithmetic overflow minus
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_minus(val: i32) -> i32 {
     #[cfg(cfail1)]
@@ -63,7 +63,7 @@ pub fn arithmetic_overflow_minus(val: i32) -> i32 {
 
 
 // Arithmetic overflow mult
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_mult(val: i32) -> i32 {
     #[cfg(cfail1)]
@@ -78,7 +78,7 @@ pub fn arithmetic_overflow_mult(val: i32) -> i32 {
 
 
 // Arithmetic overflow negation
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_negation(val: i32) -> i32 {
     #[cfg(cfail1)]
@@ -93,7 +93,7 @@ pub fn arithmetic_overflow_negation(val: i32) -> i32 {
 
 
 // Division by zero
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn division_by_zero(val: i32) -> i32 {
     #[cfg(cfail1)]
@@ -107,7 +107,7 @@ pub fn division_by_zero(val: i32) -> i32 {
 }
 
 // Division by zero
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn mod_by_zero(val: i32) -> i32 {
     #[cfg(cfail1)]
@@ -122,7 +122,7 @@ pub fn mod_by_zero(val: i32) -> i32 {
 
 
 // shift left
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn shift_left(val: i32, shift: usize) -> i32 {
     #[cfg(cfail1)]
@@ -137,7 +137,7 @@ pub fn shift_left(val: i32, shift: usize) -> i32 {
 
 
 // shift right
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn shift_right(val: i32, shift: usize) -> i32 {
     #[cfg(cfail1)]
index 006b712923b991214895ced870100496d6541793..edec03d4f057e01556e4fad11b11db31a211e56a 100644 (file)
@@ -31,7 +31,7 @@ pub fn change_field_value_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_field_value_regular_struct() -> RegularStruct {
     RegularStruct {
@@ -54,7 +54,7 @@ pub fn change_field_order_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_field_order_regular_struct() -> RegularStruct {
     RegularStruct {
@@ -82,7 +82,7 @@ pub fn add_field_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_field_regular_struct() -> RegularStruct {
     let struct1 = RegularStruct {
@@ -117,7 +117,7 @@ pub fn change_field_label_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_field_label_regular_struct() -> RegularStruct {
     let struct1 = RegularStruct {
@@ -152,7 +152,7 @@ pub fn change_constructor_path_regular_struct() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_path_regular_struct() {
     let _ = RegularStruct2 {
@@ -173,7 +173,7 @@ pub mod change_constructor_path_indirectly_regular_struct {
 
     #[rustc_clean(
         cfg="cfail2",
-        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of"
+        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> Struct {
@@ -196,7 +196,7 @@ pub fn change_field_value_tuple_struct() -> TupleStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_field_value_tuple_struct() -> TupleStruct {
     TupleStruct(0, 1, 3)
@@ -213,7 +213,7 @@ pub fn change_constructor_path_tuple_struct() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,mir_built,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_constructor_path_tuple_struct() {
     let _ = TupleStruct2(0, 1, 2);
@@ -230,7 +230,7 @@ pub mod change_constructor_path_indirectly_tuple_struct {
 
     #[rustc_clean(
         cfg="cfail2",
-        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of"
+        except="fn_sig,hir_owner,hir_owner_nodes,optimized_mir,typeck"
     )]
     #[rustc_clean(cfg="cfail3")]
     pub fn function() -> Struct {
index c8b53c27b02c8fc39bda6567d7777b102e8476a4..687580ec8afb24b10b3ae5ba5e2ce0c95ca674f6 100644 (file)
@@ -21,7 +21,7 @@ pub fn const_negation() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn const_negation() -> i32 {
     -1
@@ -36,7 +36,7 @@ pub fn const_bitwise_not() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn const_bitwise_not() -> i32 {
     !99
@@ -51,7 +51,7 @@ pub fn var_negation(x: i32, y: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn var_negation(x: i32, y: i32) -> i32 {
     -y
@@ -66,7 +66,7 @@ pub fn var_bitwise_not(x: i32, y: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn var_bitwise_not(x: i32, y: i32) -> i32 {
     !y
@@ -81,7 +81,7 @@ pub fn var_deref(x: &i32, y: &i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn var_deref(x: &i32, y: &i32) -> i32 {
     *y
@@ -96,7 +96,7 @@ pub fn first_const_add() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn first_const_add() -> i32 {
     2 + 3
@@ -111,7 +111,7 @@ pub fn second_const_add() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn second_const_add() -> i32 {
     1 + 3
@@ -126,7 +126,7 @@ pub fn first_var_add(a: i32, b: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn first_var_add(a: i32, b: i32) -> i32 {
     b + 2
@@ -141,7 +141,7 @@ pub fn second_var_add(a: i32, b: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn second_var_add(a: i32, b: i32) -> i32 {
     1 + b
@@ -156,7 +156,7 @@ pub fn plus_to_minus(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn plus_to_minus(a: i32) -> i32 {
     1 - a
@@ -171,7 +171,7 @@ pub fn plus_to_mult(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn plus_to_mult(a: i32) -> i32 {
     1 * a
@@ -186,7 +186,7 @@ pub fn plus_to_div(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn plus_to_div(a: i32) -> i32 {
     1 / a
@@ -201,7 +201,7 @@ pub fn plus_to_mod(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn plus_to_mod(a: i32) -> i32 {
     1 % a
@@ -216,7 +216,7 @@ pub fn and_to_or(a: bool, b: bool) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn and_to_or(a: bool, b: bool) -> bool {
     a || b
@@ -231,7 +231,7 @@ pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 {
     1 | a
@@ -246,7 +246,7 @@ pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 {
     1 ^ a
@@ -261,7 +261,7 @@ pub fn bitwise_and_to_lshift(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn bitwise_and_to_lshift(a: i32) -> i32 {
     a << 1
@@ -276,7 +276,7 @@ pub fn bitwise_and_to_rshift(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn bitwise_and_to_rshift(a: i32) -> i32 {
     a >> 1
@@ -291,7 +291,7 @@ pub fn eq_to_uneq(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn eq_to_uneq(a: i32) -> bool {
     a != 1
@@ -306,7 +306,7 @@ pub fn eq_to_lt(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn eq_to_lt(a: i32) -> bool {
     a < 1
@@ -321,7 +321,7 @@ pub fn eq_to_gt(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn eq_to_gt(a: i32) -> bool {
     a > 1
@@ -336,7 +336,7 @@ pub fn eq_to_le(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn eq_to_le(a: i32) -> bool {
     a <= 1
@@ -351,7 +351,7 @@ pub fn eq_to_ge(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn eq_to_ge(a: i32) -> bool {
     a >= 1
@@ -368,7 +368,7 @@ pub fn type_cast(a: u8) -> u64 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built,typeck_tables_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir,typeck", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn type_cast(a: u8) -> u64 {
     let b = a as u32;
@@ -385,7 +385,7 @@ pub fn value_cast(a: u32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn value_cast(a: u32) -> i32 {
     2 as i32
@@ -403,7 +403,7 @@ pub fn place() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn place() -> i32 {
     let mut x = 10;
@@ -423,7 +423,7 @@ pub fn rvalue() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn rvalue() -> i32 {
     let mut x = 10;
@@ -440,7 +440,7 @@ pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(except="hir_owner_nodes,optimized_mir,mir_built", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
 pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 {
     s[j]
index 36e0fcdbe74d137f8163c715efd8d01a5c4b83cb..290f1b66a73690047e1d076cccc337363d5ecc85 100644 (file)
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
@@ -48,7 +48,7 @@ pub fn change_loop_condition() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_condition() {
     let mut _x = 0;
@@ -70,7 +70,7 @@ pub fn add_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_break() {
     let mut _x = 0;
@@ -141,7 +141,7 @@ pub fn change_break_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_break_label() {
     let mut _x = 0;
@@ -191,7 +191,7 @@ pub fn change_continue_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_label() {
     let mut _x = 0;
@@ -216,7 +216,7 @@ pub fn change_continue_to_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_to_break() {
     let mut _x = 0;
index 83f09bd7be6140d71dc7937f42a2f79cbebb9246..1049dabacf2e1e9731d028db1f52281b905fe6d3 100644 (file)
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
@@ -48,7 +48,7 @@ pub fn change_loop_condition() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_condition() {
     let mut _x = 0;
@@ -70,7 +70,7 @@ pub fn add_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir, typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_break() {
     let mut _x = 0;
@@ -141,7 +141,7 @@ pub fn change_break_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_break_label() {
     let mut _x = 0;
@@ -191,7 +191,7 @@ pub fn change_continue_label() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_label() {
     let mut _x = 0;
@@ -216,7 +216,7 @@ pub fn change_continue_to_break() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_continue_to_break() {
     let mut _x = 0;
index e4d8c56752c7889335fc004caa008543f39099ae..4c60d7bd9d52653aba2c9df8a98815399013dda7 100644 (file)
@@ -21,7 +21,7 @@ pub fn xxxx() -> i32 {
 mod y {
     use x;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+    #[rustc_clean(label="typeck", cfg="rpass2")]
     pub fn yyyy() {
         x::xxxx();
     }
@@ -30,7 +30,7 @@ pub fn yyyy() {
 mod z {
     use y;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+    #[rustc_clean(label="typeck", cfg="rpass2")]
     pub fn z() {
         y::yyyy();
     }
index 847bce7ef90b0312506dcc640b129b2b0232f83f..6d7d446cb7c55bca785d230f16011d1376dd0c7e 100644 (file)
@@ -28,14 +28,14 @@ mod mod3 {
 
     #[rustc_clean(label="hir_owner", cfg="rpass2")]
     #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+    #[rustc_dirty(label="typeck", cfg="rpass2")]
     fn bar() {
         ().method();
     }
 
     #[rustc_clean(label="hir_owner", cfg="rpass2")]
     #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+    #[rustc_clean(label="typeck", cfg="rpass2")]
     fn baz() {
         22; // no method call, traits in scope don't matter
     }
index 81b84ba741dc87e190e773b19032837d700c6e09..73846712b59606303827df982fdacca965838e60 100644 (file)
 
 extern crate a;
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
-#[rustc_clean(label="typeck_tables_of", cfg="rpass3")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass3")]
 pub fn use_X() -> u32 {
     let x: a::X = 22;
     x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
-#[rustc_clean(label="typeck_tables_of", cfg="rpass3")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass3")]
 pub fn use_Y() {
     let x: a::Y = 'c';
 }
index cc35f3bdf299b8bf9dd065f7a63dae456a456225..2fc725294313bc94f8af36cd3823f6392776c383 100644 (file)
@@ -28,7 +28,7 @@ pub fn x() {
 pub mod y {
     use x;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     #[rustc_clean(label="optimized_mir", cfg="cfail2")]
     pub fn y() {
         x::x();
@@ -38,7 +38,7 @@ pub fn y() {
 pub mod z {
     use y;
 
-    #[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+    #[rustc_clean(label="typeck", cfg="cfail2")]
     #[rustc_clean(label="optimized_mir", cfg="cfail2")]
     pub fn z() {
         y::y();
index d2e1e7decf54e8d6448ac5a9a16743c0ff5b8f70..4c29f196f67c975fb70f0af8decbe0167c4fb7f8 100644 (file)
@@ -21,17 +21,17 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_X(x: X) -> u32 {
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index 68356f703bcf8e7b2ae6cf2eab2acbe65ea459d1..ee88fbdf59275b9ab48069618febdf9971b778c7 100644 (file)
@@ -24,7 +24,7 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+#[rustc_dirty(label="typeck", cfg="cfail2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     //[cfail2]~^ ERROR struct `X` has no field named `x`
@@ -32,13 +32,13 @@ pub fn use_X() -> u32 {
     //[cfail2]~^ ERROR no field `x` on type `X`
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="cfail2")]
+#[rustc_dirty(label="typeck", cfg="cfail2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
     //[cfail2]~^ ERROR no field `x` on type `X`
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="cfail2")]
+#[rustc_clean(label="typeck", cfg="cfail2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index 308ec84fa72effa56ae57252c3b26db767c913b1..b60b4b311eeb33cf4dcc534497e5ab591625bd66 100644 (file)
@@ -24,19 +24,19 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_EmbedX(x: EmbedX) -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index 9d84c2cf773b8cccb19315cbc64c0b8da20912ad..0221d510eaba7dfed6d272bc0fac3bd80cbd7df0 100644 (file)
@@ -8,18 +8,18 @@
 
 use a::*;
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index bbded1da2161999e9e813c8b2aaf406f2e4500b1..3ab90e966fb6d7bea2cee20dadc412fcbc2732fe 100644 (file)
@@ -24,19 +24,19 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn use_EmbedX(x: EmbedX) -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index 4c4028bbe5bdda2ea14ef79f1ce0344f5d9202e6..f6017b1b1c3a66c47dfaeae160af69b29be494cd 100644 (file)
@@ -25,17 +25,17 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_X(x: X) -> u32 {
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index cef2e4bab12d722653dc408011748ed985b80ca4..05c926fdded7c82a466b291ca449ec1fdeaa75df 100644 (file)
@@ -6,15 +6,15 @@
 
 extern crate a;
 
-#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")]
-#[rustc_clean(label="typeck_tables_of", cfg="rpass3")]
+#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass3")]
 pub fn use_X() -> u32 {
     let x: a::X = 22;
     x as u32
 }
 
-#[rustc_clean(label="typeck_tables_of", cfg="rpass2")]
-#[rustc_clean(label="typeck_tables_of", cfg="rpass3")]
+#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(label="typeck", cfg="rpass3")]
 pub fn use_Y() {
     let x: a::Y = 'c';
 }
index 5c192979a86967564387d6b5d1783658d20c441f..0e0d8ea90631166117a29ddc116da4348d4afc3d 100644 (file)
@@ -22,7 +22,7 @@
 -                                          // + ty: &i32
 -                                          // + val: Value(Scalar(alloc0))
 +                                          // + ty: &[&i32; 1]
-+                                          // + val: Unevaluated(DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
 -                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) }
@@ -30,7 +30,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 +                                          // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
           _0 = const core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
index 649cea6493e4500eab9c7485cc93c9e4cdf3c1a0..a885b4d3bae1b84e30918b4a8486fd9075bf6a26 100644 (file)
@@ -24,7 +24,7 @@
 -                                          // + ty: &i32
 -                                          // + val: Value(Scalar(alloc2))
 +                                          // + ty: &[&i32; 1]
-+                                          // + val: Unevaluated(DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
 -                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
@@ -32,7 +32,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 +                                          // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
           _0 = const core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
index ee4d4c39f172ca41b76f36e968fa43bfcfce3fa6..0f9c81943eda98677beb8e0aee98546620e906ea 100644 (file)
           _9 = const main::promoted[0];    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // ty::Const
                                            // + ty: &[i32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
index 3626814fa977017b16603db172f6aa0caf13c707..da2c8dffb24110c4650f9ae0a84c00c4d39eb654 100644 (file)
           _9 = const main::promoted[0];    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // ty::Const
                                            // + ty: &[i32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
index 6c5fe7454b4edbd8f2d23e45ff5fd2644bf99219..f3efef387a3b4bd1c30528fe48e31c533f4cfb3b 100644 (file)
           _3 = const main::FOO;            // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), [], None)
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None)
                                            // mir::Constant
                                            // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), [], None) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
           _1 = move _2 as usize (Misc);    // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
           StorageDead(_2);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
index b4d1f087391f31e52bfe4123c54215c147c7fbb1..68527a86aeb839847157e0af706c196225e465ad 100644 (file)
 +         _1 = const false;                // scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21
                                            // ty::Const
                                            // + ty: bool
--                                          // + val: Unevaluated(DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), [bool], None)
+-                                          // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), const_param_did: None }, [bool], None)
 +                                          // + val: Value(Scalar(0x00))
                                            // mir::Constant
                                            // + span: $DIR/control-flow-simplification.rs:12:8: 12:21
--                                          // + literal: Const { ty: bool, val: Unevaluated(DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), [bool], None) }
+-                                          // + literal: Const { ty: bool, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), const_param_did: None }, [bool], None) }
 -         switchInt(_1) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
 +         switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6
index 12e3a04d89bf2893eee8f42d25c1165412047a2f..ba5ac8d3ddf87b5bd5ca81ac69a25d226abd38ba 100644 (file)
           _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref.rs:5:6: 5:10
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 -         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 +         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
index d56f07e0f57f5430a65d2aed0983befad6156313..fa68eb348185a87bb282bc2ba80fe7befd398ea2 100644 (file)
 -                                          // + ty: i32
 -                                          // + val: Value(Scalar(0x00000004))
 +                                          // + ty: &i32
-+                                          // + val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/ref_deref.rs:5:8: 5:9
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
 -         _2 = &_3;                        // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 +                                          // + span: $DIR/ref_deref.rs:5:6: 5:10
-+                                          // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
index dd2f5bd90642856262166d96a0ba80792b071f13..483e5f1b9a4265bb6d07e83c8a8657c4f463af9f 100644 (file)
           _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
                                            // ty::Const
                                            // + ty: &(i32, i32)
-                                           // + val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
index 0b9c1caa6bdaee2566406b77f375dbb786f4d328..86e6aacab45a7b73ecc1a057ad2d84439a172e83 100644 (file)
@@ -18,7 +18,7 @@
 -                                          // + ty: i32
 -                                          // + val: Value(Scalar(0x00000004))
 +                                          // + ty: &(i32, i32)
-+                                          // + val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/ref_deref_project.rs:5:9: 5:10
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
@@ -30,7 +30,7 @@
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
 -         _2 = &(_3.1: i32);               // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
 +                                          // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-+                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
 +         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
index 70c415648822308780ad5cdc04109f7d48b0c9b2..6eb64f75ef17e8acb79239af315246609515a65d 100644 (file)
           _9 = const main::promoted[0];    // scope 0 at $DIR/slice_len.rs:5:6: 5:19
                                            // ty::Const
                                            // + ty: &[u32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
index 885f28124c4b7d4133a2007e52f0cfb10c330367..2b641bef1d8028a503f079f81f9f4ddef2f520f5 100644 (file)
           _9 = const main::promoted[0];    // scope 0 at $DIR/slice_len.rs:5:6: 5:19
                                            // ty::Const
                                            // + ty: &[u32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
index e83cc92eb43efceded364813b464c37d783d7bf0..d6ac1c57a635917129baee40ae4c83d298e3a1de 100644 (file)
@@ -38,10 +38,10 @@ fn bar() -> bool {
         _10 = const bar::promoted[1];    // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[1]))
+                                         // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:7: 12:9
-                                         // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[1])) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1])) }
         Retag(_10);                      // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         _4 = &(*_10);                    // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         Retag(_4);                       // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
@@ -52,10 +52,10 @@ fn bar() -> bool {
         _9 = const bar::promoted[0];     // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[0]))
+                                         // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:11: 12:14
-                                         // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[0])) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0])) }
         Retag(_9);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         _7 = &(*_9);                     // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         Retag(_7);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
index af2899c887a949cc17ce55d119002c4d9904902a..e7fef4622b1c6cb09e791cd3586dea2049d5978c 100644 (file)
@@ -3,34 +3,40 @@
   
   fn bar() -> bool {
       let mut _0: bool;                    // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
-+     let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++     let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
   
       bb0: {
-+         StorageLive(_1);                 // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
-+         _1 = const std::intrinsics::count_code_region(const 0_u32, const 484_u32, const 513_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++         StorageLive(_1);                 // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
++         _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const 501_u32, const 513_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // ty::Const
++                                          // + ty: u64
++                                          // + val: Value(Scalar(0x8dabe565aaa2aefd))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u64, val: Value(Scalar(0x8dabe565aaa2aefd)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x000001e4))
++                                          // + val: Value(Scalar(0x000001f5))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001e4)) }
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001f5)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000201))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000201)) }
 +     }
 + 
index 4a300230f8a9728334eb680876ec48676a067696..51378c216da641b9d2958a6def88f14c62a971ed 100644 (file)
@@ -6,35 +6,41 @@
       let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
       let mut _2: bool;                    // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
       let mut _3: !;                       // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
-+     let mut _4: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++     let mut _4: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
   
       bb0: {
 -         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
-+         StorageLive(_4);                 // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
-+         _4 = const std::intrinsics::count_code_region(const 0_u32, const 387_u32, const 465_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++         StorageLive(_4);                 // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
++         _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const 397_u32, const 465_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // ty::Const
++                                          // + ty: u64
++                                          // + val: Value(Scalar(0xde1b3f75a72fc7f7))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u64, val: Value(Scalar(0xde1b3f75a72fc7f7)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x00000183))
++                                          // + val: Value(Scalar(0x0000018d))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000183)) }
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000018d)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x000001d1))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001d1)) }
       }
   
index f65b93a34da65a918c2e68a3d24ec966fb3181b5..918dc5ec38701789962880be5ce27c1919b049c6 100644 (file)
@@ -79,13 +79,6 @@ fn main() -> () {
     }
 
     bb10: {
-        _4 = const ();                   // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
-                                         // ty::Const
-                                         // + ty: ()
-                                         // + val: Value(Scalar(<ZST>))
-                                         // mir::Constant
-                                         // + span: $DIR/issue-49232.rs:10:25: 10:30
-                                         // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
         unreachable;                     // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
     }
 
index 59c00e1b96f9669368f6f9e7df9c099834570ca8..cf5d1f3f6c6a4fde1bf7f515745565df5b3c71c1 100644 (file)
           (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1])) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) }
           StorageDead(_6);                 // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_7);                 // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _7 = (_5.0: &i32);               // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _15 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           StorageLive(_18);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           StorageLive(_19);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           StorageLive(_20);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
index 1020fc965fe86073589b8d725a0e486a73b8ade6..7739ef87fb9b712d5236c25cbddc6a83f61d751d 100644 (file)
       let mut _24: &[&str; 3];             // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
       let _25: &[&str; 3];                 // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
       let _26: [&str; 3];                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _27: &str;                   // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _28: &str;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _29: &str;                   // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _30: &str;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _31: &str;                   // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _32: &str;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _33: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _34: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let _35: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let _36: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _37: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _38: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _39: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _40: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _41: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _44: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _45: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _46: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _47: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _48: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _49: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _27: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _28: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let _29: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let _30: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _31: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _32: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let _33: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _34: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let _35: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _38: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _39: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _40: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _41: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _42: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _43: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
       scope 1 {
           debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
           let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
               debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
               let _13: &i32;               // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
               let _14: &i32;               // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-              let mut _51: &i32;           // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+              let mut _45: &i32;           // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
               scope 4 {
                   debug left_val => _13;   // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                   debug right_val => _14;  // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                  let _42: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                  let _43: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                  let mut _50: &[&str; 3]; // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                  let _36: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                  let _37: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                  let mut _44: &[&str; 3]; // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                   scope 5 {
-                      debug arg0 => _42;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                      debug arg1 => _43;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                      debug arg0 => _36;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                      debug arg1 => _37;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                       scope 6 {
-                          debug x => _45;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          debug f => _46;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          let mut _52: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _53: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _54: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _55: &&i32; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          debug x => _39;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          debug f => _40;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          let mut _46: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _47: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _48: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _49: &&i32; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
                       }
                       scope 8 {
-                          debug x => _48;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          debug f => _49;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          let mut _56: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _57: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _58: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _59: &&i32; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          debug x => _42;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          debug f => _43;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          let mut _50: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _51: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _52: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _53: &&i32; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
                       }
                   }
                   scope 10 {
                       debug pieces => _23; // in scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                      debug args => _33;   // in scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                      let mut _60: &[&str]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
-                      let mut _61: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
-                      let mut _62: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
+                      debug args => _27;   // in scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                      let mut _54: &[&str]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
+                      let mut _55: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
+                      let mut _56: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
                   }
               }
           }
           StorageLive(_10);                // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _10 = &_1;                       // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_11);                // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _51 = const main::promoted[1];   // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _45 = const main::promoted[1];   // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1])) }
-          _11 = _51;                       // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) }
+          _11 = _45;                       // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageDead(_11);                // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_23);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_24);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_25);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _50 = const main::promoted[0];   // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _44 = const main::promoted[0];   // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0])) }
-          _25 = _50;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
+          _25 = _44;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _24 = _25;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageDead(_24);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_33);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_34);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_35);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_36);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_37);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_38);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_39);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _39 = _13;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _38 = &_39;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_40);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_41);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _41 = _14;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _40 = &_41;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          (_37.0: &&i32) = move _38;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          (_37.1: &&i32) = move _40;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_40);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_38);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_42);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _42 = (_37.0: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_43);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _43 = (_37.1: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_44);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_45);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _45 = _42;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_46);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _46 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_27);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_28);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_29);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_30);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_31);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_32);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_33);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _33 = _13;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _32 = &_33;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_34);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_35);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _35 = _14;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _34 = &_35;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          (_31.0: &&i32) = move _32;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          (_31.1: &&i32) = move _34;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_34);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_32);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_36);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _36 = (_31.0: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_37);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _37 = (_31.1: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_38);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_39);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _39 = _36;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_40);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _40 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_52);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_53);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _53 = _46;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _52 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _53) -> bb6; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_46);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_47);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _47 = _40;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _46 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb6: {
-          StorageDead(_53);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_54);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_55);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _55 = _45;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _54 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _55) -> bb7; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_47);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_48);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_49);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _49 = _39;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _48 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb7: {
-          StorageDead(_55);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_44.0: &core::fmt::Opaque) = move _54; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_44.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _52; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_54);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_52);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_46);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_45);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_47);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_48);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _48 = _43;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_49);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _49 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageDead(_49);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_48);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_46);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_40);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_39);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_41);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_42);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _42 = _37;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_43);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _43 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_56);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_57);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _57 = _49;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _56 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _57) -> bb8; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_50);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_51);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _51 = _43;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _50 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb8: {
-          StorageDead(_57);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_58);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_59);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _59 = _48;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _58 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _59) -> bb9; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_51);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_52);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_53);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _53 = _42;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _52 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb9: {
-          StorageDead(_59);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_47.0: &core::fmt::Opaque) = move _58; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_47.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _56; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_58);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_56);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_49);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_48);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _36 = [move _44, move _47];      // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_47);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_44);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_43);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_42);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _35 = &_36;                      // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _34 = _35;                       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _33 = move _34 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_34);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_60);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _60 = _23;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_61);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          discriminant(_61) = 0;           // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_62);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _62 = _33;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_22.0: &[&str]) = move _60;     // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_22.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _61; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_22.2: &[std::fmt::ArgumentV1]) = move _62; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_62);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_61);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_60);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_33);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_53);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_52);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_50);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_43);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_42);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _30 = [move _38, move _41];      // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_41);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_38);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_37);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_36);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _29 = &_30;                      // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _28 = _29;                       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _27 = move _28 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_28);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_54);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _54 = _23;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_55);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          discriminant(_55) = 0;           // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_56);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _56 = _27;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_22.0: &[&str]) = move _54;     // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_22.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _55; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_22.2: &[std::fmt::ArgumentV1]) = move _56; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_56);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_55);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_54);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_27);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           StorageDead(_23);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           _21 = &_22;                      // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           _20 = _21;                       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
index 59c00e1b96f9669368f6f9e7df9c099834570ca8..cf5d1f3f6c6a4fde1bf7f515745565df5b3c71c1 100644 (file)
           (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1])) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) }
           StorageDead(_6);                 // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_7);                 // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _7 = (_5.0: &i32);               // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _15 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
           StorageLive(_18);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           StorageLive(_19);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           StorageLive(_20);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
index aa606ed22b6d07202bbc9dfd3ee87b2710b666dd..c4d0a6f4bc6aa71dba4eedc9c8d5274839d798ba 100644 (file)
       let mut _24: &[&str; 3];             // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
       let _25: &[&str; 3];                 // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
       let _26: [&str; 3];                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _27: &str;                   // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _28: &str;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _29: &str;                   // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _30: &str;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _31: &str;                   // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _32: &str;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _33: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _34: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let _35: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let _36: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _37: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _38: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _39: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _40: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let _41: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _44: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _45: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _46: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _47: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
-      let mut _48: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-      let mut _49: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _27: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _28: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let _29: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let _30: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _31: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _32: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let _33: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _34: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let _35: &i32;                       // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _38: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _39: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _40: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _41: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/libstd/macros.rs:LL:COL
+      let mut _42: &&i32;                  // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+      let mut _43: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
       scope 1 {
           debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
           let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
               debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
               let _13: &i32;               // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
               let _14: &i32;               // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-              let mut _51: &i32;           // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+              let mut _45: &i32;           // in scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
               scope 4 {
                   debug left_val => _13;   // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                   debug right_val => _14;  // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                  let _42: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                  let _43: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                  let mut _50: &[&str; 3]; // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                  let _36: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                  let _37: &&i32;          // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                  let mut _44: &[&str; 3]; // in scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                   scope 5 {
-                      debug arg0 => _42;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                      debug arg1 => _43;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                      debug arg0 => _36;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                      debug arg1 => _37;   // in scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                       scope 6 {
-                          debug x => _45;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          debug f => _46;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          let mut _52: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _53: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _54: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _55: &&i32; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          debug x => _39;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          debug f => _40;  // in scope 6 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          let mut _46: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _47: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _48: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _49: &&i32; // in scope 6 at $SRC_DIR/libstd/macros.rs:LL:COL
                       }
                       scope 8 {
-                          debug x => _48;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          debug f => _49;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                          let mut _56: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _57: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _58: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
-                          let mut _59: &&i32; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          debug x => _42;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          debug f => _43;  // in scope 8 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                          let mut _50: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _51: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _52: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
+                          let mut _53: &&i32; // in scope 8 at $SRC_DIR/libstd/macros.rs:LL:COL
                       }
                   }
                   scope 10 {
                       debug pieces => _23; // in scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                      debug args => _33;   // in scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-                      let mut _60: &[&str]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
-                      let mut _61: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
-                      let mut _62: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
+                      debug args => _27;   // in scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+                      let mut _54: &[&str]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
+                      let mut _55: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
+                      let mut _56: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/libstd/macros.rs:LL:COL
                   }
               }
           }
           StorageLive(_10);                // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _10 = &_1;                       // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_11);                // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _51 = const main::promoted[1];   // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _45 = const main::promoted[1];   // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[1])) }
-          _11 = _51;                       // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) }
+          _11 = _45;                       // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageDead(_11);                // scope 3 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_23);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_24);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageLive(_25);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _50 = const main::promoted[0];   // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _44 = const main::promoted[0];   // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(DefId(0:3 ~ issue_73223[317d]::main[0]), [], Some(promoted[0])) }
-          _25 = _50;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
+          _25 = _44;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _24 = _25;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
           StorageDead(_24);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_33);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_34);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_35);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_36);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_37);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_38);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_39);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _39 = _13;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _38 = &_39;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_40);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_41);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _41 = _14;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _40 = &_41;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          (_37.0: &&i32) = move _38;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          (_37.1: &&i32) = move _40;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_40);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_38);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_42);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _42 = (_37.0: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_43);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _43 = (_37.1: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_44);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_45);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _45 = _42;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_46);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _46 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_27);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_28);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_29);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_30);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_31);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_32);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_33);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _33 = _13;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _32 = &_33;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_34);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_35);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _35 = _14;                       // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _34 = &_35;                      // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          (_31.0: &&i32) = move _32;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          (_31.1: &&i32) = move _34;       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_34);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_32);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_36);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _36 = (_31.0: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_37);                // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _37 = (_31.1: &&i32);            // scope 4 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_38);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_39);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _39 = _36;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_40);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _40 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_52);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_53);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _53 = _46;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _52 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _53) -> bb6; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_46);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_47);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _47 = _40;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _46 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb6: {
-          StorageDead(_53);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_54);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_55);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _55 = _45;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _54 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _55) -> bb7; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_47);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_48);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_49);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _49 = _39;                       // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _48 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb7: {
-          StorageDead(_55);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_44.0: &core::fmt::Opaque) = move _54; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_44.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _52; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_54);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_52);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_46);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_45);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_47);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_48);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _48 = _43;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          StorageLive(_49);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
-          _49 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageDead(_49);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_48);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_46);                // scope 7 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_40);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_39);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_41);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_42);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _42 = _37;                       // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          StorageLive(_43);                // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
+          _43 = const <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
                                            // + span: $SRC_DIR/libcore/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_56);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_57);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _57 = _49;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _56 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _57) -> bb8; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_50);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_51);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _51 = _43;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _50 = const std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb8: {
-          StorageDead(_57);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_58);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_59);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _59 = _48;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _58 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _59) -> bb9; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_51);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_52);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_53);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _53 = _42;                       // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _52 = const std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}
                                            // + val: Value(Scalar(<ZST>))
       }
   
       bb9: {
-          StorageDead(_59);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_47.0: &core::fmt::Opaque) = move _58; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_47.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _56; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_58);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_56);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_49);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_48);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _36 = [move _44, move _47];      // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_47);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_44);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_43);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_42);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _35 = &_36;                      // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _34 = _35;                       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          _33 = move _34 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageDead(_34);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
-          StorageLive(_60);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _60 = _23;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_61);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          discriminant(_61) = 0;           // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageLive(_62);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          _62 = _33;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_22.0: &[&str]) = move _60;     // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_22.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _61; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          (_22.2: &[std::fmt::ArgumentV1]) = move _62; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_62);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_61);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_60);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
-          StorageDead(_33);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_53);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_52);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_50);                // scope 9 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_43);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_42);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _30 = [move _38, move _41];      // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_41);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_38);                // scope 5 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_37);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_36);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _29 = &_30;                      // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _28 = _29;                       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          _27 = move _28 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageDead(_28);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
+          StorageLive(_54);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _54 = _23;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_55);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          discriminant(_55) = 0;           // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageLive(_56);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          _56 = _27;                       // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_22.0: &[&str]) = move _54;     // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_22.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _55; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          (_22.2: &[std::fmt::ArgumentV1]) = move _56; // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_56);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_55);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_54);                // scope 10 at $SRC_DIR/libcore/fmt/mod.rs:LL:COL
+          StorageDead(_27);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           StorageDead(_23);                // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           _21 = &_22;                      // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
           _20 = _21;                       // scope 4 at $SRC_DIR/libstd/macros.rs:LL:COL
index 5ff4150d2ac1a1e17c4d3d28be50c541cb410a60..c53c9cf1db7cc8bdd04c670b0e464bc6a1a69041 100644 (file)
@@ -76,10 +76,10 @@ fn full_tested_match() -> () {
         _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
                                          // ty::Const
                                          // + ty: &std::option::Option<i32>
-                                         // + val: Unevaluated(DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), [], Some(promoted[0]))
+                                         // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:16:14: 16:15
-                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), [], Some(promoted[0])) }
+                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0])) }
         _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
         _4 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         StorageLive(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
index 14a7f2d500542c6b1e6edd5ae9a95c7d948b95bc..b61d936837512fd9be5cb80c312ea538df198abe 100644 (file)
@@ -184,10 +184,10 @@ fn main() -> () {
         _27 = const main::promoted[0];   // scope 7 at $DIR/retag.rs:47:21: 47:23
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Unevaluated(DefId(0:13 ~ retag[317d]::main[0]), [], Some(promoted[0]))
+                                         // + val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:47:21: 47:23
-                                         // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:13 ~ retag[317d]::main[0]), [], Some(promoted[0])) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) }
         Retag(_27);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
         _23 = &(*_27);                   // scope 7 at $DIR/retag.rs:47:21: 47:23
         Retag(_23);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
index ee7586bae820af702cea233269c9cf9e9cdc65de..0e45b6f04a8a47b1ad901697b2eb7ff2443151ec 100644 (file)
@@ -34,27 +34,27 @@ pub fn bar() ({
                            ((::alloc::fmt::format as
                                 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
-                                                                                                                                                                                                                       &str)]
-                                                                                                                                                                                                                     as
-                                                                                                                                                                                                                     [&str; 1])
-                                                                                                                                                                                                                   as
-                                                                                                                                                                                                                   &[&str; 1]),
-                                                                                                                                                                                                               (&(match (()
-                                                                                                                                                                                                                            as
-                                                                                                                                                                                                                            ())
-                                                                                                                                                                                                                      {
-                                                                                                                                                                                                                      ()
-                                                                                                                                                                                                                      =>
-                                                                                                                                                                                                                      ([]
-                                                                                                                                                                                                                          as
-                                                                                                                                                                                                                          [std::fmt::ArgumentV1; 0]),
-                                                                                                                                                                                                                  }
-                                                                                                                                                                                                                     as
-                                                                                                                                                                                                                     [std::fmt::ArgumentV1; 0])
-                                                                                                                                                                                                                   as
-                                                                                                                                                                                                                   &[std::fmt::ArgumentV1; 0]))
+                                                                                                                    fn(&[&'static str], &[std::fmt::ArgumentV1]) -> std::fmt::Arguments {std::fmt::Arguments::new_v1})((&([("test"
+                                                                                                                                                                                                                               as
+                                                                                                                                                                                                                               &str)]
+                                                                                                                                                                                                                             as
+                                                                                                                                                                                                                             [&str; 1])
+                                                                                                                                                                                                                           as
+                                                                                                                                                                                                                           &[&str; 1]),
+                                                                                                                                                                                                                       (&(match (()
+                                                                                                                                                                                                                                    as
+                                                                                                                                                                                                                                    ())
+                                                                                                                                                                                                                              {
+                                                                                                                                                                                                                              ()
+                                                                                                                                                                                                                              =>
+                                                                                                                                                                                                                              ([]
+                                                                                                                                                                                                                                  as
+                                                                                                                                                                                                                                  [std::fmt::ArgumentV1; 0]),
+                                                                                                                                                                                                                          }
+                                                                                                                                                                                                                             as
+                                                                                                                                                                                                                             [std::fmt::ArgumentV1; 0])
+                                                                                                                                                                                                                           as
+                                                                                                                                                                                                                           &[std::fmt::ArgumentV1; 0]))
                                                                                                                    as
                                                                                                                    std::fmt::Arguments))
                                as std::string::String);
diff --git a/src/test/pretty/issue-73626.rs b/src/test/pretty/issue-73626.rs
new file mode 100644 (file)
index 0000000..a002f09
--- /dev/null
@@ -0,0 +1,34 @@
+fn main(/*
+    ---
+*/) {
+    let x /* this is one line */ = 3;
+
+    let x /*
+           * this
+           * is
+           * multiple
+           * lines
+           */ = 3;
+
+    let x = /*
+           * this
+           * is
+           * multiple
+           * lines
+           * after
+           * the
+           * =
+           */ 3;
+
+    let x /*
+           * this
+           * is
+           * multiple
+           * lines
+           * including
+           * a
+
+           * blank
+           * line
+           */ = 3;
+}
index d7d078e56b2e7a55cad6923ae9c0a06668b4c5c2..0cf5d1855212d6ea064661ba22a0ba21168b188d 100644 (file)
@@ -1,6 +1,6 @@
 -include ../tools.mk
 
-# only-mingw
+# only-windows-gnu
 
 all:
        $(CXX) foo.cpp -c -o $(TMPDIR)/foo.o
index ce79cec67dc37bd944fd072d2793c9616e2a786d..f91af88efe1b715a3dc9fdc183de419de76b90e5 100644 (file)
@@ -1,10 +1,6 @@
 -include ../tools.mk
 
-# ignore-windows
 # ignore-freebsd
-# FIXME: on windows `rustc --dep-info` produces Makefile dependency with
-# windows native paths (e.g. `c:\path\to\libfoo.a`)
-# but msys make seems to fail to recognize such paths, so test fails.
 
 all:
        $(RUSTC) --emit dep-info main.rs
diff --git a/src/test/run-make-fulldeps/instrument-coverage/Makefile b/src/test/run-make-fulldeps/instrument-coverage/Makefile
new file mode 100644 (file)
index 0000000..df47305
--- /dev/null
@@ -0,0 +1,57 @@
+# needs-profiler-support
+# ignore-msvc
+
+# FIXME(richkadel): Debug the following problem, and reenable on Windows (by
+# removing the `# ignore-msvc` directive above). The current implementation
+# generates a segfault when running the instrumented `main` executable,
+# after the `main` program code executes, but before the process terminates.
+# This most likely points to a problem generating the LLVM "main.profraw"
+# file.
+
+-include ../tools.mk
+
+# This test makes sure that LLVM coverage maps are genereated in LLVM IR.
+
+COMMON_FLAGS=-Zinstrument-coverage
+
+all:
+       # Compile the test program with instrumentation, and also generate LLVM IR
+       $(RUSTC) $(COMMON_FLAGS) main.rs
+
+       # Run it in order to generate some profiling data,
+       # with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
+       # output the coverage stats for this run.
+       LLVM_PROFILE_FILE="$(TMPDIR)"/main.profraw \
+         $(call RUN,main)
+
+       # Postprocess the profiling data so it can be used by the llvm-cov tool
+       "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
+         "$(TMPDIR)"/main.profraw \
+               -o "$(TMPDIR)"/main.profdata
+
+       # Generate a coverage report using `llvm-cov show`. The output ordering
+       # can be non-deterministic, so ignore the return status. If the test fails
+       # when comparing the JSON `export`, the `show` output may be useful when
+       # debugging.
+       "$(LLVM_BIN_DIR)"/llvm-cov show \
+         --Xdemangler="$(RUST_DEMANGLER)" \
+         --show-line-counts-or-regions \
+         --instr-profile="$(TMPDIR)"/main.profdata \
+               $(call BIN,"$(TMPDIR)"/main) \
+               > "$(TMPDIR)"/actual_show_coverage.txt
+
+       # Compare the show coverage output
+       $(DIFF) typical_show_coverage.txt "$(TMPDIR)"/actual_show_coverage.txt || \
+         >&2 echo 'diff failed for `llvm-cov show` (might not be an error)'
+
+       # Generate a coverage report in JSON, using `llvm-cov export`, and fail if
+       # there are differences from the expected output.
+       "$(LLVM_BIN_DIR)"/llvm-cov export \
+         --summary-only \
+         --instr-profile="$(TMPDIR)"/main.profdata \
+               $(call BIN,"$(TMPDIR)"/main) \
+               | "$(PYTHON)" prettify_json.py \
+               > "$(TMPDIR)"/actual_export_coverage.json
+
+       # Check that the exported JSON coverage data matches what we expect
+       $(DIFF) expected_export_coverage.json "$(TMPDIR)"/actual_export_coverage.json
diff --git a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json
new file mode 100644 (file)
index 0000000..9d739a8
--- /dev/null
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "main.rs",
+          "summary": {
+            "functions": {
+              "count": 7,
+              "covered": 5,
+              "percent": 71.42857142857143
+            },
+            "instantiations": {
+              "count": 8,
+              "covered": 6,
+              "percent": 75
+            },
+            "lines": {
+              "count": 30,
+              "covered": 25,
+              "percent": 83.33333333333334
+            },
+            "regions": {
+              "count": 7,
+              "covered": 5,
+              "notcovered": 2,
+              "percent": 71.42857142857143
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 7,
+          "covered": 5,
+          "percent": 71.42857142857143
+        },
+        "instantiations": {
+          "count": 8,
+          "covered": 6,
+          "percent": 75
+        },
+        "lines": {
+          "count": 30,
+          "covered": 25,
+          "percent": 83.33333333333334
+        },
+        "regions": {
+          "count": 7,
+          "covered": 5,
+          "notcovered": 2,
+          "percent": 71.42857142857143
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.0"
+}
diff --git a/src/test/run-make-fulldeps/instrument-coverage/main.rs b/src/test/run-make-fulldeps/instrument-coverage/main.rs
new file mode 100644 (file)
index 0000000..358c256
--- /dev/null
@@ -0,0 +1,38 @@
+pub fn will_be_called() -> &'static str {
+    let val = "called";
+    println!("{}", val);
+    val
+}
+
+pub fn will_not_be_called() -> bool {
+    println!("should not have been called");
+    false
+}
+
+pub fn print<T>(left: &str, value: T, right: &str)
+where
+    T: std::fmt::Display,
+{
+    println!("{}{}{}", left, value, right);
+}
+
+pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
+where
+    F: FnOnce(&T)
+{
+    if should_wrap {
+        wrapper(&inner)
+    }
+}
+
+fn main() {
+    let less = 1;
+    let more = 100;
+
+    if less < more {
+        wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
+        wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
+    } else {
+        wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
+    }
+}
diff --git a/src/test/run-make-fulldeps/instrument-coverage/prettify_json.py b/src/test/run-make-fulldeps/instrument-coverage/prettify_json.py
new file mode 100644 (file)
index 0000000..ed92798
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+import sys
+import json
+
+# Try to decode line in order to ensure it is a valid JSON document
+for line in sys.stdin:
+    parsed = json.loads(line)
+    print (json.dumps(parsed, indent=2, separators=(',', ': '), sort_keys=True))
diff --git a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt b/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt
new file mode 100644 (file)
index 0000000..9c593d0
--- /dev/null
@@ -0,0 +1,55 @@
+    1|      2|pub fn will_be_called() -> &'static str {
+    2|      2|    let val = "called";
+    3|      2|    println!("{}", val);
+    4|      2|    val
+    5|      2|}
+    6|       |
+    7|      0|pub fn will_not_be_called() -> bool {
+    8|      0|    println!("should not have been called");
+    9|      0|    false
+   10|      0|}
+   11|       |
+   12|       |pub fn print<T>(left: &str, value: T, right: &str)
+   13|       |where
+   14|       |    T: std::fmt::Display,
+   15|      1|{
+   16|      1|    println!("{}{}{}", left, value, right);
+   17|      1|}
+   18|       |
+   19|       |pub fn wrap_with<F, T>(inner: T, should_wrap: bool, wrapper: F)
+   20|       |where
+   21|       |    F: FnOnce(&T)
+   22|      2|{
+   23|      2|    if should_wrap {
+   24|      2|        wrapper(&inner)
+   25|      2|    }
+   26|      2|}
+  ------------------
+  | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#0}, &str>:
+  |   22|      1|{
+  |   23|      1|    if should_wrap {
+  |   24|      1|        wrapper(&inner)
+  |   25|      1|    }
+  |   26|      1|}
+  ------------------
+  | main[317d481089b8c8fe]::wrap_with::<main[317d481089b8c8fe]::main::{closure#1}, &str>:
+  |   22|      1|{
+  |   23|      1|    if should_wrap {
+  |   24|      1|        wrapper(&inner)
+  |   25|      1|    }
+  |   26|      1|}
+  ------------------
+   27|       |
+   28|      1|fn main() {
+   29|      1|    let less = 1;
+   30|      1|    let more = 100;
+   31|      1|
+   32|      1|    if less < more {
+   33|      1|        wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** "));
+   34|      1|        wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** "));
+                                                                       ^0
+   35|      1|    } else {
+   36|      1|        wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, ""));
+   37|      1|    }
+   38|      1|}
+
index 483091ad4ee8b983c90d39d5061661735f792342..2037728568e2409493a3cea9ef7bc2dfc232fe7e 100644 (file)
@@ -1,6 +1,6 @@
 -include ../tools.mk
 
-# ignore-windows
+# ignore-windows-msvc
 #
 # Because of Windows exception handling, the code is not necessarily any shorter.
 # https://github.com/llvm-mirror/llvm/commit/64b2297786f7fd6f5fa24cdd4db0298fbf211466
index c405d5c74d7afcaf252f779c148302ff305c57b5..f17ce537fb813dacf340d0cc9762262076421924 100644 (file)
@@ -1,7 +1,5 @@
 -include ../tools.mk
 
-# ignore-stage1
-
 all:
        $(RUSTC) a.rs && $(RUSTC) b.rs
        $(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \
index df58d4f5d9486c5a58c5077cc2245961f0704938..27b69baf97787b794b246d27c0df5c4e4db99f50 100644 (file)
@@ -1,6 +1,4 @@
 -include ../tools.mk
 
-# ignore-stage1
-
 all:
        $(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs
index 3027ee578c79f20a2aaaca5616967105497b6ba5..ba3d3b7100745e0debe024ac76d776f86f7e868a 100644 (file)
@@ -1,6 +1,6 @@
 -include ../tools.mk
 
-# ignore-windows
+# ignore-windows-msvc
 
 all:
        $(RUSTC) --emit=obj app.rs
diff --git a/src/test/run-make-fulldeps/libs-search-path/Makefile b/src/test/run-make-fulldeps/libs-search-path/Makefile
deleted file mode 100644 (file)
index f31036f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
--include ../tools.mk
-
-# only-mingw
-
-all: empty.rs
-       cp -r $(shell cygpath -u $(shell $(RUSTC) --print sysroot)) $(TMPDIR)/sysroot
-       $(RUSTC) --target $(TARGET) --sysroot $(TMPDIR)/sysroot -L$(TMPDIR)/obj -Z print-link-args empty.rs | $(CGREP) 'lib\\crt2.o'
-       mkdir -p $(TMPDIR)/obj
-       mv $(TMPDIR)/sysroot/lib/rustlib/$(TARGET)/lib/crt2.o $(TMPDIR)/obj/crt2.o
-       $(RUSTC) --target $(TARGET) --sysroot $(TMPDIR)/sysroot -L$(TMPDIR)/obj -Z print-link-args empty.rs | $(CGREP) 'obj\\crt2.o'
diff --git a/src/test/run-make-fulldeps/libs-search-path/empty.rs b/src/test/run-make-fulldeps/libs-search-path/empty.rs
deleted file mode 100644 (file)
index f328e4d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-fn main() {}
index 9486e07d21bf7c4e093db574e8d42da6b1d3aae7..8468d102bec8312a276df6de130368ef4d492891 100644 (file)
@@ -1,8 +1,6 @@
 -include ../tools.mk
 
-ifdef IS_WINDOWS
-all:
-else
+# ignore-windows-msvc
 
 # rustc will remove one of the two redundant references to foo below.  Depending
 # on which one gets removed, we'll get a linker error on SOME platforms (like
@@ -23,5 +21,3 @@ RUSTC_FLAGS = \
 all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz)
        $(RUSTC) $(RUSTC_FLAGS) main.rs
        $(call RUN,main)
-
-endif
diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/Makefile b/src/test/run-make-fulldeps/rustdoc-determinism/Makefile
new file mode 100644 (file)
index 0000000..0534c2c
--- /dev/null
@@ -0,0 +1,16 @@
+-include ../tools.mk
+
+# Assert that the search index is generated deterministically, regardless of the
+# order that crates are documented in.
+
+# ignore-windows
+# Uses `diff`.
+
+all:
+       $(RUSTDOC) foo.rs -o $(TMPDIR)/foo_first
+       $(RUSTDOC) bar.rs -o $(TMPDIR)/foo_first
+
+       $(RUSTDOC) bar.rs -o $(TMPDIR)/bar_first
+       $(RUSTDOC) foo.rs -o $(TMPDIR)/bar_first
+
+       diff $(TMPDIR)/foo_first/search-index.js $(TMPDIR)/bar_first/search-index.js
diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs b/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs
new file mode 100644 (file)
index 0000000..ca05a6a
--- /dev/null
@@ -0,0 +1 @@
+pub struct Bar;
diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs b/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs
new file mode 100644 (file)
index 0000000..4a83567
--- /dev/null
@@ -0,0 +1 @@
+pub struct Foo;
index 7901866015bf2ffa564a7a4b8e10ddb8961baeb4..dc55c947d89a2fef1017bee007cc63dbb2735e6a 100644 (file)
@@ -1,9 +1,6 @@
 include ../tools.mk
 
-# ignore-windows
-#
-# On MINGW the --version-script, --dynamic-list, and --retain-symbol args don't
-# seem to work reliably.
+# ignore-windows-msvc
 
 NM=nm -D
 CDYLIB_NAME=liba_cdylib.so
@@ -19,6 +16,14 @@ EXE_NAME=an_executable
 COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib
 endif
 
+ifdef IS_WINDOWS
+NM=nm -g
+CDYLIB_NAME=liba_cdylib.dll.a
+RDYLIB_NAME=liba_rust_dylib.dll.a
+EXE_NAME=an_executable.exe
+COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dll.a
+endif
+
 # `grep` regex for symbols produced by either `legacy` or `v0` mangling
 RE_ANY_RUST_SYMBOL="_ZN.*h.*E\|_R[a-zA-Z0-9_]+"
 
@@ -30,38 +35,38 @@ all:
        $(RUSTC) -Zshare-generics=no a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib
 
        # Check that a cdylib exports its public #[no_mangle] functions
-       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
        # Check that a cdylib exports the public #[no_mangle] functions of dependencies
-       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
        # Check that a cdylib DOES NOT export any public Rust functions
-       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
 
        # Check that a Rust dylib exports its monomorphic functions
-       [ "$$($(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 -v __imp_ | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rust_dylib)" -eq "1" ]
        # Check that a Rust dylib does not export generics if -Zshare-generics=no
-       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | 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 -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rlib)" -eq "1" ]
        # Check that a Rust dylib does not export generics if -Zshare-generics=no
-       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | 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" ]
-       [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_rust_function_from_exe)" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
 
 
        # Check the combined case, where we generate a cdylib and an rlib in the same
        # compilation session:
        # Check that a cdylib exports its public #[no_mangle] functions
-       [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
        # Check that a cdylib exports the public #[no_mangle] functions of dependencies
-       [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
        # Check that a cdylib DOES NOT export any public Rust functions
-       [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
 
 
        $(RUSTC) -Zshare-generics=yes an_rlib.rs
@@ -70,22 +75,22 @@ all:
        $(RUSTC) -Zshare-generics=yes an_executable.rs
 
        # Check that a cdylib exports its public #[no_mangle] functions
-       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_cdylib)" -eq "1" ]
        # Check that a cdylib exports the public #[no_mangle] functions of dependencies
-       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
        # Check that a cdylib DOES NOT export any public Rust functions
-       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -v __imp_ | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
 
        # 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 -v __imp_ | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rust_dylib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rust_dylib)" -eq "1" ]
 
        # 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 -v __imp_ | grep -c public_c_function_from_rlib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_rust_function_from_rlib)" -eq "1" ]
+       [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -v __imp_ | grep -c public_generic_function_from_rlib)" -eq "1" ]
 
        # Check that an executable does not export any dynamic symbols
-       [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ]
-       [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_rust_function_from_exe)" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_c_function_from_rlib)" -eq "0" ]
+       [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -v __imp_ | grep -c public_rust_function_from_exe)" -eq "0" ]
index 04bf78ed2105be91980aef74951edbe51036dd21..8b885f1dc6d58e387669c4eb83a83bd6e3eeecbc 100644 (file)
@@ -18,6 +18,9 @@ endif
 HTMLDOCCK := '$(PYTHON)' '$(S)/src/etc/htmldocck.py'
 CGREP := "$(S)/src/etc/cat-and-grep.sh"
 
+# diff with common flags for multi-platform diffs against text output
+DIFF := diff -u --strip-trailing-cr
+
 # This is the name of the binary we will generate and run; use this
 # e.g. for `$(CC) -o $(RUN_BINFILE)`.
 RUN_BINFILE = $(TMPDIR)/$(1)
@@ -150,7 +153,7 @@ ifdef IS_MSVC
        $(CC) $< -link -dll -out:`cygpath -w $@`
 else
 %.dll: lib%.o
-       $(CC) -o $@ $< -shared
+       $(CC) -o $@ $< -shared -Wl,--out-implib=$@.a
 endif
 
 $(TMPDIR)/lib%.o: %.c
index 8d913e3993502fec1b65dd6b30f90571284f4e85..4d904472931ece12732a5a3e31b4684dbb0e6d0a 100644 (file)
@@ -1,6 +1,6 @@
 -include ../tools.mk
 
-# ignore-windows
+# ignore-windows-msvc
 
 all:
        $(RUSTC) -C opt-level=3 --emit=obj used.rs
index f28e00f7f4cf93825df45defa08944b1fee17251..96b17af46dfe9179a2474f957856966628d70ae0 100644 (file)
@@ -29,7 +29,7 @@ fn main() {
         }
         Some(s) if s.eq("--test-aslr") => {
             let cnt = run_self(&arg0);
-            if cnt != NUM_RUNS {
+            if cnt == 1 {
                 eprintln!("FAIL: {} most likely no ASLR", arg0);
                 std::process::exit(1);
             }
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs
deleted file mode 100644 (file)
index 2f01099..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(doc_alias)]
-
-#[doc(alias = "foo")] // ok!
-pub struct Bar;
-
-#[doc(alias)] //~ ERROR
-#[doc(alias = 0)] //~ ERROR
-#[doc(alias("bar"))] //~ ERROR
-pub struct Foo;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
deleted file mode 100644 (file)
index 480acc8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: doc alias attribute expects a string: #[doc(alias = "0")]
-  --> $DIR/check-doc-alias-attr.rs:6:7
-   |
-LL | #[doc(alias)]
-   |       ^^^^^
-
-error: doc alias attribute expects a string: #[doc(alias = "0")]
-  --> $DIR/check-doc-alias-attr.rs:7:7
-   |
-LL | #[doc(alias = 0)]
-   |       ^^^^^^^^^
-
-error: doc alias attribute expects a string: #[doc(alias = "0")]
-  --> $DIR/check-doc-alias-attr.rs:8:7
-   |
-LL | #[doc(alias("bar"))]
-   |       ^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/README.md b/src/test/rustdoc-ui/error-in-impl-trait/README.md
new file mode 100644 (file)
index 0000000..1176a4a
--- /dev/null
@@ -0,0 +1,7 @@
+Each of these needs to be in a separate file,
+because the `delay_span_bug` ICE in rustdoc won't be triggerred
+if even a single other error was emitted.
+
+However, conceptually they are all testing basically the same thing.
+See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128
+for more details.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs
new file mode 100644 (file)
index 0000000..112a2c4
--- /dev/null
@@ -0,0 +1,10 @@
+// edition:2018
+
+/// This used to work with ResolveBodyWithLoop.
+/// However now that we ignore type checking instead of modifying the function body,
+/// the return type is seen as `impl Future<Output = u32>`, not a `u32`.
+/// So it no longer allows errors in the function body.
+pub async fn a() -> u32 {
+    error::_in::async_fn()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr
new file mode 100644 (file)
index 0000000..086db1b
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn`
+  --> $DIR/async.rs:8:5
+   |
+LL |     error::_in::async_fn()
+   |     ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs
new file mode 100644 (file)
index 0000000..df40c12
--- /dev/null
@@ -0,0 +1,5 @@
+// manually desugared version of an `async fn` (but with a closure instead of a generator)
+pub fn a() -> impl Fn() -> u32 {
+    || content::doesnt::matter()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr
new file mode 100644 (file)
index 0000000..4ee9c4d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `content::doesnt::matter`
+  --> $DIR/closure.rs:3:8
+   |
+LL |     || content::doesnt::matter()
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs
new file mode 100644 (file)
index 0000000..0ccf2e3
--- /dev/null
@@ -0,0 +1,7 @@
+trait ValidTrait {}
+
+/// This has docs
+pub fn f() -> impl ValidTrait {
+    Vec::<DoesNotExist>::new()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr
new file mode 100644 (file)
index 0000000..72716c2
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `DoesNotExist`
+  --> $DIR/generic-argument.rs:5:11
+   |
+LL |     Vec::<DoesNotExist>::new()
+   |           ^^^^^^^^^^^^ could not resolve path `DoesNotExist`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs
new file mode 100644 (file)
index 0000000..399fb82
--- /dev/null
@@ -0,0 +1,6 @@
+pub trait ValidTrait {}
+/// This returns impl trait
+pub fn g() -> impl ValidTrait {
+    (|| error::_in::impl_trait::alias::nested::closure())()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr
new file mode 100644 (file)
index 0000000..55f9b60
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
+  --> $DIR/impl-keyword-closure.rs:4:9
+   |
+LL |     (|| error::_in::impl_trait::alias::nested::closure())()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
new file mode 100644 (file)
index 0000000..24b5734
--- /dev/null
@@ -0,0 +1,6 @@
+pub trait ValidTrait {}
+/// This returns impl trait
+pub fn g() -> impl ValidTrait {
+    error::_in::impl_trait()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr
new file mode 100644 (file)
index 0000000..3257079
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait`
+  --> $DIR/impl-keyword.rs:4:5
+   |
+LL |     error::_in::impl_trait()
+   |     ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs
new file mode 100644 (file)
index 0000000..1498fa4
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait ValidTrait {}
+type ImplTrait = impl ValidTrait;
+
+/// This returns impl trait, but using a type alias
+pub fn h() -> ImplTrait {
+    (|| error::_in::impl_trait::alias::nested::closure())()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr
new file mode 100644 (file)
index 0000000..84b2813
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
+  --> $DIR/trait-alias-closure.rs:8:9
+   |
+LL |     (|| error::_in::impl_trait::alias::nested::closure())()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
new file mode 100644 (file)
index 0000000..cf9bc48
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait ValidTrait {}
+type ImplTrait = impl ValidTrait;
+
+/// This returns impl trait, but using a type alias
+pub fn h() -> ImplTrait {
+    error::_in::impl_trait::alias()
+    //~^ ERROR failed to resolve
+}
diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr
new file mode 100644 (file)
index 0000000..9be6a3d
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias`
+  --> $DIR/trait-alias.rs:8:5
+   |
+LL |     error::_in::impl_trait::alias()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc-ui/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs
new file mode 100644 (file)
index 0000000..a927f6b
--- /dev/null
@@ -0,0 +1,49 @@
+// Ensure that rustdoc gives errors for trait impls inside function bodies that don't resolve.
+// See https://github.com/rust-lang/rust/pull/73566
+pub struct ValidType;
+pub trait ValidTrait {}
+pub trait NeedsBody {
+    type Item;
+    fn f();
+}
+
+/// This function has docs
+pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+//~^ ERROR cannot find trait `UnknownBound` in this scope
+//~| ERROR cannot find type `UnknownType` in this scope
+    impl UnknownTrait for ValidType {} //~ ERROR cannot find trait `UnknownTrait`
+    impl<T: UnknownBound> UnknownTrait for T {}
+    //~^ ERROR cannot find trait `UnknownBound` in this scope
+    //~| ERROR cannot find trait `UnknownTrait` in this scope
+    impl ValidTrait for UnknownType {}
+    //~^ ERROR cannot find type `UnknownType` in this scope
+    impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
+    //~^ ERROR cannot find trait `UnknownBound` in this scope
+
+    /// This impl has documentation
+    impl NeedsBody for ValidType {
+        type Item = UnknownType;
+        //~^ ERROR cannot find type `UnknownType` in this scope
+
+        /// This function has documentation
+        fn f() {
+            <UnknownTypeShouldBeIgnored>::a();
+            content::shouldnt::matter();
+            unknown_macro!();
+            //~^ ERROR cannot find macro `unknown_macro` in this scope
+
+            /// This is documentation for a macro
+            macro_rules! can_define_macros_here_too {
+                () => {
+                    this::content::should::also::be::ignored()
+                }
+            }
+            can_define_macros_here_too!();
+
+            /// This also is documented.
+            pub fn doubly_nested(c: UnknownType) {
+            //~^ ERROR cannot find type `UnknownType` in this scope
+            }
+        }
+    }
+}
diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr
new file mode 100644 (file)
index 0000000..608749a
--- /dev/null
@@ -0,0 +1,66 @@
+error: cannot find macro `unknown_macro` in this scope
+  --> $DIR/impl-fn-nesting.rs:32:13
+   |
+LL |             unknown_macro!();
+   |             ^^^^^^^^^^^^^
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+  --> $DIR/impl-fn-nesting.rs:11:13
+   |
+LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+   |             ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:11:30
+   |
+LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
+   |                              ^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownTrait` in this scope
+  --> $DIR/impl-fn-nesting.rs:14:10
+   |
+LL |     impl UnknownTrait for ValidType {}
+   |          ^^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownTrait` in this scope
+  --> $DIR/impl-fn-nesting.rs:15:27
+   |
+LL |     impl<T: UnknownBound> UnknownTrait for T {}
+   |                           ^^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+  --> $DIR/impl-fn-nesting.rs:15:13
+   |
+LL |     impl<T: UnknownBound> UnknownTrait for T {}
+   |             ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:18:25
+   |
+LL |     impl ValidTrait for UnknownType {}
+   |                         ^^^^^^^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `UnknownBound` in this scope
+  --> $DIR/impl-fn-nesting.rs:20:53
+   |
+LL |     impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
+   |                                                     ^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:25:21
+   |
+LL |         type Item = UnknownType;
+   |                     ^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `UnknownType` in this scope
+  --> $DIR/impl-fn-nesting.rs:44:37
+   |
+LL |             pub fn doubly_nested(c: UnknownType) {
+   |                                     ^^^^^^^^^^^ not found in this scope
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0405, E0412.
+For more information about an error, try `rustc --explain E0405`.
diff --git a/src/test/rustdoc-ui/infinite-recursive-type.rs b/src/test/rustdoc-ui/infinite-recursive-type.rs
new file mode 100644 (file)
index 0000000..32793fc
--- /dev/null
@@ -0,0 +1,4 @@
+enum E {
+//~^ ERROR recursive type `E` has infinite size
+    V(E),
+}
diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr
new file mode 100644 (file)
index 0000000..897445f
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `E` has infinite size
+  --> $DIR/infinite-recursive-type.rs:1:1
+   |
+LL | enum E {
+   | ^^^^^^ recursive type has infinite size
+LL |
+LL |     V(E),
+   |       - recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable
+   |
+LL |     V(Box<E>),
+   |       ^^^^ ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
index b7906aba5b1a9c27265a2b17ae1ae8a6045c3885..86cf9fed3dab48cb176a2009969632bc26c7a647 100644 (file)
@@ -1,7 +1,7 @@
 // check-pass
 // revisions: public private
 // [private]compile-flags: --document-private-items
-#![cfg_attr(private, deny(intra_doc_resolution_failure))]
+#![cfg_attr(private, deny(intra_doc_link_resolution_failure))]
 
 /// docs [DontDocMe]
 //[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
diff --git a/src/test/rustdoc/doc-spotlight.rs b/src/test/rustdoc/doc-spotlight.rs
new file mode 100644 (file)
index 0000000..ddd46c3
--- /dev/null
@@ -0,0 +1,36 @@
+#![feature(doc_spotlight)]
+
+pub struct Wrapper<T> {
+    inner: T,
+}
+
+impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
+
+#[doc(spotlight)]
+pub trait SomeTrait {
+    // @has doc_spotlight/trait.SomeTrait.html
+    // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
+    fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
+        Wrapper {
+            inner: self,
+        }
+    }
+}
+
+pub struct SomeStruct;
+impl SomeTrait for SomeStruct {}
+
+impl SomeStruct {
+    // @has doc_spotlight/struct.SomeStruct.html
+    // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
+    // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
+    pub fn new() -> SomeStruct {
+        SomeStruct
+    }
+}
+
+// @has doc_spotlight/fn.bare_fn.html
+// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
+pub fn bare_fn() -> SomeStruct {
+    SomeStruct
+}
diff --git a/src/test/rustdoc/impl-trait-alias.rs b/src/test/rustdoc/impl-trait-alias.rs
new file mode 100644 (file)
index 0000000..54c3f85
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(type_alias_impl_trait)]
+
+trait MyTrait {}
+impl MyTrait for i32 {}
+
+// @has impl_trait_alias/type.Foo.html 'Foo'
+/// debug type
+pub type Foo = impl MyTrait;
+
+// @has impl_trait_alias/fn.foo.html 'foo'
+/// debug function
+pub fn foo() -> Foo {
+    1
+}
index 2cb7c472cc84b141bb3e70c574e1a85323c16cc1..a1e322fb9a30704e45e120048864fd263fc8b8ae 100644 (file)
@@ -1,11 +1,13 @@
 // compile-flags: -Z force-unstable-if-unmarked
 
-// @matches internal/index.html '//*[@class="docblock-short"]/span[@class="stab internal"]' \
-//      'Internal'
+// Check that the unstable marker is not added for "rustc_private".
+
+// @!matches internal/index.html '//*[@class="docblock-short"]/span[@class="stab unstable"]'
+// @!matches internal/index.html '//*[@class="docblock-short"]/span[@class="stab internal"]'
 // @matches - '//*[@class="docblock-short"]' 'Docs'
 
-// @has internal/struct.S.html '//*[@class="stab internal"]' \
-//      'This is an internal compiler API. (rustc_private)'
+// @!has internal/struct.S.html '//*[@class="stab unstable"]'
+// @!has internal/struct.S.html '//*[@class="stab internal"]'
 /// Docs
 pub struct S;
 
diff --git a/src/test/rustdoc/intra-doc-crate/additional_doc.rs b/src/test/rustdoc/intra-doc-crate/additional_doc.rs
new file mode 100644 (file)
index 0000000..adfa7f5
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:additional_doc.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate my_rand;
+
+// @has 'additional_doc/trait.Rng.html' '//a[@href="../additional_doc/trait.Rng.html"]' 'Rng'
+// @has 'additional_doc/trait.Rng.html' '//a[@href="../my_rand/trait.RngCore.html"]' 'RngCore'
+/// This is an [`Rng`].
+pub use my_rand::Rng;
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs
new file mode 100644 (file)
index 0000000..8b8793e
--- /dev/null
@@ -0,0 +1,6 @@
+#![crate_name = "my_rand"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub trait RngCore {}
+/// Rng extends [`RngCore`].
+pub trait Rng: RngCore {}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs
new file mode 100644 (file)
index 0000000..23e3852
--- /dev/null
@@ -0,0 +1,19 @@
+#![crate_name = "hidden_dep"]
+#![deny(intra_doc_link_resolution_failure)]
+
+#[doc(hidden)]
+pub mod __reexport {
+    pub use crate::*;
+}
+
+pub mod future {
+    mod ready {
+
+        /// Link to [`ready`](function@ready)
+        pub struct Ready;
+        pub fn ready() {}
+
+    }
+    pub use self::ready::{ready, Ready};
+
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs
new file mode 100644 (file)
index 0000000..2ee5835
--- /dev/null
@@ -0,0 +1,7 @@
+#![crate_name = "a"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub struct Foo;
+
+/// Link to [Foo]
+pub struct Bar;
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs
new file mode 100644 (file)
index 0000000..abd41fe
--- /dev/null
@@ -0,0 +1,10 @@
+#![crate_name = "macro_inner"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub struct Foo;
+
+/// See also [`Foo`]
+#[macro_export]
+macro_rules! my_macro {
+    () => {}
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs
new file mode 100644 (file)
index 0000000..5d63d7e
--- /dev/null
@@ -0,0 +1,7 @@
+#![crate_name = "module_inner"]
+#![deny(intra_doc_link_resolution_failure)]
+/// [SomeType] links to [bar]
+pub struct SomeType;
+pub trait SomeTrait {}
+/// [bar] links to [SomeTrait] and also [SomeType]
+pub mod bar {}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs
new file mode 100644 (file)
index 0000000..0d5a954
--- /dev/null
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+#![crate_type="proc-macro"]
+#![crate_name="proc_macro_inner"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+/// Links to [`OtherDerive`]
+#[proc_macro_derive(DeriveA)]
+pub fn a_derive(input: TokenStream) -> TokenStream {
+    input
+}
+
+#[proc_macro_derive(OtherDerive)]
+pub fn other_derive(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs
new file mode 100644 (file)
index 0000000..3a22d13
--- /dev/null
@@ -0,0 +1,12 @@
+#![crate_name = "a"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub mod bar {
+   pub struct Bar;
+}
+
+pub mod foo {
+  use crate::bar;
+  /// link to [bar::Bar]
+  pub struct Foo;
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs
new file mode 100644 (file)
index 0000000..b8ca4e4
--- /dev/null
@@ -0,0 +1,13 @@
+#![crate_name = "bar"]
+#![deny(intra_doc_link_resolution_failure)]
+
+pub trait Foo {
+    /// [`Bar`] [`Baz`]
+    fn foo();
+}
+
+pub trait Bar {
+}
+
+pub trait Baz {
+}
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs b/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs
new file mode 100644 (file)
index 0000000..c16e39d
--- /dev/null
@@ -0,0 +1,16 @@
+#![crate_name = "inner"]
+/// this is a trait
+pub trait SomeTrait {
+    /// this is a method for [a trait][SomeTrait]
+    fn foo();
+}
+
+pub mod bar {
+    use super::SomeTrait;
+
+    pub struct BarStruct;
+
+    impl SomeTrait for BarStruct {
+        fn foo() {}
+    }
+}
diff --git a/src/test/rustdoc/intra-doc-crate/basic.rs b/src/test/rustdoc/intra-doc-crate/basic.rs
new file mode 100644 (file)
index 0000000..a245a0f
--- /dev/null
@@ -0,0 +1,9 @@
+// aux-build:intra-doc-basic.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+
+// from https://github.com/rust-lang/rust/issues/65983
+extern crate a;
+
+// @has 'basic/struct.Bar.html' '//a[@href="../a/struct.Foo.html"]' 'Foo'
+pub use a::Bar;
diff --git a/src/test/rustdoc/intra-doc-crate/hidden.rs b/src/test/rustdoc/intra-doc-crate/hidden.rs
new file mode 100644 (file)
index 0000000..e3d2af1
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:hidden.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+
+// tests https://github.com/rust-lang/rust/issues/73363
+
+extern crate hidden_dep;
+
+// @has 'hidden/struct.Ready.html' '//a/@href' '../hidden/fn.ready.html'
+pub use hidden_dep::future::{ready, Ready};
diff --git a/src/test/rustdoc/intra-doc-crate/macro.rs b/src/test/rustdoc/intra-doc-crate/macro.rs
new file mode 100644 (file)
index 0000000..72fd57b
--- /dev/null
@@ -0,0 +1,12 @@
+// ignore-tidy-linelength
+// aux-build:macro_inner.rs
+// aux-build:proc_macro.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+extern crate macro_inner;
+extern crate proc_macro_inner;
+
+// @has 'macro/macro.my_macro.html' '//a[@href="../macro_inner/struct.Foo.html"]' 'Foo'
+pub use macro_inner::my_macro;
+// @has 'macro/derive.DeriveA.html' '//a[@href="../proc_macro_inner/derive.OtherDerive.html"]' 'OtherDerive'
+pub use proc_macro_inner::DeriveA;
diff --git a/src/test/rustdoc/intra-doc-crate/module.rs b/src/test/rustdoc/intra-doc-crate/module.rs
new file mode 100644 (file)
index 0000000..67fa729
--- /dev/null
@@ -0,0 +1,8 @@
+// outer.rs
+// aux-build: module.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+extern crate module_inner;
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/trait.SomeTrait.html"]' 'SomeTrait'
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/struct.SomeType.html"]' 'SomeType'
+pub use module_inner::bar;
diff --git a/src/test/rustdoc/intra-doc-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc-crate/submodule-inner.rs
new file mode 100644 (file)
index 0000000..b4b615b
--- /dev/null
@@ -0,0 +1,8 @@
+// aux-build:submodule-inner.rs
+// build-aux-docs
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate a;
+
+// @has 'submodule_inner/struct.Foo.html' '//a[@href="../a/bar/struct.Bar.html"]' 'Bar'
+pub use a::foo::Foo;
diff --git a/src/test/rustdoc/intra-doc-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc-crate/submodule-outer.rs
new file mode 100644 (file)
index 0000000..6b30ef8
--- /dev/null
@@ -0,0 +1,16 @@
+// aux-build:submodule-outer.rs
+// edition:2018
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate bar as bar_;
+
+// from https://github.com/rust-lang/rust/issues/60883
+pub mod bar {
+    pub use ::bar_::Bar;
+}
+
+// NOTE: we re-exported both `Foo` and `Bar` here,
+// NOTE: so they are inlined and therefore we link to the current module.
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="../submodule_outer/bar/trait.Bar.html"]' 'Bar'
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="../submodule_outer/trait.Baz.html"]' 'Baz'
+pub use ::bar_::{Foo, Baz};
diff --git a/src/test/rustdoc/intra-doc-crate/traits.rs b/src/test/rustdoc/intra-doc-crate/traits.rs
new file mode 100644 (file)
index 0000000..6173312
--- /dev/null
@@ -0,0 +1,17 @@
+// ignore-test
+// ^ this is https://github.com/rust-lang/rust/issues/73829
+// aux-build:traits.rs
+// build-aux-docs
+// ignore-tidy-line-length
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate inner;
+use inner::SomeTrait;
+
+pub struct SomeStruct;
+
+ // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'SomeTrait'
+impl SomeTrait for SomeStruct {
+    // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'a trait'
+    fn foo() {}
+}
diff --git a/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs b/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs
new file mode 100644 (file)
index 0000000..65187f4
--- /dev/null
@@ -0,0 +1,18 @@
+// ignore-tidy-linelength
+
+#![deny(intra_doc_link_resolution_failure)]
+
+
+pub fn foo() {
+
+}
+
+pub mod foo {}
+// @has intra_doc_link_mod_ambiguity/struct.A.html '//a/@href' '../intra_doc_link_mod_ambiguity/foo/index.html'
+/// Module is [`module@foo`]
+pub struct A;
+
+
+// @has intra_doc_link_mod_ambiguity/struct.B.html '//a/@href' '../intra_doc_link_mod_ambiguity/fn.foo.html'
+/// Function is [`fn@foo`]
+pub struct B;
index ca83d5e2281a72f72ed3febccc1457ac374a4b94..d7ebb73b3be7d7b6dc5a6de2c08a0bd884aee477 100644 (file)
@@ -1,5 +1,5 @@
 // ignore-tidy-linelength
-#![deny(intra_doc_resolution_failure)]
+#![deny(intra_doc_link_resolution_failure)]
 
 pub mod char {}
 
diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs
new file mode 100644 (file)
index 0000000..b4aaacf
--- /dev/null
@@ -0,0 +1,9 @@
+// Regression issue for rustdoc ICE encountered in PR #72088.
+// edition:2018
+#![feature(decl_macro)]
+
+fn main() {
+    async {
+        macro m() {}
+    };
+}
index 298ff601de89f3f763fe9a86d6621d56a0f37915..b4411d927e271077c64570f21bd1beba0eb83c53 100644 (file)
@@ -6,4 +6,11 @@ fn main() {
     || {
         macro m() {}
     };
+
+    let _ = || {
+        macro n() {}
+    };
+
+    let cond = true;
+    let _ = || if cond { macro n() {} } else { panic!() };
 }
diff --git a/src/test/rustdoc/return-impl-trait.rs b/src/test/rustdoc/return-impl-trait.rs
new file mode 100644 (file)
index 0000000..1ccf5ac
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait Backend {}
+
+impl Backend for () {}
+
+pub struct Module<T>(T);
+
+pub type BackendImpl = impl Backend;
+
+// @has return_impl_trait/fn.make_module.html
+/// Documentation
+pub fn make_module() -> Module<BackendImpl> {
+    Module(())
+}
index b5038a58249d2b7c5b20fc07765386988428ae53..1fd514c6173290945a775d5873b56f72124593a8 100644 (file)
@@ -1,10 +1,8 @@
 // aux-build:rlib-crate-test.rs
-// ignore-tidy-linelength
 // ignore-cross-compile gives a different error message
 
 #![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
+//~^ ERROR: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib
 
 fn main() {}
index 342663312a8539708136fcf6b84ff25d70a45f00..7b31f28a26e7d3555411b265c23af8d0fd6fb50c 100644 (file)
@@ -1,16 +1,8 @@
 error[E0457]: plugin `rlib_crate_test` only found in rlib format, but must be available in dylib format
-  --> $DIR/macro-crate-rlib.rs:6:11
+  --> $DIR/macro-crate-rlib.rs:5:11
    |
 LL | #![plugin(rlib_crate_test)]
    |           ^^^^^^^^^^^^^^^
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/macro-crate-rlib.rs:6:1
-   |
-LL | #![plugin(rlib_crate_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
-   |
-   = note: `#[warn(deprecated)]` on by default
-
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
index 7c9c041f45784b58999606a2bc3f07da4180dfbc..1f11d19c70ea2c12cc633b317285d4592e031a5a 100644 (file)
@@ -17,7 +17,6 @@ LL |         asm!("{}", in(reg) v[..]);
    |                            ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all inline asm arguments must have a statically known size
 
 error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
@@ -27,7 +26,6 @@ LL |         asm!("{}", out(reg) v[..]);
    |                             ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all inline asm arguments must have a statically known size
 
 error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
@@ -37,7 +35,6 @@ LL |         asm!("{}", inout(reg) v[..]);
    |                               ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all inline asm arguments must have a statically known size
 
 error: aborting due to 5 previous errors
index 6daba54ac69694a7c33a768231ce1c6b26afe5ac..e96d0e0eff7192bab34e361fb513b0f52ed6419f 100644 (file)
@@ -5,7 +5,6 @@ LL |     let x = t.get();
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<T as Get>::Value`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting the associated type
index 8676c1fa223193aa718dde9d21519743d595bf1c..de0acc88324a582d489727b4719bf5c8f18feef4 100644 (file)
@@ -139,7 +139,6 @@ LL | pub struct Vec<T> {
    |                - required by this bound in `std::vec::Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 11 previous errors
 
index 69c310766c1ccf5d5c76cb2c038ab81ed1294b82..2ba854eac4665b86159b74cdba0b37d188b39ed2 100644 (file)
@@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + AddAssign<&'static str>
    |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
@@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + Display = Self;
    |       ^^^^^^^ `Self` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `Self`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider further restricting `Self`
    |
@@ -69,7 +67,6 @@ LL |     + Display = Self;
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `T`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider restricting type parameter `T`
    |
@@ -105,7 +102,6 @@ LL |     + AddAssign<&'static str>
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ no implementation for `T += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T`
 help: consider restricting type parameter `T`
    |
 LL | impl<T: std::ops::AddAssign<&'static str>> UncheckedCopy for T {}
index 84f0ba7529ea2cd40e41c71b92193405b546348b..d4fd0ca98ee548820fae161aed6e3ac19e85ae5f 100644 (file)
@@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + AddAssign<&'static str>
    |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
 help: consider further restricting `Self`
    |
 LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> {
@@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized {
 LL |     + Display = Self;
    |       ^^^^^^^ `Self` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `Self`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider further restricting `Self`
    |
@@ -69,7 +67,6 @@ LL |     + Display = Self;
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
    |
-   = help: the trait `std::fmt::Display` is not implemented for `T`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider restricting type parameter `T`
    |
@@ -105,7 +102,6 @@ LL |     + AddAssign<&'static str>
 LL | impl<T> UncheckedCopy for T {}
    |         ^^^^^^^^^^^^^ no implementation for `T += &'static str`
    |
-   = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T`
 help: consider restricting type parameter `T`
    |
 LL | impl<T: std::ops::AddAssign<&'static str>> UncheckedCopy for T {}
index 82e76ff0b7cb50d2126a364ff3d832535109689d..be3b61665b11f50c33f4db77704dbe1d97ec381c 100644 (file)
@@ -6,8 +6,6 @@ LL | trait MyTrait {
 LL |     type This = Self;
    |     ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL | trait MyTrait: std::marker::Sized {
index a37573dffff4403be106a8ca50310312c1b5424a..7813d3b6596bffa58a619d196e67db7fbd39f6a7 100644 (file)
@@ -9,8 +9,6 @@ LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self>
 LL | pub trait Add<Rhs = Self> {
    |               --- required by this bound in `std::ops::Add`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + std::marker::Sized {}
index 5fb772fa10acbdb46a1707233bfc12204b50735f..2166420070a07a1898b3156ef6ea1c068ce9bf8b 100644 (file)
@@ -7,7 +7,6 @@ LL |
 LL |     async { (ty, ty1) }
    |     ------------------- this returned value is of type `impl std::future::Future`
    |
-   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `U`
 note: captured value is not `Send`
   --> $DIR/issue-70818.rs:6:18
    |
index 603895b598c168384671140c7527625290194e66..762afa6450a955c7395e0fadba680db714b54dc7 100644 (file)
@@ -17,10 +17,12 @@ LL |     async fn frob(self) {}
    |                   ^^^^ doesn't have a size known at compile-time
    |
    = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Foo`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     async fn frob(&self) {}
+   |                   ^
 
 error: aborting due to 3 previous errors
 
index 81fc961e3dea0ab05dc15006df92c9528309e319..fd3999ae6fbeca92d9edcacbfed3794ebf0da4e2 100644 (file)
@@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     1.bar::<T>();
    |       ^^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
 help: consider further restricting this bound
    |
 LL | fn foo<T:'static + std::marker::Send>() {
index 5c169af4eb8ae33380ac6e6a6543b29516b851c3..47d8cc1f06fd1b557402e86705709f8fd31ee60f 100644 (file)
@@ -21,7 +21,6 @@ LL | pub struct Vec<T> {
    |                - required by this bound in `std::vec::Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn Trait`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
   --> $DIR/bad-sized.rs:4:37
@@ -30,7 +29,6 @@ LL |     let x: Vec<dyn Trait + Sized> = Vec::new();
    |                                     ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn Trait`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::vec::Vec::<T>::new`
 
 error: aborting due to 3 previous errors
index b9bc503f5301a35504fcaa02f9bc7ec222520f89..623252a8c11399ff4bd0f9de920133d772dd0301 100644 (file)
@@ -4,7 +4,6 @@ error[E0277]: `impl Sized` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", t);
    |                      ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `impl Sized`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting this bound
@@ -18,7 +17,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", t);
    |                      ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `T`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider restricting type parameter `T`
@@ -32,7 +30,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", t);
    |                      ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `T`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting this bound
@@ -46,7 +43,6 @@ error[E0277]: `Y` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?} {:?}", x, y);
    |                              ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `Y`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting type parameter `Y`
@@ -60,7 +56,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `X`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting this bound
@@ -74,7 +69,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug`
 LL |     println!("{:?}", x);
    |                      ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `X`
    = note: required by `std::fmt::Debug::fmt`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider further restricting type parameter `X`
index dfc4999958a5725602cbf1693362e51dd5f36199..b3e7b5b4feea4b6c446a14ed799e0e95ed1ef0d3 100644 (file)
@@ -5,7 +5,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_slice);
    |                                   ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::boxed::Box::<T>::into_boxed_slice`
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
@@ -15,7 +14,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_slice);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
@@ -25,7 +23,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_trait);
    |                                   ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::boxed::Box::<T>::into_boxed_slice`
 
 error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time
@@ -35,7 +32,6 @@ LL |     let _ = Box::into_boxed_slice(boxed_trait);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error: aborting due to 4 previous errors
index 4e7b513629d0512fdab25ab6c6d3eda8ff43ae90..7ff986ec38109d78b3829d5cff702a0f851bf95a 100644 (file)
@@ -7,7 +7,6 @@ LL |
 LL | impl <T: Sync+'static> Foo for (T,) { }
    |                        ^^^ `T` cannot be sent between threads safely
    |
-   = help: within `(T,)`, the trait `std::marker::Send` is not implemented for `T`
    = note: required because it appears within the type `(T,)`
 help: consider further restricting this bound
    |
@@ -23,7 +22,6 @@ LL | trait Foo : Send+Sync { }
 LL | impl <T: Send> Foo for (T,T) { }
    |                ^^^ `T` cannot be shared between threads safely
    |
-   = help: within `(T, T)`, the trait `std::marker::Sync` is not implemented for `T`
    = note: required because it appears within the type `(T, T)`
 help: consider further restricting this bound
    |
index 3fb1af3a67cc225b4149642fd4a65250fbe99a2f..9ee045edfe546fc2a4f4259b8e01bb6787c6fdac 100644 (file)
@@ -9,7 +9,6 @@ LL | impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { }
 LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { }
    |                                                          ---- required by this bound in `trait_superkinds_in_metadata::RequiresRequiresShareAndSend`
    |
-   = help: within `X<T>`, the trait `std::marker::Send` is not implemented for `T`
    = note: required because it appears within the type `X<T>`
 help: consider further restricting this bound
    |
index 9c5073a1e49d73b94468cb47c4981f9a1450571b..ad80b3fa8d11f39b97a2ad145e7162d0a988ec65 100644 (file)
@@ -7,7 +7,6 @@ LL |
 LL | impl <T: Sync+'static> Foo for T { }
    |                        ^^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
 help: consider further restricting this bound
    |
 LL | impl <T: Sync+'static + std::marker::Send> Foo for T { }
index e5d7615e43e31f484912f15afa25d02c2457ab3d..fb2e0fc1a61699016c5f6e92189f861a47927b75 100644 (file)
@@ -8,7 +8,6 @@ LL | impl Foo for str { }
    |      ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the trait bound `f32: Foo` is not satisfied
   --> $DIR/impl_wf.rs:27:17
diff --git a/src/test/ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs
new file mode 100644 (file)
index 0000000..b02cc1a
--- /dev/null
@@ -0,0 +1,10 @@
+#![crate_type = "lib"]
+#![feature(doc_alias)]
+
+#[doc(alias = "foo")] // ok!
+pub struct Bar;
+
+#[doc(alias)] //~ ERROR
+#[doc(alias = 0)] //~ ERROR
+#[doc(alias("bar"))] //~ ERROR
+pub struct Foo;
diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr
new file mode 100644 (file)
index 0000000..268230a
--- /dev/null
@@ -0,0 +1,20 @@
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:7:7
+   |
+LL | #[doc(alias)]
+   |       ^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:8:7
+   |
+LL | #[doc(alias = 0)]
+   |       ^^^^^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:9:7
+   |
+LL | #[doc(alias("bar"))]
+   |       ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index ffd70fac6b19bf8bfe8e29a0bb9bbc7aecf964ba..273eae995538a7dc0b62ce3b833d9fb5d9967437 100644 (file)
@@ -7,7 +7,6 @@ LL | struct X<F> where F: FnOnce() + 'static + Send {
 LL | fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static {
    |                      ^^^^ `F` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `F`
 help: consider further restricting this bound
    |
 LL | fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static + std::marker::Send {
index 691864c9e1d45652708ce77d2ec17a83a75b285f..7df29d5a098a02896f34bdf666fa479421c7b764 100644 (file)
@@ -7,7 +7,6 @@ LL | fn take_const_owned<F>(_: F) where F: FnOnce() + Sync + Send {
 LL |     take_const_owned(f);
    |                      ^ `F` cannot be shared between threads safely
    |
-   = help: the trait `std::marker::Sync` is not implemented for `F`
 help: consider further restricting this bound
    |
 LL | fn give_owned<F>(f: F) where F: FnOnce() + Send + std::marker::Sync {
index 14cf64eeb7ac69841461972e8e033910824b6869..ad67a87265bd3f0e66959bf691864ee8625610e1 100644 (file)
@@ -16,10 +16,10 @@ LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    = note: this may fail depending on what value the parameter takes
 
 error: constant expression depends on a generic parameter
-  --> $DIR/array-size-in-generic-struct-param.rs:14:5
+  --> $DIR/array-size-in-generic-struct-param.rs:14:10
    |
 LL |     arr: [u8; CFG.arr_size],
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^
    |
    = note: this may fail depending on what value the parameter takes
 
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs
new file mode 100644 (file)
index 0000000..5aa3617
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+// Currently, const parameters cannot depend on other generic parameters,
+// as our current implementation can't really support this.
+//
+// We may want to lift this restriction in the future.
+
+pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
+//~^ ERROR: the type of const parameters must not depend on other generic parameters
+
+pub struct SelfDependent<const N: [u8; N]>;
+//~^ ERROR: the type of const parameters must not depend on other generic parameters
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr
new file mode 100644 (file)
index 0000000..f6606ae
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-const-param.rs:9:52
+   |
+LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
+   |                                                    ^ the type must not depend on the parameter `N`
+
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-const-param.rs:12:40
+   |
+LL | pub struct SelfDependent<const N: [u8; N]>;
+   |                                        ^ the type must not depend on the parameter `N`
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/const-param-type-depends-on-const-param.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0770`.
index 86ab8075896aa6c51fc503bd809f6d989ed7ebfa..ea75a3d04035828c432665eb5786d001261d3ec3 100644 (file)
@@ -1,6 +1,9 @@
+// compile-flags: -Zsave-analysis
+// Regression test for #69414 ^
+
 use std::marker::PhantomData;
 
 struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
-//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
+//~^ ERROR the type of const parameters must not depend on other generic parameters
 
 fn main() {}
index 92a7edf96bccb504f52437e35a89fd5b9c0a24c1..616f0fa8f1af0796df83ee863b48b71abc2771f0 100644 (file)
@@ -1,5 +1,11 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:6:22
+   |
+LL | struct B<T, const N: T>(PhantomData<[T; N]>);
+   |                      ^ the type must not depend on the parameter `T`
+
 error[E0658]: const generics are unstable
-  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
+  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:6:19
    |
 LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    |                   ^
@@ -7,15 +13,7 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
-error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
-  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
-   |
-LL | struct B<T, const N: T>(PhantomData<[T; N]>);
-   |                      ^ `T` may not derive both `PartialEq` and `Eq`
-   |
-   = note: it is not currently possible to use a type parameter as the type of a const parameter
-
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0658, E0741.
+Some errors have detailed explanations: E0658, E0770.
 For more information about an error, try `rustc --explain E0658`.
index 654e36df37e98fcc6b58465416923e7d890faaa1..7fe04a43412a1edd26c4f33e141083bc7525e168 100644 (file)
@@ -1,12 +1,13 @@
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
-// Currently, const parameters cannot depend on type parameters, because there is no way to
-// enforce the structural-match property on an arbitrary type parameter. This restriction
-// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more
-// details.
+// Currently, const parameters cannot depend on other generic parameters,
+// as our current implementation can't really support this.
+//
+// We may want to lift this restriction in the future.
 
 pub struct Dependent<T, const X: T>([(); X]);
-//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
+//~^ ERROR: the type of const parameters must not depend on other generic parameters
+//~| ERROR: parameter `T` is never used
 
 fn main() {}
index ed05264161e538c5765ed9c2b088b8592c4115aa..d081dcbbc7a4e90db6360cea80dfe9286a3802d1 100644 (file)
@@ -1,3 +1,9 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/const-param-type-depends-on-type-param.rs:9:34
+   |
+LL | pub struct Dependent<T, const X: T>([(); X]);
+   |                                  ^ the type must not depend on the parameter `T`
+
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/const-param-type-depends-on-type-param.rs:1:12
    |
@@ -7,14 +13,15 @@ LL | #![feature(const_generics)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
-  --> $DIR/const-param-type-depends-on-type-param.rs:9:34
+error[E0392]: parameter `T` is never used
+  --> $DIR/const-param-type-depends-on-type-param.rs:9:22
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
-   |                                  ^ `T` may not derive both `PartialEq` and `Eq`
+   |                      ^ unused parameter
    |
-   = note: it is not currently possible to use a type parameter as the type of a const parameter
+   = 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; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0741`.
+Some errors have detailed explanations: E0392, E0770.
+For more information about an error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs
new file mode 100644 (file)
index 0000000..59a4d34
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(const_generics)]
+
+// All of these three items must be in `lib2` to reproduce the error
+
+pub trait TypeFn {
+    type Output;
+}
+
+pub struct GenericType<const B: i8>;
+
+// Removing the braces around `42` resolves the crash
+impl TypeFn for GenericType<{ 42 }> {
+    type Output = ();
+}
diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs
new file mode 100644 (file)
index 0000000..ccc05fd
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+
+fn foo<const N: usize, const A: [u8; N]>() {}
+//~^ ERROR the type of const parameters must not
+
+fn main() {
+    foo::<_, {[1]}>();
+    //~^ ERROR wrong number of const arguments
+    //~| ERROR wrong number of type arguments
+    //~| ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.stderr
new file mode 100644 (file)
index 0000000..fe0990d
--- /dev/null
@@ -0,0 +1,37 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-62878.rs:3:38
+   |
+LL | fn foo<const N: usize, const A: [u8; N]>() {}
+   |                                      ^ the type must not depend on the parameter `N`
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-62878.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0107]: wrong number of const arguments: expected 2, found 1
+  --> $DIR/issue-62878.rs:7:5
+   |
+LL |     foo::<_, {[1]}>();
+   |     ^^^^^^^^^^^^^^^ expected 2 const arguments
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/issue-62878.rs:7:11
+   |
+LL |     foo::<_, {[1]}>();
+   |           ^ unexpected type argument
+
+error[E0308]: mismatched types
+  --> $DIR/issue-62878.rs:7:15
+   |
+LL |     foo::<_, {[1]}>();
+   |               ^^^ expected `usize`, found array `[{integer}; 1]`
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0107, E0308, E0770.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/issues/issue-68596.rs b/src/test/ui/const-generics/issues/issue-68596.rs
new file mode 100644 (file)
index 0000000..1f96e7d
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+pub struct S(u8);
+
+impl S {
+    pub fn get<const A: u8>(&self) -> &u8 {
+        &self.0
+    }
+}
+
+fn main() {
+    const A: u8 = 5;
+    let s = S(0);
+
+    s.get::<A>();
+}
diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs
new file mode 100644 (file)
index 0000000..943a16c
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
+//~^ ERROR the type of const parameters must not
+fn main() {
+    const DATA: [u8; 4] = *b"ABCD";
+    foo::<4, DATA>();
+    //~^ ERROR constant expression depends on
+}
diff --git a/src/test/ui/const-generics/issues/issue-71169.stderr b/src/test/ui/const-generics/issues/issue-71169.stderr
new file mode 100644 (file)
index 0000000..6d4cf40
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-71169.rs:4:43
+   |
+LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
+   |                                           ^^^ the type must not depend on the parameter `LEN`
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-71169.rs:8:14
+   |
+LL |     foo::<4, DATA>();
+   |              ^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0770`.
index c32bd2847f8378a4e404e24a6a9073f507631ac5..08f948239421879811e1f2ee28c42dbfc936b91e 100644 (file)
@@ -12,6 +12,7 @@
 impl Test {
     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
         //~^ ERROR: using function pointers as const generic parameters is forbidden
+        //~| ERROR: the type of const parameters must not depend on other generic parameters
         self.0 = Self::trampiline::<Args, IDX, FN> as _
     }
 
@@ -20,6 +21,7 @@ pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Arg
         const IDX: usize,
         const FN: unsafe extern "C" fn(Args),
         //~^ ERROR: using function pointers as const generic parameters is forbidden
+        //~| ERROR: the type of const parameters must not depend on other generic parameters
     >(
         args: Args,
     ) {
index 6bb776fcfc0170e329f2dabad32566f362434a72..fd4ebe3dead81e8d52ff256acfa45a89fea337a5 100644 (file)
@@ -1,3 +1,15 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-71381.rs:13:82
+   |
+LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
+   |                                                                                  ^^^^ the type must not depend on the parameter `Args`
+
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-71381.rs:22:40
+   |
+LL |         const FN: unsafe extern "C" fn(Args),
+   |                                        ^^^^ the type must not depend on the parameter `Args`
+
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/issue-71381.rs:13:61
    |
@@ -5,10 +17,11 @@ LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "
    |                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using function pointers as const generic parameters is forbidden
-  --> $DIR/issue-71381.rs:21:19
+  --> $DIR/issue-71381.rs:22:19
    |
 LL |         const FN: unsafe extern "C" fn(Args),
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0770`.
index 64a049e743fafab50624253100b58617750687c1..06ff38dec66c74e8c157568fc04c4abb3d23c2cc 100644 (file)
@@ -3,6 +3,7 @@
 
 fn func<A, const F: fn(inner: A)>(outer: A) {
     //~^ ERROR: using function pointers as const generic parameters is forbidden
+    //~| ERROR: the type of const parameters must not depend on other generic parameters
     F(outer);
 }
 
index 9a7bf1c0a8841e660aabc24dd8476d38d153142f..e2c9f22361ebe5c5c622a21121f6b3b88c9e5e80 100644 (file)
@@ -1,8 +1,15 @@
+error[E0770]: the type of const parameters must not depend on other generic parameters
+  --> $DIR/issue-71611.rs:4:31
+   |
+LL | fn func<A, const F: fn(inner: A)>(outer: A) {
+   |                               ^ the type must not depend on the parameter `A`
+
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/issue-71611.rs:4:21
    |
 LL | fn func<A, const F: fn(inner: A)>(outer: A) {
    |                     ^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0770`.
diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs
new file mode 100644 (file)
index 0000000..aea4de3
--- /dev/null
@@ -0,0 +1,8 @@
+// check-pass
+// aux-build:const_generic_issues_lib.rs
+extern crate const_generic_issues_lib as lib2;
+fn unused_function(
+    _: <lib2::GenericType<42> as lib2::TypeFn>::Output
+) {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-73491.rs b/src/test/ui/const-generics/issues/issue-73491.rs
new file mode 100644 (file)
index 0000000..05e1513
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+const LEN: usize = 1024;
+
+fn hoge<const IN: [u32; LEN]>() {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-73508.rs b/src/test/ui/const-generics/issues/issue-73508.rs
new file mode 100644 (file)
index 0000000..ba2e2a3
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+
+pub const fn func_name<const X: *const u32>() {}
+//~^ ERROR using raw pointers
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-73508.stderr b/src/test/ui/const-generics/issues/issue-73508.stderr
new file mode 100644 (file)
index 0000000..23ad181
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-73508.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/issue-73508.rs:3:33
+   |
+LL | pub const fn func_name<const X: *const u32>() {}
+   |                                 ^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/issues/issue-74101.rs b/src/test/ui/const-generics/issues/issue-74101.rs
new file mode 100644 (file)
index 0000000..2f427ef
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+fn test<const N: [u8; 1 + 2]>() {}
+
+struct Foo<const N: [u8; 1 + 2]>;
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-74255.rs b/src/test/ui/const-generics/issues/issue-74255.rs
new file mode 100644 (file)
index 0000000..55ccf57
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(dead_code, incomplete_features)]
+
+#[derive(PartialEq, Eq)]
+enum IceEnum {
+    Variant
+}
+
+struct IceStruct;
+
+impl IceStruct {
+    fn ice_struct_fn<const I: IceEnum>() {}
+}
+
+fn main() {
+    IceStruct::ice_struct_fn::<{IceEnum::Variant}>();
+}
diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs
new file mode 100644 (file)
index 0000000..c8db91b
--- /dev/null
@@ -0,0 +1,36 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+pub struct Struct<const N: usize>(());
+
+impl<const N: usize> Struct<N> {
+    pub fn new() -> Self {
+        Struct(())
+    }
+
+    pub fn same_ty<const M: usize>(&self) -> (usize, usize) {
+        (N, M)
+    }
+
+    pub fn different_ty<const M: u8>(&self) -> (usize, u8) {
+        (N, M)
+    }
+
+    pub fn containing_ty<T, const M: u8>(&self) -> (usize, u8) {
+        (std::mem::size_of::<T>() +  N, M)
+    }
+
+    pub fn we_have_to_go_deeper<const M: usize>(&self) -> Struct<M> {
+        Struct(())
+    }
+}
+
+pub trait Foo {
+    fn foo<const M: usize>(&self) -> usize;
+}
+
+impl Foo for Struct<7> {
+    fn foo<const M: usize>(&self) -> usize {
+        M
+    }
+}
diff --git a/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs b/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs
new file mode 100644 (file)
index 0000000..ae50252
--- /dev/null
@@ -0,0 +1,26 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+#![feature(const_fn)]
+
+struct Foo;
+
+impl Foo {
+    fn foo<const N: usize>(&self) -> usize {
+        let f = self;
+        f.bar::<{
+            let f = Foo;
+            f.bar::<7>()
+        }>() + N
+    }
+
+    const fn bar<const M: usize>(&self) -> usize {
+        M
+    }
+}
+
+fn main() {
+    let f = Foo;
+
+    assert_eq!(f.foo::<13>(), 20)
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-61936.rs b/src/test/ui/const-generics/type-dependent/issue-61936.rs
new file mode 100644 (file)
index 0000000..a7a923c
--- /dev/null
@@ -0,0 +1,49 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait SliceExt<T: Clone> {
+    fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>;
+}
+
+impl <T: Clone> SliceExt<T> for [T] {
+   fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> {
+       ArrayWindows{ idx: 0, slice: &self }
+   }
+}
+
+struct ArrayWindows<'a, T, const N: usize> {
+    slice: &'a [T],
+    idx: usize,
+}
+
+impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+    type Item = [T; N];
+    fn next(&mut self) -> Option<Self::Item> {
+        // Note: this is unsound for some `T` and not meant as an example
+        // on how to implement `ArrayWindows`.
+        let mut res = unsafe{ std::mem::zeroed() };
+        let mut ptr = &mut res as *mut [T; N] as *mut T;
+
+        for i in 0..N {
+            match self.slice[self.idx..].get(i) {
+                None => return None,
+                Some(elem) => unsafe { std::ptr::write_volatile(ptr, elem.clone())},
+            };
+            ptr = ptr.wrapping_add(1);
+            self.idx += 1;
+        }
+
+        Some(res)
+    }
+}
+
+const FOUR: usize = 4;
+
+fn main() {
+    let v: Vec<usize> = vec![0; 100];
+
+    for array in v.as_slice().array_windows::<FOUR>() {
+        assert_eq!(array, [0, 0, 0, 0])
+    }
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-63695.rs b/src/test/ui/const-generics/type-dependent/issue-63695.rs
new file mode 100644 (file)
index 0000000..f3c2e17
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait T {
+    fn test<const A: i32>(&self) -> i32 { A }
+}
+
+struct S();
+
+impl T for S {}
+
+fn main() {
+    let foo = S();
+    assert_eq!(foo.test::<8i32>(), 8);
+    assert_eq!(foo.test::<16i32>(), 16);
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-1.rs b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs
new file mode 100644 (file)
index 0000000..a3d0595
--- /dev/null
@@ -0,0 +1,28 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct X;
+
+impl X {
+    pub fn getn<const N: usize>(&self) -> [u8; N] {
+        getn::<N>()
+    }
+}
+
+fn getn<const N: usize>() -> [u8; N] {
+    unsafe {
+        std::mem::zeroed()
+    }
+}
+
+fn main() {
+    // works
+    let [a,b,c] = getn::<3>();
+
+    // cannot pattern-match on an array without a fixed length
+    let [a,b,c] = X.getn::<3>();
+
+    // mismatched types, expected array `[u8; 3]` found array `[u8; _]`
+    let arr: [u8; 3] = X.getn::<3>();
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-2.rs b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs
new file mode 100644 (file)
index 0000000..c53a149
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct A<const N: usize>;
+
+struct X;
+
+impl X {
+    fn inner<const N: usize>() -> A<N> {
+        outer::<N>()
+    }
+}
+
+fn outer<const N: usize>() -> A<N> {
+    A
+}
+
+fn main() {
+    let i: A<3usize> = outer::<3usize>();
+    let o: A<3usize> = X::inner::<3usize>();
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-69816.rs b/src/test/ui/const-generics/type-dependent/issue-69816.rs
new file mode 100644 (file)
index 0000000..cbe86ce
--- /dev/null
@@ -0,0 +1,20 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait IterExt: Sized + Iterator {
+    fn default_for_size<const N: usize>(self) -> [Self::Item; N]
+    where
+        [Self::Item; N]: Default,
+    {
+        Default::default()
+    }
+}
+
+impl<T: Iterator> IterExt for T {}
+
+fn main(){
+    const N: usize = 10;
+    let arr = (0u32..10).default_for_size::<N>();
+    assert_eq!(arr, [0; 10]);
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-70217.rs b/src/test/ui/const-generics/type-dependent/issue-70217.rs
new file mode 100644 (file)
index 0000000..caa611c
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Struct<const N: usize>;
+
+impl<const N: usize> Struct<N> {
+    fn method<const M: usize>(&self) {}
+}
+
+fn test<const N: usize, const M: usize>(x: Struct<N>) {
+    Struct::<N>::method::<M>(&x);
+    x.method::<N>();
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/type-dependent/issue-70507.rs b/src/test/ui/const-generics/type-dependent/issue-70507.rs
new file mode 100644 (file)
index 0000000..6fcf411
--- /dev/null
@@ -0,0 +1,47 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait ConstChunksExactTrait<T> {
+    fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, {N}>;
+}
+
+impl <T> ConstChunksExactTrait<T> for [T] {
+    fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, {N}> {
+        assert!(N != 0);
+        let rem = self.len() % N;
+        let len = self.len() - rem;
+        let (fst, _) = self.split_at(len);
+        ConstChunksExact { v: fst, }
+    }
+}
+
+struct ConstChunksExact<'a, T: 'a, const N: usize> {
+    v: &'a [T],
+}
+
+impl <'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {N}> {
+    type Item = &'a [T; N];
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.v.len() < N {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(N);
+
+            self.v = snd;
+            let ptr = fst.as_ptr() as *const _;
+            Some(unsafe { &*ptr})
+        }
+    }
+}
+
+fn main() {
+    let slice = &[1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+    let mut iter = [[1, 2, 3], [4, 5, 6], [7, 8, 9]].iter();
+
+    for a in slice.const_chunks_exact::<3>() {
+        assert_eq!(a, iter.next().unwrap());
+    }
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-70586.rs b/src/test/ui/const-generics/type-dependent/issue-70586.rs
new file mode 100644 (file)
index 0000000..5a08885
--- /dev/null
@@ -0,0 +1,33 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+use std::marker::PhantomData;
+
+// This namespace is necessary for the ICE to trigger
+struct Namespace;
+
+impl Namespace {
+    pub fn const_chunks_exact<T, const N: usize>() -> ConstChunksExact<'static, T, N> {
+        ConstChunksExact { inner: PhantomData }
+    }
+}
+
+
+#[derive(Debug)]
+pub struct ConstChunksExact<'a, T, const N: usize> {
+    inner:  PhantomData<&'a T>
+}
+
+impl <'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, { N }> {
+    type Item = &'a [T; N];
+
+    fn next(&mut self) -> Option<Self::Item> {
+        unreachable!()
+    }
+}
+
+fn main() {
+    let mut chunks = Namespace::const_chunks_exact::<i32, 3usize>();
+    let _next: &[i32; 3] = chunks.next().unwrap();
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.rs b/src/test/ui/const-generics/type-dependent/issue-71348.rs
new file mode 100644 (file)
index 0000000..ec22dcd
--- /dev/null
@@ -0,0 +1,35 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Foo {
+    i: i32,
+}
+
+trait Get<'a, const N: &'static str> {
+    type Target: 'a;
+
+    fn get(&'a self) -> &'a Self::Target;
+}
+
+impl Foo {
+    fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
+    where
+        Self: Get<'a, N>,
+    {
+        self.get()
+    }
+}
+
+impl<'a> Get<'a, "int"> for Foo {
+    type Target = i32;
+
+    fn get(&'a self) -> &'a Self::Target {
+        &self.i
+    }
+}
+
+fn main() {
+    let foo = Foo { i: 123 };
+    assert_eq!(foo.ask::<"int">(), &123);
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.rs b/src/test/ui/const-generics/type-dependent/issue-71382.rs
new file mode 100644 (file)
index 0000000..05abd48
--- /dev/null
@@ -0,0 +1,24 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+struct Test;
+
+fn pass() -> u8 {
+    42
+}
+
+impl Test {
+    pub fn call_me(&self) -> u8 {
+        self.test::<pass>()
+    }
+
+    fn test<const FN: fn() -> u8>(&self) -> u8 {
+        //~^ ERROR using function pointers as const generic parameters is forbidden
+        FN()
+    }
+}
+
+fn main() {
+    let x = Test;
+    assert_eq!(x.call_me(), 42);
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.stderr
new file mode 100644 (file)
index 0000000..f441b71
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-71382.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/issue-71382.rs:15:23
+   |
+LL |     fn test<const FN: fn() -> u8>(&self) -> u8 {
+   |                       ^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/type-dependent/issue-71805.rs b/src/test/ui/const-generics/type-dependent/issue-71805.rs
new file mode 100644 (file)
index 0000000..6823d78
--- /dev/null
@@ -0,0 +1,41 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+use std::mem::MaybeUninit;
+
+trait CollectSlice<'a>: Iterator {
+    fn inner_array<const N: usize>(&mut self) -> [Self::Item; N];
+
+    fn collect_array<const N: usize>(&mut self) -> [Self::Item; N] {
+        let result = self.inner_array();
+        assert!(self.next().is_none());
+        result
+    }
+}
+
+impl<'a, I: ?Sized> CollectSlice<'a> for I
+where
+    I: Iterator,
+{
+    fn inner_array<const N: usize>(&mut self) -> [Self::Item; N] {
+        let mut result: [MaybeUninit<Self::Item>; N] =
+            unsafe { MaybeUninit::uninit().assume_init() };
+
+        let mut count = 0;
+        for (dest, item) in result.iter_mut().zip(self) {
+            *dest = MaybeUninit::new(item);
+            count += 1;
+        }
+
+        assert_eq!(N, count);
+
+        let temp_ptr: *const [MaybeUninit<Self::Item>; N] = &result;
+        unsafe { std::ptr::read(temp_ptr as *const [Self::Item; N]) }
+    }
+}
+
+fn main() {
+    let mut foos = [0u64; 9].iter().cloned();
+    let _bar: [u64; 9] = foos.collect_array::<9_usize>();
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-73730.rs b/src/test/ui/const-generics/type-dependent/issue-73730.rs
new file mode 100644 (file)
index 0000000..d90cc50
--- /dev/null
@@ -0,0 +1,17 @@
+// check-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait Foo<'a, A>: Iterator<Item=A> {
+    fn bar<const N: usize>(&mut self) -> *const [A; N];
+}
+
+impl<'a, A, I: ?Sized> Foo<'a, A> for I where I: Iterator<Item=A>  {
+    fn bar<const N: usize>(&mut self) -> *const [A; N] {
+        std::ptr::null()
+    }
+}
+
+fn main() {
+    (0_u8 .. 10).bar::<10_usize>();
+}
diff --git a/src/test/ui/const-generics/type-dependent/non-local.rs b/src/test/ui/const-generics/type-dependent/non-local.rs
new file mode 100644 (file)
index 0000000..e6f3eb0
--- /dev/null
@@ -0,0 +1,24 @@
+// aux-build:type_dependent_lib.rs
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+extern crate type_dependent_lib;
+
+use type_dependent_lib::*;
+
+fn main() {
+    let s = Struct::<42>::new();
+    assert_eq!(s.same_ty::<7>(), (42, 7));
+    assert_eq!(s.different_ty::<19>(), (42, 19));
+    assert_eq!(Struct::<1337>::new().different_ty::<96>(), (1337, 96));
+    assert_eq!(
+        Struct::<18>::new()
+            .we_have_to_go_deeper::<19>()
+            .containing_ty::<Option<u32>, 3>(),
+        (27, 3),
+    );
+
+    let s = Struct::<7>::new();
+    assert_eq!(s.foo::<18>(), 18);
+}
diff --git a/src/test/ui/const-generics/type-dependent/qpath.rs b/src/test/ui/const-generics/type-dependent/qpath.rs
new file mode 100644 (file)
index 0000000..f3f98e5
--- /dev/null
@@ -0,0 +1,12 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct A;
+impl A {
+    fn foo<const N: usize>() -> usize { N + 1 }
+}
+
+fn main() {
+    assert_eq!(A::foo::<7>(), 8);
+}
diff --git a/src/test/ui/const-generics/type-dependent/simple.rs b/src/test/ui/const-generics/type-dependent/simple.rs
new file mode 100644 (file)
index 0000000..cc7c50d
--- /dev/null
@@ -0,0 +1,12 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct R;
+
+impl R {
+    fn method<const N: u8>(&self) -> u8 { N }
+}
+fn main() {
+    assert_eq!(R.method::<1u8>(), 1);
+}
diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.rs b/src/test/ui/const-generics/type-dependent/type-mismatch.rs
new file mode 100644 (file)
index 0000000..0c71f33
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+struct R;
+
+impl R {
+    fn method<const N: u8>(&self) -> u8 { N }
+}
+fn main() {
+    assert_eq!(R.method::<1u16>(), 1);
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.stderr
new file mode 100644 (file)
index 0000000..5bb7c5b
--- /dev/null
@@ -0,0 +1,23 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/type-mismatch.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch.rs:10:27
+   |
+LL |     assert_eq!(R.method::<1u16>(), 1);
+   |                           ^^^^ expected `u8`, found `u16`
+   |
+help: change the type of the numeric literal from `u16` to `u8`
+   |
+LL |     assert_eq!(R.method::<1u8>(), 1);
+   |                           ^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/unknown_adt.rs b/src/test/ui/const-generics/unknown_adt.rs
new file mode 100644 (file)
index 0000000..0ba9945
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let _: UnknownStruct<7>;
+    //~^ ERROR cannot find type `UnknownStruct`
+}
diff --git a/src/test/ui/const-generics/unknown_adt.stderr b/src/test/ui/const-generics/unknown_adt.stderr
new file mode 100644 (file)
index 0000000..b2e287b
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `UnknownStruct` in this scope
+  --> $DIR/unknown_adt.rs:5:12
+   |
+LL |     let _: UnknownStruct<7>;
+   |            ^^^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
index 5f2d5e80243fe62a76362679ffc08cb042142daf..d19cf00eb9ce4e71ac35985fd6c14a9d99fdd47f 100644 (file)
@@ -1,9 +1,12 @@
 // check-pass
 
+// compile-flags: --crate-type lib
+
+#![warn(unconditional_panic)]
+
 pub struct Fixed64(i64);
 
-pub fn div(f: Fixed64) {
-    f.0 / 0;
+// HACK: this test passes only because this is a const fn that is written to metadata
+pub const fn div(f: Fixed64) {
+    f.0 / 0; //~ WARN will panic at runtime
 }
-
-fn main() {}
diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr
new file mode 100644 (file)
index 0000000..e2a3e4d
--- /dev/null
@@ -0,0 +1,14 @@
+warning: this operation will panic at runtime
+  --> $DIR/ice-assert-fail-div-by-zero.rs:11:5
+   |
+LL |     f.0 / 0;
+   |     ^^^^^^^ attempt to divide _ by zero
+   |
+note: the lint level is defined here
+  --> $DIR/ice-assert-fail-div-by-zero.rs:5:9
+   |
+LL | #![warn(unconditional_panic)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/consts/const-option.rs b/src/test/ui/consts/const-option.rs
new file mode 100644 (file)
index 0000000..fbf20b9
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+
+#![feature(const_option)]
+
+const X: Option<i32> = Some(32);
+const Y: Option<&i32> = X.as_ref();
+
+const IS_SOME: bool = X.is_some();
+const IS_NONE: bool = Y.is_none();
+
+fn main() {
+    assert!(IS_SOME);
+    assert!(!IS_NONE)
+}
index beeea87bfb1d33f0d4c556056f044cf3dc716565..bf2844cfb70d6db23fc61845f350db0117586ea3 100644 (file)
@@ -5,7 +5,6 @@ LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync));
    |                ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/const-unsized.rs:6:18
@@ -14,7 +13,6 @@ LL | const CONST_FOO: str = *"foo";
    |                  ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time
   --> $DIR/const-unsized.rs:9:18
@@ -23,7 +21,6 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
    |                  ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
   --> $DIR/const-unsized.rs:12:20
@@ -32,7 +29,6 @@ LL | static STATIC_BAR: str = *"bar";
    |                    ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/consts/const_unsafe_unreachable.rs b/src/test/ui/consts/const_unsafe_unreachable.rs
new file mode 100644 (file)
index 0000000..cfed6e5
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(const_fn)]
+#![feature(const_unreachable_unchecked)]
+
+const unsafe fn foo(x: bool) -> bool {
+    match x {
+        true => true,
+        false => std::hint::unreachable_unchecked(),
+    }
+}
+
+const BAR: bool = unsafe { foo(true) };
+
+fn main() {
+  assert_eq!(BAR, true);
+}
diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs
new file mode 100644 (file)
index 0000000..11920d8
--- /dev/null
@@ -0,0 +1,20 @@
+// build-fail
+
+#![feature(const_fn)]
+#![feature(const_unreachable_unchecked)]
+
+const unsafe fn foo(x: bool) -> bool {
+    match x {
+        true => true,
+        false => std::hint::unreachable_unchecked(),
+    }
+}
+
+#[warn(const_err)]
+const BAR: bool = unsafe { foo(false) };
+
+fn main() {
+  assert_eq!(BAR, true);
+  //~^ ERROR E0080
+  //~| ERROR erroneous constant
+}
diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr
new file mode 100644 (file)
index 0000000..3ef8043
--- /dev/null
@@ -0,0 +1,44 @@
+warning: any use of this value will cause an error
+  --> $SRC_DIR/libcore/hint.rs:LL:COL
+   |
+LL |     unsafe { intrinsics::unreachable() }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              entering unreachable code
+   |              inside `std::hint::unreachable_unchecked` at $SRC_DIR/libcore/hint.rs:LL:COL
+   |              inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18
+   |              inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28
+   | 
+  ::: $DIR/const_unsafe_unreachable_ub.rs:14:1
+   |
+LL | const BAR: bool = unsafe { foo(false) };
+   | ----------------------------------------
+   |
+note: the lint level is defined here
+  --> $DIR/const_unsafe_unreachable_ub.rs:13:8
+   |
+LL | #[warn(const_err)]
+   |        ^^^^^^^^^
+
+error[E0080]: evaluation of constant expression failed
+  --> $DIR/const_unsafe_unreachable_ub.rs:17:3
+   |
+LL |   assert_eq!(BAR, true);
+   |   ^^^^^^^^^^^---^^^^^^^^
+   |              |
+   |              referenced constant has errors
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: erroneous constant used
+  --> $DIR/const_unsafe_unreachable_ub.rs:17:3
+   |
+LL |   assert_eq!(BAR, true);
+   |   ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs
new file mode 100644 (file)
index 0000000..c8b3939
--- /dev/null
@@ -0,0 +1,57 @@
+// run-pass
+
+#![feature(const_panic)]
+#![feature(duration_consts_2)]
+#![feature(div_duration)]
+
+use std::time::Duration;
+
+fn duration() {
+    const ZERO : Duration = Duration::new(0, 0);
+    assert_eq!(ZERO, Duration::from_secs(0));
+
+    const ONE : Duration = Duration::new(0, 1);
+    assert_eq!(ONE, Duration::from_nanos(1));
+
+    const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);
+
+    const MAX_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
+    assert_eq!(MAX_ADD_ZERO, Some(MAX));
+
+    const MAX_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
+    assert_eq!(MAX_ADD_ONE, None);
+
+    const ONE_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
+    assert_eq!(ONE_SUB_ONE, Some(ZERO));
+
+    const ZERO_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
+    assert_eq!(ZERO_SUB_ONE, None);
+
+    const ONE_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
+    assert_eq!(ONE_MUL_ONE, Some(ONE));
+
+    const MAX_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
+    assert_eq!(MAX_MUL_TWO, None);
+
+    const ONE_DIV_ONE : Option<Duration> = ONE.checked_div(1);
+    assert_eq!(ONE_DIV_ONE, Some(ONE));
+
+    const ONE_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
+    assert_eq!(ONE_DIV_ZERO, None);
+
+    const MAX_AS_F32 : f32 = MAX.as_secs_f32();
+    assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
+
+    const MAX_AS_F64 : f64 = MAX.as_secs_f64();
+    assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64);
+
+    const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE);
+    assert_eq!(ONE_AS_F32, 1.0_f32);
+
+    const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
+    assert_eq!(ONE_AS_F64, 1.0_f64);
+}
+
+fn main() {
+    duration();
+}
index bcf7e3e6608eaa810d00124f4e54954ce68b461d..0d11d933af04e16af507ce8098260a03dab6f9f2 100644 (file)
@@ -25,7 +25,7 @@ mod x {
 mod y {
     use Foo;
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     pub fn use_char_assoc() {
         // Careful here: in the representation, <char as Foo>::T gets
         // normalized away, so at a certain point we had no edge to
index a603d71596ba627c0ef636ab1e8a6417a316bba0..4e659648e9edce5a2d07fdbad3287b57c4b5b8f9 100644 (file)
@@ -1,8 +1,8 @@
 error: OK
   --> $DIR/dep-graph-assoc-type-codegen.rs:28:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 18b4252a06b8443889501c3ceeb0ed1d100ab509..b12c635d2e733db2b5c00c5f41085f44b632b71a 100644 (file)
@@ -17,7 +17,7 @@ mod y {
     use x;
 
     // These dependencies SHOULD exist:
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     pub fn y() {
         x::x();
     }
@@ -28,7 +28,7 @@ mod z {
 
     // These are expected to yield errors, because changes to `x`
     // affect the BODY of `y`, but not its signature.
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path
+    #[rustc_then_this_would_need(typeck)] //~ ERROR no path
     pub fn z() {
         y::y();
     }
index de041e600672d47b8050ee5482ad56e187686efe..164c474183ad04ec1cfe1db64ed811a2c9c8afdf 100644 (file)
@@ -1,14 +1,14 @@
 error: OK
   --> $DIR/dep-graph-caller-callee.rs:20:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: no path from `x::x` to `typeck_tables_of`
+error: no path from `x::x` to `typeck`
   --> $DIR/dep-graph-caller-callee.rs:31:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 8b78d39ecae332ba72d50fb9e542cc5a9d0803e2..7ef6fac48c3a6c54f17d541b607839c78b645f69 100644 (file)
@@ -33,11 +33,11 @@ trait Bar {
     }
 
     #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     fn some_fn(x: WillChange) { }
 
     #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     fn new_foo(x: u32, y: u32) -> WillChange {
         WillChange { x: x, y: y }
     }
@@ -45,14 +45,14 @@ fn new_foo(x: u32, y: u32) -> WillChange {
     #[rustc_then_this_would_need(type_of)] //~ ERROR OK
     impl WillChange {
         #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK
-        #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+        #[rustc_then_this_would_need(typeck)] //~ ERROR OK
         fn new(x: u32, y: u32) -> WillChange { loop { } }
     }
 
     #[rustc_then_this_would_need(type_of)] //~ ERROR OK
     impl WillChange {
         #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK
-        #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+        #[rustc_then_this_would_need(typeck)] //~ ERROR OK
         fn method(&self, x: u32) { }
     }
 
@@ -81,6 +81,6 @@ trait A {
     fn b(x: WontChange) { }
 
     #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path from `WillChange`
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path from `WillChange`
+    #[rustc_then_this_would_need(typeck)] //~ ERROR no path from `WillChange`
     fn c(x: u32) { }
 }
index 2e00e5a2cbd2f07144d38e7858d342f9e3a2f09d..9d1644a00d0024eab79548a7af3d05551022efbd 100644 (file)
@@ -25,8 +25,8 @@ LL |     #[rustc_then_this_would_need(fn_sig)]
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:36:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:39:5
@@ -37,8 +37,8 @@ LL |     #[rustc_then_this_would_need(fn_sig)]
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:40:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:45:5
@@ -88,11 +88,11 @@ error: no path from `WillChange` to `fn_sig`
 LL |     #[rustc_then_this_would_need(fn_sig)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: no path from `WillChange` to `typeck_tables_of`
+error: no path from `WillChange` to `typeck`
   --> $DIR/dep-graph-struct-signature.rs:84:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:31:9
@@ -115,8 +115,8 @@ LL |         #[rustc_then_this_would_need(fn_sig)]
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:48:9
    |
-LL |         #[rustc_then_this_would_need(typeck_tables_of)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_then_this_would_need(typeck)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:54:9
@@ -127,8 +127,8 @@ LL |         #[rustc_then_this_would_need(fn_sig)]
 error: OK
   --> $DIR/dep-graph-struct-signature.rs:55:9
    |
-LL |         #[rustc_then_this_would_need(typeck_tables_of)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         #[rustc_then_this_would_need(typeck)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 22 previous errors
 
index 38622a754ddb2cb339542757677d440b0082bedc..1b3bf5a3933fe2c2b537173129c03d509a970a90 100644 (file)
@@ -29,7 +29,7 @@ impl Bar for char { }
 mod y {
     use {Foo, Bar};
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     pub fn with_char() {
         char::method('a');
     }
@@ -38,7 +38,7 @@ pub fn with_char() {
 mod z {
     use y;
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path
+    #[rustc_then_this_would_need(typeck)] //~ ERROR no path
     pub fn z() {
         y::with_char();
     }
index 3384fd7b4acf570583964d1d6069a36971fed979..ae3d725e1c051a091220df9413487aa5de8d4a85 100644 (file)
@@ -1,14 +1,14 @@
 error: OK
   --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:32:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: no path from `x::<impl Foo for u32>` to `typeck_tables_of`
+error: no path from `x::<impl Foo for u32>` to `typeck`
   --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:41:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 82306b6539c155263abd6eb158b8399eb82ceb63..ebfe8ccc3dfaffeb79e2df5434af4f28ce57937a 100644 (file)
@@ -28,7 +28,7 @@ impl Bar for char { }
 mod y {
     use {Foo, Bar};
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path
+    #[rustc_then_this_would_need(typeck)] //~ ERROR no path
     pub fn call_bar() {
         char::bar('a');
     }
@@ -37,7 +37,7 @@ pub fn call_bar() {
 mod z {
     use y;
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path
+    #[rustc_then_this_would_need(typeck)] //~ ERROR no path
     pub fn z() {
         y::call_bar();
     }
index d8a1f05dcaa7920143370e70dc097f51fdf2cb54..4823927477fe08e19ef499997d0498d65dc838ed 100644 (file)
@@ -1,14 +1,14 @@
-error: no path from `x::<impl Foo for char>` to `typeck_tables_of`
+error: no path from `x::<impl Foo for char>` to `typeck`
   --> $DIR/dep-graph-trait-impl-two-traits.rs:31:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: no path from `x::<impl Foo for char>` to `typeck_tables_of`
+error: no path from `x::<impl Foo for char>` to `typeck`
   --> $DIR/dep-graph-trait-impl-two-traits.rs:40:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index e4483b9f71ddb22a95cb50d09eb6afd2655902c3..9dd201e2a1fbcc6bee18b5e917ec1363408d11ef 100644 (file)
@@ -24,22 +24,22 @@ impl Foo for u32 { }
 mod y {
     use Foo;
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     pub fn with_char() {
         char::method('a');
     }
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     pub fn take_foo_with_char() {
         take_foo::<char>('a');
     }
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     pub fn with_u32() {
         u32::method(22);
     }
 
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     pub fn take_foo_with_u32() {
         take_foo::<u32>(22);
     }
@@ -52,7 +52,7 @@ mod z {
 
     // These are expected to yield errors, because changes to `x`
     // affect the BODY of `y`, but not its signature.
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path
+    #[rustc_then_this_would_need(typeck)] //~ ERROR no path
     pub fn z() {
         y::with_char();
         y::with_u32();
index ca9676a9478e4c826f9d34fb2131db629657a0b6..f8ead80894276400d1de6be0b3c8d8f79a30177c 100644 (file)
@@ -1,32 +1,32 @@
 error: OK
   --> $DIR/dep-graph-trait-impl.rs:27:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-trait-impl.rs:32:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-trait-impl.rs:37:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-trait-impl.rs:42:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: no path from `x::<impl Foo for char>` to `typeck_tables_of`
+error: no path from `x::<impl Foo for char>` to `typeck`
   --> $DIR/dep-graph-trait-impl.rs:55:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
index 2d4a18f2818b57d71bfe8a78d0f175ec016177cf..c9151ce79c5f64d806c42c1d08f489a7b331758f 100644 (file)
@@ -41,7 +41,7 @@ trait Trait {
 #[rustc_then_this_would_need(type_of)] //~ ERROR no path
 impl SomeType {
     #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK
-    #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+    #[rustc_then_this_would_need(typeck)] //~ ERROR OK
     fn method(&self, _: TypeAlias) {}
 }
 
@@ -49,7 +49,7 @@ fn method(&self, _: TypeAlias) {}
 type TypeAlias2 = TypeAlias;
 
 #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK
-#[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK
+#[rustc_then_this_would_need(typeck)] //~ ERROR OK
 fn function(_: TypeAlias) {
 
 }
index 393e4badc160847447f08c3608a7eadb45a94118..9baaf746fc2107b45e1410a1c49163a9a0d80b82 100644 (file)
@@ -49,8 +49,8 @@ LL | #[rustc_then_this_would_need(fn_sig)]
 error: OK
   --> $DIR/dep-graph-type-alias.rs:52:1
    |
-LL | #[rustc_then_this_would_need(typeck_tables_of)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_then_this_would_need(typeck)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
   --> $DIR/dep-graph-type-alias.rs:35:5
@@ -67,8 +67,8 @@ LL |     #[rustc_then_this_would_need(fn_sig)]
 error: OK
   --> $DIR/dep-graph-type-alias.rs:44:5
    |
-LL |     #[rustc_then_this_would_need(typeck_tables_of)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
 
index 4e1e67c7f4809eedd117de9123730ecc6bf06db4..a5374aedab86bf505c4b575fdf0c1c3659230adb 100644 (file)
@@ -5,7 +5,6 @@ LL |     f5.ptr = *z;
    |     ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error: aborting due to previous error
index 0b6f9df2d83ee367656f58eef7faa62cea479631..f8d9300f11a310dc9ac357ceef2dc5f4e5522b85 100644 (file)
@@ -14,7 +14,6 @@ LL |     f5.2 = Bar1 {f: 36};
    |     ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error: aborting due to 2 previous errors
index 434c460759fb4c4192d54e31d09e7add449e9db2..8e3eeefb9ea66c178416a21c6da4426fffae60ff 100644 (file)
@@ -14,7 +14,6 @@ LL |     f5.ptr = Bar1 {f: 36};
    |     ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error: aborting due to 2 previous errors
index cb2735147a35b9cd1be8063c370256f308add7ba..d9d6ca3292311a243ab9c7d2e730db04e38f2ce8 100644 (file)
@@ -5,7 +5,6 @@ LL |     let h: &(([isize],),) = &(*g,);
    |                              ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `(([isize],),)`, the trait `std::marker::Sized` is not implemented for `[isize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `([isize],)`
    = note: required because it appears within the type `(([isize],),)`
    = note: tuples must have a statically known size to be initialized
index 521adf601cc701ed69556ccee978dd54b8f16a52..1304f04f82062d30af80ea882abd4ef75d7644bf 100644 (file)
@@ -5,7 +5,6 @@ LL |     let h: &Fat<Fat<[isize]>> = &Fat { ptr: *g };
    |                                  ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Fat<Fat<[isize]>>`, the trait `std::marker::Sized` is not implemented for `[isize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Fat<[isize]>`
    = note: required because it appears within the type `Fat<Fat<[isize]>>`
    = note: structs must have a statically known size to be initialized
index 80d188bf2f89bd6af372162e8324f1cf922f9644..da8ead885c8987002b18994fc327451918645e78 100644 (file)
@@ -6,8 +6,6 @@ LL | fn test1<T: ?Sized + Foo>(t: &T) {
 LL |     let u: &dyn Foo = t;
    |                       ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
@@ -18,8 +16,6 @@ LL | fn test2<T: ?Sized + Foo>(t: &T) {
 LL |     let v: &dyn Foo = t as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -29,7 +25,6 @@ LL |     let _: &[&dyn Foo] = &["hi"];
    |                            ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
@@ -39,7 +34,6 @@ LL |     let _: &dyn Foo = x as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error: aborting due to 4 previous errors
index 006a334021b1419428d1f9813cfd2f85318e382d..7e90e9ce1792dae953b7ac2a9dd6dae121de6728 100644 (file)
@@ -8,7 +8,6 @@ LL | impl Foo<[isize]> for usize { }
    |      ^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[isize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized
@@ -24,7 +23,6 @@ LL | impl Foo<isize> for [usize] { }
    |      ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[usize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 2 previous errors
 
index 9da3a5f5bdb3d053297b450bddbe1277d4829544..c0ba9716fb001fad97a8c798c86bc6fae05a9785 100644 (file)
@@ -6,14 +6,20 @@ LL | struct Empty1 {}
 ...
 LL |     let e1 = Empty1;
    |              ^^^^^^
-   |              |
-   |              did you mean `Empty1 { /* fields */ }`?
-   |              help: a unit struct with a similar name exists: `XEmpty2`
    | 
   ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
 LL | pub struct XEmpty2;
    | ------------------- similarly named unit struct `XEmpty2` defined here
+   |
+help: a unit struct with a similar name exists
+   |
+LL |     let e1 = XEmpty2;
+   |              ^^^^^^^
+help: use struct literal syntax instead
+   |
+LL |     let e1 = Empty1 {};
+   |              ^^^^^^^^^
 
 error[E0423]: expected function, tuple struct or tuple variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-expr.rs:16:14
@@ -22,15 +28,16 @@ LL | struct Empty1 {}
    | ---------------- `Empty1` defined here
 ...
 LL |     let e1 = Empty1();
-   |              ^^^^^^
-   |              |
-   |              did you mean `Empty1 { /* fields */ }`?
-   |              help: a unit struct with a similar name exists: `XEmpty2`
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:2:1
+   |              ^^^^^^^^
    |
-LL | pub struct XEmpty2;
-   | ------------------- similarly named unit struct `XEmpty2` defined here
+help: a unit struct with a similar name exists
+   |
+LL |     let e1 = XEmpty2();
+   |              ^^^^^^^
+help: use struct literal syntax instead
+   |
+LL |     let e1 = Empty1 {};
+   |              ^^^^^^^^^
 
 error[E0423]: expected value, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-expr.rs:18:14
@@ -39,7 +46,7 @@ LL |     Empty3 {}
    |     --------- `E::Empty3` defined here
 ...
 LL |     let e3 = E::Empty3;
-   |              ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
+   |              ^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}`
 
 error[E0423]: expected function, tuple struct or tuple variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-expr.rs:19:14
@@ -48,35 +55,42 @@ LL |     Empty3 {}
    |     --------- `E::Empty3` defined here
 ...
 LL |     let e3 = E::Empty3();
-   |              ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
+   |              ^^^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}`
 
 error[E0423]: expected value, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-expr.rs:22:15
    |
 LL |     let xe1 = XEmpty1;
    |               ^^^^^^^
-   |               |
-   |               did you mean `XEmpty1 { /* fields */ }`?
-   |               help: a unit struct with a similar name exists: `XEmpty2`
    | 
   ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
 LL | pub struct XEmpty2;
    | ------------------- similarly named unit struct `XEmpty2` defined here
+   |
+help: a unit struct with a similar name exists
+   |
+LL |     let xe1 = XEmpty2;
+   |               ^^^^^^^
+help: use struct literal syntax instead
+   |
+LL |     let xe1 = XEmpty1 {};
+   |               ^^^^^^^^^^
 
 error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-expr.rs:23:15
    |
 LL |     let xe1 = XEmpty1();
+   |               ^^^^^^^^^
+   |
+help: a unit struct with a similar name exists
+   |
+LL |     let xe1 = XEmpty2();
    |               ^^^^^^^
-   |               |
-   |               did you mean `XEmpty1 { /* fields */ }`?
-   |               help: a unit struct with a similar name exists: `XEmpty2`
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:2:1
+help: use struct literal syntax instead
    |
-LL | pub struct XEmpty2;
-   | ------------------- similarly named unit struct `XEmpty2` defined here
+LL |     let xe1 = XEmpty1 {};
+   |               ^^^^^^^^^^
 
 error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
   --> $DIR/empty-struct-braces-expr.rs:25:19
index 0ff21c91b78fd25980a09bb4490cf02491e9c1fd..b027c82f7dd37d600ebf8e705ddb6132993cf39c 100644 (file)
@@ -5,21 +5,27 @@ LL |     Empty3 {}
    |     --------- `E::Empty3` defined here
 ...
 LL |         E::Empty3 => ()
-   |         ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
+   |         ^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}`
 
 error[E0532]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-1.rs:31:9
    |
 LL |         XE::XEmpty3 => ()
-   |         ^^^^-------
-   |         |   |
-   |         |   help: a unit variant with a similar name exists: `XEmpty4`
-   |         did you mean `XE::XEmpty3 { /* fields */ }`?
+   |         ^^^^^^^^^^^
    | 
   ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
 LL |     XEmpty4,
    |     ------- similarly named unit variant `XEmpty4` defined here
+   |
+help: a unit variant with a similar name exists
+   |
+LL |         XE::XEmpty4 => ()
+   |             ^^^^^^^
+help: use struct pattern syntax instead
+   |
+LL |         XE::XEmpty3 { /* fields */ } => ()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 80c29db8d9b77a8d67fa6e741a50f234cda1a6e0..a53b88db7d1ed3725234d3bcd8d314e1583b9527 100644 (file)
@@ -5,29 +5,31 @@ LL | struct Empty1 {}
    | ---------------- `Empty1` defined here
 ...
 LL |         Empty1() => ()
-   |         ^^^^^^
-   |         |
-   |         did you mean `Empty1 { /* fields */ }`?
-   |         help: a tuple struct with a similar name exists: `XEmpty6`
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
-   |
-LL | pub struct XEmpty6();
-   | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |         ^^^^^^^^
+   |
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
+   |         ^^^^^^^
+help: use struct pattern syntax instead
+   |
+LL |         Empty1 {} => ()
+   |         ^^^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-pat-2.rs:18:9
    |
 LL |         XEmpty1() => ()
+   |         ^^^^^^^^^
+   |
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
    |         ^^^^^^^
-   |         |
-   |         did you mean `XEmpty1 { /* fields */ }`?
-   |         help: a tuple struct with a similar name exists: `XEmpty6`
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
-   |
-LL | pub struct XEmpty6();
-   | --------------------- similarly named tuple struct `XEmpty6` defined here
+help: use struct pattern syntax instead
+   |
+LL |         XEmpty1 {} => ()
+   |         ^^^^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-pat-2.rs:21:9
@@ -36,29 +38,31 @@ LL | struct Empty1 {}
    | ---------------- `Empty1` defined here
 ...
 LL |         Empty1(..) => ()
-   |         ^^^^^^
-   |         |
-   |         did you mean `Empty1 { /* fields */ }`?
-   |         help: a tuple struct with a similar name exists: `XEmpty6`
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
-   |
-LL | pub struct XEmpty6();
-   | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |         ^^^^^^^^^^
+   |
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
+   |         ^^^^^^^
+help: use struct pattern syntax instead
+   |
+LL |         Empty1 {} => ()
+   |         ^^^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-pat-2.rs:24:9
    |
 LL |         XEmpty1(..) => ()
+   |         ^^^^^^^^^^^
+   |
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
    |         ^^^^^^^
-   |         |
-   |         did you mean `XEmpty1 { /* fields */ }`?
-   |         help: a tuple struct with a similar name exists: `XEmpty6`
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
-   |
-LL | pub struct XEmpty6();
-   | --------------------- similarly named tuple struct `XEmpty6` defined here
+help: use struct pattern syntax instead
+   |
+LL |         XEmpty1 {} => ()
+   |         ^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
index 05439b39ea39dfe80e321b4dc2dead35cc412c5a..93ace3eccef91aefa755d15ce52eea838dfc86b8 100644 (file)
@@ -5,21 +5,22 @@ LL |     Empty3 {}
    |     --------- `E::Empty3` defined here
 ...
 LL |         E::Empty3() => ()
-   |         ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
+   |         ^^^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}`
 
 error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-3.rs:21:9
    |
 LL |         XE::XEmpty3() => ()
-   |         ^^^^-------
-   |         |   |
-   |         |   help: a tuple variant with a similar name exists: `XEmpty5`
-   |         did you mean `XE::XEmpty3 { /* fields */ }`?
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:8:5
-   |
-LL |     XEmpty5(),
-   |     --------- similarly named tuple variant `XEmpty5` defined here
+   |         ^^^^^^^^^^^^^
+   |
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5() => ()
+   |             ^^^^^^^
+help: use struct pattern syntax instead
+   |
+LL |         XE::XEmpty3 { /* fields */ } => ()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:25:9
@@ -28,21 +29,22 @@ LL |     Empty3 {}
    |     --------- `E::Empty3` defined here
 ...
 LL |         E::Empty3(..) => ()
-   |         ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
+   |         ^^^^^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}`
 
 error[E0532]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
   --> $DIR/empty-struct-braces-pat-3.rs:29:9
    |
 LL |         XE::XEmpty3(..) => ()
-   |         ^^^^-------
-   |         |   |
-   |         |   help: a tuple variant with a similar name exists: `XEmpty5`
-   |         did you mean `XE::XEmpty3 { /* fields */ }`?
-   | 
-  ::: $DIR/auxiliary/empty-struct.rs:8:5
-   |
-LL |     XEmpty5(),
-   |     --------- similarly named tuple variant `XEmpty5` defined here
+   |         ^^^^^^^^^^^^^^^
+   |
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5(..) => ()
+   |             ^^^^^^^
+help: use struct pattern syntax instead
+   |
+LL |         XE::XEmpty3 { /* fields */ } => ()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
index a9ea85d14cff5e2546df7774d4859cc7008f7b5a..203fc18915647fcbacbddbf9fa101a1e0b396dc9 100644 (file)
@@ -2,13 +2,15 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
   --> $DIR/E0277.rs:13:6
    |
 LL | fn f(p: Path) { }
-   |      ^ borrow the `Path` instead
+   |      ^ doesn't have a size known at compile-time
    |
    = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `std::path::Path`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn f(p: &Path) { }
+   |         ^
 
 error[E0277]: the trait bound `i32: Foo` is not satisfied
   --> $DIR/E0277.rs:17:15
index d4860394259b7e1aeac169d0d628c8926c42cac2..077367de9d847cb47af16ddb20e5d31bd9022abb 100644 (file)
@@ -33,13 +33,16 @@ LL |     struct Foo { a: bool };
    |     ---------------------- `Foo` defined here
 LL | 
 LL |     let f = Foo();
+   |             ^^^^^
+   |
+help: a function with a similar name exists
+   |
+LL |     let f = foo();
    |             ^^^
-   |             |
-   |             did you mean `Foo { /* fields */ }`?
-   |             help: a function with a similar name exists (notice the capitalization): `foo`
-...
-LL | fn foo() {
-   | -------- similarly named function `foo` defined here
+help: use struct literal syntax instead
+   |
+LL |     let f = Foo { a: val };
+   |             ^^^^^^^^^^^^^^
 
 error[E0423]: expected value, found struct `T`
   --> $DIR/E0423.rs:14:8
index 1380840e0db2d7da12c2d32565823c10118acd79..38736de8d9ac72d7c22b392c85ab1b025ef49445 100644 (file)
@@ -1,8 +1,8 @@
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/E0478.rs:4:5
+  --> $DIR/E0478.rs:4:12
    |
 LL |     child: Box<dyn Wedding<'kiss> + 'SnowWhite>,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined on the struct at 3:22
   --> $DIR/E0478.rs:3:22
index cc00737ab591d58231daafe8bc43e5ac45fed0ec..3ba124159e0002d41d448fa6bc885da5ffc118ad 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 #![allow(unused_variables)]
-// compile-flags: --extern LooksLikeExternCrate
+// compile-flags: --extern LooksLikeExternCrate=/path/to/nowhere
 
 mod m {
     pub struct LooksLikeExternCrate;
index 0c7995fde3273f838194afc92f360afe2fa229f0..8938afd33ffde90c3d9c55e6cf46deafc7723cef 100644 (file)
@@ -8,7 +8,6 @@ LL |     assert_sized::<A>();
    |                    ^ 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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn assert_sized<T: ?Sized>() { }
@@ -24,7 +23,6 @@ LL |     assert_sized::<Foo>();
    |     ^^^^^^^^^^^^^^^^^^^ 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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Foo`
 help: consider relaxing the implicit `Sized` restriction
    |
@@ -41,7 +39,6 @@ LL |     assert_sized::<Bar<A>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
 help: consider relaxing the implicit `Sized` restriction
    |
@@ -58,7 +55,6 @@ LL |     assert_sized::<Bar<Bar<A>>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Bar<Bar<A>>`, the trait `std::marker::Sized` is not implemented for `A`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
    = note: required because it appears within the type `Bar<Bar<A>>`
 help: consider relaxing the implicit `Sized` restriction
index add3a8e79267d5f588dc4fa9ba5953df5f17da77..5a58e57d36c706ba98983a40a8939ea86f183bb9 100644 (file)
@@ -5,7 +5,6 @@ LL |         static symbol: [usize];
    |                        ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[usize]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs
new file mode 100644 (file)
index 0000000..452b45b
--- /dev/null
@@ -0,0 +1,4 @@
+#[doc(spotlight)] //~ ERROR: `#[doc(spotlight)]` is experimental
+trait SomeTrait {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr
new file mode 100644 (file)
index 0000000..010d740
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: `#[doc(spotlight)]` is experimental
+  --> $DIR/feature-gate-doc_spotlight.rs:1:1
+   |
+LL | #[doc(spotlight)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #45040 <https://github.com/rust-lang/rust/issues/45040> for more information
+   = help: add `#![feature(doc_spotlight)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index 2beeba8184a7dfb0b3a7891fa222f6c2819c0ef2..987cde191cbb98431dc46b85f41800f15ecb026d 100644 (file)
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:5
+  --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:10
    |
 LL | struct Foo<U> {
    |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
-   |     ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index b4d4c992c9086dada5c1517953c2ecbc06eb6771..d4c09ec40fd926154140e23c0a2fe9486ea01fec 100644 (file)
@@ -95,7 +95,6 @@ LL | struct TwoStrs(str, str) where str: Sized;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
@@ -108,7 +107,6 @@ LL | | }
    | |_^ doesn't have a size known at compile-time
    |
    = help: within `Dst<(dyn A + 'static)>`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Dst<(dyn A + 'static)>`
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
@@ -122,7 +120,6 @@ LL | | }
    | |_^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = help: see issue #48214
    = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
 
index d20b9e2981e8cf7d1e7ca3e38b84e274ffc4e2cf..0195cc1481e74ce1adc170620a7d909bb8c3b9ce 100644 (file)
@@ -5,9 +5,11 @@ LL | fn f(f: dyn FnOnce()) {}
    |      ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn f(f: &dyn FnOnce()) {}
+   |         ^
 
 error: aborting due to previous error
 
index 3d0930da422432793e19ee60134b905bf1f858ae..195e77022992d567c856e58d58ac571405bf79c3 100644 (file)
@@ -66,8 +66,8 @@ macro_rules! yield250 {
 }
 
 fn cycle(
-    gen: impl Generator<()> + Unpin + DiscriminantKind<Discriminant = i32>,
-    expected_max_discr: i32
+    gen: impl Generator<()> + Unpin + DiscriminantKind<Discriminant = u32>,
+    expected_max_discr: u32
 ) {
     let mut gen = Box::pin(gen);
     let mut max_discr = 0;
index 79aeec2ec02801df72fd2e4385cb06989b4de022..379bd8ebd1cada3db5a4af9ab753152f12d673d1 100644 (file)
@@ -9,7 +9,6 @@ LL | |    };
    | |____^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the yield type of a generator must have a statically known size
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -19,7 +18,6 @@ LL |    Pin::new(&mut gen).resume(());
    |                       ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 2 previous errors
 
index 89cc5dfd06018fdc4502f744a271ed9b5e8e70a9..2fab7ffb66050b103e6a3a301dc897edfeb1a626 100644 (file)
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
index efd3287853f0302d0285a9f910a5a59c94d15d27..186e142138be2fe93c23b464061d224cac0acef2 100644 (file)
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
index 5da924a512f0099b9952652d3a462286377dd239..d16bdcbbb6b00d859da406fb85c4247487512801 100644 (file)
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
index 12d84ab6a369b4d234167159022b7c2850c0a7e6..72c42917c83c92a53cd953e56ac28ba32510fee9 100644 (file)
@@ -16,7 +16,6 @@ LL |     type F<'a>: Fn() -> u32;
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
    |
-   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
    = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
 help: consider restricting type parameter `T`
    |
index 95f4aa9e6dbaa749c272752699726ce9c8189d19..7a6c07d4e082e0f5b013861be53e27f712452a0e 100644 (file)
@@ -8,7 +8,6 @@ LL | impl Tsized for () {}
    |      ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[()]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
index 81164030d8eefbbfdd30719761603426177ef8b2..96044a89289464a86d01f8d1b44be3a9beb7741f 100644 (file)
 
 macro_rules! foo /* 0#0 */ { ($ x : ident) => { y + $ x } }
 
-fn bar /* 0#0 */() { let x /* 0#0 */ = 1; y /* 0#1 */ + x /* 0#0 */ }
+fn bar /* 0#0 */() {
+    let x /* 0#0 */ = 1;
+    y /* 0#1 */ + x /* 0#0 */
+}
 
 fn y /* 0#0 */() { }
 
index c55dbd7d2fafe9559d669780b399b9e2bc9d0929..96f961a2aaf6bd19c1029f3f7a6f8cf816ba8f34 100644 (file)
@@ -16,7 +16,6 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) }
    |             doesn't have a size known at compile-time
    |
    = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
@@ -38,7 +37,6 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
    |             doesn't have a size known at compile-time
    |
    = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/issues/auxiliary/issue-73112.rs b/src/test/ui/issues/auxiliary/issue-73112.rs
new file mode 100644 (file)
index 0000000..6210c29
--- /dev/null
@@ -0,0 +1,10 @@
+#[repr(transparent)]
+pub struct PageTableEntry {
+    entry: u64,
+}
+
+#[repr(align(4096))]
+#[repr(C)]
+pub struct PageTable {
+    entries: [PageTableEntry; 512],
+}
index d7a4bf4f21f18dc946084e62b64fa2ce0796d2f8..d241e6406d579080e67cfc6792716150a766c509 100644 (file)
@@ -56,7 +56,6 @@ LL | impl<'self> Serializable<str> for &'self str {
    |             ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait Serializable<'self, T: ?Sized> {
index 542d8a904c4e30299d8ac03fda271e094631f0f0..4e41acf433e599889fd76c95814411db40293920 100644 (file)
@@ -5,7 +5,6 @@ LL |     let _x = "test" as &dyn (::std::any::Any);
    |              ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::any::Any`
 
 error: aborting due to previous error
index 987bc512163d67c8d4d6ac4c7649df2de1907e6c..68ceebc5b651d2e334378a738a2924a41515c259 100644 (file)
@@ -5,7 +5,6 @@ LL |     &mut something
    |          ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[T]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
index c3445024c37529af1863ebaabeafe5884f91ccd9..812778911a865fde362eac5e410c57cbf3b11002 100644 (file)
@@ -5,7 +5,6 @@ LL |     (|| Box::new(*(&[0][..])))();
    |                  ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::boxed::Box::<T>::new`
 
 error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
@@ -15,7 +14,6 @@ LL |     (|| Box::new(*(&[0][..])))();
    |         ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
index 383cdd4979ad9ad46007915e25745e81e3b2d847..3b5dfd1ad158c27660af7b02c325e7a2d1d58f0e 100644 (file)
@@ -8,7 +8,6 @@ LL | enum Option<T> {
    |             - required by this bound in `Option`
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/issue-18919.rs:7:13
    |
index 27992da0ebd2f05b3cb92be638e27a38f0abc0f8..a54f1008e4ba9c9b915f935d38537b79ee42aa48 100644 (file)
@@ -5,7 +5,7 @@ LL |     FooB { x: i32, y: i32 }
    |     ----------------------- `FooB` defined here
 ...
 LL |         FooB(a, b) => println!("{} {}", a, b),
-   |         ^^^^ did you mean `FooB { /* fields */ }`?
+   |         ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }`
 
 error: aborting due to previous error
 
index 0a080171a795158e949f8f6e90dc8d18fe6380a5..63f0701974b8b1efe1b37028d63ad523c3f976c0 100644 (file)
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Qiz` cannot be made into an object
-  --> $DIR/issue-19380.rs:11:3
+  --> $DIR/issue-19380.rs:11:9
    |
 LL | trait Qiz {
    |       --- this trait cannot be made into an object...
@@ -7,7 +7,7 @@ LL |   fn qiz();
    |      --- ...because associated function `qiz` has no `self` parameter
 ...
 LL |   foos: &'static [&'static (dyn Qiz + 'static)]
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
    |
 help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
    |
index 775f9702401a66f140cd936c425b90d6daad056a..cbaa7507244a391cd4e70748b86b5e0ca8589f56 100644 (file)
@@ -7,8 +7,6 @@ LL | trait From<Src> {
 LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self> {
    |                                                 ^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: std::marker::Sized {
index 1dab637e489db29d2fbb7980ae53808d41c3201e..0e96b12066937aa43679beb3806910ec90b31e23 100644 (file)
@@ -10,7 +10,6 @@ LL | pub struct Vec<T> {
    |                - required by this bound in `std::vec::Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
index 5e050f27ac5465102ce295a3a328a148a9cd6715..5e06e3bc95c3655f9bb5f94e34604a52e05298b9 100644 (file)
@@ -5,7 +5,6 @@ LL |     for item in *things { *item = 0 }
    |                 ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator<Item = &'a mut u8>`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::iter::IntoIterator::into_iter`
 
 error: aborting due to previous error
index 229f99f90640ba01d8f1c25a88abe732affd77bb..6f22fe6a99717be6140539dfa6eded3bbd97b138 100644 (file)
@@ -1,11 +1,10 @@
 error[E0277]: the size for values of type `[std::string::String]` cannot be known at compilation time
-  --> $DIR/issue-22874.rs:2:5
+  --> $DIR/issue-22874.rs:2:11
    |
 LL |     rows: [[String]],
-   |     ^^^^^^^^^^^^^^^^ 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 `[std::string::String]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error: aborting due to previous error
index cffa52361696c93c21c41727c3a2befab1c64466..46b4be6fd36496adbb5719a647920f9f481d675e 100644 (file)
@@ -8,7 +8,6 @@ LL | struct Vec<T> {
    |            - required by this bound in `Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/issue-23281.rs:8:12
    |
index 344443e783038171bfdc1a71a8b6db9ac186a997..d2714408d8a39629cf0114d4072a64c9750f05bb 100644 (file)
@@ -5,7 +5,6 @@ LL |     static foo: dyn Fn() -> u32 = || -> u32 {
    |                 ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
index 1ddea73e00ae0ee214bec8bea40b715e919eded0..5dbcc96e87488440f6c70dec125ae5e6b7740289 100644 (file)
@@ -1,14 +1,21 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/issue-27060-2.rs:3:5
+  --> $DIR/issue-27060-2.rs:3:11
    |
 LL | pub struct Bad<T: ?Sized> {
    |                - this type parameter needs to be `std::marker::Sized`
 LL |     data: T,
-   |     ^^^^^^^ 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 `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     data: &T,
+   |           ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     data: Box<T>,
+   |           ^^^^ ^
 
 error: aborting due to previous error
 
index 3eb9d3c62039f0b945b1feacecd12d790205c135..de1810e99aac6c6f859a17b8d23c38442319afb7 100644 (file)
@@ -4,14 +4,15 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
 LL |     fn foo(self) -> &'static i32 {
    |            ^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting `Self`
    |
 LL |     fn foo(self) -> &'static i32 where Self: std::marker::Sized {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     fn foo(&self) -> &'static i32 {
+   |            ^
 
 error: aborting due to previous error
 
index 48b151c73c9565b147a975a9f8f0e39e3297243b..98de768a5a819af9a6442ee541631ca90eb96e6d 100644 (file)
@@ -5,7 +5,6 @@ LL |     &X(*Y)
    |      ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
index afe4d42edd8c8da6ec5b6931f4eb6aee65417c48..97905e2f8fa432532c2cecd8ea9c4a1e435b36cd 100644 (file)
@@ -1,11 +1,6 @@
 fn main () {
     let sr: Vec<(u32, _, _) = vec![];
     //~^ ERROR expected one of `,` or `>`, found `=`
-    //~| ERROR expected value, found struct `Vec`
-    //~| ERROR mismatched types
-    //~| ERROR invalid left-hand side of assignment
-    //~| ERROR expected expression, found reserved identifier `_`
-    //~| ERROR expected expression, found reserved identifier `_`
     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
-    //~^ ERROR no method named `iter` found
+    //~^ ERROR a value of type `std::vec::Vec<(u32, _, _)>` cannot be built
 }
index c68b271807b99597216be4bb9c5f55f4f4cd8e06..364f8264db463b8b64b5c077523070a3f1856969 100644 (file)
@@ -1,55 +1,19 @@
-error: expected expression, found reserved identifier `_`
-  --> $DIR/issue-34334.rs:2:23
-   |
-LL |     let sr: Vec<(u32, _, _) = vec![];
-   |                       ^ expected expression
-
-error: expected expression, found reserved identifier `_`
-  --> $DIR/issue-34334.rs:2:26
-   |
-LL |     let sr: Vec<(u32, _, _) = vec![];
-   |                          ^ expected expression
-
 error: expected one of `,` or `>`, found `=`
   --> $DIR/issue-34334.rs:2:29
    |
 LL |     let sr: Vec<(u32, _, _) = vec![];
-   |         ---                 ^ expected one of `,` or `>`
-   |         | |
-   |         | help: use `=` if you meant to assign
+   |         --                  ^ expected one of `,` or `>`
+   |         |
    |         while parsing the type for `sr`
 
-error[E0423]: expected value, found struct `Vec`
-  --> $DIR/issue-34334.rs:2:13
-   |
-LL |     let sr: Vec<(u32, _, _) = vec![];
-   |             ^^^ did you mean `Vec { /* fields */ }`?
-
-error[E0308]: mismatched types
-  --> $DIR/issue-34334.rs:2:31
-   |
-LL |     let sr: Vec<(u32, _, _) = vec![];
-   |                               ^^^^^^ expected `bool`, found struct `std::vec::Vec`
-   |
-   = note: expected type `bool`
-            found struct `std::vec::Vec<_>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0070]: invalid left-hand side of assignment
-  --> $DIR/issue-34334.rs:2:29
-   |
-LL |     let sr: Vec<(u32, _, _) = vec![];
-   |             --------------- ^
-   |             |
-   |             cannot assign to this expression
-
-error[E0599]: no method named `iter` found for unit type `()` in the current scope
-  --> $DIR/issue-34334.rs:9:36
+error[E0277]: a value of type `std::vec::Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()`
+  --> $DIR/issue-34334.rs:4:87
    |
 LL |     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
-   |                                    ^^^^ method not found in `()`
+   |                                                                                       ^^^^^^^ value of type `std::vec::Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
+   |
+   = help: the trait `std::iter::FromIterator<()>` is not implemented for `std::vec::Vec<(u32, _, _)>`
 
-error: aborting due to 7 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0070, E0308, E0423, E0599.
-For more information about an error, try `rustc --explain E0070`.
+For more information about this error, try `rustc --explain E0277`.
index 825c0de5e53ea945971674066b764463d26ae691..0f0b80a9ff8d3f00153e31a3cef2828341c624ae 100644 (file)
@@ -5,8 +5,16 @@ LL |     V([Box<E>]),
    |       ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box<E>]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     V(&[Box<E>]),
+   |       ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     V(Box<[Box<E>]>),
+   |       ^^^^        ^
 
 error: aborting due to previous error
 
index d3168ef9e4aaf2ada6c176152be95c66edfb66bc..e96bbe1a99312d369b30b3b1b0d810cdeaf4cda3 100644 (file)
@@ -5,9 +5,11 @@ LL | fn _test(ref _p: str) {}
    |          ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn _test(ref _p: &str) {}
+   |                  ^
 
 error: aborting due to previous error
 
index 9d854e4be9eadb94a59bb34a548de16e86e32f81..35aa1acdc1c9b04305d465eb88ba788ef9d002d8 100644 (file)
@@ -5,9 +5,11 @@ LL | pub fn example(ref s: str) {}
    |                ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | pub fn example(ref s: &str) {}
+   |                       ^
 
 error: aborting due to previous error
 
index 0d4797a7a067353359371a75bba3175e2d7a3e57..fbe87aa2dbee592a94511c0d05741462362b9b41 100644 (file)
@@ -5,13 +5,15 @@ LL |     fn baz(_: Self::Target) where Self: Deref {}
    |            ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<Self as std::ops::Deref>::Target`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 help: consider further restricting the associated type
    |
 LL |     fn baz(_: Self::Target) where Self: Deref, <Self as std::ops::Deref>::Target: std::marker::Sized {}
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     fn baz(_: &Self::Target) where Self: Deref {}
+   |               ^
 
 error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time
   --> $DIR/issue-42312.rs:8:10
@@ -20,9 +22,11 @@ LL | pub fn f(_: dyn ToString) {}
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | pub fn f(_: &dyn ToString) {}
+   |             ^
 
 error: aborting due to 2 previous errors
 
index 992c691bf21ef2cba62f36c07ce9e2e820777163..9205a518c8c3a59d296d166f3da0298505b6f110 100644 (file)
@@ -5,7 +5,6 @@ LL |     pub static mut symbol: [i8];
    |                            ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
index d886ecc11d17b6abb726ae9ace156011e29c69f1..897984d0ae410eb483502ad901f698e0d9e55336 100644 (file)
@@ -5,9 +5,11 @@ LL | fn new_struct(r: dyn A + 'static)
    |               ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn new_struct(r: &dyn A + 'static)
+   |                  ^
 
 error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
   --> $DIR/issue-5883.rs:8:8
@@ -19,7 +21,6 @@ LL |     Struct { r: r }
    |     --------------- this returned value is of type `Struct`
    |
    = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Struct`
    = note: the return type of a function must have a statically known size
 
index e7544934da0c83e8c4e228f7a952b2a7d9c11b1d..a2b11764a2fc64cfd46297caa3ab313676789d93 100644 (file)
@@ -1,7 +1,6 @@
 // edition:2018
 // run-pass
 // ignore-emscripten no threads support
-// ignore-sgx no thread sleep support
 
 use std::thread;
 use std::time::Duration;
index e54466faedde613e9b4327477c7c157d542cf09a..771a5c285aff8c578d49770ee811395dd3c4f527 100644 (file)
@@ -14,7 +14,7 @@ LL |     Struct{ s: i32 },
    |     ---------------- `MyEnum::Struct` defined here
 ...
 LL |         MyEnum::Struct => "",
-   |         ^^^^^^^^^^^^^^ did you mean `MyEnum::Struct { /* fields */ }`?
+   |         ^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `MyEnum::Struct { s }`
 
 error: aborting due to 2 previous errors
 
index 44e5d38abbc54a37467e4756b2c66cfc357a3213..12053d8a1291c3ae8ae3a089e370c7108ce35c3e 100644 (file)
@@ -5,11 +5,16 @@ LL | struct X {}
    | ----------- `X` defined here
 LL | 
 LL | const Y: X = X("ö");
-   | -------------^------
-   | |            |
-   | |            did you mean `X { /* fields */ }`?
-   | |            help: a constant with a similar name exists: `Y`
-   | similarly named constant `Y` defined here
+   |              ^^^^^^
+   |
+help: a constant with a similar name exists
+   |
+LL | const Y: X = Y("ö");
+   |              ^
+help: use struct literal syntax instead
+   |
+LL | const Y: X = X {};
+   |              ^^^^
 
 error: aborting due to previous error
 
index 114f2d62e561ad0204af45e6a342a927b5bf3ab6..fef64ebf2d365ebe7d463e2096faea63f0344437 100644 (file)
@@ -10,7 +10,6 @@ LL |     type Ctx = dyn Alias<T>;
    |                ^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-73112.rs b/src/test/ui/issues/issue-73112.rs
new file mode 100644 (file)
index 0000000..cc7be9c
--- /dev/null
@@ -0,0 +1,13 @@
+// aux-build:issue-73112.rs
+
+extern crate issue_73112;
+
+fn main() {
+    use issue_73112::PageTable;
+
+    #[repr(C, packed)]
+    struct SomeStruct {
+    //~^ ERROR packed type cannot transitively contain a `#[repr(align)]` type [E0588]
+        page_table: PageTable,
+    }
+}
diff --git a/src/test/ui/issues/issue-73112.stderr b/src/test/ui/issues/issue-73112.stderr
new file mode 100644 (file)
index 0000000..5a54837
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
+  --> $DIR/issue-73112.rs:9:5
+   |
+LL | /     struct SomeStruct {
+LL | |
+LL | |         page_table: PageTable,
+LL | |     }
+   | |_____^
+   |
+note: `PageTable` has a `#[repr(align)]` attribute
+  --> $DIR/auxiliary/issue-73112.rs:8:1
+   |
+LL | / pub struct PageTable {
+LL | |     entries: [PageTableEntry; 512],
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0588`.
diff --git a/src/test/ui/issues/issue-73886.rs b/src/test/ui/issues/issue-73886.rs
new file mode 100644 (file)
index 0000000..2f1ec8c
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    let _ = &&[0] as &[_];
+    //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]`
+    let _ = 7u32 as Option<_>;
+    //~^ ERROR non-primitive cast: `u32` as `std::option::Option<_>`
+}
diff --git a/src/test/ui/issues/issue-73886.stderr b/src/test/ui/issues/issue-73886.stderr
new file mode 100644 (file)
index 0000000..e8ab7db
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]`
+  --> $DIR/issue-73886.rs:2:13
+   |
+LL |     let _ = &&[0] as &[_];
+   |             ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error[E0605]: non-primitive cast: `u32` as `std::option::Option<_>`
+  --> $DIR/issue-73886.rs:4:13
+   |
+LL |     let _ = 7u32 as Option<_>;
+   |             ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0605`.
diff --git a/src/test/ui/issues/issue-74086.rs b/src/test/ui/issues/issue-74086.rs
new file mode 100644 (file)
index 0000000..f68a665
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    static BUG: fn(_) -> u8 = |_| 8;
+    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121]
+}
diff --git a/src/test/ui/issues/issue-74086.stderr b/src/test/ui/issues/issue-74086.stderr
new file mode 100644 (file)
index 0000000..4127f48
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/issue-74086.rs:2:20
+   |
+LL |     static BUG: fn(_) -> u8 = |_| 8;
+   |                    ^
+   |                    |
+   |                    not allowed in type signatures
+   |                    help: use type parameters instead: `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
index 27b5185377d97be2ef4fd6190189376504a12879..3e7e9a51cdd3ad044d8bee4281abad20283c0345 100644 (file)
@@ -2,7 +2,6 @@
 #![allow(unused_must_use)]
 #![allow(deprecated)]
 // ignore-emscripten no threads support
-// ignore-sgx no thread sleep support
 
 use std::sync::mpsc::{TryRecvError, channel};
 use std::thread;
index a2f70a8c24082dba0613c22cf0abc126e1871fc1..eb400cf061547ed13b5ca8c4cb518c0d6cf789d5 100644 (file)
@@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 help: consider restricting type parameter `T`
@@ -31,7 +30,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 help: consider restricting type parameter `T`
index cc98f1d9f34b805875efd2ef28dc3ef5c6d16946..ab9dfc9b8a7795bfc0f4d6fdd07353633fdbab1c 100644 (file)
@@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 help: consider restricting type parameter `T`
@@ -31,7 +30,6 @@ error[E0277]: `T` cannot be sent between threads safely
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 help: consider restricting type parameter `T`
index 6e19251c72800067151d91e803dfde45f56d515a..98bf9923823d7d7f34ceb588c6ebd262b6c8b1b0 100644 (file)
@@ -9,8 +9,6 @@ LL | fn test<T>() {
 LL |     let _: [u8; sof::<T>()];
    |                       ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | pub const fn sof<T: ?Sized>() -> usize {
index 1987f5890c0411a700faf4bd8ff4921887e9bca0..ce0495dd8b0cbaa3a0b137715e6d7f03122530f2 100644 (file)
@@ -8,10 +8,10 @@ LL | #![feature(lazy_normalization_consts)]
    = note: see issue #72219 <https://github.com/rust-lang/rust/issues/72219> for more information
 
 error: constant expression depends on a generic parameter
-  --> $DIR/issue-57739.rs:12:5
+  --> $DIR/issue-57739.rs:12:12
    |
 LL |     array: [u8; T::SIZE],
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^
    |
    = note: this may fail depending on what value the parameter takes
 
diff --git a/src/test/ui/lazy_normalization_consts/trait-resolution-breakage.rs b/src/test/ui/lazy_normalization_consts/trait-resolution-breakage.rs
new file mode 100644 (file)
index 0000000..df1c99e
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+
+trait Trait<T> {
+    const ASSOC_CONST: usize = 0;
+}
+
+impl Trait<()> for u8 {}
+
+// `u8::ASSOC_CONST` is resolved today, but will be ambiguous
+// under lazy normalization.
+fn foo<T, U>() -> [(T, U); u8::ASSOC_CONST]
+where
+    u8: Trait<T> + Trait<U>,
+{
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/lazy_normalization_consts/unevaluated-consts.rs b/src/test/ui/lazy_normalization_consts/unevaluated-consts.rs
new file mode 100644 (file)
index 0000000..3f90d22
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+
+// If we allow the parent generics here without using lazy normalization
+// this results in a cycle error.
+struct Foo<T, U>(T, U);
+
+impl<T> From<[u8; 1 + 1]> for Foo<T, [u8; 1 + 1]> {
+    fn from(value: [u8; 1 + 1]) -> Foo<T, [u8; 1 + 1]> {
+        todo!();
+    }
+}
+
+fn break_me<T>()
+where
+    [u8; 1 + 1]: From<[u8; 1 + 1]>
+{}
+
+fn main() {}
index d682478db0eeff8b302d2e0f9e54e44ffb3f3193..e5083e3a088b6b53be9e6b1f8d8976d8c47d31b2 100644 (file)
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:19:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10
    |
 LL | struct Foo<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     foo: &'static T
-   |     ^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |          ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error[E0309]: the parameter type `K` may not live long enough
   --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19
diff --git a/src/test/ui/lint/lint-ctypes-73747.rs b/src/test/ui/lint/lint-ctypes-73747.rs
new file mode 100644 (file)
index 0000000..293ffd5
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+
+#[repr(transparent)]
+struct NonNullRawComPtr<T: ComInterface> {
+    inner: std::ptr::NonNull<<T as ComInterface>::VTable>,
+}
+
+trait ComInterface {
+    type VTable;
+}
+
+extern "C" fn invoke<T: ComInterface>(_: Option<NonNullRawComPtr<T>>) {}
+
+fn main() {}
index 67dd7abcf79ef2b7f648fa298ebdfa2957f6ab51..aa02e578663286e4add09881b496b47a5a247af5 100644 (file)
@@ -71,7 +71,8 @@ pub extern "C" fn str_type(p: &str) { }
 //~^ ERROR: uses type `str`
 
 pub extern "C" fn box_type(p: Box<u32>) { }
-//~^ ERROR uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn opt_box_type(p: Option<Box<u32>>) { }
 
 pub extern "C" fn char_type(p: char) { }
 //~^ ERROR uses type `char`
@@ -106,7 +107,6 @@ pub extern "C" fn fn_type2(p: fn()) { }
 //~^ ERROR uses type `fn()`
 
 pub extern "C" fn fn_contained(p: RustBadRet) { }
-//~^ ERROR: uses type `std::boxed::Box<u32>`
 
 pub extern "C" fn transparent_i128(p: TransparentI128) { }
 //~^ ERROR: uses type `i128`
@@ -115,7 +115,6 @@ pub extern "C" fn transparent_str(p: TransparentStr) { }
 //~^ ERROR: uses type `str`
 
 pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
-//~^ ERROR: uses type `std::boxed::Box<u32>`
 
 pub extern "C" fn good3(fptr: Option<extern fn()>) { }
 
index 66cf195327890e40fd95e15d4a9450ef354b6fc2..d0a449514e50ef767db39de3abc0817ba96eeab5 100644 (file)
@@ -21,17 +21,8 @@ LL | pub extern "C" fn str_type(p: &str) { }
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
 
-error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:73:31
-   |
-LL | pub extern "C" fn box_type(p: Box<u32>) { }
-   |                               ^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
 error: `extern` fn uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:76:32
+  --> $DIR/lint-ctypes-fn.rs:77:32
    |
 LL | pub extern "C" fn char_type(p: char) { }
    |                                ^^^^ not FFI-safe
@@ -40,7 +31,7 @@ LL | pub extern "C" fn char_type(p: char) { }
    = note: the `char` type has no C equivalent
 
 error: `extern` fn uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:79:32
+  --> $DIR/lint-ctypes-fn.rs:80:32
    |
 LL | pub extern "C" fn i128_type(p: i128) { }
    |                                ^^^^ not FFI-safe
@@ -48,7 +39,7 @@ LL | pub extern "C" fn i128_type(p: i128) { }
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` fn uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:82:32
+  --> $DIR/lint-ctypes-fn.rs:83:32
    |
 LL | pub extern "C" fn u128_type(p: u128) { }
    |                                ^^^^ not FFI-safe
@@ -56,7 +47,7 @@ LL | pub extern "C" fn u128_type(p: u128) { }
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:85:33
+  --> $DIR/lint-ctypes-fn.rs:86:33
    |
 LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    |                                 ^^^^^^^^^^ not FFI-safe
@@ -65,7 +56,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:88:34
+  --> $DIR/lint-ctypes-fn.rs:89:34
    |
 LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    |                                  ^^^^^^^ not FFI-safe
@@ -74,7 +65,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:91:32
+  --> $DIR/lint-ctypes-fn.rs:92:32
    |
 LL | pub extern "C" fn zero_size(p: ZeroSize) { }
    |                                ^^^^^^^^ not FFI-safe
@@ -88,7 +79,7 @@ LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:94:40
+  --> $DIR/lint-ctypes-fn.rs:95:40
    |
 LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -101,7 +92,7 @@ LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:97:51
+  --> $DIR/lint-ctypes-fn.rs:98:51
    |
 LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    |                                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -109,7 +100,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:102:30
+  --> $DIR/lint-ctypes-fn.rs:103:30
    |
 LL | pub extern "C" fn fn_type(p: RustFn) { }
    |                              ^^^^^^ not FFI-safe
@@ -118,7 +109,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:105:31
+  --> $DIR/lint-ctypes-fn.rs:106:31
    |
 LL | pub extern "C" fn fn_type2(p: fn()) { }
    |                               ^^^^ not FFI-safe
@@ -126,15 +117,6 @@ LL | pub extern "C" fn fn_type2(p: fn()) { }
    = help: consider using an `extern fn(...) -> ...` function pointer instead
    = note: this function pointer has Rust-specific calling convention
 
-error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:108:35
-   |
-LL | pub extern "C" fn fn_contained(p: RustBadRet) { }
-   |                                   ^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
 error: `extern` fn uses type `i128`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:111:39
    |
@@ -152,17 +134,8 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
 
-error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:117:37
-   |
-LL | pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
-   |                                     ^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
-   = note: this struct has unspecified layout
-
 error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:161:43
+  --> $DIR/lint-ctypes-fn.rs:160:43
    |
 LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    |                                           ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -170,7 +143,7 @@ LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:174:39
+  --> $DIR/lint-ctypes-fn.rs:173:39
    |
 LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    |                                       ^^^^^^ not FFI-safe
@@ -179,7 +152,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    = note: this struct has unspecified layout
 
 error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:177:41
+  --> $DIR/lint-ctypes-fn.rs:176:41
    |
 LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
    |                                         ^^^^^^ not FFI-safe
@@ -187,5 +160,5 @@ LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
-error: aborting due to 20 previous errors
+error: aborting due to 17 previous errors
 
index a439a1f339aea6e6521600683dc947f522232cae..bdf95350c70451c6a82eb66a03c8332f790b95e8 100644 (file)
@@ -48,6 +48,8 @@ pub struct StructWithProjectionAndLifetime<'a>(
     pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
     pub fn str_type(p: &str); //~ ERROR: uses type `str`
     pub fn box_type(p: Box<u32>); //~ ERROR uses type `std::boxed::Box<u32>`
+    pub fn opt_box_type(p: Option<Box<u32>>);
+    //~^ ERROR uses type `std::option::Option<std::boxed::Box<u32>>`
     pub fn char_type(p: char); //~ ERROR uses type `char`
     pub fn i128_type(p: i128); //~ ERROR uses type `i128`
     pub fn u128_type(p: u128); //~ ERROR uses type `u128`
index 9821f858d9caf26dd995b4d5242bea3186a5005a..13b9adca3f9f5af7c4cd86f6d369daac55ae66b8 100644 (file)
@@ -58,8 +58,17 @@ LL |     pub fn box_type(p: Box<u32>);
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
+error: `extern` block uses type `std::option::Option<std::boxed::Box<u32>>`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:51:28
+   |
+LL |     pub fn opt_box_type(p: Option<Box<u32>>);
+   |                            ^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
+
 error: `extern` block uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:51:25
+  --> $DIR/lint-ctypes.rs:53:25
    |
 LL |     pub fn char_type(p: char);
    |                         ^^^^ not FFI-safe
@@ -68,7 +77,7 @@ LL |     pub fn char_type(p: char);
    = note: the `char` type has no C equivalent
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:52:25
+  --> $DIR/lint-ctypes.rs:54:25
    |
 LL |     pub fn i128_type(p: i128);
    |                         ^^^^ not FFI-safe
@@ -76,7 +85,7 @@ LL |     pub fn i128_type(p: i128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:53:25
+  --> $DIR/lint-ctypes.rs:55:25
    |
 LL |     pub fn u128_type(p: u128);
    |                         ^^^^ not FFI-safe
@@ -84,7 +93,7 @@ LL |     pub fn u128_type(p: u128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:54:26
+  --> $DIR/lint-ctypes.rs:56:26
    |
 LL |     pub fn trait_type(p: &dyn Clone);
    |                          ^^^^^^^^^^ not FFI-safe
@@ -92,7 +101,7 @@ LL |     pub fn trait_type(p: &dyn Clone);
    = note: trait objects have no C equivalent
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:55:26
+  --> $DIR/lint-ctypes.rs:57:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
    |                          ^^^^^^^^^^ not FFI-safe
@@ -101,7 +110,7 @@ LL |     pub fn tuple_type(p: (i32, i32));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:56:27
+  --> $DIR/lint-ctypes.rs:58:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
    |                           ^^^^^^^ not FFI-safe
@@ -110,7 +119,7 @@ LL |     pub fn tuple_type2(p: I32Pair);
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:57:25
+  --> $DIR/lint-ctypes.rs:59:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
    |                         ^^^^^^^^ not FFI-safe
@@ -124,7 +133,7 @@ LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:58:33
+  --> $DIR/lint-ctypes.rs:60:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -137,7 +146,7 @@ LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:61:12
+  --> $DIR/lint-ctypes.rs:63:12
    |
 LL |         -> ::std::marker::PhantomData<bool>;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -145,7 +154,7 @@ LL |         -> ::std::marker::PhantomData<bool>;
    = note: composed only of `PhantomData`
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:62:23
+  --> $DIR/lint-ctypes.rs:64:23
    |
 LL |     pub fn fn_type(p: RustFn);
    |                       ^^^^^^ not FFI-safe
@@ -154,7 +163,7 @@ LL |     pub fn fn_type(p: RustFn);
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:63:24
+  --> $DIR/lint-ctypes.rs:65:24
    |
 LL |     pub fn fn_type2(p: fn());
    |                        ^^^^ not FFI-safe
@@ -163,7 +172,7 @@ LL |     pub fn fn_type2(p: fn());
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:64:28
+  --> $DIR/lint-ctypes.rs:66:28
    |
 LL |     pub fn fn_contained(p: RustBadRet);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -172,7 +181,7 @@ LL |     pub fn fn_contained(p: RustBadRet);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:65:32
+  --> $DIR/lint-ctypes.rs:67:32
    |
 LL |     pub fn transparent_i128(p: TransparentI128);
    |                                ^^^^^^^^^^^^^^^ not FFI-safe
@@ -180,7 +189,7 @@ LL |     pub fn transparent_i128(p: TransparentI128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:66:31
+  --> $DIR/lint-ctypes.rs:68:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
    |                               ^^^^^^^^^^^^^^ not FFI-safe
@@ -189,7 +198,7 @@ LL |     pub fn transparent_str(p: TransparentStr);
    = note: string slices have no C equivalent
 
 error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:67:30
+  --> $DIR/lint-ctypes.rs:69:30
    |
 LL |     pub fn transparent_fn(p: TransparentBadFn);
    |                              ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -198,7 +207,7 @@ LL |     pub fn transparent_fn(p: TransparentBadFn);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:68:27
+  --> $DIR/lint-ctypes.rs:70:27
    |
 LL |     pub fn raw_array(arr: [u8; 8]);
    |                           ^^^^^^^ not FFI-safe
@@ -207,7 +216,7 @@ LL |     pub fn raw_array(arr: [u8; 8]);
    = note: passing raw arrays by value is not FFI-safe
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:70:34
+  --> $DIR/lint-ctypes.rs:72:34
    |
 LL |     pub static static_u128_type: u128;
    |                                  ^^^^ not FFI-safe
@@ -215,12 +224,12 @@ LL |     pub static static_u128_type: u128;
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:71:40
+  --> $DIR/lint-ctypes.rs:73:40
    |
 LL |     pub static static_u128_array_type: [u128; 16];
    |                                        ^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: aborting due to 23 previous errors
+error: aborting due to 24 previous errors
 
index 473be434a7524931c374fe960c661e17176f3ded..78d3060886dd0e73cf33b5ab38af8b239570aed9 100644 (file)
@@ -23,6 +23,18 @@ enum WrapEnum<T> { Wrapped(T) }
 #[repr(transparent)]
 pub(crate) struct NonBig(u64);
 
+/// A two-variant enum, thus needs a tag and may not remain uninitialized.
+enum Fruit {
+    Apple,
+    Banana,
+}
+
+/// Looks like two variants but really only has one.
+enum OneFruit {
+    Apple(!),
+    Banana,
+}
+
 #[allow(unused)]
 fn generic<T: 'static>() {
     unsafe {
@@ -80,6 +92,9 @@ fn main() {
         let _val: NonBig = mem::zeroed();
         let _val: NonBig = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
 
+        let _val: Fruit = mem::zeroed();
+        let _val: Fruit = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
         // Transmute-from-0
         let _val: &'static i32 = mem::transmute(0usize); //~ ERROR: does not permit zero-initialization
         let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization
@@ -96,5 +111,9 @@ fn main() {
         let _val: MaybeUninit<&'static i32> = mem::zeroed();
         let _val: i32 = mem::zeroed();
         let _val: bool = MaybeUninit::zeroed().assume_init();
+        // Some things that happen to work due to rustc implementation details,
+        // but are not guaranteed to keep working.
+        let _val: i32 = mem::uninitialized();
+        let _val: OneFruit = mem::uninitialized();
     }
 }
index bf0562713a497f1667792a8a37d2e2a7c512f7cf..3bf8a66ab0ae5268c2f4035de4eed89d32ee050e 100644 (file)
@@ -1,5 +1,5 @@
 error: the type `&T` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:29:32
+  --> $DIR/uninitialized-zeroed.rs:41:32
    |
 LL |         let _val: &'static T = mem::zeroed();
    |                                ^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | #![deny(invalid_value)]
    = note: references must be non-null
 
 error: the type `&T` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:30:32
+  --> $DIR/uninitialized-zeroed.rs:42:32
    |
 LL |         let _val: &'static T = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |         let _val: &'static T = mem::uninitialized();
    = note: references must be non-null
 
 error: the type `Wrap<&T>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:32:38
+  --> $DIR/uninitialized-zeroed.rs:44:38
    |
 LL |         let _val: Wrap<&'static T> = mem::zeroed();
    |                                      ^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `Wrap<&T>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:33:38
+  --> $DIR/uninitialized-zeroed.rs:45:38
    |
 LL |         let _val: Wrap<&'static T> = mem::uninitialized();
    |                                      ^^^^^^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `!` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:40:23
+  --> $DIR/uninitialized-zeroed.rs:52:23
    |
 LL |         let _val: ! = mem::zeroed();
    |                       ^^^^^^^^^^^^^
@@ -67,7 +67,7 @@ LL |         let _val: ! = mem::zeroed();
    = note: the `!` type has no valid value
 
 error: the type `!` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:41:23
+  --> $DIR/uninitialized-zeroed.rs:53:23
    |
 LL |         let _val: ! = mem::uninitialized();
    |                       ^^^^^^^^^^^^^^^^^^^^
@@ -78,7 +78,7 @@ LL |         let _val: ! = mem::uninitialized();
    = note: the `!` type has no valid value
 
 error: the type `(i32, !)` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:43:30
+  --> $DIR/uninitialized-zeroed.rs:55:30
    |
 LL |         let _val: (i32, !) = mem::zeroed();
    |                              ^^^^^^^^^^^^^
@@ -89,7 +89,7 @@ LL |         let _val: (i32, !) = mem::zeroed();
    = note: the `!` type has no valid value
 
 error: the type `(i32, !)` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:44:30
+  --> $DIR/uninitialized-zeroed.rs:56:30
    |
 LL |         let _val: (i32, !) = mem::uninitialized();
    |                              ^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |         let _val: (i32, !) = mem::uninitialized();
    = note: the `!` type has no valid value
 
 error: the type `Void` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:46:26
+  --> $DIR/uninitialized-zeroed.rs:58:26
    |
 LL |         let _val: Void = mem::zeroed();
    |                          ^^^^^^^^^^^^^
@@ -111,7 +111,7 @@ LL |         let _val: Void = mem::zeroed();
    = note: enums with no variants have no valid value
 
 error: the type `Void` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:47:26
+  --> $DIR/uninitialized-zeroed.rs:59:26
    |
 LL |         let _val: Void = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -122,7 +122,7 @@ LL |         let _val: Void = mem::uninitialized();
    = note: enums with no variants have no valid value
 
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:49:34
+  --> $DIR/uninitialized-zeroed.rs:61:34
    |
 LL |         let _val: &'static i32 = mem::zeroed();
    |                                  ^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL |         let _val: &'static i32 = mem::zeroed();
    = note: references must be non-null
 
 error: the type `&i32` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:50:34
+  --> $DIR/uninitialized-zeroed.rs:62:34
    |
 LL |         let _val: &'static i32 = mem::uninitialized();
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL |         let _val: &'static i32 = mem::uninitialized();
    = note: references must be non-null
 
 error: the type `Ref` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:52:25
+  --> $DIR/uninitialized-zeroed.rs:64:25
    |
 LL |         let _val: Ref = mem::zeroed();
    |                         ^^^^^^^^^^^^^
@@ -159,7 +159,7 @@ LL | struct Ref(&'static i32);
    |            ^^^^^^^^^^^^
 
 error: the type `Ref` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:53:25
+  --> $DIR/uninitialized-zeroed.rs:65:25
    |
 LL |         let _val: Ref = mem::uninitialized();
    |                         ^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +174,7 @@ LL | struct Ref(&'static i32);
    |            ^^^^^^^^^^^^
 
 error: the type `fn()` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:55:26
+  --> $DIR/uninitialized-zeroed.rs:67:26
    |
 LL |         let _val: fn() = mem::zeroed();
    |                          ^^^^^^^^^^^^^
@@ -185,7 +185,7 @@ LL |         let _val: fn() = mem::zeroed();
    = note: function pointers must be non-null
 
 error: the type `fn()` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:56:26
+  --> $DIR/uninitialized-zeroed.rs:68:26
    |
 LL |         let _val: fn() = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -196,7 +196,7 @@ LL |         let _val: fn() = mem::uninitialized();
    = note: function pointers must be non-null
 
 error: the type `Wrap<fn()>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:58:32
+  --> $DIR/uninitialized-zeroed.rs:70:32
    |
 LL |         let _val: Wrap<fn()> = mem::zeroed();
    |                                ^^^^^^^^^^^^^
@@ -211,7 +211,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `Wrap<fn()>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:59:32
+  --> $DIR/uninitialized-zeroed.rs:71:32
    |
 LL |         let _val: Wrap<fn()> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -226,7 +226,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `WrapEnum<fn()>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:61:36
+  --> $DIR/uninitialized-zeroed.rs:73:36
    |
 LL |         let _val: WrapEnum<fn()> = mem::zeroed();
    |                                    ^^^^^^^^^^^^^
@@ -241,7 +241,7 @@ LL | enum WrapEnum<T> { Wrapped(T) }
    |                            ^
 
 error: the type `WrapEnum<fn()>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:62:36
+  --> $DIR/uninitialized-zeroed.rs:74:36
    |
 LL |         let _val: WrapEnum<fn()> = mem::uninitialized();
    |                                    ^^^^^^^^^^^^^^^^^^^^
@@ -256,7 +256,7 @@ LL | enum WrapEnum<T> { Wrapped(T) }
    |                            ^
 
 error: the type `Wrap<(RefPair, i32)>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:64:42
+  --> $DIR/uninitialized-zeroed.rs:76:42
    |
 LL |         let _val: Wrap<(RefPair, i32)> = mem::zeroed();
    |                                          ^^^^^^^^^^^^^
@@ -271,7 +271,7 @@ LL | struct RefPair((&'static i32, i32));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: the type `Wrap<(RefPair, i32)>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:65:42
+  --> $DIR/uninitialized-zeroed.rs:77:42
    |
 LL |         let _val: Wrap<(RefPair, i32)> = mem::uninitialized();
    |                                          ^^^^^^^^^^^^^^^^^^^^
@@ -286,7 +286,7 @@ LL | struct RefPair((&'static i32, i32));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: the type `std::ptr::NonNull<i32>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:67:34
+  --> $DIR/uninitialized-zeroed.rs:79:34
    |
 LL |         let _val: NonNull<i32> = mem::zeroed();
    |                                  ^^^^^^^^^^^^^
@@ -297,7 +297,7 @@ LL |         let _val: NonNull<i32> = mem::zeroed();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `std::ptr::NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:68:34
+  --> $DIR/uninitialized-zeroed.rs:80:34
    |
 LL |         let _val: NonNull<i32> = mem::uninitialized();
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -308,7 +308,7 @@ LL |         let _val: NonNull<i32> = mem::uninitialized();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `*const dyn std::marker::Send` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:70:37
+  --> $DIR/uninitialized-zeroed.rs:82:37
    |
 LL |         let _val: *const dyn Send = mem::zeroed();
    |                                     ^^^^^^^^^^^^^
@@ -319,7 +319,7 @@ LL |         let _val: *const dyn Send = mem::zeroed();
    = note: the vtable of a wide raw pointer must be non-null
 
 error: the type `*const dyn std::marker::Send` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:71:37
+  --> $DIR/uninitialized-zeroed.rs:83:37
    |
 LL |         let _val: *const dyn Send = mem::uninitialized();
    |                                     ^^^^^^^^^^^^^^^^^^^^
@@ -330,7 +330,7 @@ LL |         let _val: *const dyn Send = mem::uninitialized();
    = note: the vtable of a wide raw pointer must be non-null
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:75:26
+  --> $DIR/uninitialized-zeroed.rs:87:26
    |
 LL |         let _val: bool = mem::uninitialized();
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -341,7 +341,7 @@ LL |         let _val: bool = mem::uninitialized();
    = note: booleans must be either `true` or `false`
 
 error: the type `Wrap<char>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:78:32
+  --> $DIR/uninitialized-zeroed.rs:90:32
    |
 LL |         let _val: Wrap<char> = mem::uninitialized();
    |                                ^^^^^^^^^^^^^^^^^^^^
@@ -356,7 +356,7 @@ LL | struct Wrap<T> { wrapped: T }
    |                  ^^^^^^^^^^
 
 error: the type `NonBig` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:81:28
+  --> $DIR/uninitialized-zeroed.rs:93:28
    |
 LL |         let _val: NonBig = mem::uninitialized();
    |                            ^^^^^^^^^^^^^^^^^^^^
@@ -366,8 +366,26 @@ LL |         let _val: NonBig = mem::uninitialized();
    |
    = note: `NonBig` must be initialized inside its custom valid range
 
+error: the type `Fruit` does not permit being left uninitialized
+  --> $DIR/uninitialized-zeroed.rs:96:27
+   |
+LL |         let _val: Fruit = mem::uninitialized();
+   |                           ^^^^^^^^^^^^^^^^^^^^
+   |                           |
+   |                           this code causes undefined behavior when executed
+   |                           help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+   |
+note: enums have to be initialized to a variant
+  --> $DIR/uninitialized-zeroed.rs:27:1
+   |
+LL | / enum Fruit {
+LL | |     Apple,
+LL | |     Banana,
+LL | | }
+   | |_^
+
 error: the type `&i32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:84:34
+  --> $DIR/uninitialized-zeroed.rs:99:34
    |
 LL |         let _val: &'static i32 = mem::transmute(0usize);
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
@@ -378,7 +396,7 @@ LL |         let _val: &'static i32 = mem::transmute(0usize);
    = note: references must be non-null
 
 error: the type `&[i32]` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:85:36
+  --> $DIR/uninitialized-zeroed.rs:100:36
    |
 LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -389,7 +407,7 @@ LL |         let _val: &'static [i32] = mem::transmute((0usize, 0usize));
    = note: references must be non-null
 
 error: the type `std::num::NonZeroU32` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:86:32
+  --> $DIR/uninitialized-zeroed.rs:101:32
    |
 LL |         let _val: NonZeroU32 = mem::transmute(0);
    |                                ^^^^^^^^^^^^^^^^^
@@ -400,7 +418,7 @@ LL |         let _val: NonZeroU32 = mem::transmute(0);
    = note: `std::num::NonZeroU32` must be non-null
 
 error: the type `std::ptr::NonNull<i32>` does not permit zero-initialization
-  --> $DIR/uninitialized-zeroed.rs:89:34
+  --> $DIR/uninitialized-zeroed.rs:104:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -411,7 +429,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `std::ptr::NonNull<i32>` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:90:34
+  --> $DIR/uninitialized-zeroed.rs:105:34
    |
 LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -422,7 +440,7 @@ LL |         let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
    = note: `std::ptr::NonNull<i32>` must be non-null
 
 error: the type `bool` does not permit being left uninitialized
-  --> $DIR/uninitialized-zeroed.rs:91:26
+  --> $DIR/uninitialized-zeroed.rs:106:26
    |
 LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -432,5 +450,5 @@ LL |         let _val: bool = MaybeUninit::uninit().assume_init();
    |
    = note: booleans must be either `true` or `false`
 
-error: aborting due to 35 previous errors
+error: aborting due to 36 previous errors
 
index 95936de218b8fe5d25de453501655ddde3c5ba76..71abda520653e56b14eed5bbf1356b582530580a 100644 (file)
@@ -209,7 +209,6 @@ LL |     let _ = fat_v as *const dyn Foo;
    |             ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -219,7 +218,6 @@ LL |     let _ = a as *const dyn Foo;
    |             ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0606]: casting `&{float}` as `f32` is invalid
index 24b6b55db6692fe286045cc3290ec9523c63e566..40304a674a63365b6e6321fd16128427b0ce0326 100644 (file)
@@ -2,8 +2,7 @@
 
 fn main() {
     if let S { a, b, c, d } = S(1, 2, 3, 4) {
-    //~^ ERROR struct `S` does not have fields named `a`, `b`, `c`, `d` [E0026]
-    //~| ERROR pattern does not mention fields `0`, `1`, `2`, `3` [E0027]
+    //~^ ERROR tuple variant `S` written as struct variant
         println!("hi");
     }
 }
index f7037468996f43c296692a92fb98af24d3e81376..6583524aad18f9ba401e3a9e9310549adaf2a9ad 100644 (file)
@@ -1,18 +1,9 @@
-error[E0026]: struct `S` does not have fields named `a`, `b`, `c`, `d`
-  --> $DIR/missing-fields-in-struct-pattern.rs:4:16
-   |
-LL |     if let S { a, b, c, d } = S(1, 2, 3, 4) {
-   |                ^  ^  ^  ^ struct `S` does not have these fields
-
-error[E0027]: pattern does not mention fields `0`, `1`, `2`, `3`
+error[E0769]: tuple variant `S` written as struct variant
   --> $DIR/missing-fields-in-struct-pattern.rs:4:12
    |
 LL |     if let S { a, b, c, d } = S(1, 2, 3, 4) {
-   |            ^^^^^^^^^^^^^^^^ missing fields `0`, `1`, `2`, `3`
-   |
-   = note: trying to match a tuple variant with a struct variant pattern
+   |            ^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `S(a, b, c, d)`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0026, E0027.
-For more information about an error, try `rustc --explain E0026`.
+For more information about this error, try `rustc --explain E0769`.
index bce5fdcd119f72b3bef5d00e5ee3726bcb8dfbd8..a889542fec0be8a673acdb4ae1299898771c8759 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 // compile-flags:--test
 // ignore-emscripten
-// ignore-sgx no thread sleep support
 
 use std::sync::mpsc::channel;
 use std::sync::mpsc::TryRecvError;
@@ -37,6 +36,8 @@ fn new2() -> (Barrier, Barrier) {
     fn wait(self) {
         self.shared.fetch_add(1, Ordering::SeqCst);
         while self.shared.load(Ordering::SeqCst) != self.count {
+            #[cfg(target_env = "sgx")]
+            thread::yield_now();
         }
     }
 }
index ee730910ee44153be90e0c503aaa40b825cfacd0..636789c9cc3004714f54843a4af0574e6b5834fc 100644 (file)
@@ -51,12 +51,16 @@ LL |         TV(),
    |         ---- similarly named tuple variant `TV` defined here
 ...
 LL |     check(m7::V);
-   |           ^^^^^ did you mean `m7::V { /* fields */ }`?
+   |           ^^^^^
    |
 help: a tuple variant with a similar name exists
    |
 LL |     check(m7::TV);
    |               ^^
+help: use struct literal syntax instead
+   |
+LL |     check(m7::V {});
+   |           ^^^^^^^^
 help: consider importing one of these items instead
    |
 LL | use m8::V;
@@ -68,7 +72,7 @@ error[E0423]: expected value, found struct variant `xm7::V`
   --> $DIR/namespace-mix.rs:106:11
    |
 LL |     check(xm7::V);
-   |           ^^^^^^ did you mean `xm7::V { /* fields */ }`?
+   |           ^^^^^^
    | 
   ::: $DIR/auxiliary/namespace-mix.rs:7:9
    |
@@ -79,6 +83,10 @@ help: a tuple variant with a similar name exists
    |
 LL |     check(xm7::TV);
    |                ^^
+help: use struct literal syntax instead
+   |
+LL |     check(xm7::V { /* fields */ });
+   |           ^^^^^^^^^^^^^^^^^^^^^^^
 help: consider importing one of these items instead
    |
 LL | use m8::V;
index 0272326c7bc4fd033c896da823972846f4c9d2ef..6986d966d69ecb9c00754cb45678b567a7dce264 100644 (file)
@@ -16,7 +16,7 @@ LL |     Foo { a: usize, b: usize },
    |     -------------------------- `Enum::Foo` defined here
 ...
 LL |         Enum::Foo(a, b) => {}
-   |         ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`?
+   |         ^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `Enum::Foo { a, b }`
 
 error: aborting due to 2 previous errors
 
index d0018cef5f03396979509710ba4b5415d23ad6a4..6e87e5c6912c3b925c82a3c3a46c4547e025be36 100644 (file)
@@ -5,7 +5,7 @@ error: internal compiler error: unexpected panic
 
 note: the compiler unexpectedly panicked. this is a bug.
 
-note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
+note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
 
 note: rustc VERSION running on TARGET
 
index fd0307f15c79aa95bf5dad28e79052760b918369..e143747d637ee0292c2ee79aed7ba4e340f73c61 100644 (file)
@@ -7,7 +7,6 @@ LL | fn is_zen<T: Zen>(_: T) {}
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
-   = help: the trait `std::marker::Sync` is not implemented for `T`
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
@@ -25,7 +24,6 @@ LL | fn is_zen<T: Zen>(_: T) {}
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
-   = help: the trait `std::marker::Sync` is not implemented for `T`
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
index 301edc0d086b11fee1b251fd47b5ab7ebba36190..1894cd218ee347f94546d2b7fa32a878f5937ad1 100644 (file)
@@ -8,12 +8,12 @@ print-type-size     variant `Some`: 12 bytes
 print-type-size         field `.0`: 12 bytes
 print-type-size     variant `None`: 0 bytes
 print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 1 bytes
 print-type-size     variant `Record`: 7 bytes
-print-type-size         field `.val`: 4 bytes
-print-type-size         field `.post`: 2 bytes
 print-type-size         field `.pre`: 1 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size         field `.val`: 4 bytes
 print-type-size     variant `None`: 0 bytes
-print-type-size     end padding: 1 bytes
 print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
 print-type-size     discriminant: 4 bytes
 print-type-size     variant `Some`: 4 bytes
index 05009358106fabd70b01c070397dca8c5e3dea16..e179feba7a799e59e279c003c8cff34d3573d990 100644 (file)
@@ -19,7 +19,6 @@ LL |     let range = *arr..;
    |                 ^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required by `std::ops::RangeFrom`
 
 error: aborting due to 3 previous errors
index ea9be77a3e8b5bb85a54ad9b715d467c0d5e261f..22586b5de91ff9e2158c52df337f083e74fedeac 100644 (file)
@@ -5,10 +5,10 @@ LL |     z: Box<dyn Is<'a>+'b+'c>,
    |                          ^^
 
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:5
+  --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:8
    |
 LL |     z: Box<dyn Is<'a>+'b+'c>,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 11:15
   --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15
index 9f39508604110df3c48abb2becb2a3a1208a8828..1ddbf73a46372dc13dbc2c54a9f20a4fc6d8ca23 100644 (file)
@@ -1,8 +1,8 @@
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/regions-wf-trait-object.rs:7:5
+  --> $DIR/regions-wf-trait-object.rs:7:8
    |
 LL |     x: Box<dyn TheTrait<'a>+'b>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 6:15
   --> $DIR/regions-wf-trait-object.rs:6:15
index 39b444498102c5a360b7c107e30f697cfdbd6191..13e7a59732db1562a16665b127c77a3cfc5ef9ef 100644 (file)
@@ -5,7 +5,7 @@ LL |     Variant { x: usize }
    |     -------------------- `Foo::Variant` defined here
 ...
 LL |     let f = Foo::Variant(42);
-   |             ^^^^^^^^^^^^ did you mean `Foo::Variant { /* fields */ }`?
+   |             ^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `Foo::Variant { x: val }`
 
 error: aborting due to previous error
 
index 4d20f1580264c6db3f20419fa70179edb146666a..d1690d4eef7ef2fcb00b294fc4d362841564990f 100644 (file)
@@ -5,13 +5,13 @@ LL |     Madoka { age: u32 }
    |     ------------------- `Homura::Madoka` defined here
 ...
 LL |     let homura = Homura::Madoka;
-   |                  ^^^^^^^^^^^^^^ did you mean `Homura::Madoka { /* fields */ }`?
+   |                  ^^^^^^^^^^^^^^ help: use struct literal syntax instead: `Homura::Madoka { age: val }`
 
 error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Madoka`
   --> $DIR/issue-19452.rs:13:18
    |
 LL |     let homura = issue_19452_aux::Homura::Madoka;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `issue_19452_aux::Homura::Madoka { /* fields */ }`?
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `issue_19452_aux::Homura::Madoka { /* fields */ }`
 
 error: aborting due to 2 previous errors
 
index d9a28e63dce8bda73e8653b06778158d4601ba10..c9b9aeb45ba42c582911f9c89164cfb5d8f34f46 100644 (file)
@@ -6,9 +6,15 @@ LL | struct Handle {}
 ...
 LL |         handle: Handle
    |                 ^^^^^^
-   |                 |
-   |                 did you mean `Handle { /* fields */ }`?
-   |                 help: a local variable with a similar name exists: `handle`
+   |
+help: a local variable with a similar name exists
+   |
+LL |         handle: handle
+   |                 ^^^^^^
+help: use struct literal syntax instead
+   |
+LL |         handle: Handle {}
+   |                 ^^^^^^^^^
 
 error: aborting due to previous error
 
index 89eb3d97ce0a54eacec2b968e3a906648b8051a8..4ed93ad3279adec5bb4ea680e90ed9ab29b84d6b 100644 (file)
@@ -5,9 +5,11 @@ LL | fn foo(_x: K) {}
    |        ^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo(_x: &K) {}
+   |            ^
 
 error: aborting due to previous error
 
index 252d50c70f8c4cea50c2aeeb29153240b40cc403..a118f94191df3647b132c610fb8487d812351e7f 100644 (file)
@@ -7,7 +7,7 @@ LL | | }
    | |_- `Monster` defined here
 ...
 LL |       let _m = Monster();
-   |                ^^^^^^^ did you mean `Monster { /* fields */ }`?
+   |                ^^^^^^^^^ help: use struct literal syntax instead: `Monster { damage: val }`
 
 error: aborting due to previous error
 
index 16baa6c9b623311e58b0b4b6168b412118466e8c..3904a00dde1dd5ead0d6271f70163c3e6020e3c8 100644 (file)
@@ -44,7 +44,7 @@ LL | |             },
    | |_____________- `Z::Struct` defined here
 ...
 LL |           let _: Z = Z::Struct;
-   |                      ^^^^^^^^^ did you mean `Z::Struct { /* fields */ }`?
+   |                      ^^^^^^^^^ help: use struct literal syntax instead: `Z::Struct { s: val }`
 
 error[E0423]: expected value, found enum `m::E`
   --> $DIR/privacy-enum-ctor.rs:41:16
@@ -83,7 +83,7 @@ LL | |         },
    | |_________- `m::E::Struct` defined here
 ...
 LL |       let _: E = m::E::Struct;
-   |                  ^^^^^^^^^^^^ did you mean `m::E::Struct { /* fields */ }`?
+   |                  ^^^^^^^^^^^^ help: use struct literal syntax instead: `m::E::Struct { s: val }`
 
 error[E0423]: expected value, found enum `E`
   --> $DIR/privacy-enum-ctor.rs:49:16
@@ -115,7 +115,7 @@ LL | |         },
    | |_________- `E::Struct` defined here
 ...
 LL |       let _: E = E::Struct;
-   |                  ^^^^^^^^^ did you mean `E::Struct { /* fields */ }`?
+   |                  ^^^^^^^^^ help: use struct literal syntax instead: `E::Struct { s: val }`
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:57:12
@@ -195,7 +195,7 @@ LL | |             },
    | |_____________- `m::n::Z::Struct` defined here
 ...
 LL |       let _: Z = m::n::Z::Struct;
-   |                  ^^^^^^^^^^^^^^^ did you mean `m::n::Z::Struct { /* fields */ }`?
+   |                  ^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `m::n::Z::Struct { s: val }`
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:68:12
index e0305b129a8816ccff926d2240b5f371bacbe5bf..a72f69cf1cd8d48a713069f3141e4d0602b684e3 100644 (file)
@@ -25,7 +25,7 @@ LL | |     }
    | |_____- `S2` defined here
 ...
 LL |       S2;
-   |       ^^ did you mean `S2 { /* fields */ }`?
+   |       ^^ help: use struct literal syntax instead: `S2 { s: val }`
 
 error[E0423]: expected value, found struct `xcrate::S`
   --> $DIR/privacy-struct-ctor.rs:43:5
index 2bb51731583a6ffded7c220c0c825f69638b1999..a449fac11930d8ce0571b2bace6738863aa20da3 100644 (file)
@@ -1,10 +1,10 @@
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/dont-infer-static.rs:8:5
+  --> $DIR/dont-infer-static.rs:8:10
    |
 LL | struct Foo<U> {
    |            - help: consider adding an explicit lifetime bound...: `U: 'static`
 LL |     bar: Bar<U>
-   |     ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds
+   |          ^^^^^^ ...so that the type `U` will meet its required lifetime bounds
 
 error: aborting due to previous error
 
index 3fb1cf9f557b2c86d71de72e61fa2c51c0895381..310545b92d5492d23f7d698790a9dfdcbe47001e 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(non_ascii_idents)]
 
 extern crate ьаг; //~ ERROR cannot load a crate with a non-ascii name `ьаг`
-//~| ERROR can't find crate for `ьаг`
 
 fn main() {}
index 1e424237fd238480f5a37082015ed1f34df0f8f0..11108f2fb86789ce88b273be499e3a7c0a54b750 100644 (file)
@@ -4,12 +4,5 @@ error: cannot load a crate with a non-ascii name `ьаг`
 LL | extern crate ьаг;
    | ^^^^^^^^^^^^^^^^^
 
-error[E0463]: can't find crate for `ьаг`
-  --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1
-   |
-LL | extern crate ьаг;
-   | ^^^^^^^^^^^^^^^^^ can't find crate
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0463`.
index e1acdbff06189efd8b07c8f493e927ec98596900..0249848b35ac0b12621a0b0739ba1e1dcd72f53f 100644 (file)
@@ -3,7 +3,5 @@
 #![feature(non_ascii_idents)]
 
 use му_сгате::baz; //~  ERROR cannot load a crate with a non-ascii name `му_сгате`
-                   //~| can't find crate for `му_сгате`
-
 
 fn main() {}
index c06405ebb37ec6a15e736c607e7387babfb0606d..8d3548ed33dcf8a70047df8c8cb1cbbe97382eab 100644 (file)
@@ -4,12 +4,5 @@ error: cannot load a crate with a non-ascii name `му_сгате`
 LL | use му_сгате::baz;
    |     ^^^^^^^^
 
-error[E0463]: can't find crate for `му_сгате`
-  --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5
-   |
-LL | use му_сгате::baz;
-   |     ^^^^^^^^ can't find crate
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0463`.
index 757578b84750c870c0b9751dcfdff8c351d6db9f..3b3a4a4f3250cb21d66b98a7a535a7618167fef5 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // ignore-emscripten no threads support
-// ignore-sgx no thread sleep support
 
 use std::thread::{self, sleep};
 use std::time::Duration;
index 7f3c49e753fd7e4ebc0f8a7e5f23f0d532e3c32a..3da8725d88a0caa6c900fbbf7fd1a413bb577703 100644 (file)
@@ -24,7 +24,6 @@ LL |     type U<'a>: PartialEq<&'a Self>;
 LL |     default type U<'a> = &'a T;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T`
    |
-   = help: the trait `std::cmp::PartialEq` is not implemented for `T`
    = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T`
 help: consider further restricting this bound
    |
index cc767de3845d28c1d382d6add13d8a70df7ccb3f..52d3aefe125c03b6bd374a543283c33eae17eabc 100644 (file)
@@ -19,14 +19,15 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/str-array-assignment.rs:7:7
    |
 LL |   let v = s[..2];
-   |       ^   ------ help: consider borrowing here: `&s[..2]`
-   |       |
-   |       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 `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: consider borrowing here
+   |
+LL |   let v = &s[..2];
+   |           ^
 
 error[E0308]: mismatched types
   --> $DIR/str-array-assignment.rs:9:17
index 2fd805e64699154a842f92855d2e8279e7ea4313..7c834165e7f1c1c96abe76392e7ff059e7bb02b1 100644 (file)
@@ -8,7 +8,6 @@ LL |     s[1..2] = bot();
    |               ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn bot<T: ?Sized>() -> T { loop {} }
@@ -21,7 +20,6 @@ LL |     s[1..2] = bot();
    |     ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the left-hand-side of an assignment must have a statically known size
 
 error[E0277]: the type `str` cannot be indexed by `usize`
index bcdeed262ecbaef15f43765ac03555b878878446..8dab8add80b8ab0b12dcd9428aacc4ad0b648cfd 100644 (file)
@@ -80,7 +80,6 @@ LL |     <str as Foo<u8>>::bar;
    |     ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str`
 
 error: aborting due to 5 previous errors
index fb5e6fbcfe712ee52fb2b55dffc34c296c672b95..a40d5e4bf7ba13a2f7c21eb5001aff0cedc5a212 100644 (file)
@@ -80,7 +80,6 @@ LL |     <str as Foo<u8>>::bar;
    |     ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str`
 
 error: aborting due to 5 previous errors
index ee08f51f802703dc509c8f40536cf943db0d4be2..f4c0d0f96c428af0922d047fb84ee5c1049b6422 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9
    |
 LL | struct X<T>(T);
    |          - required by this bound in `X`
@@ -7,10 +7,8 @@ LL | struct X<T>(T);
 LL | struct Struct5<T: ?Sized>{
    |                - this type parameter needs to be `std::marker::Sized`
 LL |     _t: X<T>,
-   |     ^^^^^^^^ 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 `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
    |
@@ -28,8 +26,6 @@ LL |     fn func1() -> Struct1<Self>;
 LL | struct Struct1<T>{
    |                - required by this bound in `Struct1`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     fn func1() -> Struct1<Self> where Self: std::marker::Sized;
@@ -48,8 +44,6 @@ LL |     fn func2<'a>() -> Struct2<'a, Self>;
 LL | struct Struct2<'a, T>{
    |                    - required by this bound in `Struct2`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
@@ -68,8 +62,6 @@ LL |     fn func3() -> Struct3<Self>;
 LL | struct Struct3<T>{
    |                - required by this bound in `Struct3`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
    |
@@ -91,8 +83,6 @@ LL |     fn func4() -> Struct4<Self>;
 LL | struct Struct4<T>{
    |                - required by this bound in `Struct4`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Self`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider further restricting `Self`
    |
 LL |     fn func4() -> Struct4<Self> where Self: std::marker::Sized;
index b03bea1eddbf08391a6531e223912e3ae95e4c6a..45309486db46ffaed203f1cc96af8407837c3aae 100644 (file)
@@ -7,10 +7,16 @@ LL |     B { a: usize },
    |     -------------- `E::B` defined here
 ...
 LL |     let _: E = E::B;
-   |                ^^^-
-   |                |  |
-   |                |  help: a tuple variant with a similar name exists: `A`
-   |                did you mean `E::B { /* fields */ }`?
+   |                ^^^^
+   |
+help: a tuple variant with a similar name exists
+   |
+LL |     let _: E = E::A;
+   |                   ^
+help: use struct literal syntax instead
+   |
+LL |     let _: E = E::B { a: val };
+   |                ^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:29:20
index fbcfba6653f274bf3e1a7d2873420f54d78267c4..7f6f082d7a8d7ca9762e94a7b4a51aad1f743d61 100644 (file)
@@ -5,7 +5,7 @@ LL | struct X {}
    | ----------- `X` defined here
 LL | fn main() {
 LL |     vec![X]; //…
-   |          ^ did you mean `X { /* fields */ }`?
+   |          ^ help: use struct literal syntax instead: `X {}`
 
 error: aborting due to previous error
 
index b073e10749cc1334e1c19fda8322aa5125c95e57..2b7c29e20cd31092e670f09108329e26518b5394 100644 (file)
@@ -2,13 +2,15 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
   --> $DIR/path-by-value.rs:3:6
    |
 LL | fn f(p: Path) { }
-   |      ^ borrow the `Path` instead
+   |      ^ doesn't have a size known at compile-time
    |
    = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `std::path::Path`
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn f(p: &Path) { }
+   |         ^
 
 error: aborting due to previous error
 
index 0c52778b0d8861ccd736881dd22a45c984546b11..33af13d943f74d97d6fd393355c594eb0721b3b2 100644 (file)
@@ -7,7 +7,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `impl Sync` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `impl Sync`
 help: consider further restricting this bound
    |
 LL | fn use_impl_sync(val: impl Sync + std::marker::Send) {
@@ -22,7 +21,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL | fn use_where<S>(val: S) where S: Sync + std::marker::Send {
@@ -37,7 +35,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL | fn use_bound<S: Sync + std::marker::Send>(val: S) {
@@ -52,7 +49,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL |     Sync + std::marker::Send
@@ -67,7 +63,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider further restricting this bound
    |
 LL | fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug + std::marker::Send {
@@ -82,7 +77,6 @@ LL | fn is_send<T: Send>(val: T) {}
 LL |     is_send(val);
    |             ^^^ `S` cannot be sent between threads safely
    |
-   = help: the trait `std::marker::Send` is not implemented for `S`
 help: consider restricting type parameter `S`
    |
 LL | fn use_unbound<S: std::marker::Send>(val: S) {
index 1f1948fa8fa2c364f2c2f907bfc437b2a57e8f69..08b47dc531857c1ef493f5f94378f3f5d0eb6a29 100644 (file)
@@ -4,7 +4,6 @@
 // ignore-emscripten no threads or sockets support
 // ignore-netbsd system ulimit (Too many open files)
 // ignore-openbsd system ulimit (Too many open files)
-// ignore-sgx no thread sleep support
 
 use std::io::prelude::*;
 use std::net::{TcpListener, TcpStream};
index 3188ee83e7d39f4cc5bd16c7340cc8b1606a4f40..324316ceaf6badf19550dcb900a6355378e1fdd9 100644 (file)
@@ -1,8 +1,8 @@
 error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
-  --> $DIR/cycle-cache-err-60010.rs:27:5
+  --> $DIR/cycle-cache-err-60010.rs:27:13
    |
 LL |     _parse: <ParseQuery as Query<RootDatabase>>::Data,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
 
index 5e685105b45a3ebc4a8ca2820bda3fa4dc8875b8..daca91abff8433fc9573cf8b44951a1ac0896e1c 100644 (file)
@@ -13,9 +13,11 @@ LL | fn foo(_x: Foo + Send) {
    |        ^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo(_x: &Foo + Send) {
+   |            ^
 
 error: aborting due to previous error; 1 warning emitted
 
index 271ed07ce42ab1455d2f75cd5bf46d98c875ec2b..d7549835a09051c5e433291322160acc13ef62eb 100644 (file)
@@ -13,13 +13,13 @@ LL | impl<T: Trait> Foo<T> {
    |       ^^^^^^^
 
 error[E0277]: the trait bound `isize: Trait` is not satisfied
-  --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5
+  --> $DIR/trait-bounds-on-structs-and-enums.rs:19:8
    |
 LL | struct Foo<T:Trait> {
    |              ----- required by this bound in `Foo`
 ...
 LL |     a: Foo<isize>,
-   |     ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `isize`
+   |        ^^^^^^^^^^ the trait `Trait` is not implemented for `isize`
 
 error[E0277]: the trait bound `usize: Trait` is not satisfied
   --> $DIR/trait-bounds-on-structs-and-enums.rs:23:10
@@ -31,13 +31,13 @@ LL |     Quux(Bar<usize>),
    |          ^^^^^^^^^^ the trait `Trait` is not implemented for `usize`
 
 error[E0277]: the trait bound `U: Trait` is not satisfied
-  --> $DIR/trait-bounds-on-structs-and-enums.rs:27:5
+  --> $DIR/trait-bounds-on-structs-and-enums.rs:27:8
    |
 LL | struct Foo<T:Trait> {
    |              ----- required by this bound in `Foo`
 ...
 LL |     b: Foo<U>,
-   |     ^^^^^^^^^ the trait `Trait` is not implemented for `U`
+   |        ^^^^^^ the trait `Trait` is not implemented for `U`
    |
 help: consider restricting type parameter `U`
    |
@@ -68,13 +68,13 @@ LL |     Foo<i32>,
    |     ^^^^^^^^ the trait `Trait` is not implemented for `i32`
 
 error[E0277]: the trait bound `u8: Trait` is not satisfied
-  --> $DIR/trait-bounds-on-structs-and-enums.rs:39:22
+  --> $DIR/trait-bounds-on-structs-and-enums.rs:39:29
    |
 LL | enum Bar<T:Trait> {
    |            ----- required by this bound in `Bar`
 ...
 LL |     DictionaryLike { field: Bar<u8> },
-   |                      ^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u8`
+   |                             ^^^^^^^ the trait `Trait` is not implemented for `u8`
 
 error: aborting due to 7 previous errors
 
index 4dddcd68f26c90a801d32595ce9d2f53beaa8cd3..86a313baa5c385ad1fd47b4bf4c7ddd4a5767f86 100644 (file)
@@ -11,9 +11,6 @@ LL |     mem::size_of::<U>();
    |
 LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
-   |
-   = help: the trait `std::marker::Sized` is not implemented for `U`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:10:5
@@ -29,8 +26,6 @@ LL |     mem::size_of::<Misc<U>>();
 LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
-   = help: within `Misc<U>`, the trait `std::marker::Sized` is not implemented for `U`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Misc<U>`
 
 error[E0277]: the trait bound `u64: std::convert::From<T>` is not satisfied
@@ -69,7 +64,6 @@ LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[T]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error[E0277]: the size for values of type `[&U]` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:31:5
@@ -83,7 +77,6 @@ LL | pub const fn size_of<T>() -> usize {
    |                      - required by this bound in `std::mem::size_of`
    |
    = help: the trait `std::marker::Sized` is not implemented for `[&U]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to 7 previous errors
 
index 006fa933d34cadd8671ee2055674e1ed61483357..4f4695612de0b9dea8c73400ed097b1a1de3df77 100644 (file)
@@ -5,7 +5,6 @@ LL | fn cant_return_str() -> str {
    |                         ^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: the return type of a function must have a statically known size
 
 error[E0599]: no method named `test` found for type `i32` in the current scope
index 247d68ef2a1f0edd078cf7fe2ee4e54a0e7e65b8..28e30cbdd9d967c8782cc09adbd547de6fd338ab 100644 (file)
@@ -19,7 +19,6 @@ LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
 LL |     5u32
    |     ---- this returned value is of type `u32`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `U`
    = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `U`
    |
@@ -35,7 +34,6 @@ LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
 LL |     5u32
    |     ---- this returned value is of type `u32`
    |
-   = help: the trait `std::fmt::Debug` is not implemented for `V`
    = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `V`
    |
index 6a3f3c98f127a96d1b5e0a3c93e7d1e1f95b0018..73a11a5e743f6a7f85810bfbcc0d86d54cf7fd3d 100644 (file)
@@ -5,6 +5,7 @@
 #![feature(never_type)]
 
 use std::mem::size_of;
+use std::num::NonZeroU8;
 
 struct t {a: u8, b: i8}
 struct u {a: u8, b: i8, c: u8}
@@ -102,6 +103,23 @@ enum Option2<A, B> {
     None
 }
 
+// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
+//   Niche-filling:
+//     { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
+//   Tagged:
+//     { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
+// Both are the same size (due to padding),
+// but the tagged layout is better as the tag creates a niche with 254 invalid values,
+// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
+pub enum CanBeNicheFilledButShouldnt {
+    A(NonZeroU8, u32),
+    B
+}
+pub enum AlwaysTaggedBecauseItHasNoNiche {
+    A(u8, u32),
+    B
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -145,4 +163,11 @@ pub fn main() {
     assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
     assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
+
+    assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
+    assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
+    assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
+    assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
+    assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
+    assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
 }
index 856d4ff6334bc785c0a506bc6420316d8a8fa923..cbd39f5f9e6ed5c842acc199414cfb3063475edd 100644 (file)
@@ -4,7 +4,7 @@ enum X {
 
 fn main() {
     match X::Y(0) {
-        X::Y { number } => {} //~ ERROR does not have a field named `number`
-        //~^ ERROR pattern does not mention field `0`
+        X::Y { number } => {}
+        //~^ ERROR tuple variant `X::Y` written as struct variant
     }
 }
index c2bba98d10a837e6f80c9d1d6e4596acc3ad62be..bd4d2071c2059ac2c9208a87442863114340b098 100644 (file)
@@ -1,18 +1,9 @@
-error[E0026]: variant `X::Y` does not have a field named `number`
-  --> $DIR/issue-41314.rs:7:16
-   |
-LL |         X::Y { number } => {}
-   |                ^^^^^^ variant `X::Y` does not have this field
-
-error[E0027]: pattern does not mention field `0`
+error[E0769]: tuple variant `X::Y` written as struct variant
   --> $DIR/issue-41314.rs:7:9
    |
 LL |         X::Y { number } => {}
-   |         ^^^^^^^^^^^^^^^ missing field `0`
-   |
-   = note: trying to match a tuple variant with a struct variant pattern
+   |         ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `X::Y(number)`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0026, E0027.
-For more information about an error, try `rustc --explain E0026`.
+For more information about this error, try `rustc --explain E0769`.
index 9cba3578449c30b4444c1d91ed5c578b6a40fb5b..7398b48a238d1c7c31022c78a39a13fa2f0a3fb4 100644 (file)
@@ -7,7 +7,6 @@ LL |     is_send::<T>()
 LL | fn is_send<T:Send>() {
    |              ---- required by this bound in `is_send`
    |
-   = help: the trait `std::marker::Send` is not implemented for `T`
 help: consider restricting type parameter `T`
    |
 LL | fn foo<T: std::marker::Send>() {
index 99a70230892833d8996864bcce78c3fe2db850aa..133c5231031fd65a8d86b67159828b3b539d8362 100644 (file)
@@ -32,6 +32,7 @@ fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
 
 fn test8(_f: fn() -> _) { }
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
 
 struct Test9;
 
@@ -98,6 +99,7 @@ fn fn_test6(_: _) { }
 
     fn fn_test8(_f: fn() -> _) { }
     //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+    //~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
 
     struct FnTest9;
 
index 6c0653d5fcb7c64f28458f2cef69b81d33036122..a1945f2b9cf4e88b314f5d395d555a76f3a1ced4 100644 (file)
@@ -1,35 +1,35 @@
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:152:18
+  --> $DIR/typeck_type_placeholder_item.rs:154:18
    |
 LL | struct BadStruct<_>(_);
    |                  ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:155:16
+  --> $DIR/typeck_type_placeholder_item.rs:157:16
    |
 LL | trait BadTrait<_> {}
    |                ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:165:19
+  --> $DIR/typeck_type_placeholder_item.rs:167:19
    |
 LL | struct BadStruct1<_, _>(_);
    |                   ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:165:22
+  --> $DIR/typeck_type_placeholder_item.rs:167:22
    |
 LL | struct BadStruct1<_, _>(_);
    |                      ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/typeck_type_placeholder_item.rs:170:19
+  --> $DIR/typeck_type_placeholder_item.rs:172:19
    |
 LL | struct BadStruct2<_, T>(_, T);
    |                   ^ expected identifier, found reserved identifier
 
 error: associated constant in `impl` without body
-  --> $DIR/typeck_type_placeholder_item.rs:201:5
+  --> $DIR/typeck_type_placeholder_item.rs:203:5
    |
 LL |     const C: _;
    |     ^^^^^^^^^^-
@@ -37,7 +37,7 @@ LL |     const C: _;
    |               help: provide a definition for the constant: `= <expr>;`
 
 error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/typeck_type_placeholder_item.rs:165:22
+  --> $DIR/typeck_type_placeholder_item.rs:167:22
    |
 LL | struct BadStruct1<_, _>(_);
    |                   -  ^ already used
@@ -131,6 +131,15 @@ help: use type parameters instead
 LL | fn test7<T>(x: T) { let _x: usize = x; }
    |         ^^^    ^
 
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:33:22
+   |
+LL | fn test8(_f: fn() -> _) { }
+   |                      ^
+   |                      |
+   |                      not allowed in type signatures
+   |                      help: use type parameters instead: `T`
+
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:33:22
    |
@@ -143,7 +152,7 @@ LL | fn test8<T>(_f: fn() -> T) { }
    |         ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:46:26
+  --> $DIR/typeck_type_placeholder_item.rs:47:26
    |
 LL | fn test11(x: &usize) -> &_ {
    |                         -^
@@ -152,7 +161,7 @@ LL | fn test11(x: &usize) -> &_ {
    |                         help: replace with the correct return type: `&&usize`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:51:52
+  --> $DIR/typeck_type_placeholder_item.rs:52:52
    |
 LL | unsafe fn test12(x: *const usize) -> *const *const _ {
    |                                      --------------^
@@ -161,7 +170,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ {
    |                                      help: replace with the correct return type: `*const *const usize`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:65:8
+  --> $DIR/typeck_type_placeholder_item.rs:66:8
    |
 LL |     a: _,
    |        ^ not allowed in type signatures
@@ -180,13 +189,13 @@ LL |     b: (T, T),
    |
 
 error: missing type for `static` item
-  --> $DIR/typeck_type_placeholder_item.rs:71:12
+  --> $DIR/typeck_type_placeholder_item.rs:72:12
    |
 LL |     static A = 42;
    |            ^ help: provide a type for the item: `A: i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:73:15
+  --> $DIR/typeck_type_placeholder_item.rs:74:15
    |
 LL |     static B: _ = 42;
    |               ^
@@ -195,13 +204,13 @@ LL |     static B: _ = 42;
    |               help: replace `_` with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:75:15
+  --> $DIR/typeck_type_placeholder_item.rs:76:15
    |
 LL |     static C: Option<_> = Some(42);
    |               ^^^^^^^^^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:78:21
+  --> $DIR/typeck_type_placeholder_item.rs:79:21
    |
 LL |     fn fn_test() -> _ { 5 }
    |                     ^
@@ -210,7 +219,7 @@ LL |     fn fn_test() -> _ { 5 }
    |                     help: replace with the correct return type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:81:23
+  --> $DIR/typeck_type_placeholder_item.rs:82:23
    |
 LL |     fn fn_test2() -> (_, _) { (5, 5) }
    |                      -^--^-
@@ -220,7 +229,7 @@ LL |     fn fn_test2() -> (_, _) { (5, 5) }
    |                      help: replace with the correct return type: `(i32, i32)`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:84:22
+  --> $DIR/typeck_type_placeholder_item.rs:85:22
    |
 LL |     static FN_TEST3: _ = "test";
    |                      ^
@@ -229,7 +238,7 @@ LL |     static FN_TEST3: _ = "test";
    |                      help: replace `_` with the correct type: `&str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:87:22
+  --> $DIR/typeck_type_placeholder_item.rs:88:22
    |
 LL |     static FN_TEST4: _ = 145;
    |                      ^
@@ -238,13 +247,13 @@ LL |     static FN_TEST4: _ = 145;
    |                      help: replace `_` with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:90:22
+  --> $DIR/typeck_type_placeholder_item.rs:91:22
    |
 LL |     static FN_TEST5: (_, _) = (1, 2);
    |                      ^^^^^^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:93:20
+  --> $DIR/typeck_type_placeholder_item.rs:94:20
    |
 LL |     fn fn_test6(_: _) { }
    |                    ^ not allowed in type signatures
@@ -255,7 +264,7 @@ LL |     fn fn_test6<T>(_: T) { }
    |                ^^^    ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:96:20
+  --> $DIR/typeck_type_placeholder_item.rs:97:20
    |
 LL |     fn fn_test7(x: _) { let _x: usize = x; }
    |                    ^ not allowed in type signatures
@@ -266,7 +275,16 @@ LL |     fn fn_test7<T>(x: T) { let _x: usize = x; }
    |                ^^^    ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:99:29
+  --> $DIR/typeck_type_placeholder_item.rs:100:29
+   |
+LL |     fn fn_test8(_f: fn() -> _) { }
+   |                             ^
+   |                             |
+   |                             not allowed in type signatures
+   |                             help: use type parameters instead: `T`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:100:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
    |                             ^ not allowed in type signatures
@@ -277,7 +295,7 @@ LL |     fn fn_test8<T>(_f: fn() -> T) { }
    |                ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:121:12
+  --> $DIR/typeck_type_placeholder_item.rs:123:12
    |
 LL |         a: _,
    |            ^ not allowed in type signatures
@@ -296,13 +314,13 @@ LL |         b: (T, T),
    |
 
 error[E0282]: type annotations needed
-  --> $DIR/typeck_type_placeholder_item.rs:126:18
+  --> $DIR/typeck_type_placeholder_item.rs:128:18
    |
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                  ^ cannot infer type
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:126:28
+  --> $DIR/typeck_type_placeholder_item.rs:128:28
    |
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                            ^  ^ not allowed in type signatures
@@ -310,7 +328,7 @@ LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                            not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:130:30
+  --> $DIR/typeck_type_placeholder_item.rs:132:30
    |
 LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
    |                             -^--^-
@@ -320,7 +338,7 @@ LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
    |                             help: replace with the correct return type: `(i32, i32)`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:133:33
+  --> $DIR/typeck_type_placeholder_item.rs:135:33
    |
 LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           ------^-
@@ -329,7 +347,7 @@ LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           help: replace with the correct return type: `(i32, i32)`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:152:21
+  --> $DIR/typeck_type_placeholder_item.rs:154:21
    |
 LL | struct BadStruct<_>(_);
    |                     ^ not allowed in type signatures
@@ -340,7 +358,7 @@ LL | struct BadStruct<T>(T);
    |                  ^  ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:157:15
+  --> $DIR/typeck_type_placeholder_item.rs:159:15
    |
 LL | impl BadTrait<_> for BadStruct<_> {}
    |               ^                ^ not allowed in type signatures
@@ -353,13 +371,13 @@ LL | impl<T> BadTrait<T> for BadStruct<T> {}
    |     ^^^          ^                ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:160:34
+  --> $DIR/typeck_type_placeholder_item.rs:162:34
    |
 LL | fn impl_trait() -> impl BadTrait<_> {
    |                                  ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:165:25
+  --> $DIR/typeck_type_placeholder_item.rs:167:25
    |
 LL | struct BadStruct1<_, _>(_);
    |                         ^ not allowed in type signatures
@@ -370,7 +388,7 @@ LL | struct BadStruct1<T, _>(T);
    |                   ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:170:25
+  --> $DIR/typeck_type_placeholder_item.rs:172:25
    |
 LL | struct BadStruct2<_, T>(_, T);
    |                         ^ not allowed in type signatures
@@ -381,13 +399,13 @@ LL | struct BadStruct2<U, T>(U, T);
    |                   ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:174:14
+  --> $DIR/typeck_type_placeholder_item.rs:176:14
    |
 LL | type X = Box<_>;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:42:27
+  --> $DIR/typeck_type_placeholder_item.rs:43:27
    |
 LL |     fn test10(&self, _x : _) { }
    |                           ^ not allowed in type signatures
@@ -398,7 +416,7 @@ LL |     fn test10<T>(&self, _x : T) { }
    |              ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:138:31
+  --> $DIR/typeck_type_placeholder_item.rs:140:31
    |
 LL |     fn method_test1(&self, x: _);
    |                               ^ not allowed in type signatures
@@ -409,7 +427,7 @@ LL |     fn method_test1<T>(&self, x: T);
    |                    ^^^           ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:140:31
+  --> $DIR/typeck_type_placeholder_item.rs:142:31
    |
 LL |     fn method_test2(&self, x: _) -> _;
    |                               ^     ^ not allowed in type signatures
@@ -422,7 +440,7 @@ LL |     fn method_test2<T>(&self, x: T) -> T;
    |                    ^^^           ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:142:31
+  --> $DIR/typeck_type_placeholder_item.rs:144:31
    |
 LL |     fn method_test3(&self) -> _;
    |                               ^ not allowed in type signatures
@@ -433,7 +451,7 @@ LL |     fn method_test3<T>(&self) -> T;
    |                    ^^^           ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:144:26
+  --> $DIR/typeck_type_placeholder_item.rs:146:26
    |
 LL |     fn assoc_fn_test1(x: _);
    |                          ^ not allowed in type signatures
@@ -444,7 +462,7 @@ LL |     fn assoc_fn_test1<T>(x: T);
    |                      ^^^    ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:146:26
+  --> $DIR/typeck_type_placeholder_item.rs:148:26
    |
 LL |     fn assoc_fn_test2(x: _) -> _;
    |                          ^     ^ not allowed in type signatures
@@ -457,7 +475,7 @@ LL |     fn assoc_fn_test2<T>(x: T) -> T;
    |                      ^^^    ^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:148:28
+  --> $DIR/typeck_type_placeholder_item.rs:150:28
    |
 LL |     fn assoc_fn_test3() -> _;
    |                            ^ not allowed in type signatures
@@ -468,7 +486,7 @@ LL |     fn assoc_fn_test3<T>() -> T;
    |                      ^^^      ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:60:37
+  --> $DIR/typeck_type_placeholder_item.rs:61:37
    |
 LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
    |                                     ^ not allowed in type signatures
@@ -479,7 +497,7 @@ LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
    |                  ^^^                   ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:108:34
+  --> $DIR/typeck_type_placeholder_item.rs:110:34
    |
 LL |         fn fn_test10(&self, _x : _) { }
    |                                  ^ not allowed in type signatures
@@ -490,7 +508,7 @@ LL |         fn fn_test10<T>(&self, _x : T) { }
    |                     ^^^             ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:116:41
+  --> $DIR/typeck_type_placeholder_item.rs:118:41
    |
 LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
    |                                         ^ not allowed in type signatures
@@ -501,25 +519,25 @@ LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
    |                      ^^^                   ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:180:21
+  --> $DIR/typeck_type_placeholder_item.rs:182:21
    |
 LL | type Y = impl Trait<_>;
    |                     ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:188:14
+  --> $DIR/typeck_type_placeholder_item.rs:190:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:190:14
+  --> $DIR/typeck_type_placeholder_item.rs:192:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:192:14
+  --> $DIR/typeck_type_placeholder_item.rs:194:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -528,7 +546,7 @@ LL |     const D: _ = 42;
    |              help: replace `_` with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:39:24
+  --> $DIR/typeck_type_placeholder_item.rs:40:24
    |
 LL |     fn test9(&self) -> _ { () }
    |                        ^
@@ -537,7 +555,7 @@ LL |     fn test9(&self) -> _ { () }
    |                        help: replace with the correct return type: `()`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:57:24
+  --> $DIR/typeck_type_placeholder_item.rs:58:24
    |
 LL |     fn clone(&self) -> _ { Test9 }
    |                        ^
@@ -546,7 +564,7 @@ LL |     fn clone(&self) -> _ { Test9 }
    |                        help: replace with the correct return type: `Test9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:105:31
+  --> $DIR/typeck_type_placeholder_item.rs:107:31
    |
 LL |         fn fn_test9(&self) -> _ { () }
    |                               ^
@@ -555,7 +573,7 @@ LL |         fn fn_test9(&self) -> _ { () }
    |                               help: replace with the correct return type: `()`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:113:28
+  --> $DIR/typeck_type_placeholder_item.rs:115:28
    |
 LL |         fn clone(&self) -> _ { FnTest9 }
    |                            ^
@@ -564,25 +582,25 @@ LL |         fn clone(&self) -> _ { FnTest9 }
    |                            help: replace with the correct return type: `main::FnTest9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:197:14
+  --> $DIR/typeck_type_placeholder_item.rs:199:14
    |
 LL |     type A = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:199:14
+  --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:201:14
+  --> $DIR/typeck_type_placeholder_item.rs:203:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:204:14
+  --> $DIR/typeck_type_placeholder_item.rs:206:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -590,7 +608,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace `_` with the correct type: `i32`
 
-error: aborting due to 64 previous errors
+error: aborting due to 66 previous errors
 
 Some errors have detailed explanations: E0121, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.
index 68cb66d89d2184627e38187f0d082a585c069994..48654347285d3be45c7a97d9f4641788e03ef972 100644 (file)
@@ -48,18 +48,18 @@ error: union patterns should have exactly one field
 LL |     let U { a, b } = u;
    |         ^^^^^^^^^^
 
-error[E0026]: union `U` does not have a field named `c`
-  --> $DIR/union-fields-2.rs:18:19
-   |
-LL |     let U { a, b, c } = u;
-   |                   ^ union `U` does not have this field
-
 error: union patterns should have exactly one field
   --> $DIR/union-fields-2.rs:18:9
    |
 LL |     let U { a, b, c } = u;
    |         ^^^^^^^^^^^^^
 
+error[E0026]: union `U` does not have a field named `c`
+  --> $DIR/union-fields-2.rs:18:19
+   |
+LL |     let U { a, b, c } = u;
+   |                   ^ union `U` does not have this field
+
 error: union patterns should have exactly one field
   --> $DIR/union-fields-2.rs:20:9
    |
index 62dacd064bed0b63ee047bdc105bbc4faeaa1d3b..b916bbe8ad10a3deedaf7a5e30f613d613d856e3 100644 (file)
@@ -1,26 +1,40 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/union-sized-field.rs:4:5
+  --> $DIR/union-sized-field.rs:4:12
    |
 LL | union Foo<T: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
 LL |     value: T,
-   |     ^^^^^^^^ 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 `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     value: &T,
+   |            ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     value: Box<T>,
+   |            ^^^^ ^
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/union-sized-field.rs:9:5
+  --> $DIR/union-sized-field.rs:9:12
    |
 LL | struct Foo2<T: ?Sized> {
    |             - this type parameter needs to be `std::marker::Sized`
 LL |     value: T,
-   |     ^^^^^^^^ 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 `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     value: &T,
+   |            ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     value: Box<T>,
+   |            ^^^^ ^
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/union-sized-field.rs:15:11
@@ -30,9 +44,16 @@ LL | enum Foo3<T: ?Sized> {
 LL |     Value(T),
    |           ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     Value(&T),
+   |           ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     Value(Box<T>),
+   |           ^^^^ ^
 
 error: aborting due to 3 previous errors
 
index e702f2c61bee3ff543755b0f549ad5158210a30a..f62a3b4d14b974c3c417fe22a54122c5f9ca4b75 100644 (file)
@@ -1,22 +1,38 @@
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:4:5
+  --> $DIR/union-unsized.rs:4:8
    |
 LL |     a: str,
-   |     ^^^^^^ 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 `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     a: &str,
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     a: Box<str>,
+   |        ^^^^   ^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:12:5
+  --> $DIR/union-unsized.rs:12:8
    |
 LL |     b: str,
-   |     ^^^^^^ 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 `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     b: &str,
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     b: Box<str>,
+   |        ^^^^   ^
 
 error: aborting due to 2 previous errors
 
index 35f63a91b2b531885b57bc084ea2ac852ea6d1d2..2ed35dc0e2c12202403cccaecbab212b7814e00b 100644 (file)
@@ -5,7 +5,6 @@ LL |     let _x: fn(_) -> Test = Test;
    |                             ^^^^ doesn't have a size known at compile-time
    |
    = help: within `Test`, the trait `std::marker::Sized` is not implemented for `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Test`
    = note: the return type of a function must have a statically known size
 
index d42fddb3a4a26aec1c22f9aa4e5cf5678d21ad40..461efcf3dbf292d5c6014fc6b36eaff73aad8bee 100644 (file)
@@ -5,7 +5,6 @@ LL |     let _x: fn(_) -> Test = Test;
    |                             ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
index 7b6c2d11ea169786581385b24106a818380f03c7..04a8de1b5dc5b4ccfc9fdacc528f8f82a02923d1 100644 (file)
@@ -5,7 +5,6 @@ LL |     A as fn(str) -> A<str>;
    |     ^ doesn't have a size known at compile-time
    |
    = help: within `main::A<str>`, the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `main::A<str>`
    = note: the return type of a function must have a statically known size
 
index be006c09d6f5c6cd177827509358902cd6d7b7fa..8e5f753082734ee55df4a3293c7c703a62de06da 100644 (file)
@@ -5,7 +5,6 @@ LL |     A as fn(str) -> A<str>;
    |     ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
index 43c35cdd7b5b09b461042a8243dffd42c787b1fe..0a9b43dac334494c4ef9cee3a87d20cf018f59b4 100644 (file)
@@ -5,7 +5,6 @@ LL |     udrop::<(i32, [u8])>((42, *foo()));
    |                          ^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `({integer}, [u8])`
    = note: tuples must have a statically known size to be initialized
 
@@ -16,7 +15,6 @@ LL |     udrop::<A<[u8]>>(A { 0: *foo() });
    |                      ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `A<[u8]>`
    = note: structs must have a statically known size to be initialized
 
@@ -27,7 +25,6 @@ LL |     udrop::<A<[u8]>>(A(*foo()));
    |                      ^ doesn't have a size known at compile-time
    |
    = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `A<[u8]>`
    = note: the return type of a function must have a statically known size
 
index f9a7452a5ebf228206b0d2cb44cb76fdb75e5bc9..11435ec0353bc68ae6b35a3374c2cdf6cd9d1255 100644 (file)
@@ -5,7 +5,6 @@ LL |     udrop as fn([u8]);
    |     ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
index 3ff6f30db2a845c537bee9a76f784c7d116fd40c..19978ae24cacb75094e17314ebb342ff3f91ab4c 100644 (file)
@@ -7,9 +7,6 @@ LL | fn foo<T: ?Sized>() { bar::<T>() }
    |        -                    ^ doesn't have a size known at compile-time
    |        |
    |        this type parameter needs to be `std::marker::Sized`
-   |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 
 error: aborting due to previous error
 
index 1908aee25ea7bf6e094db07ba296ff89b8937534..fdfdb9b4e2a5b636be8a0c62a44aac7d0adfa57b 100644 (file)
@@ -9,8 +9,6 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |         |
    |         this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
   --> $DIR/unsized-enum.rs:4:10
    |
index bc3b3831f32699ed06c2fe6699b99150a2805ede..988c310167682affcebaabbc6c10927aaabdcda3 100644 (file)
@@ -7,22 +7,36 @@ LL |     // parameter
 LL |     VA(W),
    |        ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `W`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VA(&W),
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VA(Box<W>),
+   |        ^^^^ ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:25:8
+  --> $DIR/unsized-enum2.rs:25:11
    |
 LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
    |                   - this type parameter needs to be `std::marker::Sized`
 ...
 LL |     VB{x: X},
-   |        ^^^^ 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 `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VB{x: &X},
+   |           ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VB{x: Box<X>},
+   |           ^^^^ ^
 
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:27:15
@@ -33,22 +47,36 @@ LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
 LL |     VC(isize, Y),
    |               ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Y`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VC(isize, &Y),
+   |               ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VC(isize, Box<Y>),
+   |               ^^^^ ^
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:29:18
+  --> $DIR/unsized-enum2.rs:29:21
    |
 LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
    |                                         - this type parameter needs to be `std::marker::Sized`
 ...
 LL |     VD{u: isize, x: Z},
-   |                  ^^^^ 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 `Z`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VD{u: isize, x: &Z},
+   |                     ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VD{u: isize, x: Box<Z>},
+   |                     ^^^^ ^
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:33:8
@@ -57,18 +85,34 @@ LL |     VE([u8]),
    |        ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VE(&[u8]),
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VE(Box<[u8]>),
+   |        ^^^^    ^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:35:8
+  --> $DIR/unsized-enum2.rs:35:11
    |
 LL |     VF{x: str},
-   |        ^^^^^^ 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 `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VF{x: &str},
+   |           ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VF{x: Box<str>},
+   |           ^^^^   ^
 
 error[E0277]: the size for values of type `[f32]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:37:15
@@ -77,18 +121,34 @@ LL |     VG(isize, [f32]),
    |               ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[f32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VG(isize, &[f32]),
+   |               ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VG(isize, Box<[f32]>),
+   |               ^^^^     ^
 
 error[E0277]: the size for values of type `[u32]` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:39:18
+  --> $DIR/unsized-enum2.rs:39:21
    |
 LL |     VH{u: isize, x: [u32]},
-   |                  ^^^^^^^^ 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 `[u32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VH{u: isize, x: &[u32]},
+   |                     ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VH{u: isize, x: Box<[u32]>},
+   |                     ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:53:8
@@ -97,18 +157,34 @@ LL |     VM(dyn Foo),
    |        ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VM(&dyn Foo),
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VM(Box<dyn Foo>),
+   |        ^^^^       ^
 
 error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:55:8
+  --> $DIR/unsized-enum2.rs:55:11
    |
 LL |     VN{x: dyn Bar},
-   |        ^^^^^^^^^^ 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 `(dyn Bar + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VN{x: &dyn Bar},
+   |           ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VN{x: Box<dyn Bar>},
+   |           ^^^^       ^
 
 error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:57:15
@@ -117,18 +193,34 @@ LL |     VO(isize, dyn FooBar),
    |               ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VO(isize, &dyn FooBar),
+   |               ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VO(isize, Box<dyn FooBar>),
+   |               ^^^^          ^
 
 error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:59:18
+  --> $DIR/unsized-enum2.rs:59:21
    |
 LL |     VP{u: isize, x: dyn BarFoo},
-   |                  ^^^^^^^^^^^^^ 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 `(dyn BarFoo + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VP{u: isize, x: &dyn BarFoo},
+   |                     ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VP{u: isize, x: Box<dyn BarFoo>},
+   |                     ^^^^          ^
 
 error[E0277]: the size for values of type `[i8]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:63:8
@@ -137,18 +229,34 @@ LL |     VQ(<&'static [i8] as Deref>::Target),
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[i8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VQ(&<&'static [i8] as Deref>::Target),
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VQ(Box<<&'static [i8] as Deref>::Target>),
+   |        ^^^^                                ^
 
 error[E0277]: the size for values of type `[char]` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:65:8
+  --> $DIR/unsized-enum2.rs:65:11
    |
 LL |     VR{x: <&'static [char] as Deref>::Target},
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 `[char]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VR{x: &<&'static [char] as Deref>::Target},
+   |           ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VR{x: Box<<&'static [char] as Deref>::Target>},
+   |           ^^^^                                  ^
 
 error[E0277]: the size for values of type `[f64]` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:67:15
@@ -157,18 +265,34 @@ LL |     VS(isize, <&'static [f64] as Deref>::Target),
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `[f64]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VS(isize, &<&'static [f64] as Deref>::Target),
+   |               ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VS(isize, Box<<&'static [f64] as Deref>::Target>),
+   |               ^^^^                                 ^
 
 error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:69:18
+  --> $DIR/unsized-enum2.rs:69:21
    |
 LL |     VT{u: isize, x: <&'static [i32] as Deref>::Target},
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 `[i32]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VT{u: isize, x: &<&'static [i32] as Deref>::Target},
+   |                     ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VT{u: isize, x: Box<<&'static [i32] as Deref>::Target>},
+   |                     ^^^^                                 ^
 
 error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:43:8
@@ -177,20 +301,36 @@ LL |     VI(Path1),
    |        ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper1 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path1`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VI(&Path1),
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VI(Box<Path1>),
+   |        ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:45:8
+  --> $DIR/unsized-enum2.rs:45:11
    |
 LL |     VJ{x: Path2},
-   |        ^^^^^^^^ doesn't have a size known at compile-time
+   |           ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path2`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VJ{x: &Path2},
+   |           ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VJ{x: Box<Path2>},
+   |           ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:47:15
@@ -199,20 +339,36 @@ LL |     VK(isize, Path3),
    |               ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper3 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path3`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VK(isize, &Path3),
+   |               ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VK(isize, Box<Path3>),
+   |               ^^^^     ^
 
 error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot be known at compilation time
-  --> $DIR/unsized-enum2.rs:49:18
+  --> $DIR/unsized-enum2.rs:49:21
    |
 LL |     VL{u: isize, x: Path4},
-   |                  ^^^^^^^^ doesn't have a size known at compile-time
+   |                     ^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Path4`
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     VL{u: isize, x: &Path4},
+   |                     ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     VL{u: isize, x: Box<Path4>},
+   |                     ^^^^     ^
 
 error: aborting due to 20 previous errors
 
index ed2c2e75cbd441f88666ffe1d93d7441ad55a87f..6b54db7148a749cb81b5f298a20de9bb35f53c42 100644 (file)
@@ -5,7 +5,6 @@ LL |     foo11("bar", &"baz");
    |           ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -15,7 +14,6 @@ LL |     foo12(&"bar", "baz");
    |                   ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -25,7 +23,6 @@ LL |     foo21("bar", &"baz");
    |           ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<str>`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -35,7 +32,6 @@ LL |     foo22(&"bar", "baz");
    |                   ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required for the cast to the object type `dyn std::convert::AsRef<str>`
 
 error: aborting due to 4 previous errors
index e0f077d66f99c8920ea3372279d71c7706251dea..50b54593f3aa149460594ac2bb50cfb207e10d95 100644 (file)
@@ -9,8 +9,6 @@ LL | impl<X: ?Sized> S5<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
   --> $DIR/unsized-inherent-impl-self-type.rs:5:11
    |
index d92d1d9113e5c56377e8ac4415114357a52562a5..0c8529bf1a9af43148872913ca3876254ebf5e74 100644 (file)
@@ -9,8 +9,6 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |         |
    |         this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/unsized-struct.rs:4:12
    |
@@ -30,8 +28,6 @@ LL | fn bar2<T: ?Sized>() { is_sized::<Bar<T>>() }
    |         |
    |         this type parameter needs to be `std::marker::Sized`
    |
-   = help: within `Bar<T>`, the trait `std::marker::Sized` is not implemented for `T`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<T>`
 
 error: aborting due to 2 previous errors
index 73c5439da53b67e83e3c1b66033ef78a04b7ce43..4514208a90dc9a5cfe0955dc0c94fc73193c1485 100644 (file)
@@ -9,8 +9,6 @@ LL | impl<X: ?Sized> T3<X> for S5<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
   --> $DIR/unsized-trait-impl-self-type.rs:8:11
    |
index e423a9bdeab6f9f1c00b86f6a5ca516fdb3c9df9..f48d4ef9f14617b98ffb8ef017c49dbf9f5516b6 100644 (file)
@@ -9,8 +9,6 @@ LL | impl<X: ?Sized> T2<X> for S4<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T2<Z: ?Sized> {
index e0a0389dc46908247f7093f74dd12a77d554e496..ddddae4eaba57cf51d1094b02b3e0d5066210125 100644 (file)
@@ -9,8 +9,6 @@ LL |     f2::<X>(x);
 LL | fn f2<X>(x: &X) {
    |       - required by this bound in `f2`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f2<X: ?Sized>(x: &X) {
@@ -27,8 +25,6 @@ LL |     f4::<X>(x);
 LL | fn f4<X: T>(x: &X) {
    |       - required by this bound in `f4`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | fn f4<X: T + ?Sized>(x: &X) {
@@ -45,8 +41,6 @@ LL | fn f8<X: ?Sized>(x1: &S<X>, x2: &S<X>) {
 LL |     f5(x1);
    |        ^^ doesn't have a size known at compile-time
    |
-   = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
 help: consider relaxing the implicit `Sized` restriction
    |
@@ -61,8 +55,6 @@ LL | fn f9<X: ?Sized>(x1: Box<S<X>>) {
 LL |     f5(&(*x1, 34));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: only the last element of a tuple may have a dynamically sized type
 
@@ -74,8 +66,6 @@ LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
 LL |     f5(&(32, *x1));
    |         ^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
    = note: tuples must have a statically known size to be initialized
@@ -91,8 +81,6 @@ LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
 LL |     f5(&(32, *x1));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
 help: consider relaxing the implicit `Sized` restriction
index de4da309791c0d5a928e510f27c52292476c571f..3fd0b429becc186fd39609cdd341a58f7fa7ffbe 100644 (file)
@@ -1,47 +1,77 @@
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized5.rs:4:5
+  --> $DIR/unsized5.rs:4:9
    |
 LL | struct S1<X: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
 LL |     f1: X,
-   |     ^^^^^ 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 `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     f1: &X,
+   |         ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     f1: Box<X>,
+   |         ^^^^ ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized5.rs:10:5
+  --> $DIR/unsized5.rs:10:8
    |
 LL | struct S2<X: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
 LL |     f: isize,
 LL |     g: X,
-   |     ^^^^ 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 `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     g: &X,
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     g: Box<X>,
+   |        ^^^^ ^
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/unsized5.rs:15:5
+  --> $DIR/unsized5.rs:15:8
    |
 LL |     f: str,
-   |     ^^^^^^ 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 `str`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     f: &str,
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     f: Box<str>,
+   |        ^^^^   ^
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/unsized5.rs:20:5
+  --> $DIR/unsized5.rs:20:8
    |
 LL |     f: [u8],
-   |     ^^^^^^^ 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 `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     f: &[u8],
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     f: Box<[u8]>,
+   |        ^^^^    ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized5.rs:25:8
@@ -51,21 +81,35 @@ LL | enum E<X: ?Sized> {
 LL |     V1(X, isize),
    |        ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     V1(&X, isize),
+   |        ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     V1(Box<X>, isize),
+   |        ^^^^ ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
-  --> $DIR/unsized5.rs:29:8
+  --> $DIR/unsized5.rs:29:12
    |
 LL | enum F<X: ?Sized> {
    |        - this type parameter needs to be `std::marker::Sized`
 LL |     V2{f1: X, f: isize},
-   |        ^^^^^ 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 `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     V2{f1: &X, f: isize},
+   |            ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     V2{f1: Box<X>, f: isize},
+   |            ^^^^ ^
 
 error: aborting due to 6 previous errors
 
index 337afd2ee7e100ca38470b61b3a528cacf91c50b..f045bfe2444bc8490d32292336a78a2337d879a7 100644 (file)
@@ -7,8 +7,6 @@ LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
 LL |     let y: Y;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Y`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -21,8 +19,6 @@ LL |     let _: W; // <-- this is OK, no bindings created, no initializer.
 LL |     let _: (isize, (X, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
@@ -34,8 +30,6 @@ LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
 LL |     let y: (isize, (Z, usize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Z`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
@@ -46,8 +40,6 @@ LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
 LL |     let y: X;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -60,8 +52,6 @@ LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
 LL |     let y: (isize, (Y, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `Y`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
@@ -72,8 +62,6 @@ LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -86,8 +74,6 @@ LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -100,8 +86,6 @@ LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -113,8 +97,6 @@ LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -127,8 +109,6 @@ LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -141,8 +121,6 @@ LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -154,10 +132,11 @@ LL | fn g1<X: ?Sized>(x: X) {}
    |       |
    |       this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn g1<X: ?Sized>(x: &X) {}
+   |                     ^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:40:22
@@ -167,10 +146,11 @@ LL | fn g2<X: ?Sized + T>(x: X) {}
    |       |
    |       this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn g2<X: ?Sized + T>(x: &X) {}
+   |                         ^
 
 error: aborting due to 13 previous errors
 
index e616a5cf0f9c216a7a473b472f883df748f27de8..7dbddd4ed24430579ccc44e484b859a91482cb3a 100644 (file)
@@ -9,8 +9,6 @@ LL | impl<X: ?Sized + T> T1<X> for S3<X> {
    |      |
    |      this type parameter needs to be `std::marker::Sized`
    |
-   = help: the trait `std::marker::Sized` is not implemented for `X`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: consider relaxing the implicit `Sized` restriction
    |
 LL | trait T1<Z: T + ?Sized> {
index b222d07580eaf167c04f7d85f34f5357a493f548..fedec1909fd3374e38132e42dd4c26d6ea5dabd5 100644 (file)
@@ -1,11 +1,10 @@
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/wf-array-elem-sized.rs:7:5
+  --> $DIR/wf-array-elem-sized.rs:7:10
    |
 LL |     foo: [[u8]],
-   |     ^^^^^^^^^^^ 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 `[u8]`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: slice and array elements must have `Sized` type
 
 error: aborting due to previous error
index 0a3665fcf0436b191cff8afab827dbbb2868c1a8..1eb7010c77a79988e88589ad0f93444f90ec3eb4 100644 (file)
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied
-  --> $DIR/wf-enum-fields-struct-variant.rs:13:9
+  --> $DIR/wf-enum-fields-struct-variant.rs:13:12
    |
 LL | struct IsCopy<T:Copy> {
    |                 ---- required by this bound in `IsCopy`
 ...
 LL |         f: IsCopy<A>
-   |         ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
+   |            ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
    |
 help: consider restricting type parameter `A`
    |
index 731d31ac34f628d7009c171e5d2c0977fd00a21b..938336d3ace76f769d954888bfcb70395c95002c 100644 (file)
@@ -22,7 +22,6 @@ LL | struct Vec<T> {
    |            - required by this bound in `Vec`
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
 help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
   --> $DIR/wf-fn-where-clause.rs:16:12
    |
index c0bb3a50b1f1eb7a09e2f8246e4271703a3aff1e..212c61e1e5e07336f10cd5dac645d4c0923aac78 100644 (file)
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/wf-in-fn-type-arg.rs:9:5
+  --> $DIR/wf-in-fn-type-arg.rs:9:8
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ---- required by this bound in `MustBeCopy`
 ...
 LL |     x: fn(MustBeCopy<T>)
-   |     ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |        ^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
index e203058250790776ea76103ab6bb71afdaaec627..3fb05fe81763bd4f5da0ec4516bd5e1036d7a231 100644 (file)
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/wf-in-fn-type-ret.rs:9:5
+  --> $DIR/wf-in-fn-type-ret.rs:9:8
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ---- required by this bound in `MustBeCopy`
 ...
 LL |     x: fn() -> MustBeCopy<T>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |        ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
index a79c446247794ad59a1fdbc56bfd1922059da488..44cacf4ef4dfe5d75fadd5041c0f93ed50af7178 100644 (file)
@@ -1,20 +1,20 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-fn-type-static.rs:13:5
+  --> $DIR/wf-in-fn-type-static.rs:13:8
    |
 LL | struct Foo<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // needs T: 'static
 LL |     x: fn() -> &'static T
-   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-fn-type-static.rs:18:5
+  --> $DIR/wf-in-fn-type-static.rs:18:8
    |
 LL | struct Bar<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // needs T: Copy
 LL |     x: fn(&'static T)
-   |     ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error: aborting due to 2 previous errors
 
index c0057f3c82977fd990fc09b3251108ec65239106..c50a6bb6e4d878939e0c963e3a3306dcf5d556c6 100644 (file)
@@ -1,11 +1,11 @@
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-obj-type-static.rs:14:5
+  --> $DIR/wf-in-obj-type-static.rs:14:8
    |
 LL | struct Foo<T> {
    |            - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // needs T: 'static
 LL |     x: dyn Object<&'static T>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
+   |        ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at
 
 error: aborting due to previous error
 
index 6d85cdde7f99191552029c12d7d32a9671e9d29b..129f9484df29bef1993cfcec02bf9311fed5f650 100644 (file)
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/wf-in-obj-type-trait.rs:11:5
+  --> $DIR/wf-in-obj-type-trait.rs:11:8
    |
 LL | struct MustBeCopy<T:Copy> {
    |                     ---- required by this bound in `MustBeCopy`
 ...
 LL |     x: dyn Object<MustBeCopy<T>>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
index cda3b8fe4fddb2a0b701afe67452b83490febb56..d7d0b7a0820a8739a344e97e126c8971e972bcea 100644 (file)
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied
-  --> $DIR/wf-struct-field.rs:12:5
+  --> $DIR/wf-struct-field.rs:12:11
    |
 LL | struct IsCopy<T:Copy> {
    |                 ---- required by this bound in `IsCopy`
 ...
 LL |     data: IsCopy<A>
-   |     ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
+   |           ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
    |
 help: consider restricting type parameter `A`
    |
index e4a4b9c58060238a22eac415436778690f13768e..813d5d4fdb12b62c24b271fa6457c6d15865f498 100644 (file)
@@ -2,7 +2,7 @@ error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithFields
   --> $DIR/xcrate-unit-struct.rs:9:13
    |
 LL |     let _ = xcrate_unit_struct::StructWithFields;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `xcrate_unit_struct::StructWithFields { /* fields */ }`?
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }`
 
 error: aborting due to previous error
 
index 5c50587ea973d7bcf89a05b5867da0f195d33ec7..6ac89f2b1b82a4142670a507c77445f98737dfe2 100644 (file)
     "powerpc-unknown-linux-gnu",
     "powerpc64-unknown-linux-gnu",
     "powerpc64le-unknown-linux-gnu",
+    "riscv64gc-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
     "x86_64-apple-darwin",
     "x86_64-pc-windows-gnu",
     "x86_64-pc-windows-msvc",
     "x86_64-unknown-freebsd",
+    "x86_64-unknown-illumos",
     "x86_64-unknown-linux-gnu",
     "x86_64-unknown-linux-musl",
     "x86_64-unknown-netbsd",
index 4f74d9b2a771c58b7ef4906b2668afd075bc8081..43cf77395cad5b79887b20b7cf19d418bbd703a9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 4f74d9b2a771c58b7ef4906b2668afd075bc8081
+Subproject commit 43cf77395cad5b79887b20b7cf19d418bbd703a9
index 70445d7ef2503df26d21d5de4700a35054aa595b..98fd0df685fdb31711ea1c8234f9afea43e62c0a 100644 (file)
@@ -12,7 +12,7 @@ labels: L-lint
 
 - Kind: *See <https://github.com/rust-lang/rust-clippy/blob/master/README.md#clippy> for list of lint kinds*
 
-*What benefit of this lint over old code?*
+*What is the advantage of the recommended code over the original code*
 
 For example:
 - Remove bounce checking inserted by ...
index 0c80394f03e3c83851d4f9b83ba4c6bfc7495032..fd0cd7a1890bd79c8630a52fcd17a39d729ed61f 100644 (file)
@@ -240,7 +240,8 @@ jobs:
         - 'Geal/nom'
         - 'rust-lang/stdarch'
         - 'serde-rs/serde'
-        - 'chronotope/chrono'
+        # FIXME: chrono currently cannot be compiled with `--all-targets`
+        # - 'chronotope/chrono'
         - 'hyperium/hyper'
         - 'rust-random/rand'
         - 'rust-lang/futures-rs'
index adc945a69441d5a59fb288d31f98f66c979bb904..5d08b44ba404f9294f0b45973e017e571c208058 100644 (file)
@@ -1352,6 +1352,7 @@ Released 2018-09-13
 [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
 [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
 [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
+[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
@@ -1508,9 +1509,11 @@ Released 2018-09-13
 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
+[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
 [`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
 [`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
+[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
 [`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
 [`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
 [`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
@@ -1575,6 +1578,7 @@ Released 2018-09-13
 [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
+[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
 [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
 [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
 [`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
@@ -1586,6 +1590,7 @@ Released 2018-09-13
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
+[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
@@ -1612,6 +1617,7 @@ Released 2018-09-13
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
+[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
index 9f7bdcb1be7e568183adf643df7cc3798620c985..69a734e4ee4c2126a6bef72218d0b9a4b5e4aafc 100644 (file)
@@ -245,7 +245,7 @@ this to work, you will need the fix of `git subtree` available
 [here][gitgitgadget-pr].
 
 [gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493
-[subtree]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#external-dependencies-subtree
+[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree
 [`rust-lang/rust`]: https://github.com/rust-lang/rust
 
 ## Issue and PR triage
index da60856fac932341e63ca5fe8558319b1e4e7667..e84481f9b5385a2a538cbfc1b3ffb75a0afc702d 100644 (file)
@@ -86,7 +86,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                     _ => (),
                 }
 
-                let (l_ty, r_ty) = (cx.tables().expr_ty(l), cx.tables().expr_ty(r));
+                let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r));
                 if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
                     span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
                     self.expr_span = Some(expr.span);
@@ -96,8 +96,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                 }
             },
             hir::ExprKind::Unary(hir::UnOp::UnNeg, arg) => {
-                let ty = cx.tables().expr_ty(arg);
-                if constant_simple(cx, cx.tables(), expr).is_none() {
+                let ty = cx.typeck_results().expr_ty(arg);
+                if constant_simple(cx, cx.typeck_results(), expr).is_none() {
                     if ty.is_integral() {
                         span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
                         self.expr_span = Some(expr.span);
index cffe8d94e27979565e332e3c0df97e1c1549f991..982d5ecf8d02f03aae9cc3fd52b19be5685fb266 100644 (file)
@@ -72,7 +72,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             }
             if_chain! {
                 if let ExprKind::Unary(_, ref lit) = e.kind;
-                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), lit);
+                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit);
                 if is_true;
                 then {
                     lint_true(true);
@@ -121,7 +121,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
         if let ExprKind::DropTemps(ref expr) = expr.kind;
         if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind;
         // bind the first argument of the `assert!` macro
-        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), expr);
+        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
         // arm 1 pattern
         if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind;
         if let ExprKind::Lit(ref lit) = lit_expr.kind;
index bc6e868823f77c78a158c0d1fdac6a14958069f3..dab1e96e282f051c75f8184b718f745fb711cace 100644 (file)
@@ -82,8 +82,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             hir::ExprKind::Assign(assignee, e, _) => {
                 if let hir::ExprKind::Binary(op, l, r) = &e.kind {
                     let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
-                        let ty = cx.tables().expr_ty(assignee);
-                        let rty = cx.tables().expr_ty(rhs);
+                        let ty = cx.typeck_results().expr_ty(assignee);
+                        let rty = cx.typeck_results().expr_ty(rhs);
                         macro_rules! ops {
                             ($op:expr,
                              $cx:expr,
@@ -167,7 +167,7 @@ macro_rules! ops {
                         // a = b commutative_op a
                         // Limited to primitive type as these ops are know to be commutative
                         if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
-                            && cx.tables().expr_ty(assignee).is_primitive_ty()
+                            && cx.typeck_results().expr_ty(assignee).is_primitive_ty()
                         {
                             match op.node {
                                 hir::BinOpKind::Add
index efd3f0f671cddd844770d359e0fcb550c19da98e..277fe350055ec357a81f6a4a0f0a95f03e74fca6 100644 (file)
@@ -53,7 +53,7 @@
 ];
 
 fn type_is_atomic(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables().expr_ty(expr).kind {
+    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind {
         ATOMIC_TYPES
             .iter()
             .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty]))
index 3f7d6ba6467701fd2a5aec843328a61037123f10..27a7fa8862237196e2cd6c08efeeb95a90aa7b4c 100644 (file)
@@ -2,8 +2,8 @@
 
 use crate::reexport::Name;
 use crate::utils::{
-    first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg,
-    span_lint_and_then, without_block_comments,
+    first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_help,
+    span_lint_and_sugg, span_lint_and_then, without_block_comments,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
@@ -17,7 +17,7 @@
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{Symbol, SymbolStr};
 use semver::Version;
 
 static UNIX_SYSTEMS: &[&str] = &[
     "unknown_lints for scoped Clippy lints"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
+    ///
+    /// **Why is this bad?** Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
+    /// These lints should only be enabled on a lint-by-lint basis and with careful consideration.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```rust
+    /// #![deny(clippy::restriction)]
+    /// ```
+    ///
+    /// Good:
+    /// ```rust
+    /// #![deny(clippy::as_conversions)]
+    /// ```
+    pub BLANKET_CLIPPY_RESTRICTION_LINTS,
+    style,
+    "enabling the complete restriction group"
+}
+
 declare_clippy_lint! {
     /// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
     /// with `#[rustfmt::skip]`.
     DEPRECATED_SEMVER,
     USELESS_ATTRIBUTE,
     UNKNOWN_CLIPPY_LINTS,
+    BLANKET_CLIPPY_RESTRICTION_LINTS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Attributes {
     fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
         if let Some(items) = &attr.meta_item_list() {
             if let Some(ident) = attr.ident() {
-                match &*ident.as_str() {
+                let ident = &*ident.as_str();
+                match ident {
                     "allow" | "warn" | "deny" | "forbid" => {
-                        check_clippy_lint_names(cx, items);
+                        check_clippy_lint_names(cx, ident, items);
                     },
                     _ => {},
                 }
@@ -363,38 +388,47 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
     }
 }
 
-#[allow(clippy::single_match_else)]
-fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) {
-    let lint_store = cx.lints();
-    for lint in items {
+fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
+    fn extract_name(lint: &NestedMetaItem) -> Option<SymbolStr> {
         if_chain! {
             if let Some(meta_item) = lint.meta_item();
             if meta_item.path.segments.len() > 1;
             if let tool_name = meta_item.path.segments[0].ident;
             if tool_name.as_str() == "clippy";
-            let name = meta_item.path.segments.last().unwrap().ident.name;
-            if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(
-                &name.as_str(),
-                Some(tool_name.name),
-            );
+            let lint_name = meta_item.path.segments.last().unwrap().ident.name;
             then {
+                return Some(lint_name.as_str());
+            }
+        }
+        None
+    }
+
+    let lint_store = cx.lints();
+    for lint in items {
+        if let Some(lint_name) = extract_name(lint) {
+            if let CheckLintNameResult::Tool(Err((None, _))) =
+                lint_store.check_lint_name(&lint_name, Some(sym!(clippy)))
+            {
                 span_lint_and_then(
                     cx,
                     UNKNOWN_CLIPPY_LINTS,
                     lint.span(),
-                    &format!("unknown clippy lint: clippy::{}", name),
+                    &format!("unknown clippy lint: clippy::{}", lint_name),
                     |diag| {
-                        let name_lower = name.as_str().to_lowercase();
-                        let symbols = lint_store.get_lints().iter().map(
-                            |l| Symbol::intern(&l.name_lower())
-                        ).collect::<Vec<_>>();
+                        let name_lower = lint_name.to_lowercase();
+                        let symbols = lint_store
+                            .get_lints()
+                            .iter()
+                            .map(|l| Symbol::intern(&l.name_lower()))
+                            .collect::<Vec<_>>();
                         let sugg = find_best_match_for_name(
                             symbols.iter(),
-                            &format!("clippy::{}", name_lower),
+                            Symbol::intern(&format!("clippy::{}", name_lower)),
                             None,
                         );
-                        if name.as_str().chars().any(char::is_uppercase)
-                            && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok() {
+                        if lint_name.chars().any(char::is_uppercase)
+                            && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok()
+                        {
                             diag.span_suggestion(
                                 lint.span(),
                                 "lowercase the lint name",
@@ -409,16 +443,25 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) {
                                 Applicability::MachineApplicable,
                             );
                         }
-                    }
+                    },
+                );
+            } else if lint_name == "restriction" && ident != "allow" {
+                span_lint_and_help(
+                    cx,
+                    BLANKET_CLIPPY_RESTRICTION_LINTS,
+                    lint.span(),
+                    "restriction lints are not meant to be all enabled",
+                    None,
+                    "try enabling only the lints you really need",
                 );
             }
-        };
+        }
     }
 }
 
 fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if let ItemKind::Fn(_, _, eid) = item.kind {
-        is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value)
+        is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
     } else {
         true
     }
@@ -426,7 +469,7 @@ fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
 
 fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
     match item.kind {
-        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value),
+        ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value),
         _ => false,
     }
 }
@@ -435,36 +478,37 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool {
     match item.kind {
         TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
         TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
-            is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value)
+            is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
         },
         _ => false,
     }
 }
 
-fn is_relevant_block(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, block: &Block<'_>) -> bool {
-    if let Some(stmt) = block.stmts.first() {
-        match &stmt.kind {
+fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool {
+    block.stmts.first().map_or(
+        block
+            .expr
+            .as_ref()
+            .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)),
+        |stmt| match &stmt.kind {
             StmtKind::Local(_) => true,
-            StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, tables, expr),
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
             _ => false,
-        }
-    } else {
-        block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e))
-    }
+        },
+    )
 }
 
-fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: &Expr<'_>) -> bool {
+fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool {
     match &expr.kind {
-        ExprKind::Block(block, _) => is_relevant_block(cx, tables, block),
-        ExprKind::Ret(Some(e)) => is_relevant_expr(cx, tables, e),
+        ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block),
+        ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e),
         ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
         ExprKind::Call(path_expr, _) => {
             if let ExprKind::Path(qpath) = &path_expr.kind {
-                if let Some(fun_id) = tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
-                    !match_def_path(cx, fun_id, &paths::BEGIN_PANIC)
-                } else {
-                    true
-                }
+                typeck_results
+                    .qpath_res(qpath, path_expr.hir_id)
+                    .opt_def_id()
+                    .map_or(true, |fun_id| !match_def_path(cx, fun_id, &paths::BEGIN_PANIC))
             } else {
                 true
             }
index 20b91bc0f1bafcbc4e2b7cf6065262fef1553d07..b10b1e0a65ab94e0b3ea232fdad304ba689ab776 100644 (file)
@@ -11,7 +11,7 @@
     /// non-async-aware MutexGuard.
     ///
     /// **Why is this bad?** The Mutex types found in syd::sync and parking_lot
-    /// are not designed to operator in an async context across await points.
+    /// are not designed to operate in an async context across await points.
     ///
     /// There are two potential solutions. One is to use an asynx-aware Mutex
     /// type. Many asynchronous foundation crates provide such a Mutex type. The
@@ -59,8 +59,8 @@ fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
                 hir_id: body.value.hir_id,
             };
             let def_id = cx.tcx.hir().body_owner_def_id(body_id);
-            let tables = cx.tcx.typeck_tables_of(def_id);
-            check_interior_types(cx, &tables.generator_interior_types, body.value.span);
+            let typeck_results = cx.tcx.typeck(def_id);
+            check_interior_types(cx, &typeck_results.generator_interior_types, body.value.span);
         }
     }
 }
index d1d177e7a4abb2c0a10820c804920c460688d3ff..81a34021e8a018aa78faf6cf5b57deb9ba40bf23 100644 (file)
@@ -319,7 +319,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
 }
 
 fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> {
-    match constant(cx, cx.tables(), lit)?.0 {
+    match constant(cx, cx.typeck_results(), lit)?.0 {
         Constant::Int(n) => Some(n),
         _ => None,
     }
index 32d0979e99b6071801f8de393d53fc14ec429354..18529f2113e77bc16a36b798f3a71ac1539c2917 100644 (file)
@@ -111,8 +111,12 @@ fn negate(bin_op_kind: BinOpKind) -> Option<BinOpKind> {
             match &e.kind {
                 ExprKind::Unary(UnOp::UnNot, inner) => return Ok(Bool::Not(box self.run(inner)?)),
                 ExprKind::Binary(binop, lhs, rhs) => match &binop.node {
-                    BinOpKind::Or => return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?)),
-                    BinOpKind::And => return Ok(Bool::And(self.extract(BinOpKind::And, &[lhs, rhs], Vec::new())?)),
+                    BinOpKind::Or => {
+                        return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?));
+                    },
+                    BinOpKind::And => {
+                        return Ok(Bool::And(self.extract(BinOpKind::And, &[lhs, rhs], Vec::new())?));
+                    },
                     _ => (),
                 },
                 ExprKind::Lit(lit) => match lit.node {
@@ -248,7 +252,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
             })
         },
         ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => {
-            let type_of_receiver = cx.tables().expr_ty(&args[0]);
+            let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
             if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type))
                 && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type))
             {
@@ -450,7 +454,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                 self.bool_expr(e)
             },
             ExprKind::Unary(UnOp::UnNot, inner) => {
-                if self.cx.tables().node_types()[inner.hir_id].is_bool() {
+                if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
                     self.bool_expr(e);
                 } else {
                     walk_expr(self, e);
@@ -465,7 +469,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 }
 
 fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
-    let ty = cx.tables().expr_ty(expr);
+    let ty = cx.typeck_results().expr_ty(expr);
     get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
 }
 
index 1cdfea1f526555805c303c1124fb839291d77b8c..dde799fcae4cc4165b82ca6f153c97d4286f5cbb 100644 (file)
@@ -53,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                     if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind;
                     if op.node == BinOpKind::Eq;
                     if match_type(cx,
-                               walk_ptrs_ty(cx.tables().expr_ty(&filter_args[0])),
+                               walk_ptrs_ty(cx.typeck_results().expr_ty(&filter_args[0])),
                                &paths::SLICE_ITER);
                     then {
                         let needle = match get_path_name(l) {
@@ -63,7 +63,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                                 _ => { return; }
                             }
                         };
-                        if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables().expr_ty(needle)).kind {
+                        if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind {
                             return;
                         }
                         let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
index 6bbdbe957cc83697841a4ac16117bb1e883c41c4..14ef8c319eff1c63b322e21c935fd0c94af8381c 100644 (file)
@@ -60,7 +60,7 @@ fn check<'tcx>(
         let mut helper = CCHelper { cc: 1, returns: 0 };
         helper.visit_expr(expr);
         let CCHelper { cc, returns } = helper;
-        let ret_ty = cx.tables().node_type(expr.hir_id);
+        let ret_ty = cx.typeck_results().node_type(expr.hir_id);
         let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) {
             returns
         } else {
index 8090f4673aae0e225f5507869893c6cfcd4c639b..42bff564de03d471b49264bee9da3daaa691cb19 100644 (file)
@@ -115,7 +115,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
                 COLLAPSIBLE_IF,
                 block.span,
                 "this `else { if .. }` block can be collapsed",
-                "try",
+                "collapse nested if block",
                 snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability).into_owned(),
                 applicability,
             );
@@ -142,7 +142,7 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
                 let rhs = Sugg::ast(cx, check_inner, "..");
                 diag.span_suggestion(
                     expr.span,
-                    "try",
+                    "collapse nested if block",
                     format!(
                         "if {} {}",
                         lhs.and(&rhs),
index 26476af4cb629c34cf343901488a7ee70e2b7174..99f161a0510f4286c7f682016562dd7e99439a6a 100644 (file)
@@ -99,7 +99,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 }
 
                 // Check that the type being compared implements `core::cmp::Ord`
-                let ty = cx.tables().expr_ty(lhs1);
+                let ty = cx.typeck_results().expr_ty(lhs1);
                 let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]));
 
                 if !is_ord {
@@ -122,8 +122,5 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 }
 
 fn kind_is_cmp(kind: BinOpKind) -> bool {
-    match kind {
-        BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq => true,
-        _ => false,
-    }
+    matches!(kind, BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq)
 }
index 2f963dfcf8b186418c60996005b866bf40853dbf..49ff86a205d96cb20bb7a5d4a4a510b2e6f5d7f4 100644 (file)
@@ -174,12 +174,12 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
 
 pub fn constant<'tcx>(
     lcx: &LateContext<'tcx>,
-    tables: &ty::TypeckTables<'tcx>,
+    typeck_results: &ty::TypeckResults<'tcx>,
     e: &Expr<'_>,
 ) -> Option<(Constant, bool)> {
     let mut cx = ConstEvalLateContext {
         lcx,
-        tables,
+        typeck_results,
         param_env: lcx.param_env,
         needed_resolution: false,
         substs: lcx.tcx.intern_substs(&[]),
@@ -189,20 +189,20 @@ pub fn constant<'tcx>(
 
 pub fn constant_simple<'tcx>(
     lcx: &LateContext<'tcx>,
-    tables: &ty::TypeckTables<'tcx>,
+    typeck_results: &ty::TypeckResults<'tcx>,
     e: &Expr<'_>,
 ) -> Option<Constant> {
-    constant(lcx, tables, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
+    constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
 }
 
-/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`.
+/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
 pub fn constant_context<'a, 'tcx>(
     lcx: &'a LateContext<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
 ) -> ConstEvalLateContext<'a, 'tcx> {
     ConstEvalLateContext {
         lcx,
-        tables,
+        typeck_results,
         param_env: lcx.param_env,
         needed_resolution: false,
         substs: lcx.tcx.intern_substs(&[]),
@@ -211,7 +211,7 @@ pub fn constant_context<'a, 'tcx>(
 
 pub struct ConstEvalLateContext<'a, 'tcx> {
     lcx: &'a LateContext<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     needed_resolution: bool,
     substs: SubstsRef<'tcx>,
@@ -224,21 +224,21 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
             return self.ifthenelse(cond, then, otherwise);
         }
         match e.kind {
-            ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.tables.expr_ty(e)),
+            ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
             ExprKind::Block(ref block, _) => self.block(block),
-            ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.tables.expr_ty_opt(e))),
+            ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
             ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
             ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
             ExprKind::Repeat(ref value, _) => {
-                let n = match self.tables.expr_ty(e).kind {
+                let n = match self.typeck_results.expr_ty(e).kind {
                     ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
                     _ => span_bug!(e.span, "typeck error"),
                 };
                 self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
             },
             ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
-                UnOp::UnNot => self.constant_not(&o, self.tables.expr_ty(e)),
-                UnOp::UnNeg => self.constant_negate(&o, self.tables.expr_ty(e)),
+                UnOp::UnNot => self.constant_not(&o, self.typeck_results.expr_ty(e)),
+                UnOp::UnNeg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
                 UnOp::UnDeref => Some(o),
             }),
             ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
@@ -247,7 +247,7 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
                 if_chain! {
                     if args.is_empty();
                     if let ExprKind::Path(qpath) = &callee.kind;
-                    let res = self.tables.qpath_res(qpath, callee.hir_id);
+                    let res = self.typeck_results.qpath_res(qpath, callee.hir_id);
                     if let Some(def_id) = res.opt_def_id();
                     let def_path: Vec<_> = self.lcx.get_def_path(def_id).into_iter().map(Symbol::as_str).collect();
                     let def_path: Vec<&str> = def_path.iter().take(4).map(|s| &**s).collect();
@@ -319,10 +319,10 @@ fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant>> {
 
     /// Lookup a possibly constant expression from a `ExprKind::Path`.
     fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> {
-        let res = self.tables.qpath_res(qpath, id);
+        let res = self.typeck_results.qpath_res(qpath, id);
         match res {
             Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
-                let substs = self.tables.node_substs(id);
+                let substs = self.typeck_results.node_substs(id);
                 let substs = if self.substs.is_empty() {
                     substs
                 } else {
@@ -332,7 +332,13 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<C
                 let result = self
                     .lcx
                     .tcx
-                    .const_eval_resolve(self.param_env, def_id, substs, None, None)
+                    .const_eval_resolve(
+                        self.param_env,
+                        ty::WithOptConstParam::unknown(def_id),
+                        substs,
+                        None,
+                        None,
+                    )
                     .ok()
                     .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
                 let result = miri_to_const(&result);
@@ -396,7 +402,7 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
-            (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty_opt(left)?.kind {
+            (Constant::Int(l), Some(Constant::Int(r))) => match self.typeck_results.expr_ty_opt(left)?.kind {
                 ty::Int(ity) => {
                     let l = sext(self.lcx.tcx, l, ity);
                     let r = sext(self.lcx.tcx, r, ity);
@@ -488,23 +494,25 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
 pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
     use rustc_middle::mir::interpret::{ConstValue, Scalar};
     match result.val {
-        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => match result.ty.kind {
-            ty::Bool => Some(Constant::Bool(d == 1)),
-            ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)),
-            ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
-                d.try_into().expect("invalid f32 bit representation"),
-            ))),
-            ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
-                d.try_into().expect("invalid f64 bit representation"),
-            ))),
-            ty::RawPtr(type_and_mut) => {
-                if let ty::Uint(_) = type_and_mut.ty.kind {
-                    return Some(Constant::RawPtr(d));
-                }
-                None
-            },
-            // FIXME: implement other conversions.
-            _ => None,
+        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => {
+            match result.ty.kind {
+                ty::Bool => Some(Constant::Bool(d == 1)),
+                ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)),
+                ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
+                    d.try_into().expect("invalid f32 bit representation"),
+                ))),
+                ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
+                    d.try_into().expect("invalid f64 bit representation"),
+                ))),
+                ty::RawPtr(type_and_mut) => {
+                    if let ty::Uint(_) = type_and_mut.ty.kind {
+                        return Some(Constant::RawPtr(d));
+                    }
+                    None
+                },
+                // FIXME: implement other conversions.
+                _ => None,
+            }
         },
         ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind {
             ty::Ref(_, tam, _) => match tam.kind {
index 1257032337acc959f9f170e6c5103f4eb6e7796f..1f8bff8d71e0f33d77c8e1c3b06237196d98baf6 100644 (file)
@@ -320,7 +320,7 @@ fn bindings_impl<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, map: &mut FxHashMa
             },
             PatKind::Binding(.., ident, ref as_pat) => {
                 if let Entry::Vacant(v) = map.entry(ident.name) {
-                    v.insert(cx.tables().pat_ty(pat));
+                    v.insert(cx.typeck_results().pat_ty(pat));
                 }
                 if let Some(ref as_pat) = *as_pat {
                     bindings_impl(cx, as_pat, map);
index fab95db01960475c85435786223925dcdc756d6d..ea2447681293de4d1e438e15330fdc7d239f8a7e 100644 (file)
@@ -54,7 +54,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
                         // TODO: Work out a way to put "whatever the imported way of referencing
                         // this type in this file" rather than a fully-qualified type.
-                        let expr_ty = cx.tables().expr_ty(expr);
+                        let expr_ty = cx.typeck_results().expr_ty(expr);
                         if let ty::Adt(..) = expr_ty.kind {
                             let replacement = format!("{}::default()", expr_ty);
                             span_lint_and_sugg(
index 6e8ca647dd7ae930e9c7dde397c4ae78e0178314..818d8188a787a6608f3071810b539010fea3ffcb 100644 (file)
@@ -153,5 +153,13 @@ macro_rules! declare_deprecated_lint {
     ///
     /// **Deprecation reason:** Associated-constants are now preferred.
     pub REPLACE_CONSTS,
-    "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants"
+    "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants"
+}
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The regex! macro does not exist anymore.
+    pub REGEX_MACRO,
+    "the regex! macro has been removed from the regex crate in 2018"
 }
index d740d88a77d6cb8b018764c43b54840901066dc8..102cf597d22e368ee04d86b01ffd5a57de24cbd0 100644 (file)
@@ -73,9 +73,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) {
     match method_name {
         "deref" => {
-            if cx.tcx.lang_items().deref_trait().map_or(false, |id| {
-                implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
-            }) {
+            let impls_deref_trait = cx.tcx.lang_items().deref_trait().map_or(false, |id| {
+                implements_trait(cx, cx.typeck_results().expr_ty(&call_expr), id, &[])
+            });
+            if impls_deref_trait {
                 span_lint_and_sugg(
                     cx,
                     EXPLICIT_DEREF_METHODS,
@@ -88,9 +89,10 @@ fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var
             }
         },
         "deref_mut" => {
-            if cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
-                implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
-            }) {
+            let impls_deref_mut_trait = cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
+                implements_trait(cx, cx.typeck_results().expr_ty(&call_expr), id, &[])
+            });
+            if impls_deref_mut_trait {
                 span_lint_and_sugg(
                     cx,
                     EXPLICIT_DEREF_METHODS,
index dcf772572e8cb03bd0b46ee51825bc9110085be1..57ff569f14b0f7bb18d54817b5a38742172254f2 100644 (file)
@@ -119,7 +119,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 let lint;
                 let msg;
                 let arg = &args[0];
-                let arg_ty = cx.tables().expr_ty(arg);
+                let arg_ty = cx.typeck_results().expr_ty(arg);
 
                 if let ty::Ref(..) = arg_ty.kind {
                     if match_def_path(cx, def_id, &paths::DROP) {
index 2ded375091c60f5be1822c2030b018f24b58346e..1dfb2eaa579728d98bf628f9e3b467f9ca6725c5 100644 (file)
@@ -43,8 +43,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind;
             if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind;
-            if match_type(cx, walk_ptrs_ty(cx.tables().expr_ty(&args[0])), &paths::DURATION);
-            if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables(), right);
+            if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::DURATION);
+            if let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right);
             then {
                 let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {
                     ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
index 4d2e17933ed6b55ffebad53cef764e58e80e0ce5..d616502a82a0c07adbbbda1150fb47580ca3558e 100644 (file)
@@ -106,7 +106,7 @@ fn check_cond<'a>(cx: &LateContext<'_>, check: &'a Expr<'a>) -> Option<(&'static
         if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind;
         then {
             let map = &params[0];
-            let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(map));
+            let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(map));
 
             return if match_type(cx, obj_ty, &paths::BTREEMAP) {
                 Some(("BTreeMap", map, key))
index cbc93d772dd91b04b344ae2dd9003a657e3a2aad..140cd21c34e67916b9922565cbaf11ec46a9adef 100644 (file)
@@ -103,8 +103,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},
                     // &foo == &bar
                     (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
-                        let lty = cx.tables().expr_ty(l);
-                        let rty = cx.tables().expr_ty(r);
+                        let lty = cx.typeck_results().expr_ty(l);
+                        let rty = cx.typeck_results().expr_ty(r);
                         let lcpy = is_copy(cx, lty);
                         let rcpy = is_copy(cx, rty);
                         // either operator autorefs or both args are copyable
@@ -126,7 +126,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             )
                         } else if lcpy
                             && !rcpy
-                            && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()])
+                            && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
                         {
                             span_lint_and_then(
                                 cx,
@@ -145,7 +145,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                             )
                         } else if !lcpy
                             && rcpy
-                            && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()])
+                            && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
                         {
                             span_lint_and_then(
                                 cx,
@@ -166,10 +166,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     },
                     // &foo == bar
                     (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), _) => {
-                        let lty = cx.tables().expr_ty(l);
+                        let lty = cx.typeck_results().expr_ty(l);
                         let lcpy = is_copy(cx, lty);
                         if (requires_ref || lcpy)
-                            && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()])
+                            && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
                         {
                             span_lint_and_then(
                                 cx,
@@ -190,10 +190,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     },
                     // foo == &bar
                     (_, &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
-                        let rty = cx.tables().expr_ty(r);
+                        let rty = cx.typeck_results().expr_ty(r);
                         let rcpy = is_copy(cx, rty);
                         if (requires_ref || rcpy)
-                            && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()])
+                            && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
                         {
                             span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |diag| {
                                 let rsnip = snippet(cx, r.span, "...").to_string();
@@ -214,20 +214,20 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 }
 
 fn is_valid_operator(op: BinOp) -> bool {
-    match op.node {
+    matches!(
+        op.node,
         BinOpKind::Sub
-        | BinOpKind::Div
-        | BinOpKind::Eq
-        | BinOpKind::Lt
-        | BinOpKind::Le
-        | BinOpKind::Gt
-        | BinOpKind::Ge
-        | BinOpKind::Ne
-        | BinOpKind::And
-        | BinOpKind::Or
-        | BinOpKind::BitXor
-        | BinOpKind::BitAnd
-        | BinOpKind::BitOr => true,
-        _ => false,
-    }
+            | BinOpKind::Div
+            | BinOpKind::Eq
+            | BinOpKind::Lt
+            | BinOpKind::Le
+            | BinOpKind::Gt
+            | BinOpKind::Ge
+            | BinOpKind::Ne
+            | BinOpKind::And
+            | BinOpKind::Or
+            | BinOpKind::BitXor
+            | BinOpKind::BitAnd
+            | BinOpKind::BitOr
+    )
 }
index 8a2683806182648aee3c7601a2e8c032fe002c83..dbd1ff514f0e13292b6d7a8a0aa2efc7b2e220d6 100644 (file)
@@ -48,7 +48,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 }
 
 fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) {
-    if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables(), e) {
+    if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), e) {
         span_lint(
             cx,
             ERASING_OP,
index b10181062ff10042703b31c373d875ad64658841..82549c12d0a207c31b839bcc726dba37d9e61e07 100644 (file)
@@ -84,7 +84,7 @@ fn check_fn(
 
         let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
         cx.tcx.infer_ctxt().enter(|infcx| {
-            ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body);
+            ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
         });
 
         for node in v.set {
@@ -105,10 +105,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
         _ => return false,
     }
 
-    match map.find(map.get_parent_node(id)) {
-        Some(Node::Param(_)) => true,
-        _ => false,
-    }
+    matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_)))
 }
 
 impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
index ceed6a74c4fcc3d1ffb4110022b8b7e879296c69..87254c1dbc490a9fac3706194fa35d9759f4d4cc 100644 (file)
@@ -97,7 +97,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
             // Are the expression or the arguments type-adjusted? Then we need the closure
             if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));
 
-            let fn_ty = cx.tables().expr_ty(caller);
+            let fn_ty = cx.typeck_results().expr_ty(caller);
 
             if matches!(fn_ty.kind, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));
 
@@ -128,7 +128,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
             // Are the expression or the arguments type-adjusted? Then we need the closure
             if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));
 
-            let method_def_id = cx.tables().type_dependent_def_id(ex.hir_id).unwrap();
+            let method_def_id = cx.typeck_results().type_dependent_def_id(ex.hir_id).unwrap();
             if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));
 
             if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter());
@@ -153,7 +153,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
 /// Tries to determine the type for universal function call to be used instead of the closure
 fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_arg: &Expr<'_>) -> Option<String> {
     let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
-    let actual_type_of_self = &cx.tables().node_type(self_arg.hir_id);
+    let actual_type_of_self = &cx.typeck_results().node_type(self_arg.hir_id);
 
     if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
         if match_borrow_depth(expected_type_of_self, &actual_type_of_self)
@@ -175,10 +175,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
 fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
     match (&lhs.kind, &rhs.kind) {
         (ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2),
-        (l, r) => match (l, r) {
-            (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
-            (_, _) => true,
-        },
+        (l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))),
     }
 }
 
index 01b0d3c5edec22c938853328299f5ccf508ea5f0..c00638ecc0c1d26619ef188f3b66da2f1e6a5bc4 100644 (file)
@@ -137,7 +137,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
             ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
             ExprKind::Call(ref func, _) => {
-                let typ = self.cx.tables().expr_ty(func);
+                let typ = self.cx.typeck_results().expr_ty(func);
                 match typ.kind {
                     ty::FnDef(..) | ty::FnPtr(_) => {
                         let sig = typ.fn_sig(self.cx.tcx);
@@ -149,7 +149,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                 }
             },
             ExprKind::MethodCall(..) => {
-                let borrowed_table = self.cx.tables();
+                let borrowed_table = self.cx.typeck_results();
                 if borrowed_table.expr_ty(e).is_never() {
                     self.report_diverging_sub_expr(e);
                 }
index 01ed0c426d436b56f72235a872f0ccab93fb37a1..000762334f61eb022944aa0ca69fb84e3a21bf41 100644 (file)
@@ -73,7 +73,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
 
     struct FindPanicUnwrap<'a, 'tcx> {
         lcx: &'a LateContext<'tcx>,
-        tables: &'tcx ty::TypeckTables<'tcx>,
+        typeck_results: &'tcx ty::TypeckResults<'tcx>,
         result: Vec<Span>,
     }
 
@@ -96,7 +96,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-                let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
+                let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0]));
                 if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
                     || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
                 {
@@ -124,7 +124,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
                 let impl_item_def_id = cx.tcx.hir().local_def_id(impl_item.id.hir_id);
                 let mut fpu = FindPanicUnwrap {
                     lcx: cx,
-                    tables: cx.tcx.typeck_tables_of(impl_item_def_id),
+                    typeck_results: cx.tcx.typeck(impl_item_def_id),
                     result: Vec::new(),
                 };
                 fpu.visit_expr(&body.value);
index a3d2a949535a494cbe5687829d21c6da8c82046e..358b9f6dcd0a5eb3cd66c092c3d238c1ee1376a9 100644 (file)
@@ -61,7 +61,7 @@
 impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
-            let ty = cx.tables().expr_ty(expr);
+            let ty = cx.typeck_results().expr_ty(expr);
             if let ty::Float(fty) = ty.kind;
             if let hir::ExprKind::Lit(ref lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
index 4efd06892679649ca485e4fa45dd3dca4b6efd29..93f6ec92ec71328512aeb92b4b6b5976139fc45b 100644 (file)
@@ -1,11 +1,11 @@
 use crate::consts::{
     constant, constant_simple, Constant,
-    Constant::{F32, F64},
+    Constant::{Int, F32, F64},
 };
-use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
+use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 // Returns the specialized log method for a given base if base is constant
 // and is one of 2, 10 and e
 fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> {
-    if let Some((value, _)) = constant(cx, cx.tables(), base) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), base) {
         if F32(2.0) == value || F64(2.0) == value {
             return Some("log2");
         } else if F32(10.0) == value || F64(10.0) == value {
@@ -136,7 +136,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
     if_chain! {
         // if the expression is a float literal and it is unsuffixed then
         // add a suffix so the suggestion is valid and unambiguous
-        if let ty::Float(float_ty) = cx.tables().expr_ty(expr).kind;
+        if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind;
         if let ExprKind::Lit(lit) = &expr.kind;
         if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
         then {
@@ -188,7 +188,10 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
         rhs,
     ) = &args[0].kind
     {
-        let recv = match (constant(cx, cx.tables(), lhs), constant(cx, cx.tables(), rhs)) {
+        let recv = match (
+            constant(cx, cx.typeck_results(), lhs),
+            constant(cx, cx.typeck_results(), rhs),
+        ) {
             (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs,
             (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs,
             _ => return,
@@ -233,7 +236,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
 
 fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
-    if let Some((value, _)) = constant(cx, cx.tables(), &args[0]) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
         let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
             "exp"
         } else if F32(2.0) == value || F64(2.0) == value {
@@ -254,7 +257,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     }
 
     // Check argument
-    if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
         let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
             (
                 SUBOPTIMAL_FLOPS,
@@ -293,16 +296,131 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     }
 }
 
+fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+        if value == Int(2) {
+            if let Some(parent) = get_parent_expr(cx, expr) {
+                if let Some(grandparent) = get_parent_expr(cx, parent) {
+                    if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind {
+                        if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+                            return;
+                        }
+                    }
+                }
+
+                if let ExprKind::Binary(
+                    Spanned {
+                        node: BinOpKind::Add, ..
+                    },
+                    ref lhs,
+                    ref rhs,
+                ) = parent.kind
+                {
+                    let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
+
+                    span_lint_and_sugg(
+                        cx,
+                        SUBOPTIMAL_FLOPS,
+                        parent.span,
+                        "square can be computed more efficiently",
+                        "consider using",
+                        format!(
+                            "{}.mul_add({}, {})",
+                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, &other_addend, ".."),
+                        ),
+                        Applicability::MachineApplicable,
+                    );
+
+                    return;
+                }
+            }
+
+            span_lint_and_sugg(
+                cx,
+                SUBOPTIMAL_FLOPS,
+                expr.span,
+                "square can be computed more efficiently",
+                "consider using",
+                format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
+    if let ExprKind::Binary(
+        Spanned {
+            node: BinOpKind::Add, ..
+        },
+        ref add_lhs,
+        ref add_rhs,
+    ) = args[0].kind
+    {
+        // check if expression of the form x * x + y * y
+        if_chain! {
+            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lmul_lhs, ref lmul_rhs) = add_lhs.kind;
+            if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref rmul_lhs, ref rmul_rhs) = add_rhs.kind;
+            if are_exprs_equal(cx, lmul_lhs, lmul_rhs);
+            if are_exprs_equal(cx, rmul_lhs, rmul_rhs);
+            then {
+                return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, "..")));
+            }
+        }
+
+        // check if expression of the form x.powi(2) + y.powi(2)
+        if_chain! {
+            if let ExprKind::MethodCall(
+                PathSegment { ident: lmethod_name, .. },
+                ref _lspan,
+                ref largs,
+                _
+            ) = add_lhs.kind;
+            if let ExprKind::MethodCall(
+                PathSegment { ident: rmethod_name, .. },
+                ref _rspan,
+                ref rargs,
+                _
+            ) = add_rhs.kind;
+            if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
+            if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), &largs[1]);
+            if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), &rargs[1]);
+            if Int(2) == lvalue && Int(2) == rvalue;
+            then {
+                return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], "..")));
+            }
+        }
+    }
+
+    None
+}
+
+fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+    if let Some(message) = detect_hypot(cx, args) {
+        span_lint_and_sugg(
+            cx,
+            IMPRECISE_FLOPS,
+            expr.span,
+            "hypotenuse can be computed more accurately",
+            "consider using",
+            message,
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
 // TODO: Lint expressions of the form `x.exp() - y` where y > 1
 // and suggest usage of `x.exp_m1() - (y - 1)` instead
 fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) = expr.kind;
-        if cx.tables().expr_ty(lhs).is_floating_point();
-        if let Some((value, _)) = constant(cx, cx.tables(), rhs);
+        if cx.typeck_results().expr_ty(lhs).is_floating_point();
+        if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
         if F32(1.0) == value || F64(1.0) == value;
         if let ExprKind::MethodCall(ref path, _, ref method_args, _) = lhs.kind;
-        if cx.tables().expr_ty(&method_args[0]).is_floating_point();
+        if cx.typeck_results().expr_ty(&method_args[0]).is_floating_point();
         if path.ident.name.as_str() == "exp";
         then {
             span_lint_and_sugg(
@@ -324,8 +442,8 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
 fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
     if_chain! {
         if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lhs, ref rhs) = &expr.kind;
-        if cx.tables().expr_ty(lhs).is_floating_point();
-        if cx.tables().expr_ty(rhs).is_floating_point();
+        if cx.typeck_results().expr_ty(lhs).is_floating_point();
+        if cx.typeck_results().expr_ty(rhs).is_floating_point();
         then {
             return Some((lhs, rhs));
         }
@@ -344,6 +462,14 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
         rhs,
     ) = &expr.kind
     {
+        if let Some(parent) = get_parent_expr(cx, expr) {
+            if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = parent.kind {
+                if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+                    return;
+                }
+            }
+        }
+
         let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
             (inner_lhs, inner_rhs, rhs)
         } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
@@ -404,7 +530,7 @@ fn are_exprs_equal(cx: &LateContext<'_>, expr1: &Expr<'_>, expr2: &Expr<'_>) ->
 
 /// Returns true iff expr is some zero literal
 fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match constant_simple(cx, cx.tables(), expr) {
+    match constant_simple(cx, cx.typeck_results(), expr) {
         Some(Constant::Int(i)) => i == 0,
         Some(Constant::F32(f)) => f == 0.0,
         Some(Constant::F64(f)) => f == 0.0,
@@ -479,16 +605,112 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
     }
 }
 
+fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
+    if_chain! {
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, ref args_a, _) = expr_a.kind;
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, ref args_b, _) = expr_b.kind;
+        then {
+            return method_name_a.as_str() == method_name_b.as_str() &&
+                args_a.len() == args_b.len() &&
+                (
+                    ["ln", "log2", "log10"].contains(&&*method_name_a.as_str()) ||
+                    method_name_a.as_str() == "log" && args_a.len() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1])
+                );
+        }
+    }
+
+    false
+}
+
+fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    // check if expression of the form x.logN() / y.logN()
+    if_chain! {
+        if let ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Div, ..
+            },
+            lhs,
+            rhs,
+        ) = &expr.kind;
+        if are_same_base_logs(cx, lhs, rhs);
+        if let ExprKind::MethodCall(_, _, ref largs, _) = lhs.kind;
+        if let ExprKind::MethodCall(_, _, ref rargs, _) = rhs.kind;
+        then {
+            span_lint_and_sugg(
+                cx,
+                SUBOPTIMAL_FLOPS,
+                expr.span,
+                "log base can be expressed more clearly",
+                "consider using",
+                format!("{}.log({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."),),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    if_chain! {
+        if let ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Div, ..
+            },
+            div_lhs,
+            div_rhs,
+        ) = &expr.kind;
+        if let ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Mul, ..
+            },
+            mul_lhs,
+            mul_rhs,
+        ) = &div_lhs.kind;
+        if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), div_rhs);
+        if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), mul_rhs);
+        then {
+            // TODO: also check for constant values near PI/180 or 180/PI
+            if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
+               (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
+            {
+                span_lint_and_sugg(
+                    cx,
+                    SUBOPTIMAL_FLOPS,
+                    expr.span,
+                    "conversion to degrees can be done more accurately",
+                    "consider using",
+                    format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")),
+                    Applicability::MachineApplicable,
+                );
+            } else if
+                (F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
+                (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
+            {
+                span_lint_and_sugg(
+                    cx,
+                    SUBOPTIMAL_FLOPS,
+                    expr.span,
+                    "conversion to radians can be done more accurately",
+                    "consider using",
+                    format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind {
-            let recv_ty = cx.tables().expr_ty(&args[0]);
+            let recv_ty = cx.typeck_results().expr_ty(&args[0]);
 
             if recv_ty.is_floating_point() {
                 match &*path.ident.name.as_str() {
                     "ln" => check_ln1p(cx, expr, args),
                     "log" => check_log_base(cx, expr, args),
                     "powf" => check_powf(cx, expr, args),
+                    "powi" => check_powi(cx, expr, args),
+                    "sqrt" => check_hypot(cx, expr, args),
                     _ => {},
                 }
             }
@@ -496,6 +718,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             check_expm1(cx, expr);
             check_mul_add(cx, expr);
             check_custom_abs(cx, expr);
+            check_log_division(cx, expr);
+            check_radians(cx, expr);
         }
     }
 }
index 33b6bfc459f9143fff8bcd47899d6aef1f6a183f..572c839502f4f20acc62d6a6182e918706421622 100644 (file)
@@ -90,7 +90,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &
         if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind;
         if pats.len() == 1;
         then {
-            let ty = walk_ptrs_ty(cx.tables().pat_ty(&pats[0]));
+            let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0]));
             if ty.kind != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                 return None;
             }
index 156246fb8bbb01b190871ffc912c76536530c344..1bd16e6cce53a3a5fae6dab1fb18b936c1679682 100644 (file)
@@ -305,18 +305,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
 }
 
 fn is_block(expr: &Expr) -> bool {
-    if let ExprKind::Block(..) = expr.kind {
-        true
-    } else {
-        false
-    }
+    matches!(expr.kind, ExprKind::Block(..))
 }
 
 /// Check if the expression is an `if` or `if let`
 fn is_if(expr: &Expr) -> bool {
-    if let ExprKind::If(..) = expr.kind {
-        true
-    } else {
-        false
-    }
+    matches!(expr.kind, ExprKind::If(..))
 }
index 3f030dd84225b74cc3f9d0e7b162066029dd0f32..3ee0b3f74b8c5a3bf96e3877fa6fbe91d757f9b8 100644 (file)
@@ -392,11 +392,11 @@ fn check_raw_ptr(
                 .collect::<FxHashSet<_>>();
 
             if !raw_ptrs.is_empty() {
-                let tables = cx.tcx.body_tables(body.id());
+                let typeck_results = cx.tcx.typeck_body(body.id());
                 let mut v = DerefVisitor {
                     cx,
                     ptrs: raw_ptrs,
-                    tables,
+                    typeck_results,
                 };
 
                 intravisit::walk_expr(&mut v, expr);
@@ -494,13 +494,8 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut FxHashSet<
         return false; // ignore `_` patterns
     }
     let def_id = pat.hir_id.owner.to_def_id();
-    if cx.tcx.has_typeck_tables(def_id) {
-        is_mutable_ty(
-            cx,
-            &cx.tcx.typeck_tables_of(def_id.expect_local()).pat_ty(pat),
-            pat.span,
-            tys,
-        )
+    if cx.tcx.has_typeck_results(def_id) {
+        is_mutable_ty(cx, &cx.tcx.typeck(def_id.expect_local()).pat_ty(pat), pat.span, tys)
     } else {
         false
     }
@@ -539,7 +534,7 @@ fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option<hir::HirId> {
 struct DerefVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     ptrs: FxHashSet<hir::HirId>,
-    tables: &'a ty::TypeckTables<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
 }
 
 impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
@@ -548,7 +543,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         match expr.kind {
             hir::ExprKind::Call(ref f, args) => {
-                let ty = self.tables.expr_ty(f);
+                let ty = self.typeck_results.expr_ty(f);
 
                 if type_is_unsafe_function(self.cx, ty) {
                     for arg in args {
@@ -557,7 +552,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
                 }
             },
             hir::ExprKind::MethodCall(_, _, args, _) => {
-                let def_id = self.tables.type_dependent_def_id(expr.hir_id).unwrap();
+                let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
                 let base_type = self.cx.tcx.type_of(def_id);
 
                 if type_is_unsafe_function(self.cx, base_type) {
@@ -614,10 +609,10 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
                 let mut tys = FxHashSet::default();
                 for arg in args {
                     let def_id = arg.hir_id.owner.to_def_id();
-                    if self.cx.tcx.has_typeck_tables(def_id)
+                    if self.cx.tcx.has_typeck_results(def_id)
                         && is_mutable_ty(
                             self.cx,
-                            self.cx.tcx.typeck_tables_of(def_id.expect_local()).expr_ty(arg),
+                            self.cx.tcx.typeck(def_id.expect_local()).expr_ty(arg),
                             arg.span,
                             &mut tys,
                         )
@@ -645,13 +640,7 @@ fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
     use hir::ExprKind::{Field, Index, Path};
 
     match e.kind {
-        Path(ref qpath) => {
-            if let Res::Local(_) = qpath_res(cx, qpath, e.hir_id) {
-                false
-            } else {
-                true
-            }
-        },
+        Path(ref qpath) => !matches!(qpath_res(cx, qpath, e.hir_id), Res::Local(_)),
         Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner),
         _ => false,
     }
index 2d93ecc00a769328d46ca8bf0dc09172ae1510b3..48ebcf5ebcd9c03db387dfa8a249d4ebd3cc189f 100644 (file)
@@ -54,7 +54,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
             // Argument 0 (the struct we're calling the method on) is a vector
             if let Some(struct_calling_on) = args.get(0);
-            let struct_ty = cx.tables().expr_ty(struct_calling_on);
+            let struct_ty = cx.typeck_results().expr_ty(struct_calling_on);
             if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type));
 
             // Argument to "get" is a subtraction
index dc9d636bc6de14d7b1e33349181e233810a7550c..4c62637858cde2b64cd942f9a45741772c9ee7fb 100644 (file)
@@ -62,8 +62,8 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_
     // `1 << 0` is a common pattern in bit manipulation code
     if_chain! {
         if let BinOpKind::Shl = cmp.node;
-        if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables(), right);
-        if let Some(Constant::Int(1)) = constant_simple(cx, cx.tables(), left);
+        if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), right);
+        if let Some(Constant::Int(1)) = constant_simple(cx, cx.typeck_results(), left);
         then {
             return true;
         }
@@ -74,8 +74,8 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_
 
 #[allow(clippy::cast_possible_wrap)]
 fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
-    if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables(), e) {
-        let check = match cx.tables().expr_ty(e).kind {
+    if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
+        let check = match cx.typeck_results().expr_ty(e).kind {
             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
             ty::Uint(uty) => clip(cx.tcx, !0, uty),
             _ => return,
index f911cb68ea57946a0769b0e3f575bd8bc6454ead..2e55094d90c6f33f5ca4e24c68dea3239fe1ac31 100644 (file)
@@ -135,13 +135,10 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 }
 
-impl<'tcx> ArmVisitor<'_, 'tcx> {
+impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
     fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool {
-        if let Some(arm_mutex) = self.found_mutex {
-            SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)
-        } else {
-            false
-        }
+        self.found_mutex
+            .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex))
     }
 }
 
@@ -149,7 +146,7 @@ fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Opt
     if_chain! {
         if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind;
         if path.ident.to_string() == "lock";
-        let ty = cx.tables().expr_ty(&args[0]);
+        let ty = cx.typeck_results().expr_ty(&args[0]);
         if is_type_diagnostic_item(cx, ty, sym!(mutex_type));
         then {
             Some(&args[0])
index 9e2989dc01e52700f3f32d2006892fe5e5831a3f..5b22df5fe491e70e3afcadb2933e176a6492ff47 100644 (file)
@@ -45,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
             if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _)  = body[0].pat.kind; //get operation
             if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
-            if is_type_diagnostic_item(cx, cx.tables().expr_ty(&result_types[0]), sym!(result_type));
+            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym!(result_type));
             if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
 
             then {
index f38530aca0cec8de00cc5114bede50e792f9f272..5f931a0addedf6b3781460b545d15a7ec46dc629 100644 (file)
@@ -81,7 +81,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 };
 
                 // Check if the variable in the condition statement is an integer
-                if !cx.tables().expr_ty(cond_var).is_integral() {
+                if !cx.typeck_results().expr_ty(cond_var).is_integral() {
                     return;
                 }
 
@@ -93,7 +93,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                     ExprKind::Lit(ref cond_lit) => {
                         // Check if the constant is zero
                         if let LitKind::Int(0, _) = cond_lit.node {
-                            if cx.tables().expr_ty(cond_left).is_signed() {
+                            if cx.typeck_results().expr_ty(cond_left).is_signed() {
                             } else {
                                 print_lint_and_sugg(cx, &var_name, expr);
                             };
index 5857a405b0cf37800293a1abecddbeb58341900a..a1f58e54ae38e97ec6d8c5e17b64e7227b61fd1e 100644 (file)
@@ -88,7 +88,7 @@
 impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Index(ref array, ref index) = &expr.kind {
-            let ty = cx.tables().expr_ty(array);
+            let ty = cx.typeck_results().expr_ty(array);
             if let Some(range) = higher::range(cx, index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
                 if let ty::Array(_, s) = ty.kind {
@@ -143,7 +143,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 // Catchall non-range index, i.e., [n] or [n << m]
                 if let ty::Array(..) = ty.kind {
                     // Index is a constant uint.
-                    if let Some(..) = constant(cx, cx.tables(), index) {
+                    if let Some(..) = constant(cx, cx.typeck_results(), index) {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
                         return;
                     }
@@ -169,14 +169,18 @@ fn to_const_range<'tcx>(
     range: higher::Range<'_>,
     array_size: u128,
 ) -> (Option<u128>, Option<u128>) {
-    let s = range.start.map(|expr| constant(cx, cx.tables(), expr).map(|(c, _)| c));
+    let s = range
+        .start
+        .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
     let start = match s {
         Some(Some(Constant::Int(x))) => Some(x),
         Some(_) => None,
         None => Some(0),
     };
 
-    let e = range.end.map(|expr| constant(cx, cx.tables(), expr).map(|(c, _)| c));
+    let e = range
+        .end
+        .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
     let end = match e {
         Some(Some(Constant::Int(x))) => {
             if range.limits == RangeLimits::Closed {
index 3ffc2dd60d9c0b362077840c1b5f99b5384bdfba..e511d3ea330466b9b85dba31dcc59504904d6857 100644 (file)
@@ -231,13 +231,13 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             }
             if method.ident.name == sym!(last) && args.len() == 1 {
                 let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR).map_or(false, |id| {
-                    !implements_trait(cx, cx.tables().expr_ty(&args[0]), id, &[])
+                    !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[])
                 });
                 if not_double_ended {
                     return is_infinite(cx, &args[0]);
                 }
             } else if method.ident.name == sym!(collect) {
-                let ty = cx.tables().expr_ty(expr);
+                let ty = cx.typeck_results().expr_ty(expr);
                 if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
                     return is_infinite(cx, &args[0]);
                 }
index e754c7b482a6882bf84043a756e0b86ceeadcbd7..31181c10d23dbed70a1927e5bba2d3b0ada51069 100644 (file)
@@ -50,7 +50,7 @@ fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>)
         if let hir::ExprKind::Binary(binop, left, right) = &expr.kind;
         if let hir::BinOpKind::Div = &binop.node;
         then {
-            let (left_ty, right_ty) = (cx.tables().expr_ty(left), cx.tables().expr_ty(right));
+            let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right));
             return left_ty.is_integral() && right_ty.is_integral();
         }
     }
index 8eb986c25ff790e8ff97a23ad5704dfe66b2a703..a7c715879232b980b078c1e00399e0cb2ec8017b 100644 (file)
@@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::Repeat(_, _) = expr.kind;
-            if let ty::Array(element_type, cst) = cx.tables().expr_ty(expr).kind;
+            if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind;
             if let ConstKind::Value(val) = cst.val;
             if let ConstValue::Scalar(element_count) = val;
             if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
index 26d96428771d6263db2c6623c3e54982b51bdee6..00d0b8b4e5b7f3c98303e03bd1819f025da3677c 100644 (file)
@@ -300,18 +300,14 @@ fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
         return false;
     }
 
-    let ty = &walk_ptrs_ty(cx.tables().expr_ty(expr));
+    let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr));
     match ty.kind {
-        ty::Dynamic(ref tt, ..) => {
-            if let Some(principal) = tt.principal() {
-                cx.tcx
-                    .associated_items(principal.def_id())
-                    .in_definition_order()
-                    .any(|item| is_is_empty(cx, &item))
-            } else {
-                false
-            }
-        },
+        ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| {
+            cx.tcx
+                .associated_items(principal.def_id())
+                .in_definition_order()
+                .any(|item| is_is_empty(cx, &item))
+        }),
         ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
         ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
         ty::Array(..) | ty::Slice(..) | ty::Str => true,
index ddc41f89f8dec7da826c5106416de00b5299d14f..fa560ffb980c82407d748018b6b12717c7572267 100644 (file)
@@ -1,6 +1,5 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -9,7 +8,7 @@
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
-use crate::utils::{in_macro, match_qpath, snippet_opt, span_lint_and_then};
+use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_then};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `let`-bindings, which are subsequently
@@ -97,22 +96,6 @@ struct BorrowVisitor<'a, 'tcx> {
     borrows: bool,
 }
 
-impl BorrowVisitor<'_, '_> {
-    fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> {
-        match &expr.kind {
-            ExprKind::MethodCall(..) => self.cx.tables().type_dependent_def_id(expr.hir_id),
-            ExprKind::Call(
-                Expr {
-                    kind: ExprKind::Path(qpath),
-                    ..
-                },
-                ..,
-            ) => self.cx.qpath_res(qpath, expr.hir_id).opt_def_id(),
-            _ => None,
-        }
-    }
-}
-
 impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
     type Map = Map<'tcx>;
 
@@ -121,7 +104,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        if let Some(def_id) = self.fn_def_id(expr) {
+        if let Some(def_id) = fn_def_id(self.cx, expr) {
             self.borrows = self
                 .cx
                 .tcx
index 706c73ce66c6191c3751b5a89eaa0e355146c874..8243b0a29bc68b3642828e3c7295b45f8627c614 100644 (file)
@@ -73,7 +73,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
                 then {
                     let span = stmt.span.to(if_.span);
 
-                    let has_interior_mutability = !cx.tables().node_type(canonical_id).is_freeze(
+                    let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
                         cx.tcx.at(span),
                         cx.param_env,
                     );
index c7dda3c9928260bcbf06a015d456f479c8288f47..ae2f6131b5b8fb0bdf653081ca3c0f905c9c9886 100644 (file)
@@ -76,7 +76,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
             if let PatKind::Wild = local.pat.kind;
             if let Some(ref init) = local.init;
             then {
-                let init_ty = cx.tables().expr_ty(init);
+                let init_ty = cx.typeck_results().expr_ty(init);
                 let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
                     GenericArgKind::Type(inner_ty) => {
                         SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
@@ -94,7 +94,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
                     )
-                } else if is_must_use_ty(cx, cx.tables().expr_ty(init)) {
+                } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
                     span_lint_and_help(
                         cx,
                         LET_UNDERSCORE_MUST_USE,
index 501220f28e5db4d2fb57facf9825dcd142392432..32e79317f82254119bf9b3075ef15f3b827f3ea7 100644 (file)
@@ -229,6 +229,7 @@ macro_rules! declare_clippy_lint {
 mod manual_async_fn;
 mod manual_non_exhaustive;
 mod map_clone;
+mod map_identity;
 mod map_unit_fn;
 mod match_on_vec_items;
 mod matches;
@@ -263,10 +264,12 @@ macro_rules! declare_clippy_lint {
 mod non_expressive_names;
 mod open_options;
 mod option_env_unwrap;
+mod option_if_let_else;
 mod overflow_check_conditional;
 mod panic_unimplemented;
 mod partialeq_ne_impl;
 mod path_buf_push_overwrite;
+mod pattern_type_mismatch;
 mod precedence;
 mod ptr;
 mod ptr_offset_with_cast;
@@ -274,11 +277,11 @@ macro_rules! declare_clippy_lint {
 mod ranges;
 mod redundant_clone;
 mod redundant_field_names;
-mod redundant_pattern_matching;
 mod redundant_pub_crate;
 mod redundant_static_lifetimes;
 mod reference;
 mod regex;
+mod repeat_once;
 mod returns;
 mod serde_api;
 mod shadow;
@@ -459,7 +462,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     );
     store.register_removed(
         "clippy::replace_consts",
-        "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants",
+        "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants",
+    );
+    store.register_removed(
+        "clippy::regex_macro",
+        "the regex! macro has been removed from the regex crate in 2018",
     );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
@@ -473,6 +480,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &assign_ops::ASSIGN_OP_PATTERN,
         &assign_ops::MISREFACTORED_ASSIGN_OP,
         &atomic_ordering::INVALID_ATOMIC_ORDERING,
+        &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
         &attrs::DEPRECATED_CFG_ATTR,
         &attrs::DEPRECATED_SEMVER,
         &attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
@@ -608,17 +616,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &manual_async_fn::MANUAL_ASYNC_FN,
         &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
         &map_clone::MAP_CLONE,
+        &map_identity::MAP_IDENTITY,
         &map_unit_fn::OPTION_MAP_UNIT_FN,
         &map_unit_fn::RESULT_MAP_UNIT_FN,
         &match_on_vec_items::MATCH_ON_VEC_ITEMS,
         &matches::INFALLIBLE_DESTRUCTURING_MATCH,
         &matches::MATCH_AS_REF,
         &matches::MATCH_BOOL,
+        &matches::MATCH_LIKE_MATCHES_MACRO,
         &matches::MATCH_OVERLAPPING_ARM,
         &matches::MATCH_REF_PATS,
         &matches::MATCH_SINGLE_BINDING,
         &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
         &matches::MATCH_WILD_ERR_ARM,
+        &matches::REDUNDANT_PATTERN_MATCHING,
         &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
         &matches::SINGLE_MATCH,
         &matches::SINGLE_MATCH_ELSE,
@@ -726,6 +737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &non_expressive_names::SIMILAR_NAMES,
         &open_options::NONSENSICAL_OPEN_OPTIONS,
         &option_env_unwrap::OPTION_ENV_UNWRAP,
+        &option_if_let_else::OPTION_IF_LET_ELSE,
         &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
         &panic_unimplemented::PANIC,
         &panic_unimplemented::PANIC_PARAMS,
@@ -734,6 +746,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &panic_unimplemented::UNREACHABLE,
         &partialeq_ne_impl::PARTIALEQ_NE_IMPL,
         &path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
+        &pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
         &precedence::PRECEDENCE,
         &ptr::CMP_NULL,
         &ptr::MUT_FROM_REF,
@@ -746,14 +759,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &ranges::REVERSED_EMPTY_RANGES,
         &redundant_clone::REDUNDANT_CLONE,
         &redundant_field_names::REDUNDANT_FIELD_NAMES,
-        &redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING,
         &redundant_pub_crate::REDUNDANT_PUB_CRATE,
         &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
         &reference::DEREF_ADDROF,
         &reference::REF_IN_DEREF,
         &regex::INVALID_REGEX,
-        &regex::REGEX_MACRO,
         &regex::TRIVIAL_REGEX,
+        &repeat_once::REPEAT_ONCE,
         &returns::NEEDLESS_RETURN,
         &returns::UNUSED_UNIT,
         &serde_api::SERDE_API_MISUSE,
@@ -946,7 +958,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box missing_doc::MissingDoc::new());
     store.register_late_pass(|| box missing_inline::MissingInline);
     store.register_late_pass(|| box if_let_some_result::OkIfLet);
-    store.register_late_pass(|| box redundant_pattern_matching::RedundantPatternMatching);
     store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
     store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
     let enum_variant_size_threshold = conf.enum_variant_size_threshold;
@@ -990,7 +1001,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box checked_conversions::CheckedConversions);
     store.register_late_pass(|| box integer_division::IntegerDivision);
     store.register_late_pass(|| box inherent_to_string::InherentToString);
-    store.register_late_pass(|| box trait_bounds::TraitBounds);
+    let max_trait_bounds = conf.max_trait_bounds;
+    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
     store.register_late_pass(|| box comparison_chain::ComparisonChain);
     store.register_late_pass(|| box mut_key::MutableKeyType);
     store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
@@ -1027,7 +1039,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let array_size_threshold = conf.array_size_threshold;
     store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
     store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
-    store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic);
+    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
     store.register_early_pass(|| box as_conversions::AsConversions);
     store.register_early_pass(|| box utils::internal_lints::ProduceIce);
     store.register_late_pass(|| box let_underscore::LetUnderscore);
@@ -1043,6 +1055,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
     store.register_late_pass(|| box unnamed_address::UnnamedAddress);
     store.register_late_pass(|| box dereference::Dereferencing);
+    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
     store.register_late_pass(|| box future_not_send::FutureNotSend);
     store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
     store.register_late_pass(|| box if_let_mutex::IfLetMutex);
@@ -1057,6 +1070,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
     store.register_late_pass(|| box macro_use::MacroUseImports::default());
+    store.register_late_pass(|| box map_identity::MapIdentity);
+    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
+    store.register_late_pass(|| box repeat_once::RepeatOnce);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1090,6 +1106,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&panic_unimplemented::TODO),
         LintId::of(&panic_unimplemented::UNIMPLEMENTED),
         LintId::of(&panic_unimplemented::UNREACHABLE),
+        LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
         LintId::of(&shadow::SHADOW_REUSE),
         LintId::of(&shadow::SHADOW_SAME),
         LintId::of(&strings::STRING_ADD),
@@ -1146,6 +1163,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&needless_continue::NEEDLESS_CONTINUE),
         LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
         LintId::of(&non_expressive_names::SIMILAR_NAMES),
+        LintId::of(&option_if_let_else::OPTION_IF_LET_ELSE),
+        LintId::of(&ranges::RANGE_MINUS_ONE),
         LintId::of(&ranges::RANGE_PLUS_ONE),
         LintId::of(&shadow::SHADOW_UNRELATED),
         LintId::of(&strings::STRING_ADD_ASSIGN),
@@ -1186,6 +1205,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
         LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
         LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
+        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
         LintId::of(&attrs::DEPRECATED_CFG_ATTR),
         LintId::of(&attrs::DEPRECATED_SEMVER),
         LintId::of(&attrs::MISMATCHED_TARGET_OS),
@@ -1273,13 +1293,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
         LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
         LintId::of(&map_clone::MAP_CLONE),
+        LintId::of(&map_identity::MAP_IDENTITY),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
         LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
         LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
         LintId::of(&matches::MATCH_AS_REF),
+        LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
         LintId::of(&matches::MATCH_OVERLAPPING_ARM),
         LintId::of(&matches::MATCH_REF_PATS),
         LintId::of(&matches::MATCH_SINGLE_BINDING),
+        LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
         LintId::of(&matches::SINGLE_MATCH),
         LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
         LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
@@ -1364,18 +1387,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&ptr::PTR_ARG),
         LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
         LintId::of(&question_mark::QUESTION_MARK),
-        LintId::of(&ranges::RANGE_MINUS_ONE),
         LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
         LintId::of(&ranges::REVERSED_EMPTY_RANGES),
         LintId::of(&redundant_clone::REDUNDANT_CLONE),
         LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
-        LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING),
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
         LintId::of(&reference::DEREF_ADDROF),
         LintId::of(&reference::REF_IN_DEREF),
         LintId::of(&regex::INVALID_REGEX),
-        LintId::of(&regex::REGEX_MACRO),
         LintId::of(&regex::TRIVIAL_REGEX),
+        LintId::of(&repeat_once::REPEAT_ONCE),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
         LintId::of(&serde_api::SERDE_API_MISUSE),
@@ -1437,6 +1458,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_group(true, "clippy::style", Some("clippy_style"), vec![
         LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
         LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
+        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
         LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
         LintId::of(&bit_mask::VERBOSE_BIT_MASK),
         LintId::of(&blacklisted_name::BLACKLISTED_NAME),
@@ -1470,8 +1492,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
         LintId::of(&map_clone::MAP_CLONE),
         LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
+        LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
         LintId::of(&matches::MATCH_OVERLAPPING_ARM),
         LintId::of(&matches::MATCH_REF_PATS),
+        LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
         LintId::of(&matches::SINGLE_MATCH),
         LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
         LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
@@ -1508,9 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&ptr::PTR_ARG),
         LintId::of(&question_mark::QUESTION_MARK),
         LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
-        LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING),
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
-        LintId::of(&regex::REGEX_MACRO),
         LintId::of(&regex::TRIVIAL_REGEX),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
@@ -1550,6 +1572,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
         LintId::of(&loops::MUT_RANGE_BOUND),
         LintId::of(&loops::WHILE_LET_LOOP),
+        LintId::of(&map_identity::MAP_IDENTITY),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
         LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
         LintId::of(&matches::MATCH_AS_REF),
@@ -1580,10 +1603,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
         LintId::of(&precedence::PRECEDENCE),
         LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
-        LintId::of(&ranges::RANGE_MINUS_ONE),
         LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
         LintId::of(&reference::DEREF_ADDROF),
         LintId::of(&reference::REF_IN_DEREF),
+        LintId::of(&repeat_once::REPEAT_ONCE),
         LintId::of(&swap::MANUAL_SWAP),
         LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
         LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
index a79f94855bdab7eb701d7d1e89fd2ba473b3a952..168f9f953e4d899b70174f8db6d06b55610f1a09 100644 (file)
@@ -129,10 +129,10 @@ fn check_fn_inner<'tcx>(
     }
 
     let mut bounds_lts = Vec::new();
-    let types = generics.params.iter().filter(|param| match param.kind {
-        GenericParamKind::Type { .. } => true,
-        _ => false,
-    });
+    let types = generics
+        .params
+        .iter()
+        .filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
     for typ in types {
         for bound in typ.bounds {
             let mut visitor = RefVisitor::new(cx);
@@ -337,10 +337,10 @@ fn into_vec(self) -> Option<Vec<RefLt>> {
     fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) {
         if let Some(ref last_path_segment) = last_path_segment(qpath).args {
             if !last_path_segment.parenthesized
-                && !last_path_segment.args.iter().any(|arg| match arg {
-                    GenericArg::Lifetime(_) => true,
-                    _ => false,
-                })
+                && !last_path_segment
+                    .args
+                    .iter()
+                    .any(|arg| matches!(arg, GenericArg::Lifetime(_)))
             {
                 let hir_id = ty.hir_id;
                 match self.cx.qpath_res(qpath, hir_id) {
index 7ba43562d7d447b565095ae2b033d1f125df6483..a36fdca5d5de6a5816d8ff369501fad9c651b3dd 100644 (file)
@@ -264,10 +264,13 @@ fn check_for_mistyped_suffix(
 
         let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent {
             (exponent, &["32", "64"][..], 'f')
-        } else if let Some(fraction) = &mut num_lit.fraction {
-            (fraction, &["32", "64"][..], 'f')
         } else {
-            (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i')
+            num_lit
+                .fraction
+                .as_mut()
+                .map_or((&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), |fraction| {
+                    (fraction, &["32", "64"][..], 'f')
+                })
         };
 
         let mut split = part.rsplit('_');
index d821b5134841e586e402ca2c884480d3be49d40f..7e3876ff49b462fcc71810ad11684343cf9a188f 100644 (file)
@@ -535,7 +535,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 if_chain! {
                     if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind;
                     if let Some(iter_def_id) = get_trait_def_id(cx, &paths::ITERATOR);
-                    if implements_trait(cx, cx.tables().expr_ty(iter_expr), iter_def_id, &[]);
+                    if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]);
                     then {
                         return;
                     }
@@ -686,13 +686,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
                 NeverLoopResult::AlwaysBreak
             }
         },
-        ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => {
-            if let Some(ref e) = *e {
-                combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
-            } else {
-                NeverLoopResult::AlwaysBreak
-            }
-        },
+        ExprKind::Break(_, ref e) | ExprKind::Ret(ref e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
+            combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
+        }),
         ExprKind::InlineAsm(ref asm) => asm
             .operands
             .iter()
@@ -985,8 +981,8 @@ fn detect_manual_memcpy<'tcx>(
                         if_chain! {
                             if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind;
                             if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind;
-                            if is_slice_like(cx, cx.tables().expr_ty(seqexpr_left))
-                                && is_slice_like(cx, cx.tables().expr_ty(seqexpr_right));
+                            if is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_left))
+                                && is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_right));
                             if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id);
                             if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id);
 
@@ -1254,8 +1250,8 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr:
                     lint_iter_method(cx, args, arg, method_name);
                 }
             } else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) {
-                let receiver_ty = cx.tables().expr_ty(&args[0]);
-                let receiver_ty_adjusted = cx.tables().expr_ty_adjusted(&args[0]);
+                let receiver_ty = cx.typeck_results().expr_ty(&args[0]);
+                let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]);
                 if TyS::same_type(receiver_ty, receiver_ty_adjusted) {
                     let mut applicability = Applicability::MachineApplicable;
                     let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
@@ -1300,7 +1296,7 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr:
 
 /// Checks for `for` loops over `Option`s and `Result`s.
 fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
-    let ty = cx.tables().expr_ty(arg);
+    let ty = cx.typeck_results().expr_ty(arg);
     if is_type_diagnostic_item(cx, ty, sym!(option_type)) {
         span_lint_and_help(
             cx,
@@ -1404,8 +1400,9 @@ fn check_for_loop_explicit_counter<'tcx>(
 /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
 /// actual `Iterator` that the loop uses.
 fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
-    let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR)
-        .map_or(false, |id| implements_trait(cx, cx.tables().expr_ty(arg), id, &[]));
+    let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |id| {
+        implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
+    });
     if impls_iterator {
         format!(
             "{}",
@@ -1416,7 +1413,7 @@ fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut
         // (&mut x).into_iter() ==> x.iter_mut()
         match &arg.kind {
             ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner)
-                if has_iter_method(cx, cx.tables().expr_ty(&arg_inner)).is_some() =>
+                if has_iter_method(cx, cx.typeck_results().expr_ty(&arg_inner)).is_some() =>
             {
                 let meth_name = match mutability {
                     Mutability::Mut => "iter_mut",
@@ -1449,7 +1446,7 @@ fn check_for_loop_over_map_kv<'tcx>(
     if let PatKind::Tuple(ref pat, _) = pat.kind {
         if pat.len() == 2 {
             let arg_span = arg.span;
-            let (new_pat_span, kind, ty, mutbl) = match cx.tables().expr_ty(arg).kind {
+            let (new_pat_span, kind, ty, mutbl) = match cx.typeck_results().expr_ty(arg).kind {
                 ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
                     (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl),
                     (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not),
@@ -1594,7 +1591,14 @@ fn check_for_mutation<'tcx>(
     };
     let def_id = body.hir_id.owner.to_def_id();
     cx.tcx.infer_ctxt().enter(|infcx| {
-        ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(body);
+        ExprUseVisitor::new(
+            &mut delegate,
+            &infcx,
+            def_id.expect_local(),
+            cx.param_env,
+            cx.typeck_results(),
+        )
+        .walk_expr(body);
     });
     delegate.mutation_span()
 }
@@ -1688,7 +1692,7 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
                             if index_used_directly {
                                 self.indexed_directly.insert(
                                     seqvar.segments[0].ident.name,
-                                    (Some(extent), self.cx.tables().node_type(seqexpr.hir_id)),
+                                    (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
                                 );
                             }
                             return false;  // no need to walk further *on the variable*
@@ -1700,7 +1704,7 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
                             if index_used_directly {
                                 self.indexed_directly.insert(
                                     seqvar.segments[0].ident.name,
-                                    (None, self.cx.tables().node_type(seqexpr.hir_id)),
+                                    (None, self.cx.typeck_results().node_type(seqexpr.hir_id)),
                                 );
                             }
                             return false;  // no need to walk further *on the variable*
@@ -1768,7 +1772,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             ExprKind::Call(ref f, args) => {
                 self.visit_expr(f);
                 for expr in args {
-                    let ty = self.cx.tables().expr_ty_adjusted(expr);
+                    let ty = self.cx.typeck_results().expr_ty_adjusted(expr);
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = ty.kind {
                         if mutbl == Mutability::Mut {
@@ -1779,7 +1783,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 }
             },
             ExprKind::MethodCall(_, _, args, _) => {
-                let def_id = self.cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
+                let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
                 for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) {
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = ty.kind {
@@ -1866,7 +1870,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     // no walk_ptrs_ty: calling iter() on a reference can make sense because it
     // will allow further borrows afterwards
-    let ty = cx.tables().expr_ty(e);
+    let ty = cx.typeck_results().expr_ty(e);
     is_iterable_array(ty, cx) ||
     is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
     match_type(cx, ty, &paths::LINKED_LIST) ||
@@ -1881,13 +1885,9 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
     // IntoIterator is currently only implemented for array sizes <= 32 in rustc
     match ty.kind {
-        ty::Array(_, n) => {
-            if let Some(val) = n.try_eval_usize(cx.tcx, cx.param_env) {
-                (0..=32).contains(&val)
-            } else {
-                false
-            }
-        },
+        ty::Array(_, n) => n
+            .try_eval_usize(cx.tcx, cx.param_env)
+            .map_or(false, |val| (0..=32).contains(&val)),
         _ => false,
     }
 }
@@ -1899,11 +1899,7 @@ fn extract_expr_from_first_stmt<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<
         return None;
     }
     if let StmtKind::Local(ref local) = block.stmts[0].kind {
-        if let Some(expr) = local.init {
-            Some(expr)
-        } else {
-            None
-        }
+        local.init //.map(|expr| expr)
     } else {
         None
     }
@@ -2023,15 +2019,13 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
                 if let PatKind::Binding(.., ident, _) = local.pat.kind {
                     self.name = Some(ident.name);
 
-                    self.state = if let Some(ref init) = local.init {
+                    self.state = local.init.as_ref().map_or(VarState::Declared, |init| {
                         if is_integer_const(&self.cx, init, 0) {
                             VarState::Warn
                         } else {
                             VarState::Declared
                         }
-                    } else {
-                        VarState::Declared
-                    }
+                    })
                 }
             }
         }
@@ -2105,17 +2099,11 @@ fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<HirId> {
 }
 
 fn is_loop(expr: &Expr<'_>) -> bool {
-    match expr.kind {
-        ExprKind::Loop(..) => true,
-        _ => false,
-    }
+    matches!(expr.kind, ExprKind::Loop(..))
 }
 
 fn is_conditional(expr: &Expr<'_>) -> bool {
-    match expr.kind {
-        ExprKind::Match(..) => true,
-        _ => false,
-    }
+    matches!(expr.kind, ExprKind::Match(..))
 }
 
 fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
@@ -2241,7 +2229,7 @@ fn path_name(e: &Expr<'_>) -> Option<Name> {
 }
 
 fn check_infinite_loop<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
-    if constant(cx, cx.tables(), cond).is_some() {
+    if constant(cx, cx.typeck_results(), cond).is_some() {
         // A pure constant condition (e.g., `while false`) is not linted.
         return;
     }
@@ -2377,7 +2365,7 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
         if let Some(ref generic_args) = chain_method.args;
         if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
         then {
-            let ty = cx.tables().node_type(ty.hir_id);
+            let ty = cx.typeck_results().node_type(ty.hir_id);
             if is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
                 is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) ||
                 match_type(cx, ty, &paths::BTREEMAP) ||
index 905a3f3ca71c71b6652dc43b5d25269487605f64..641e6a17043246937384a2ae7c946d44a91fc634 100644 (file)
@@ -52,7 +52,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
             if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind;
             if args.len() == 2;
             if method.ident.as_str() == "map";
-            let ty = cx.tables().expr_ty(&args[0]);
+            let ty = cx.typeck_results().expr_ty(&args[0]);
             if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR);
             if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
             let closure_body = cx.tcx.hir().body(body_id);
@@ -70,7 +70,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
                         match closure_expr.kind {
                             hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
                                 if ident_eq(name, inner) {
-                                    if let ty::Ref(.., Mutability::Not) = cx.tables().expr_ty(inner).kind {
+                                    if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind {
                                         lint(cx, e.span, args[0].span, true);
                                     }
                                 }
@@ -79,7 +79,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
                                 if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone"
                                     && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
 
-                                    let obj_ty = cx.tables().expr_ty(&obj[0]);
+                                    let obj_ty = cx.typeck_results().expr_ty(&obj[0]);
                                     if let ty::Ref(_, ty, _) = obj_ty.kind {
                                         let copy = is_copy(cx, ty);
                                         lint(cx, e.span, args[0].span, copy);
diff --git a/src/tools/clippy/clippy_lints/src/map_identity.rs b/src/tools/clippy/clippy_lints/src/map_identity.rs
new file mode 100644 (file)
index 0000000..d4c2e66
--- /dev/null
@@ -0,0 +1,126 @@
+use crate::utils::{
+    is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks,
+    span_lint_and_sugg,
+};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function.
+    ///
+    /// **Why is this bad?** It can be written more concisely without the call to `map`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x = [1, 2, 3];
+    /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let x = [1, 2, 3];
+    /// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
+    /// ```
+    pub MAP_IDENTITY,
+    complexity,
+    "using iterator.map(|x| x)"
+}
+
+declare_lint_pass!(MapIdentity => [MAP_IDENTITY]);
+
+impl<'tcx> LateLintPass<'tcx> for MapIdentity {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        if_chain! {
+            if let Some([caller, func]) = get_map_argument(cx, expr);
+            if is_expr_identity_function(cx, func);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    MAP_IDENTITY,
+                    expr.span.trim_start(caller.span).unwrap(),
+                    "unnecessary map of the identity function",
+                    "remove the call to `map`",
+                    String::new(),
+                    Applicability::MachineApplicable
+                )
+            }
+        }
+    }
+}
+
+/// Returns the arguments passed into map() if the expression is a method call to
+/// map(). Otherwise, returns None.
+fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> {
+    if_chain! {
+        if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind;
+        if args.len() == 2 && method.ident.as_str() == "map";
+        let caller_ty = cx.typeck_results().expr_ty(&args[0]);
+        if match_trait_method(cx, expr, &paths::ITERATOR)
+            || is_type_diagnostic_item(cx, caller_ty, sym!(result_type))
+            || is_type_diagnostic_item(cx, caller_ty, sym!(option_type));
+        then {
+            Some(args)
+        } else {
+            None
+        }
+    }
+}
+
+/// Checks if an expression represents the identity function
+/// Only examines closures and `std::convert::identity`
+fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
+        ExprKind::Path(QPath::Resolved(_, ref path)) => match_path(path, &paths::STD_CONVERT_IDENTITY),
+        _ => false,
+    }
+}
+
+/// Checks if a function's body represents the identity function
+/// Looks for bodies of the form `|x| x`, `|x| return x`, `|x| { return x }` or `|x| {
+/// return x; }`
+fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
+    let params = func.params;
+    let body = remove_blocks(&func.value);
+
+    // if there's less/more than one parameter, then it is not the identity function
+    if params.len() != 1 {
+        return false;
+    }
+
+    match body.kind {
+        ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat),
+        ExprKind::Ret(Some(ref ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
+        ExprKind::Block(ref block, _) => {
+            if_chain! {
+                if block.stmts.len() == 1;
+                if let StmtKind::Semi(ref expr) | StmtKind::Expr(ref expr) = block.stmts[0].kind;
+                if let ExprKind::Ret(Some(ref ret_val)) = expr.kind;
+                then {
+                    match_expr_param(cx, ret_val, params[0].pat)
+                } else {
+                    false
+                }
+            }
+        },
+        _ => false,
+    }
+}
+
+/// Returns true iff an expression returns the same thing as a parameter's pattern
+fn match_expr_param(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
+    if let PatKind::Binding(_, _, ident, _) = pat.kind {
+        match_var(expr, ident.name) && !(cx.typeck_results().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr))
+    } else {
+        false
+    }
+}
index 316a71c500512d287b449ee4dfe4ecdde637093f..198251c58ddc50dde677ebcc7397924f1981b26f 100644 (file)
@@ -101,7 +101,7 @@ fn is_unit_type(ty: Ty<'_>) -> bool {
 }
 
 fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
-    let ty = cx.tables().expr_ty(expr);
+    let ty = cx.typeck_results().expr_ty(expr);
 
     if let ty::FnDef(id, _) = ty.kind {
         if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
@@ -112,7 +112,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 }
 
 fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
-    is_unit_type(cx.tables().expr_ty(expr))
+    is_unit_type(cx.typeck_results().expr_ty(expr))
 }
 
 /// The expression inside a closure may or may not have surrounding braces and
@@ -205,13 +205,14 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
 fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
     let var_arg = &map_args[0];
 
-    let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(option_type)) {
-        ("Option", "Some", OPTION_MAP_UNIT_FN)
-    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(result_type)) {
-        ("Result", "Ok", RESULT_MAP_UNIT_FN)
-    } else {
-        return;
-    };
+    let (map_type, variant, lint) =
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(option_type)) {
+            ("Option", "Some", OPTION_MAP_UNIT_FN)
+        } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(result_type)) {
+            ("Result", "Ok", RESULT_MAP_UNIT_FN)
+        } else {
+            return;
+        };
     let fn_arg = &map_args[1];
 
     if is_unit_function(cx, fn_arg) {
index 0003aa94a031e708134efdb416bac03615a56a6b..4f8f2cb171d5bf2358c772e46e172176fa0f36fa 100644 (file)
@@ -88,13 +88,13 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti
 }
 
 fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let ty = cx.tables().expr_ty(expr);
+    let ty = cx.typeck_results().expr_ty(expr);
     let ty = walk_ptrs_ty(ty);
     is_type_diagnostic_item(cx, ty, sym!(vec_type))
 }
 
 fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let ty = cx.tables().expr_ty(expr);
+    let ty = cx.typeck_results().expr_ty(expr);
     let ty = walk_ptrs_ty(ty);
     match_type(cx, ty, &utils::paths::RANGE_FULL)
 }
index b754a45aa404fff34f544e54dceee07490e24c46..ea6fb9e902576ee17d43ffd250a6b5277fd4fbfe 100644 (file)
 use rustc_errors::Applicability;
 use rustc_hir::def::CtorKind;
 use rustc_hir::{
-    Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat, PatKind,
-    QPath, RangeEnd,
+    Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, Local, MatchSource, Mutability, Node, Pat,
+    PatKind, QPath, RangeEnd,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
+use rustc_span::source_map::{Span, Spanned};
 use std::cmp::Ordering;
 use std::collections::Bound;
 
     "a match on a struct that binds all fields but still uses the wildcard pattern"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Lint for redundant pattern matching over `Result` or
+    /// `Option`
+    ///
+    /// **Why is this bad?** It's more concise and clear to just use the proper
+    /// utility function
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// if let Ok(_) = Ok::<i32, i32>(42) {}
+    /// if let Err(_) = Err::<i32, i32>(42) {}
+    /// if let None = None::<()> {}
+    /// if let Some(_) = Some(42) {}
+    /// match Ok::<i32, i32>(42) {
+    ///     Ok(_) => true,
+    ///     Err(_) => false,
+    /// };
+    /// ```
+    ///
+    /// The more idiomatic use would be:
+    ///
+    /// ```rust
+    /// if Ok::<i32, i32>(42).is_ok() {}
+    /// if Err::<i32, i32>(42).is_err() {}
+    /// if None::<()>.is_none() {}
+    /// if Some(42).is_some() {}
+    /// Ok::<i32, i32>(42).is_ok();
+    /// ```
+    pub REDUNDANT_PATTERN_MATCHING,
+    style,
+    "use the proper utility function avoiding an `if let`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `match`  or `if let` expressions producing a
+    /// `bool` that could be written using `matches!`
+    ///
+    /// **Why is this bad?** Readability and needless complexity.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = Some(5);
+    ///
+    /// // Bad
+    /// let a = match x {
+    ///     Some(0) => true,
+    ///     _ => false,
+    /// };
+    ///
+    /// let a = if let Some(0) = x {
+    ///     true
+    /// } else {
+    ///     false
+    /// };
+    ///
+    /// // Good
+    /// let a = matches!(x, Some(0));
+    /// ```
+    pub MATCH_LIKE_MATCHES_MACRO,
+    style,
+    "a match that could be written with the matches! macro"
+}
+
 #[derive(Default)]
 pub struct Matches {
     infallible_destructuring_match_linted: bool,
@@ -427,7 +495,9 @@ pub struct Matches {
     WILDCARD_IN_OR_PATTERNS,
     MATCH_SINGLE_BINDING,
     INFALLIBLE_DESTRUCTURING_MATCH,
-    REST_PAT_IN_FULLY_BOUND_STRUCTS
+    REST_PAT_IN_FULLY_BOUND_STRUCTS,
+    REDUNDANT_PATTERN_MATCHING,
+    MATCH_LIKE_MATCHES_MACRO
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -435,6 +505,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if in_external_macro(cx.sess(), expr.span) {
             return;
         }
+
+        redundant_pattern_match::check(cx, expr);
+        check_match_like_matches(cx, expr);
+
         if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind {
             check_single_match(cx, ex, arms, expr);
             check_match_bool(cx, ex, arms, expr);
@@ -530,17 +604,23 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
             // the lint noisy in unnecessary situations
             return;
         }
-        let els = remove_blocks(&arms[1].body);
-        let els = if is_unit_expr(els) {
+        let els = arms[1].body;
+        let els = if is_unit_expr(remove_blocks(els)) {
             None
-        } else if let ExprKind::Block(_, _) = els.kind {
-            // matches with blocks that contain statements are prettier as `if let + else`
-            Some(els)
+        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
+            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
+                // single statement/expr "else" block, don't lint
+                return;
+            } else {
+                // block with 2+ statements or 1 expr and 1+ statement
+                Some(els)
+            }
         } else {
-            // allow match arms with just expressions
-            return;
+            // not a block, don't lint
+            return; 
         };
-        let ty = cx.tables().expr_ty(ex);
+
+        let ty = cx.typeck_results().expr_ty(ex);
         if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
             check_single_match_single_pattern(cx, ex, arms, expr, els);
             check_single_match_opt_like(cx, ex, arms, expr, ty, els);
@@ -632,7 +712,7 @@ fn check_single_match_opt_like(
 
 fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     // Type of expression is `bool`.
-    if cx.tables().expr_ty(ex).kind == ty::Bool {
+    if cx.typeck_results().expr_ty(ex).kind == ty::Bool {
         span_lint_and_then(
             cx,
             MATCH_BOOL,
@@ -695,8 +775,8 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
 }
 
 fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
-    if arms.len() >= 2 && cx.tables().expr_ty(ex).is_integral() {
-        let ranges = all_ranges(cx, arms, cx.tables().expr_ty(ex));
+    if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
+        let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
         let type_ranges = type_ranges(&ranges);
         if !type_ranges.is_empty() {
             if let Some((start, end)) = overlapping(&type_ranges) {
@@ -714,7 +794,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms
 }
 
 fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
-    let ex_ty = walk_ptrs_ty(cx.tables().expr_ty(ex));
+    let ex_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(ex));
     if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
         for arm in arms {
             if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
@@ -755,7 +835,7 @@ fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 }
 
 fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
-    let ty = cx.tables().expr_ty(ex);
+    let ty = cx.typeck_results().expr_ty(ex);
     if !ty.is_enum() {
         // If there isn't a nice closed set of possible values that can be conveniently enumerated,
         // don't complain about not enumerating the mall.
@@ -802,13 +882,8 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                     // Some simple checks for exhaustive patterns.
                     // There is a room for improvements to detect more cases,
                     // but it can be more expensive to do so.
-                    let is_pattern_exhaustive = |pat: &&Pat<'_>| {
-                        if let PatKind::Wild | PatKind::Binding(.., None) = pat.kind {
-                            true
-                        } else {
-                            false
-                        }
-                    };
+                    let is_pattern_exhaustive =
+                        |pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None));
                     if patterns.iter().all(is_pattern_exhaustive) {
                         missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
                     }
@@ -935,8 +1010,8 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
                 "as_mut"
             };
 
-            let output_ty = cx.tables().expr_ty(expr);
-            let input_ty = cx.tables().expr_ty(ex);
+            let output_ty = cx.typeck_results().expr_ty(expr);
+            let input_ty = cx.typeck_results().expr_ty(ex);
 
             let cast = if_chain! {
                 if let ty::Adt(_, substs) = input_ty.kind;
@@ -989,6 +1064,79 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
     }
 }
 
+/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
+fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+    if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind {
+        match match_source {
+            MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false),
+            MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true),
+            _ => return,
+        }
+    }
+}
+
+/// Lint a `match` or desugared `if let` for replacement by `matches!`
+fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) {
+    if_chain! {
+        if arms.len() == 2;
+        if cx.typeck_results().expr_ty(expr).is_bool();
+        if is_wild(&arms[1].pat);
+        if let Some(first) = find_bool_lit(&arms[0].body.kind, desugared);
+        if let Some(second) = find_bool_lit(&arms[1].body.kind, desugared);
+        if first != second;
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+
+            let pat_and_guard = if let Some(Guard::If(g)) = arms[0].guard {
+                format!("{} if {}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability), snippet_with_applicability(cx, g.span, "..", &mut applicability))
+            } else {
+                format!("{}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability))
+            };
+            span_lint_and_sugg(
+                cx,
+                MATCH_LIKE_MATCHES_MACRO,
+                expr.span,
+                &format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }),
+                "try this",
+                format!(
+                    "{}matches!({}, {})",
+                    if first { "" } else { "!" },
+                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
+                    pat_and_guard,
+                ),
+                applicability,
+            )
+        }
+    }
+}
+
+/// Extract a `bool` or `{ bool }`
+fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> {
+    match ex {
+        ExprKind::Lit(Spanned {
+            node: LitKind::Bool(b), ..
+        }) => Some(*b),
+        ExprKind::Block(
+            rustc_hir::Block {
+                stmts: &[],
+                expr: Some(exp),
+                ..
+            },
+            _,
+        ) if desugared => {
+            if let ExprKind::Lit(Spanned {
+                node: LitKind::Bool(b), ..
+            }) = exp.kind
+            {
+                Some(b)
+            } else {
+                None
+            }
+        },
+        _ => None,
+    }
+}
+
 fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
         return;
@@ -1006,13 +1154,13 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
     match match_body.kind {
         ExprKind::Block(block, _) => {
             // macro + expr_ty(body) == ()
-            if block.span.from_expansion() && cx.tables().expr_ty(&match_body).is_unit() {
+            if block.span.from_expansion() && cx.typeck_results().expr_ty(&match_body).is_unit() {
                 snippet_body.push(';');
             }
         },
         _ => {
             // expr_ty(body) == ()
-            if cx.tables().expr_ty(&match_body).is_unit() {
+            if cx.typeck_results().expr_ty(&match_body).is_unit() {
                 snippet_body.push(';');
             }
         },
@@ -1107,11 +1255,11 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
             {
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
                     let lhs = match lhs {
-                        Some(lhs) => constant(cx, cx.tables(), lhs)?.0,
+                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
                         None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
                     };
                     let rhs = match rhs {
-                        Some(rhs) => constant(cx, cx.tables(), rhs)?.0,
+                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
                         None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
                     };
                     let rhs = match range_end {
@@ -1125,7 +1273,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                 }
 
                 if let PatKind::Lit(ref value) = pat.kind {
-                    let value = constant(cx, cx.tables(), value)?.0;
+                    let value = constant(cx, cx.typeck_results(), value)?.0;
                     return Some(SpannedRange {
                         span: pat.span,
                         node: (value.clone(), Bound::Included(value)),
@@ -1179,10 +1327,7 @@ fn is_unit_expr(expr: &Expr<'_>) -> bool {
 
 // Checks if arm has the form `None => None`
 fn is_none_arm(arm: &Arm<'_>) -> bool {
-    match arm.pat.kind {
-        PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => true,
-        _ => false,
-    }
+    matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE))
 }
 
 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
@@ -1293,6 +1438,229 @@ fn cmp(&self, other: &Self) -> Ordering {
     None
 }
 
+mod redundant_pattern_match {
+    use super::REDUNDANT_PATTERN_MATCHING;
+    use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
+    use if_chain::if_chain;
+    use rustc_ast::ast::LitKind;
+    use rustc_errors::Applicability;
+    use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
+    use rustc_lint::LateContext;
+    use rustc_middle::ty;
+    use rustc_mir::const_eval::is_const_fn;
+    use rustc_span::source_map::Symbol;
+
+    pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
+            match match_source {
+                MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
+                MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
+                MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
+                _ => {},
+            }
+        }
+    }
+
+    fn find_sugg_for_if_let<'tcx>(
+        cx: &LateContext<'tcx>,
+        expr: &'tcx Expr<'_>,
+        op: &Expr<'_>,
+        arms: &[Arm<'_>],
+        keyword: &'static str,
+    ) {
+        fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
+            if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
+                return Some("is_ok()");
+            }
+            if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
+                return Some("is_err()");
+            }
+            if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
+                return Some("is_some()");
+            }
+            if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
+                return Some("is_none()");
+            }
+            None
+        }
+
+        let hir_id = expr.hir_id;
+        let good_method = match arms[0].pat.kind {
+            PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
+                if let PatKind::Wild = patterns[0].kind {
+                    find_suggestion(cx, hir_id, path)
+                } else {
+                    None
+                }
+            },
+            PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
+            _ => None,
+        };
+        let good_method = match good_method {
+            Some(method) => method,
+            None => return,
+        };
+
+        // check that `while_let_on_iterator` lint does not trigger
+        if_chain! {
+            if keyword == "while";
+            if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
+            if method_path.ident.name == sym!(next);
+            if match_trait_method(cx, op, &paths::ITERATOR);
+            then {
+                return;
+            }
+        }
+
+        span_lint_and_then(
+            cx,
+            REDUNDANT_PATTERN_MATCHING,
+            arms[0].pat.span,
+            &format!("redundant pattern matching, consider using `{}`", good_method),
+            |diag| {
+                // while let ... = ... { ... }
+                // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+                let expr_span = expr.span;
+
+                // while let ... = ... { ... }
+                //                 ^^^
+                let op_span = op.span.source_callsite();
+
+                // while let ... = ... { ... }
+                // ^^^^^^^^^^^^^^^^^^^
+                let span = expr_span.until(op_span.shrink_to_hi());
+                diag.span_suggestion(
+                    span,
+                    "try this",
+                    format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
+                    Applicability::MachineApplicable, // snippet
+                );
+            },
+        );
+    }
+
+    fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
+        if arms.len() == 2 {
+            let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
+
+            let hir_id = expr.hir_id;
+            let found_good_method = match node_pair {
+                (
+                    PatKind::TupleStruct(ref path_left, ref patterns_left, _),
+                    PatKind::TupleStruct(ref path_right, ref patterns_right, _),
+                ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
+                    if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
+                        find_good_method_for_match(
+                            arms,
+                            path_left,
+                            path_right,
+                            &paths::RESULT_OK,
+                            &paths::RESULT_ERR,
+                            "is_ok()",
+                            "is_err()",
+                            || can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
+                            || can_suggest(cx, hir_id, sym!(result_type), "is_err"),
+                        )
+                    } else {
+                        None
+                    }
+                },
+                (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
+                | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
+                    if patterns.len() == 1 =>
+                {
+                    if let PatKind::Wild = patterns[0].kind {
+                        find_good_method_for_match(
+                            arms,
+                            path_left,
+                            path_right,
+                            &paths::OPTION_SOME,
+                            &paths::OPTION_NONE,
+                            "is_some()",
+                            "is_none()",
+                            || can_suggest(cx, hir_id, sym!(option_type), "is_some"),
+                            || can_suggest(cx, hir_id, sym!(option_type), "is_none"),
+                        )
+                    } else {
+                        None
+                    }
+                },
+                _ => None,
+            };
+
+            if let Some(good_method) = found_good_method {
+                span_lint_and_then(
+                    cx,
+                    REDUNDANT_PATTERN_MATCHING,
+                    expr.span,
+                    &format!("redundant pattern matching, consider using `{}`", good_method),
+                    |diag| {
+                        let span = expr.span.to(op.span);
+                        diag.span_suggestion(
+                            span,
+                            "try this",
+                            format!("{}.{}", snippet(cx, op.span, "_"), good_method),
+                            Applicability::MaybeIncorrect, // snippet
+                        );
+                    },
+                );
+            }
+        }
+    }
+
+    #[allow(clippy::too_many_arguments)]
+    fn find_good_method_for_match<'a>(
+        arms: &[Arm<'_>],
+        path_left: &QPath<'_>,
+        path_right: &QPath<'_>,
+        expected_left: &[&str],
+        expected_right: &[&str],
+        should_be_left: &'a str,
+        should_be_right: &'a str,
+        can_suggest_left: impl Fn() -> bool,
+        can_suggest_right: impl Fn() -> bool,
+    ) -> Option<&'a str> {
+        let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
+            (&(*arms[0].body).kind, &(*arms[1].body).kind)
+        } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
+            (&(*arms[1].body).kind, &(*arms[0].body).kind)
+        } else {
+            return None;
+        };
+
+        match body_node_pair {
+            (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
+                (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
+                (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
+                _ => None,
+            },
+            _ => None,
+        }
+    }
+
+    fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
+        if !in_constant(cx, hir_id) {
+            return true;
+        }
+
+        // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
+        cx.tcx
+            .get_diagnostic_item(diag_item)
+            .and_then(|def_id| {
+                cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
+                    cx.tcx
+                        .associated_items(*imp)
+                        .in_definition_order()
+                        .find_map(|item| match item.kind {
+                            ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
+                            _ => None,
+                        })
+                })
+            })
+            .map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
+    }
+}
+
 #[test]
 fn test_overlapping() {
     use rustc_span::source_map::DUMMY_SP;
index 06c568513035f068bea8ccc71419fbfd13f67f4d..c71c2ee7d70afeaf8ab5e63718b781197ef49654 100644 (file)
@@ -38,7 +38,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::MEM_DISCRIMINANT);
             // type is non-enum
-            let ty_param = cx.tables().node_substs(func.hir_id).type_at(0);
+            let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
             if !ty_param.is_enum();
 
             then {
index b895ba324c78a7ab5c9efaf57ae56ee751bd47d1..8c6fd10f98a1e178c4fa6bbdb7b731592208f1f6 100644 (file)
@@ -31,7 +31,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             if let ExprKind::Path(ref qpath) = path_expr.kind {
                 if let Some(def_id) = qpath_res(cx, qpath, path_expr.hir_id).opt_def_id() {
                     if match_def_path(cx, def_id, &paths::MEM_FORGET) {
-                        let forgot_ty = cx.tables().expr_ty(&args[0]);
+                        let forgot_ty = cx.typeck_results().expr_ty(&args[0]);
 
                         if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
                             span_lint(cx, MEM_FORGET, e.span, "usage of `mem::forget` on `Drop` type");
index 25f332cdcc2868d48142fa3b72424b7930cb1d4c..bb0acecc5a92d1a7a5d8fefdfad4ada9372ef443 100644 (file)
@@ -138,7 +138,7 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &E
 fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
     if_chain! {
         // check if replacement is mem::MaybeUninit::uninit().assume_init()
-        if let Some(method_def_id) = cx.tables().type_dependent_def_id(src.hir_id);
+        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(src.hir_id);
         if cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id);
         then {
             let mut applicability = Applicability::MachineApplicable;
@@ -179,7 +179,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
                     applicability,
                 );
             } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
-                    !cx.tables().expr_ty(src).is_primitive() {
+                    !cx.typeck_results().expr_ty(src).is_primitive() {
                 span_lint_and_help(
                     cx,
                     MEM_REPLACE_WITH_UNINIT,
index fcf7b509eadbf6cf0eb518e7e7a6196264c614d0..498f12518f8a33745325056f1264dcdb5f6565d2 100644 (file)
@@ -157,7 +157,7 @@ fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::
 
     /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
     fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-        if !match_type(cx, cx.tables().expr_ty(&args[0]), Self::TYPE_QPATH) {
+        if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
             return;
         }
 
index 1c0018a5b95e2c16703c84de8a9fa36732022442..e5f815772eba946fe32d5221d39c8620e83d553d 100644 (file)
@@ -11,9 +11,9 @@
 /// Checks for the `INEFFICIENT_TO_STRING` lint
 pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) {
     if_chain! {
-        if let Some(to_string_meth_did) = cx.tables().type_dependent_def_id(expr.hir_id);
+        if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
-        if let Some(substs) = cx.tables().node_substs_opt(expr.hir_id);
+        if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
         let self_ty = substs.type_at(0);
         let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
         if deref_count >= 1;
index 9c04b6d57b90f82c1040708f5e1e224f6aca8e6c..40a625758616455c3d0e174c7a6fc747fca11cf7 100644 (file)
@@ -11,7 +11,7 @@ pub fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>]
     let arith_lhs = &args[1][0];
     let arith_rhs = &args[1][1];
 
-    let ty = cx.tables().expr_ty(arith_lhs);
+    let ty = cx.typeck_results().expr_ty(arith_lhs);
     if !ty.is_integral() {
         return;
     }
@@ -101,7 +101,7 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<M
         }
     }
 
-    let ty = cx.tables().expr_ty(expr);
+    let ty = cx.typeck_results().expr_ty(expr);
     let ty_str = ty.to_string();
 
     // `std::T::MAX` `std::T::MIN` constants
index 216db12f0115fb31943b72d255a64023ed7b70fc..4877556a49e37daaf59173ede295f148af2d4895 100644 (file)
@@ -1433,7 +1433,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                 lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
                 lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
 
-                let self_ty = cx.tables().expr_ty_adjusted(&args[0]);
+                let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
                 if args.len() == 1 && method_call.ident.name == sym!(clone) {
                     lint_clone_on_copy(cx, expr, &args[0], self_ty);
                     lint_clone_on_ref_ptr(cx, expr, &args[0]);
@@ -1639,7 +1639,7 @@ fn check_unwrap_or_default(
             if let hir::ExprKind::Path(ref qpath) = fun.kind;
             let path = &*last_path_segment(qpath).ident.as_str();
             if ["default", "new"].contains(&path);
-            let arg_ty = cx.tables().expr_ty(arg);
+            let arg_ty = cx.typeck_results().expr_ty(arg);
             if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
             if implements_trait(cx, arg_ty, default_trait_id, &[]);
 
@@ -1679,7 +1679,7 @@ fn check_general_case<'tcx>(
     ) {
         if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
             if path.ident.as_str() == "len" {
-                let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
+                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
 
                 match ty.kind {
                     ty::Slice(_) | ty::Array(_, _) => return,
@@ -1707,7 +1707,7 @@ fn check_general_case<'tcx>(
             if { finder.visit_expr(&arg); finder.found };
             if !contains_return(&arg);
 
-            let self_ty = cx.tables().expr_ty(self_expr);
+            let self_ty = cx.typeck_results().expr_ty(self_expr);
 
             if let Some(&(_, fn_has_arguments, poss, suffix)) =
                 know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
@@ -1786,7 +1786,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex
                     if call_args.len() == 1
                         && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
                         && {
-                            let arg_type = cx.tables().expr_ty(&call_args[0]);
+                            let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
                             let base_type = walk_ptrs_ty(arg_type);
                             base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
                         }
@@ -1805,7 +1805,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex
     // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
     // converted to string.
     fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
-        let arg_ty = cx.tables().expr_ty(arg);
+        let arg_ty = cx.typeck_results().expr_ty(arg);
         if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) {
             return false;
         }
@@ -1835,19 +1835,20 @@ fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                     false
                 }
             },
-            hir::ExprKind::MethodCall(..) => cx
-                .tables()
-                .type_dependent_def_id(arg.hir_id)
-                .map_or(false, |method_id| {
-                    matches!(
-                        cx.tcx.fn_sig(method_id).output().skip_binder().kind,
-                        ty::Ref(ty::ReStatic, ..)
-                    )
-                }),
-            hir::ExprKind::Path(ref p) => match cx.qpath_res(p, arg.hir_id) {
-                hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) => true,
-                _ => false,
+            hir::ExprKind::MethodCall(..) => {
+                cx.typeck_results()
+                    .type_dependent_def_id(arg.hir_id)
+                    .map_or(false, |method_id| {
+                        matches!(
+                            cx.tcx.fn_sig(method_id).output().skip_binder().kind,
+                            ty::Ref(ty::ReStatic, ..)
+                        )
+                    })
             },
+            hir::ExprKind::Path(ref p) => matches!(
+                cx.qpath_res(p, arg.hir_id),
+                hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _)
+            ),
             _ => false,
         }
     }
@@ -1891,7 +1892,7 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
         return;
     }
 
-    let receiver_type = cx.tables().expr_ty_adjusted(&args[0]);
+    let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
     let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
         "||"
     } else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
@@ -1957,7 +1958,7 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
 
 /// Checks for the `CLONE_ON_COPY` lint.
 fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
-    let ty = cx.tables().expr_ty(expr);
+    let ty = cx.typeck_results().expr_ty(expr);
     if let ty::Ref(_, inner, _) = arg_ty.kind {
         if let ty::Ref(_, innermost, _) = inner.kind {
             span_lint_and_then(
@@ -2005,7 +2006,9 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
                     // &*x is a nop, &x.clone() is not
                     hir::ExprKind::AddrOf(..) => return,
                     // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
-                    hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => return,
+                    hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => {
+                        return;
+                    },
 
                     _ => {},
                 },
@@ -2021,20 +2024,14 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
             }
 
             // x.clone() might have dereferenced x, possibly through Deref impls
-            if cx.tables().expr_ty(arg) == ty {
+            if cx.typeck_results().expr_ty(arg) == ty {
                 snip = Some(("try removing the `clone` call", format!("{}", snippet)));
             } else {
                 let deref_count = cx
-                    .tables()
+                    .typeck_results()
                     .expr_adjustments(arg)
                     .iter()
-                    .filter(|adj| {
-                        if let ty::adjustment::Adjust::Deref(_) = adj.kind {
-                            true
-                        } else {
-                            false
-                        }
-                    })
+                    .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
                     .count();
                 let derefs: String = iter::repeat('*').take(deref_count).collect();
                 snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
@@ -2044,14 +2041,14 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
         }
         span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| {
             if let Some((text, snip)) = snip {
-                diag.span_suggestion(expr.span, text, snip, Applicability::Unspecified);
+                diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
             }
         });
     }
 }
 
 fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
-    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(arg));
+    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg));
 
     if let ty::Adt(_, subst) = obj_ty.kind {
         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
@@ -2085,7 +2082,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
     let arg = &args[1];
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
         let target = &arglists[0][0];
-        let self_ty = walk_ptrs_ty(cx.tables().expr_ty(target));
+        let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target));
         let ref_str = if self_ty.kind == ty::Str {
             ""
         } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
@@ -2113,7 +2110,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
 }
 
 fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
+    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
     if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
         lint_string_extend(cx, expr, args);
     }
@@ -2121,7 +2118,7 @@ fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>
 
 fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) {
     if_chain! {
-        let source_type = cx.tables().expr_ty(source);
+        let source_type = cx.typeck_results().expr_ty(source);
         if let ty::Adt(def, substs) = source_type.kind;
         if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
         if match_type(cx, substs.type_at(0), &paths::CSTRING);
@@ -2141,8 +2138,8 @@ fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir:
 
 fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
     if_chain! {
-        if is_type_diagnostic_item(cx, cx.tables().expr_ty(expr), sym!(vec_type));
-        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables().expr_ty(&iter_args[0]));
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym!(vec_type));
+        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0]));
         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
 
         then {
@@ -2249,7 +2246,7 @@ fn check_fold_with_op(
 
 fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
     if match_trait_method(cx, expr, &paths::ITERATOR) {
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.tables(), &args[1]) {
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) {
             span_lint(
                 cx,
                 ITERATOR_STEP_BY_ZERO,
@@ -2273,7 +2270,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
         parent_expr_opt = get_parent_expr(cx, parent_expr);
     }
 
-    if derefs_to_slice(cx, caller_expr, cx.tables().expr_ty(caller_expr)).is_some() {
+    if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
         // caller is a Slice
         if_chain! {
             if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
@@ -2294,8 +2291,11 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
                 );
             }
         }
-    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(caller_expr), sym!(vec_type))
-        || matches!(&walk_ptrs_ty(cx.tables().expr_ty(caller_expr)).kind, ty::Array(_, _))
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
+        || matches!(
+            &walk_ptrs_ty(cx.typeck_results().expr_ty(caller_expr)).kind,
+            ty::Array(_, _)
+        )
     {
         // caller is a Vec or an Array
         let mut applicability = Applicability::MachineApplicable;
@@ -2322,11 +2322,11 @@ fn lint_iter_nth<'tcx>(
 ) {
     let iter_args = nth_and_iter_args[1];
     let mut_str = if is_mut { "_mut" } else { "" };
-    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables().expr_ty(&iter_args[0])).is_some() {
+    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() {
         "slice"
-    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(&iter_args[0]), sym!(vec_type)) {
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vec_type)) {
         "Vec"
-    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
         "VecDeque"
     } else {
         let nth_args = nth_and_iter_args[0];
@@ -2347,7 +2347,7 @@ fn lint_iter_nth<'tcx>(
 fn lint_iter_nth_zero<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
     if_chain! {
         if match_trait_method(cx, expr, &paths::ITERATOR);
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.tables(), &nth_args[1]);
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]);
         then {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
@@ -2367,7 +2367,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args:
     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
     // because they do not implement `IndexMut`
     let mut applicability = Applicability::MachineApplicable;
-    let expr_ty = cx.tables().expr_ty(&get_args[0]);
+    let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
     let get_args_str = if get_args.len() > 1 {
         snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
     } else {
@@ -2460,20 +2460,16 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
             ty::Slice(_) => true,
             ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
             ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)),
-            ty::Array(_, size) => {
-                if let Some(size) = size.try_eval_usize(cx.tcx, cx.param_env) {
-                    size < 32
-                } else {
-                    false
-                }
-            },
+            ty::Array(_, size) => size
+                .try_eval_usize(cx.tcx, cx.param_env)
+                .map_or(false, |size| size < 32),
             ty::Ref(_, inner, _) => may_slice(cx, inner),
             _ => false,
         }
     }
 
     if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
-        if path.ident.name == sym!(iter) && may_slice(cx, cx.tables().expr_ty(&args[0])) {
+        if path.ident.name == sym!(iter) && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
             Some(&args[0])
         } else {
             None
@@ -2496,7 +2492,7 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
 fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&unwrap_args[0]));
+    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0]));
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
         Some((UNWRAP_USED, "an Option", "None"))
@@ -2524,7 +2520,7 @@ fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::E
 
 /// lint use of `expect()` for `Option`s and `Result`s
 fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&expect_args[0]));
+    let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0]));
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
         Some((EXPECT_USED, "an Option", "None"))
@@ -2550,8 +2546,8 @@ fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::E
 fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
     if_chain! {
         // lint if the caller of `ok()` is a `Result`
-        if is_type_diagnostic_item(cx, cx.tables().expr_ty(&ok_args[0]), sym!(result_type));
-        let result_type = cx.tables().expr_ty(&ok_args[0]);
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym!(result_type));
+        let result_type = cx.typeck_results().expr_ty(&ok_args[0]);
         if let Some(error_type) = get_error_type(cx, result_type);
         if has_debug_impl(error_type, cx);
 
@@ -2589,7 +2585,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     }
 
     // lint if caller of `.map().flatten()` is an Option
-    if is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) {
         let msg = "called `map(..).flatten()` on an `Option`. \
                     This is more succinctly expressed by calling `.and_then(..)`";
         let self_snippet = snippet(cx, map_args[0].span, "..");
@@ -2615,8 +2611,8 @@ fn lint_map_unwrap_or_else<'tcx>(
     unwrap_args: &'tcx [hir::Expr<'_>],
 ) {
     // lint if the caller of `map()` is an `Option`
-    let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type));
-    let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(result_type));
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type));
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type));
 
     if is_option || is_result {
         // Don't make a suggestion that may fail to compile due to mutably borrowing
@@ -2666,8 +2662,8 @@ fn lint_map_unwrap_or_else<'tcx>(
 
 /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
 fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
-    let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_or_args[0]), sym!(option_type));
-    let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_or_args[0]), sym!(result_type));
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(option_type));
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(result_type));
 
     // There are two variants of this `map_or` lint:
     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
@@ -3024,7 +3020,7 @@ fn lint_chars_cmp(
         if segment.ident.name == sym!(Some);
         then {
             let mut applicability = Applicability::MachineApplicable;
-            let self_ty = walk_ptrs_ty(cx.tables().expr_ty_adjusted(&args[0][0]));
+            let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0]));
 
             if self_ty.kind != ty::Str {
                 return false;
@@ -3152,8 +3148,8 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re
     if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
         // check if the type after `as_ref` or `as_mut` is the same as before
         let recvr = &as_ref_args[0];
-        let rcv_ty = cx.tables().expr_ty(recvr);
-        let res_ty = cx.tables().expr_ty(expr);
+        let rcv_ty = cx.typeck_results().expr_ty(recvr);
+        let res_ty = cx.typeck_results().expr_ty(expr);
         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
         let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
@@ -3222,7 +3218,7 @@ fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Ex
         if args.is_empty();
         if let hir::ExprKind::Path(ref path) = callee.kind;
         if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
-        if !is_maybe_uninit_ty_valid(cx, cx.tables().expr_ty_adjusted(outer));
+        if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer));
         then {
             span_lint(
                 cx,
@@ -3264,7 +3260,7 @@ fn lint_option_as_ref_deref<'tcx>(
 ) {
     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
 
-    let option_ty = cx.tables().expr_ty(&as_ref_args[0]);
+    let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
     if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) {
         return;
     }
@@ -3294,10 +3290,10 @@ fn lint_option_as_ref_deref<'tcx>(
                         if let hir::ExprKind::Path(qpath) = &args[0].kind;
                         if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id);
                         if closure_body.params[0].pat.hir_id == local_id;
-                        let adj = cx.tables().expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
+                        let adj = cx.typeck_results().expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
                         if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
                         then {
-                            let method_did = cx.tables().type_dependent_def_id(closure_expr.hir_id).unwrap();
+                            let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
                             deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
                         } else {
                             false
@@ -3587,7 +3583,7 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     if_chain! {
         if args.len() == 2;
-        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.tables().expr_ty(&args[0]).kind;
+        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind;
         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
         if layout.is_zst();
         then {
@@ -3597,7 +3593,7 @@ fn check_pointer_offset(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir:
 }
 
 fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let ty = cx.tables().expr_ty(&args[0]);
+    let ty = cx.typeck_results().expr_ty(&args[0]);
 
     if !match_type(cx, ty, &paths::FILE_TYPE) {
         return;
index 672eb75c57fc677988be130109bf982b18f16c96..95fa28e1c0f75507fb99feb648e68347458f5a2d 100644 (file)
@@ -20,8 +20,8 @@ pub(super) fn lint<'tcx>(
     map_span: Span,
 ) {
     // lint if the caller of `map()` is an `Option`
-    if is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)) {
-        if !is_copy(cx, cx.tables().expr_ty(&unwrap_args[1])) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) {
+        if !is_copy(cx, cx.typeck_results().expr_ty(&unwrap_args[1])) {
             // Do not lint if the `map` argument uses identifiers in the `map`
             // argument that are also used in the `unwrap_or` argument
 
index fdcba1105428841bfa4555a0c2d46c24bf5b13c0..75e123eb5939d971b7c7943485ea569894377ee1 100644 (file)
@@ -77,13 +77,10 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
             }
             (true, true)
         },
-        hir::ExprKind::Block(ref block, _) => {
-            if let Some(expr) = &block.expr {
-                check_expression(cx, arg_id, &expr)
-            } else {
-                (false, false)
-            }
-        },
+        hir::ExprKind::Block(ref block, _) => block
+            .expr
+            .as_ref()
+            .map_or((false, false), |expr| check_expression(cx, arg_id, &expr)),
         hir::ExprKind::Match(_, arms, _) => {
             let mut found_mapping = false;
             let mut found_filtering = false;
index 0a2d577396a5f94940442dc582e7e0c0a9b69e35..dae39aaf5e2165e6ffa9e31e5f8ffc5ffd0062c4 100644 (file)
@@ -36,7 +36,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 }
                 match (
                     outer_max,
-                    Constant::partial_cmp(cx.tcx, cx.tables().expr_ty(ie), &outer_c, &inner_c),
+                    Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c),
                 ) {
                     (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
                     _ => {
@@ -53,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
-#[derive(PartialEq, Eq, Debug)]
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
 enum MinMax {
     Min,
     Max,
@@ -62,7 +62,7 @@ enum MinMax {
 fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
     if let ExprKind::Call(ref path, ref args) = expr.kind {
         if let ExprKind::Path(ref qpath) = path.kind {
-            cx.tables()
+            cx.typeck_results()
                 .qpath_res(qpath, path.hir_id)
                 .opt_def_id()
                 .and_then(|def_id| {
@@ -86,16 +86,15 @@ fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Opt
     if args.len() != 2 {
         return None;
     }
-    if let Some(c) = constant_simple(cx, cx.tables(), &args[0]) {
-        if constant_simple(cx, cx.tables(), &args[1]).is_none() {
-            // otherwise ignore
-            Some((m, c, &args[1]))
-        } else {
-            None
-        }
-    } else if let Some(c) = constant_simple(cx, cx.tables(), &args[1]) {
-        Some((m, c, &args[0]))
-    } else {
-        None
-    }
+    constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else(
+        || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])),
+        |c| {
+            if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() {
+                // otherwise ignore
+                Some((m, c, &args[1]))
+            } else {
+                None
+            }
+        },
+    )
 }
index d7e1a62a19d5204bd9d0e81bbe9b6c64bbc44dbe..fc10e5077b8391c429a958d91fed858aab8f88f2 100644 (file)
@@ -3,11 +3,11 @@
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, StmtKind, Ty,
-    TyKind, UnOp,
+    self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
+    StmtKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{ExpnKind, Span};
@@ -371,8 +371,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 if op.is_comparison() {
                     check_nan(cx, left, expr);
                     check_nan(cx, right, expr);
-                    check_to_owned(cx, left, right);
-                    check_to_owned(cx, right, left);
+                    check_to_owned(cx, left, right, true);
+                    check_to_owned(cx, right, left, false);
                 }
                 if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) {
                     if is_allowed(cx, left) || is_allowed(cx, right) {
@@ -496,7 +496,7 @@ fn get_lint_and_message(
 fn check_nan(cx: &LateContext<'_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
     if_chain! {
         if !in_constant(cx, cmp_expr.hir_id);
-        if let Some((value, _)) = constant(cx, cx.tables(), expr);
+        if let Some((value, _)) = constant(cx, cx.typeck_results(), expr);
         then {
             let needs_lint = match value {
                 Constant::F32(num) => num.is_nan(),
@@ -517,7 +517,7 @@ fn check_nan(cx: &LateContext<'_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
 }
 
 fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
-    if let Some((_, res)) = constant(cx, cx.tables(), expr) {
+    if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) {
         res
     } else {
         false
@@ -525,7 +525,7 @@ fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool
 }
 
 fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
-    match constant(cx, cx.tables(), expr) {
+    match constant(cx, cx.typeck_results(), expr) {
         Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(),
         Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(),
         Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f {
@@ -557,7 +557,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let value = &walk_ptrs_ty(cx.tables().expr_ty(expr)).kind;
+    let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind;
 
     if let ty::Array(arr_ty, _) = value {
         return matches!(arr_ty.kind, ty::Float(_));
@@ -567,14 +567,33 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _))
+    matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind, ty::Array(_, _))
 }
 
-fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
+fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
+    #[derive(Default)]
+    struct EqImpl {
+        ty_eq_other: bool,
+        other_eq_ty: bool,
+    }
+
+    impl EqImpl {
+        fn is_implemented(&self) -> bool {
+            self.ty_eq_other || self.other_eq_ty
+        }
+    }
+
+    fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option<EqImpl> {
+        cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl {
+            ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]),
+            other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]),
+        })
+    }
+
     let (arg_ty, snip) = match expr.kind {
         ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
             if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
-                (cx.tables().expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
+                (cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
             } else {
                 return;
             }
@@ -582,7 +601,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
         ExprKind::Call(ref path, ref v) if v.len() == 1 => {
             if let ExprKind::Path(ref path) = path.kind {
                 if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
-                    (cx.tables().expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
+                    (cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
                 } else {
                     return;
                 }
@@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
         _ => return,
     };
 
-    let other_ty = cx.tables().expr_ty_adjusted(other);
-    let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() {
-        Some(id) => id,
-        None => return,
-    };
+    let other_ty = cx.typeck_results().expr_ty(other);
 
-    let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| {
-        implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])
-    });
-    let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| {
-        implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])
-    });
-    let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]);
+    let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
+    let with_deref = arg_ty
+        .builtin_deref(true)
+        .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty))
+        .unwrap_or_default();
 
-    if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
+    if !with_deref.is_implemented() && !without_deref.is_implemented() {
         return;
     }
 
-    let other_gets_derefed = match other.kind {
-        ExprKind::Unary(UnOp::UnDeref, _) => true,
-        _ => false,
-    };
+    let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _));
 
     let lint_span = if other_gets_derefed {
         expr.span.to(other.span)
@@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
                 return;
             }
 
-            let try_hint = if deref_arg_impl_partial_eq_other {
-                // suggest deref on the left
-                format!("*{}", snip)
+            let expr_snip;
+            let eq_impl;
+            if with_deref.is_implemented() {
+                expr_snip = format!("*{}", snip);
+                eq_impl = with_deref;
             } else {
-                // suggest dropping the to_owned on the left
-                snip.to_string()
+                expr_snip = snip.to_string();
+                eq_impl = without_deref;
             };
 
+            let span;
+            let hint;
+            if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) {
+                span = expr.span;
+                hint = expr_snip;
+            } else {
+                span = expr.span.to(other.span);
+                if eq_impl.ty_eq_other {
+                    hint = format!("{} == {}", expr_snip, snippet(cx, other.span, ".."));
+                } else {
+                    hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip);
+                }
+            }
+
             diag.span_suggestion(
-                lint_span,
+                span,
                 "try",
-                try_hint,
+                hint,
                 Applicability::MachineApplicable, // snippet
             );
         },
@@ -656,16 +682,10 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
 /// `unused_variables`'s idea
 /// of what it means for an expression to be "used".
 fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let Some(parent) = get_parent_expr(cx, expr) {
-        match parent.kind {
-            ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => {
-                SpanlessEq::new(cx).eq_expr(rhs, expr)
-            },
-            _ => is_used(cx, parent),
-        }
-    } else {
-        true
-    }
+    get_parent_expr(cx, expr).map_or(true, |parent| match parent.kind {
+        ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => SpanlessEq::new(cx).eq_expr(rhs, expr),
+        _ => is_used(cx, parent),
+    })
 }
 
 /// Tests whether an expression is in a macro expansion (e.g., something
@@ -674,12 +694,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
     use rustc_span::hygiene::MacroKind;
     if expr.span.from_expansion() {
         let data = expr.span.ctxt().outer_expn_data();
-
-        if let ExpnKind::Macro(MacroKind::Attr, _) = data.kind {
-            true
-        } else {
-            false
-        }
+        matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _))
     } else {
         false
     }
@@ -694,7 +709,7 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
     }
 }
 
-fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &Ty<'_>) {
+fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
     if_chain! {
         if let TyKind::Ptr(ref mut_ty) = ty.kind;
         if let ExprKind::Lit(ref lit) = e.kind;
index ad39e59d0678a29bdac0ae5420e3443869865d33..b84a1a3fe249449a81a574ea2be25118976bbd7e 100644 (file)
@@ -641,28 +641,22 @@ fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) {
             );
         }
 
-        #[allow(clippy::trivially_copy_pass_by_ref)]
-        fn is_wild<P: std::ops::Deref<Target = Pat>>(pat: &&P) -> bool {
-            if let PatKind::Wild = pat.kind {
-                true
-            } else {
-                false
-            }
-        }
-
         if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
             if let Some((left_index, left_pat)) = patterns[..rest_index]
                 .iter()
                 .rev()
-                .take_while(is_wild)
+                .take_while(|pat| matches!(pat.kind, PatKind::Wild))
                 .enumerate()
                 .last()
             {
                 span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
             }
 
-            if let Some((right_index, right_pat)) =
-                patterns[rest_index + 1..].iter().take_while(is_wild).enumerate().last()
+            if let Some((right_index, right_pat)) = patterns[rest_index + 1..]
+                .iter()
+                .take_while(|pat| matches!(pat.kind, PatKind::Wild))
+                .enumerate()
+                .last()
             {
                 span_lint(
                     cx,
index bf80b62afe6e04d99882a6500136cacc0d26153f..9c9626735370180deccffb545cc5579933943f59 100644 (file)
@@ -71,10 +71,11 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp
 fn is_executable(cx: &LateContext<'_>) -> bool {
     use rustc_session::config::CrateType;
 
-    cx.tcx.sess.crate_types().iter().any(|t: &CrateType| match t {
-        CrateType::Executable => true,
-        _ => false,
-    })
+    cx.tcx
+        .sess
+        .crate_types()
+        .iter()
+        .any(|t: &CrateType| matches!(t, CrateType::Executable))
 }
 
 declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
index 59ccc6333fdcd838dc28da84c89ba7062a7c32b4..5d4436bd206d2b48d61edcbbee93b20cd02b26bf 100644 (file)
@@ -37,8 +37,8 @@ struct OperandInfo {
 }
 
 fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
-    match constant(cx, cx.tables(), operand) {
-        Some((Constant::Int(v), _)) => match cx.tables().expr_ty(expr).kind {
+    match constant(cx, cx.typeck_results(), operand) {
+        Some((Constant::Int(v), _)) => match cx.typeck_results().expr_ty(expr).kind {
             ty::Int(ity) => {
                 let value = sext(cx.tcx, v, ity);
                 return Some(OperandInfo {
@@ -106,7 +106,7 @@ fn check_const_operands<'tcx>(
 }
 
 fn check_non_const_operands<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, operand: &Expr<'_>) {
-    let operand_type = cx.tables().expr_ty(operand);
+    let operand_type = cx.typeck_results().expr_ty(operand);
     if might_have_negative_value(operand_type) {
         span_lint_and_then(
             cx,
index d8fb8a4bb776bafc273841a6ee4ac824aa94a807..9f8f401cc0f67d4e869fb002e914d4bfa18f1d7d 100644 (file)
@@ -76,7 +76,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
         if let hir::PatKind::Wild = local.pat.kind {
             return;
         }
-        check_ty(cx, local.span, cx.tables().pat_ty(&*local.pat));
+        check_ty(cx, local.span, cx.typeck_results().pat_ty(&*local.pat));
     }
 }
 
index 259b4c73d7609b1cef0fe22899f677d41575c195..b02e86bca27195c2a39a7639176adee31fbf2368 100644 (file)
@@ -69,7 +69,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
                     expr.span,
                     "generally you want to avoid `&mut &mut _` if possible",
                 );
-            } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.tables().expr_ty(e).kind {
+            } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind {
                 span_lint(
                     self.cx,
                     MUT_MUT,
index 53341b6eba752a019c1c948312068a549b94d029..b8dc5081632972827f9fc9203246dabc8649d096 100644 (file)
@@ -37,14 +37,14 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     check_arguments(
                         cx,
                         arguments,
-                        cx.tables().expr_ty(fn_expr),
+                        cx.typeck_results().expr_ty(fn_expr),
                         &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                     );
                 }
             },
             ExprKind::MethodCall(ref path, _, ref arguments, _) => {
-                let def_id = cx.tables().type_dependent_def_id(e.hir_id).unwrap();
-                let substs = cx.tables().node_substs(e.hir_id);
+                let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
+                let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
                 check_arguments(cx, arguments, method_type, &path.ident.as_str())
             },
index 78d2356748f1ed6b164a1bd4939ebb77293ee5a3..7f529f0404c00af727db852f1725efe0e3647569 100644 (file)
@@ -135,7 +135,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 return;
             },
             ExprKind::Path(_) => {
-                if let Some(adj) = self.cx.tables().adjustments().get(expr.hir_id) {
+                if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
                     if adj
                         .iter()
                         .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
index 1a821491fcaf2f5e78004cccf452478151838814..568898aa5c9b7773f4e0fb53679def984114065b 100644 (file)
@@ -66,7 +66,7 @@
 
 impl<'tcx> LateLintPass<'tcx> for Mutex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let ty = cx.tables().expr_ty(expr);
+        let ty = cx.typeck_results().expr_ty(expr);
         if let ty::Adt(_, subst) = ty.kind {
             if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) {
                 let mutex_param = subst.type_at(0);
index e15376b932628a229319a445c5f2ec4d6903844f..8e44f2ec2408c8807cc55d5889040346c3c65a76 100644 (file)
@@ -229,7 +229,10 @@ fn check_comparison<'a, 'tcx>(
     use self::Expression::{Bool, Other};
 
     if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind {
-        let (l_ty, r_ty) = (cx.tables().expr_ty(left_side), cx.tables().expr_ty(right_side));
+        let (l_ty, r_ty) = (
+            cx.typeck_results().expr_ty(left_side),
+            cx.typeck_results().expr_ty(right_side),
+        );
         if l_ty.is_bool() && r_ty.is_bool() {
             let mut applicability = Applicability::MachineApplicable;
 
index 1bea93fcb75220ba364c05b91bc70a0b369cd9d2..415ab556c9fd4eb830e88f4a230fcc2296d59410 100644 (file)
@@ -46,8 +46,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             return;
         }
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
-            if let ty::Ref(..) = cx.tables().expr_ty(inner).kind {
-                for adj3 in cx.tables().expr_adjustments(e).windows(3) {
+            if let ty::Ref(..) = cx.typeck_results().expr_ty(inner).kind {
+                for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
                     if let [Adjustment {
                         kind: Adjust::Deref(_), ..
                     }, Adjustment {
@@ -85,7 +85,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         }
         if_chain! {
             if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
-            if let ty::Ref(_, tam, mutbl) = cx.tables().pat_ty(pat).kind;
+            if let ty::Ref(_, tam, mutbl) = cx.typeck_results().pat_ty(pat).kind;
             if mutbl == Mutability::Not;
             if let ty::Ref(_, _, mutbl) = tam.kind;
             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
index 29e5d4d1664986fbed4e31198c5f2e770359a950..81774b617ac2e5c9bbd4e4ae0b507cfc10ff16b0 100644 (file)
@@ -135,7 +135,8 @@ fn check_fn(
         } = {
             let mut ctx = MovedVariablesCtxt::default();
             cx.tcx.infer_ctxt().enter(|infcx| {
-                euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body);
+                euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
+                    .consume_body(body);
             });
             ctx
         };
index 6ec73041604e60b1ff0e43f929fe5cfbbcf94b61..ce3f066eff5e7d5d6c8227563c818a826fc98ff1 100644 (file)
@@ -47,7 +47,7 @@
 impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind {
-            let ty = cx.tables().expr_ty(expr);
+            let ty = cx.typeck_results().expr_ty(expr);
             if let ty::Adt(def, _) = ty.kind {
                 if fields.len() == def.non_enum_variant().fields.len() {
                     span_lint(
index 1be766d8e8dc5765b420543bcc62353be4a850df..95613a1b82ef0f32101c061c696730dabea56ea7 100644 (file)
@@ -56,7 +56,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
             then {
 
-                let ty = cx.tables().expr_ty(left);
+                let ty = cx.typeck_results().expr_ty(left);
 
                 let implements_ord = {
                     if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) {
index 1346145da327ed4027d745093dfde18c16c79c7f..6b6c950e0abee23231a72782d11db11e1771e9a7 100644 (file)
@@ -44,8 +44,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Lit(ref l) = lit.kind;
-        if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.tables().expr_ty_opt(lit));
-        if cx.tables().expr_ty(exp).is_integral();
+        if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit));
+        if cx.typeck_results().expr_ty(exp).is_integral();
         then {
             span_lint(cx, NEG_MULTIPLY, span, "Negation by multiplying with `-1`");
         }
index 2597f5f6f17e22aebc3aa680de1c78cad85fa645..621ebdef2f0b17462cbabee5e277f369899cf47a 100644 (file)
@@ -80,10 +80,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                             // can't be implemented for unsafe new
                             return;
                         }
-                        if impl_item.generics.params.iter().any(|gen| match gen.kind {
-                            hir::GenericParamKind::Type { .. } => true,
-                            _ => false,
-                        }) {
+                        if impl_item
+                            .generics
+                            .params
+                            .iter()
+                            .any(|gen| matches!(gen.kind, hir::GenericParamKind::Type { .. }))
+                        {
                             // when the result of `new()` depends on a type parameter we should not require
                             // an
                             // impl of `Default`
index 95283dae714703c5c6144b2791e306a3db4feb5f..b1b5b3439a0e384e6335d7c40665fdcc631d8d73 100644 (file)
@@ -48,7 +48,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
     match expr.kind {
         ExprKind::Lit(..) | ExprKind::Closure(..) => true,
-        ExprKind::Path(..) => !has_drop(cx, cx.tables().expr_ty(expr)),
+        ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
         ExprKind::Index(ref a, ref b) | ExprKind::Binary(_, ref a, ref b) => {
             has_no_effect(cx, a) && has_no_effect(cx, b)
         },
@@ -61,7 +61,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         | ExprKind::AddrOf(_, _, ref inner)
         | ExprKind::Box(ref inner) => has_no_effect(cx, inner),
         ExprKind::Struct(_, ref fields, ref base) => {
-            !has_drop(cx, cx.tables().expr_ty(expr))
+            !has_drop(cx, cx.typeck_results().expr_ty(expr))
                 && fields.iter().all(|field| has_no_effect(cx, &field.expr))
                 && base.as_ref().map_or(true, |base| has_no_effect(cx, base))
         },
@@ -70,7 +70,8 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                 let res = qpath_res(cx, qpath, callee.hir_id);
                 match res {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => {
-                        !has_drop(cx, cx.tables().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
+                        !has_drop(cx, cx.typeck_results().expr_ty(expr))
+                            && args.iter().all(|arg| has_no_effect(cx, arg))
                     },
                     _ => false,
                 }
@@ -137,7 +138,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
         | ExprKind::AddrOf(_, _, ref inner)
         | ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
         ExprKind::Struct(_, ref fields, ref base) => {
-            if has_drop(cx, cx.tables().expr_ty(expr)) {
+            if has_drop(cx, cx.typeck_results().expr_ty(expr)) {
                 None
             } else {
                 Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
@@ -148,7 +149,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
                 let res = qpath_res(cx, qpath, callee.hir_id);
                 match res {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
-                        if !has_drop(cx, cx.tables().expr_ty(expr)) =>
+                        if !has_drop(cx, cx.typeck_results().expr_ty(expr)) =>
                     {
                         Some(args.iter().collect())
                     },
index c11a2ff9ee07ef4cd62d191acb8b651d942b51db..031d69e86a13edb2c7c5406127dcf67f6d6bd65d 100644 (file)
@@ -237,13 +237,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             }
 
             let ty = if needs_check_adjustment {
-                let adjustments = cx.tables().expr_adjustments(dereferenced_expr);
-                if let Some(i) = adjustments.iter().position(|adj| match adj.kind {
-                    Adjust::Borrow(_) | Adjust::Deref(_) => true,
-                    _ => false,
-                }) {
+                let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr);
+                if let Some(i) = adjustments
+                    .iter()
+                    .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
+                {
                     if i == 0 {
-                        cx.tables().expr_ty(dereferenced_expr)
+                        cx.typeck_results().expr_ty(dereferenced_expr)
                     } else {
                         adjustments[i - 1].target
                     }
@@ -252,7 +252,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     return;
                 }
             } else {
-                cx.tables().expr_ty(dereferenced_expr)
+                cx.typeck_results().expr_ty(dereferenced_expr)
             };
 
             verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
index 7128fee9bcf5157c238e089486bdf75db299a080..1d4772bb3d606a41a5dd4af3d1b9d9d8dd332ee1 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{Ident, SymbolStr};
+use rustc_span::symbol::{Ident, Symbol};
 use std::cmp::Ordering;
 
 declare_clippy_lint! {
@@ -75,7 +75,7 @@ pub struct NonExpressiveNames {
 impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]);
 
 struct ExistingName {
-    interned: SymbolStr,
+    interned: Symbol,
     span: Span,
     len: usize,
     exemptions: &'static [&'static str],
@@ -218,18 +218,19 @@ fn check_ident(&mut self, ident: Ident) {
             let mut split_at = None;
             match existing_name.len.cmp(&count) {
                 Ordering::Greater => {
-                    if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
+                    if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned.as_str()) {
                         continue;
                     }
                 },
                 Ordering::Less => {
-                    if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
+                    if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned.as_str(), &interned_name) {
                         continue;
                     }
                 },
                 Ordering::Equal => {
                     let mut interned_chars = interned_name.chars();
-                    let mut existing_chars = existing_name.interned.chars();
+                    let interned_str = existing_name.interned.as_str();
+                    let mut existing_chars = interned_str.chars();
                     let first_i = interned_chars.next().expect("we know we have at least one char");
                     let first_e = existing_chars.next().expect("we know we have at least one char");
                     let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();
@@ -302,7 +303,7 @@ fn check_ident(&mut self, ident: Ident) {
         }
         self.0.names.push(ExistingName {
             exemptions: get_exemptions(&interned_name).unwrap_or(&[]),
-            interned: interned_name,
+            interned: ident.name,
             span: ident.span,
             len: count,
         });
index 2b83efa84f64dff645bcf55e095e65aee222ab32..e99d0317ba2e8ca1b6e3bcf5744ec4071931c1da 100644 (file)
@@ -30,7 +30,7 @@
 impl<'tcx> LateLintPass<'tcx> for OpenOptions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind {
-            let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&arguments[0]));
+            let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0]));
             if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
                 let mut options = Vec::new();
                 get_open_options(cx, &arguments[0], &mut options);
@@ -58,7 +58,7 @@ enum OpenOption {
 
 fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
     if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind {
-        let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&arguments[0]));
+        let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0]));
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
         if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
new file mode 100644 (file)
index 0000000..065f863
--- /dev/null
@@ -0,0 +1,268 @@
+use crate::utils;
+use crate::utils::sugg::Sugg;
+use crate::utils::{match_type, paths, span_lint_and_sugg};
+use if_chain::if_chain;
+
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
+use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Lints usage of  `if let Some(v) = ... { y } else { x }` which is more
+    /// idiomatically done with `Option::map_or` (if the else bit is a simple
+    /// expression) or `Option::map_or_else` (if the else bit is a longer
+    /// block).
+    ///
+    /// **Why is this bad?**
+    /// Using the dedicated functions of the Option type is clearer and
+    /// more concise than an if let expression.
+    ///
+    /// **Known problems:**
+    /// This lint uses whether the block is just an expression or if it has
+    /// more statements to decide whether to use `Option::map_or` or
+    /// `Option::map_or_else`. If you have a single expression which calls
+    /// an expensive function, then it would be more efficient to use
+    /// `Option::map_or_else`, but this lint would suggest `Option::map_or`.
+    ///
+    /// Also, this lint uses a deliberately conservative metric for checking
+    /// if the inside of either body contains breaks or continues which will
+    /// cause it to not suggest a fix if either block contains a loop with
+    /// continues or breaks contained within the loop.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// # let optional: Option<u32> = Some(0);
+    /// # fn do_complicated_function() -> u32 { 5 };
+    /// let _ = if let Some(foo) = optional {
+    ///     foo
+    /// } else {
+    ///     5
+    /// };
+    /// let _ = if let Some(foo) = optional {
+    ///     foo
+    /// } else {
+    ///     let y = do_complicated_function();
+    ///     y*y
+    /// };
+    /// ```
+    ///
+    /// should be
+    ///
+    /// ```rust
+    /// # let optional: Option<u32> = Some(0);
+    /// # fn do_complicated_function() -> u32 { 5 };
+    /// let _ = optional.map_or(5, |foo| foo);
+    /// let _ = optional.map_or_else(||{
+    ///     let y = do_complicated_function();
+    ///     y*y
+    /// }, |foo| foo);
+    /// ```
+    pub OPTION_IF_LET_ELSE,
+    pedantic,
+    "reimplementation of Option::map_or"
+}
+
+declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
+
+/// Returns true iff the given expression is the result of calling `Result::ok`
+fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
+    if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind {
+        path.ident.name.to_ident_string() == "ok"
+            && match_type(cx, &cx.typeck_results().expr_ty(&receiver), &paths::RESULT)
+    } else {
+        false
+    }
+}
+
+/// A struct containing information about occurences of the
+/// `if let Some(..) = .. else` construct that this lint detects.
+struct OptionIfLetElseOccurence {
+    option: String,
+    method_sugg: String,
+    some_expr: String,
+    none_expr: String,
+    wrap_braces: bool,
+}
+
+struct ReturnBreakContinueMacroVisitor {
+    seen_return_break_continue: bool,
+}
+impl ReturnBreakContinueMacroVisitor {
+    fn new() -> ReturnBreakContinueMacroVisitor {
+        ReturnBreakContinueMacroVisitor {
+            seen_return_break_continue: false,
+        }
+    }
+}
+impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
+    type Map = Map<'tcx>;
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+        if self.seen_return_break_continue {
+            // No need to look farther if we've already seen one of them
+            return;
+        }
+        match &ex.kind {
+            ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => {
+                self.seen_return_break_continue = true;
+            },
+            // Something special could be done here to handle while or for loop
+            // desugaring, as this will detect a break if there's a while loop
+            // or a for loop inside the expression.
+            _ => {
+                if utils::in_macro(ex.span) {
+                    self.seen_return_break_continue = true;
+                } else {
+                    rustc_hir::intravisit::walk_expr(self, ex);
+                }
+            },
+        }
+    }
+}
+
+fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
+    let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new();
+    recursive_visitor.visit_expr(expression);
+    recursive_visitor.seen_return_break_continue
+}
+
+/// Extracts the body of a given arm. If the arm contains only an expression,
+/// then it returns the expression. Otherwise, it returns the entire block
+fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
+    if let ExprKind::Block(
+        Block {
+            stmts: statements,
+            expr: Some(expr),
+            ..
+        },
+        _,
+    ) = &arm.body.kind
+    {
+        if let [] = statements {
+            Some(&expr)
+        } else {
+            Some(&arm.body)
+        }
+    } else {
+        None
+    }
+}
+
+/// If this is the else body of an if/else expression, then we need to wrap
+/// it in curcly braces. Otherwise, we don't.
+fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
+        if let Some(Expr {
+            kind:
+                ExprKind::Match(
+                    _,
+                    arms,
+                    MatchSource::IfDesugar {
+                        contains_else_clause: true,
+                    }
+                    | MatchSource::IfLetDesugar {
+                        contains_else_clause: true,
+                    },
+                ),
+            ..
+        }) = parent.expr
+        {
+            expr.hir_id == arms[1].body.hir_id
+        } else {
+            false
+        }
+    })
+}
+
+fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
+    format!(
+        "{}{}",
+        Sugg::hir(cx, cond_expr, "..").maybe_par(),
+        if as_mut {
+            ".as_mut()"
+        } else if as_ref {
+            ".as_ref()"
+        } else {
+            ""
+        }
+    )
+}
+
+/// If this expression is the option if let/else construct we're detecting, then
+/// this function returns an `OptionIfLetElseOccurence` struct with details if
+/// this construct is found, or None if this construct is not found.
+fn detect_option_if_let_else(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OptionIfLetElseOccurence> {
+    if_chain! {
+        if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly
+        if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
+        if arms.len() == 2;
+        if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already
+        if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind;
+        if utils::match_qpath(struct_qpath, &paths::OPTION_SOME);
+        if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
+        if !contains_return_break_continue_macro(arms[0].body);
+        if !contains_return_break_continue_macro(arms[1].body);
+        then {
+            let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
+            let some_body = extract_body_from_arm(&arms[0])?;
+            let none_body = extract_body_from_arm(&arms[1])?;
+            let method_sugg = match &none_body.kind {
+                ExprKind::Block(..) => "map_or_else",
+                _ => "map_or",
+            };
+            let capture_name = id.name.to_ident_string();
+            let wrap_braces = should_wrap_in_braces(cx, expr);
+            let (as_ref, as_mut) = match &cond_expr.kind {
+                ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
+                ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
+                _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut),
+            };
+            let cond_expr = match &cond_expr.kind {
+                // Pointer dereferencing happens automatically, so we can omit it in the suggestion
+                ExprKind::Unary(UnOp::UnDeref, expr) | ExprKind::AddrOf(_, _, expr) => expr,
+                _ => cond_expr,
+            };
+            Some(OptionIfLetElseOccurence {
+                option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
+                method_sugg: method_sugg.to_string(),
+                some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")),
+                none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")),
+                wrap_braces,
+            })
+        } else {
+            None
+        }
+    }
+}
+
+impl<'a> LateLintPass<'a> for OptionIfLetElse {
+    fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) {
+        if let Some(detection) = detect_option_if_let_else(cx, expr) {
+            span_lint_and_sugg(
+                cx,
+                OPTION_IF_LET_ELSE,
+                expr.span,
+                format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
+                "try",
+                format!(
+                    "{}{}.{}({}, {}){}",
+                    if detection.wrap_braces { "{ " } else { "" },
+                    detection.option,
+                    detection.method_sugg,
+                    detection.none_expr,
+                    detection.some_expr,
+                    if detection.wrap_braces { " }" } else { "" },
+                ),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+}
index 0850f88df44fec4b7cf14d17456fa7b9f6dd868b..4d4a9676654826b36360539531c092a5b85de056 100644 (file)
@@ -36,8 +36,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
             if let ExprKind::Path(QPath::Resolved(_, ref path3)) = second.kind;
             if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
-            if cx.tables().expr_ty(ident1).is_integral();
-            if cx.tables().expr_ty(ident2).is_integral();
+            if cx.typeck_results().expr_ty(ident1).is_integral();
+            if cx.typeck_results().expr_ty(ident2).is_integral();
             then {
                 if let BinOpKind::Lt = op.node {
                     if let BinOpKind::Add = op2.node {
@@ -61,8 +61,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
             if let ExprKind::Path(QPath::Resolved(_, ref path3)) = first.kind;
             if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
-            if cx.tables().expr_ty(ident1).is_integral();
-            if cx.tables().expr_ty(ident2).is_integral();
+            if cx.typeck_results().expr_ty(ident1).is_integral();
+            if cx.typeck_results().expr_ty(ident2).is_integral();
             then {
                 if let BinOpKind::Gt = op.node {
                     if let BinOpKind::Add = op2.node {
index 48e609542793b2de9f086f53d74aae96b7e8a2c0..66a145a7f14b39b2cd81eec5c976033afd5bc3a3 100644 (file)
@@ -46,7 +46,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
             if path.ident.name == sym!(push);
             if args.len() == 2;
-            if match_type(cx, walk_ptrs_ty(cx.tables().expr_ty(&args[0])), &paths::PATH_BUF);
+            if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &paths::PATH_BUF);
             if let Some(get_index_arg) = args.get(1);
             if let ExprKind::Lit(ref lit) = get_index_arg.kind;
             if let LitKind::Str(ref path_lit, _) = lit.node;
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
new file mode 100644 (file)
index 0000000..ef26fc6
--- /dev/null
@@ -0,0 +1,311 @@
+use crate::utils::{last_path_segment, span_lint_and_help};
+use rustc_hir::{
+    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
+    QPath, Stmt, StmtKind,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for patterns that aren't exact representations of the types
+    /// they are applied to.
+    ///
+    /// To satisfy this lint, you will have to adjust either the expression that is matched
+    /// against or the pattern itself, as well as the bindings that are introduced by the
+    /// adjusted patterns. For matching you will have to either dereference the expression
+    /// with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
+    /// or `&mut <pattern>` depending on the reference mutability. For the bindings you need
+    /// to use the inverse. You can leave them as plain bindings if you wish for the value
+    /// to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
+    /// a reference into the matched structure.
+    ///
+    /// If you are looking for a way to learn about ownership semantics in more detail, it
+    /// is recommended to look at IDE options available to you to highlight types, lifetimes
+    /// and reference semantics in your code. The available tooling would expose these things
+    /// in a general way even outside of the various pattern matching mechanics. Of course
+    /// this lint can still be used to highlight areas of interest and ensure a good understanding
+    /// of ownership semantics.
+    ///
+    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
+    /// because it increases ownership hints in the code, and will guard against some changes
+    /// in ownership.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// This example shows the basic adjustments necessary to satisfy the lint. Note how
+    /// the matched expression is explicitly dereferenced with `*` and the `inner` variable
+    /// is bound to a shared borrow via `ref inner`.
+    ///
+    /// ```rust,ignore
+    /// // Bad
+    /// let value = &Some(Box::new(23));
+    /// match value {
+    ///     Some(inner) => println!("{}", inner),
+    ///     None => println!("none"),
+    /// }
+    ///
+    /// // Good
+    /// let value = &Some(Box::new(23));
+    /// match *value {
+    ///     Some(ref inner) => println!("{}", inner),
+    ///     None => println!("none"),
+    /// }
+    /// ```
+    ///
+    /// The following example demonstrates one of the advantages of the more verbose style.
+    /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
+    /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot
+    /// accidentally modify the wrong part of the structure.
+    ///
+    /// ```rust,ignore
+    /// // Bad
+    /// let mut values = vec![(2, 3), (3, 4)];
+    /// for (a, b) in &mut values {
+    ///     *a += *b;
+    /// }
+    ///
+    /// // Good
+    /// let mut values = vec![(2, 3), (3, 4)];
+    /// for &mut (ref mut a, b) in &mut values {
+    ///     *a += b;
+    /// }
+    /// ```
+    pub PATTERN_TYPE_MISMATCH,
+    restriction,
+    "type of pattern does not match the expression type"
+}
+
+declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);
+
+impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if let StmtKind::Local(ref local) = stmt.kind {
+            if let Some(init) = &local.init {
+                if let Some(init_ty) = cx.typeck_results().node_type_opt(init.hir_id) {
+                    let pat = &local.pat;
+                    if in_external_macro(cx.sess(), pat.span) {
+                        return;
+                    }
+                    let deref_possible = match local.source {
+                        LocalSource::Normal => DerefPossible::Possible,
+                        _ => DerefPossible::Impossible,
+                    };
+                    apply_lint(cx, pat, init_ty, deref_possible);
+                }
+            }
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
+            match source {
+                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
+                    if let Some(expr_ty) = cx.typeck_results().node_type_opt(expr.hir_id) {
+                        'pattern_checks: for arm in arms {
+                            let pat = &arm.pat;
+                            if in_external_macro(cx.sess(), pat.span) {
+                                continue 'pattern_checks;
+                            }
+                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
+                                break 'pattern_checks;
+                            }
+                        }
+                    }
+                },
+                _ => (),
+            }
+        }
+    }
+
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        _: intravisit::FnKind<'tcx>,
+        _: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        _: Span,
+        hir_id: HirId,
+    ) {
+        if let Some(fn_sig) = cx.typeck_results().liberated_fn_sigs().get(hir_id) {
+            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
+                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
+            }
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+enum DerefPossible {
+    Possible,
+    Impossible,
+}
+
+fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, expr_ty: Ty<'tcx>, deref_possible: DerefPossible) -> bool {
+    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
+    if let Some((span, mutability, level)) = maybe_mismatch {
+        span_lint_and_help(
+            cx,
+            PATTERN_TYPE_MISMATCH,
+            span,
+            "type of pattern does not match the expression type",
+            None,
+            &format!(
+                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
+                match (deref_possible, level) {
+                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
+                    _ => "",
+                },
+                match mutability {
+                    Mutability::Mut => "&mut _",
+                    Mutability::Not => "&_",
+                },
+            ),
+        );
+        true
+    } else {
+        false
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+enum Level {
+    Top,
+    Lower,
+}
+
+#[allow(rustc::usage_of_ty_tykind)]
+fn find_first_mismatch<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &Pat<'_>,
+    ty: Ty<'tcx>,
+    level: Level,
+) -> Option<(Span, Mutability, Level)> {
+    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
+        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
+            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
+        }
+    }
+
+    if let TyKind::Ref(_, _, mutability) = ty.kind {
+        if is_non_ref_pattern(&pat.kind) {
+            return Some((pat.span, mutability, level));
+        }
+    }
+
+    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
+        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
+            if let Some(variant) = get_variant(adt_def, qpath) {
+                let field_defs = &variant.fields;
+                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
+            }
+        }
+    }
+
+    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
+        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
+            if let Some(variant) = get_variant(adt_def, qpath) {
+                let field_defs = &variant.fields;
+                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
+                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
+            }
+        }
+    }
+
+    if let PatKind::Tuple(ref pats, _) = pat.kind {
+        if let TyKind::Tuple(..) = ty.kind {
+            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
+        }
+    }
+
+    if let PatKind::Or(sub_pats) = pat.kind {
+        for pat in sub_pats {
+            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
+            if let Some(mismatch) = maybe_mismatch {
+                return Some(mismatch);
+            }
+        }
+    }
+
+    None
+}
+
+fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
+    if adt_def.is_struct() {
+        if let Some(variant) = adt_def.variants.iter().next() {
+            return Some(variant);
+        }
+    }
+
+    if adt_def.is_enum() {
+        let pat_ident = last_path_segment(qpath).ident;
+        for variant in &adt_def.variants {
+            if variant.ident == pat_ident {
+                return Some(variant);
+            }
+        }
+    }
+
+    None
+}
+
+fn find_first_mismatch_in_tuple<'tcx, I>(
+    cx: &LateContext<'tcx>,
+    pats: &[&Pat<'_>],
+    ty_iter_src: I,
+) -> Option<(Span, Mutability, Level)>
+where
+    I: IntoIterator<Item = Ty<'tcx>>,
+{
+    let mut field_tys = ty_iter_src.into_iter();
+    'fields: for pat in pats {
+        let field_ty = if let Some(ty) = field_tys.next() {
+            ty
+        } else {
+            break 'fields;
+        };
+
+        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
+        if let Some(mismatch) = maybe_mismatch {
+            return Some(mismatch);
+        }
+    }
+
+    None
+}
+
+fn find_first_mismatch_in_struct<'tcx>(
+    cx: &LateContext<'tcx>,
+    field_pats: &[FieldPat<'_>],
+    field_defs: &[FieldDef],
+    substs_ref: SubstsRef<'tcx>,
+) -> Option<(Span, Mutability, Level)> {
+    for field_pat in field_pats {
+        'definitions: for field_def in field_defs {
+            if field_pat.ident == field_def.ident {
+                let field_ty = field_def.ty(cx.tcx, substs_ref);
+                let pat = &field_pat.pat;
+                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
+                if let Some(mismatch) = maybe_mismatch {
+                    return Some(mismatch);
+                }
+                break 'definitions;
+            }
+        }
+    }
+
+    None
+}
+
+fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
+    match pat_kind {
+        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
+        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
+        _ => false,
+    }
+}
index 23793678fa0e2ae7ee55a2919606b04325340381..4797771e7bdbb4aa9e95dba4f3a00c9f587cda42 100644 (file)
@@ -148,17 +148,11 @@ fn is_arith_expr(expr: &Expr) -> bool {
 #[must_use]
 fn is_bit_op(op: BinOpKind) -> bool {
     use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr};
-    match op {
-        BitXor | BitAnd | BitOr | Shl | Shr => true,
-        _ => false,
-    }
+    matches!(op, BitXor | BitAnd | BitOr | Shl | Shr)
 }
 
 #[must_use]
 fn is_arith_op(op: BinOpKind) -> bool {
     use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub};
-    match op {
-        Add | Sub | Mul | Div | Rem => true,
-        _ => false,
-    }
+    matches!(op, Add | Sub | Mul | Div | Rem)
 }
index 61e186a4b4653f59c6218c3ad05e4f275b9a567f..0a2d1b5fbe6ac56b2fe0e1f27aecb0db8e5a71fa 100644 (file)
@@ -105,12 +105,12 @@ fn expr_as_ptr_offset_call<'tcx>(
 
 // Is the type of the expression a usize?
 fn is_expr_ty_usize<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
-    cx.tables().expr_ty(expr) == cx.tcx.types.usize
+    cx.typeck_results().expr_ty(expr) == cx.tcx.types.usize
 }
 
 // Is the type of the expression a raw pointer?
 fn is_expr_ty_raw_ptr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
-    cx.tables().expr_ty(expr).is_unsafe_ptr()
+    cx.typeck_results().expr_ty(expr).is_unsafe_ptr()
 }
 
 fn build_suggestion<'tcx>(
index cc9c2f196079f001e552d7c407d80aa1beee54fa..fb12c565afd863048bbcbc895f1abb4fbf36b082 100644 (file)
@@ -135,13 +135,13 @@ fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>
     }
 
     fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
-        let expr_ty = cx.tables().expr_ty(expression);
+        let expr_ty = cx.typeck_results().expr_ty(expression);
 
         !expr_ty.is_copy_modulo_regions(cx.tcx.at(expression.span), cx.param_env)
     }
 
     fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
-        let expr_ty = cx.tables().expr_ty(expression);
+        let expr_ty = cx.typeck_results().expr_ty(expression);
 
         is_type_diagnostic_item(cx, expr_ty, sym!(option_type))
     }
index c164ec9aaf173ef2fa42bd36c3ff1b89c028e1b3..4c1f2e8e01a8c9b485399aa994a8a1ada33ff8aa 100644 (file)
     /// exclusive ranges, because they essentially add an extra branch that
     /// LLVM may fail to hoist out of the loop.
     ///
+    /// This will cause a warning that cannot be fixed if the consumer of the
+    /// range only accepts a specific range type, instead of the generic
+    /// `RangeBounds` trait
+    /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+    ///
     /// **Example:**
     /// ```rust,ignore
     /// for x..(y+1) { .. }
     /// **Why is this bad?** The code is more readable with an exclusive range
     /// like `x..y`.
     ///
-    /// **Known problems:** None.
+    /// **Known problems:** This will cause a warning that cannot be fixed if
+    /// the consumer of the range only accepts a specific range type, instead of
+    /// the generic `RangeBounds` trait
+    /// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
     ///
     /// **Example:**
     /// ```rust,ignore
@@ -83,7 +91,7 @@
     /// for x..y { .. }
     /// ```
     pub RANGE_MINUS_ONE,
-    complexity,
+    pedantic,
     "`x..=(y-1)` reads better as `x..y`"
 }
 
@@ -272,10 +280,10 @@ fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
 
     if_chain! {
         if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr);
-        let ty = cx.tables().expr_ty(start);
+        let ty = cx.typeck_results().expr_ty(start);
         if let ty::Int(_) | ty::Uint(_) = ty.kind;
-        if let Some((start_idx, _)) = constant(cx, cx.tables(), start);
-        if let Some((end_idx, _)) = constant(cx, cx.tables(), end);
+        if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
+        if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end);
         if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
         if is_empty_range(limits, ordering);
         then {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs b/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs
deleted file mode 100644 (file)
index d8d16ef..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_mir::const_eval::is_const_fn;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Symbol;
-
-declare_clippy_lint! {
-    /// **What it does:** Lint for redundant pattern matching over `Result` or
-    /// `Option`
-    ///
-    /// **Why is this bad?** It's more concise and clear to just use the proper
-    /// utility function
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    ///
-    /// ```rust
-    /// if let Ok(_) = Ok::<i32, i32>(42) {}
-    /// if let Err(_) = Err::<i32, i32>(42) {}
-    /// if let None = None::<()> {}
-    /// if let Some(_) = Some(42) {}
-    /// match Ok::<i32, i32>(42) {
-    ///     Ok(_) => true,
-    ///     Err(_) => false,
-    /// };
-    /// ```
-    ///
-    /// The more idiomatic use would be:
-    ///
-    /// ```rust
-    /// if Ok::<i32, i32>(42).is_ok() {}
-    /// if Err::<i32, i32>(42).is_err() {}
-    /// if None::<()>.is_none() {}
-    /// if Some(42).is_some() {}
-    /// Ok::<i32, i32>(42).is_ok();
-    /// ```
-    pub REDUNDANT_PATTERN_MATCHING,
-    style,
-    "use the proper utility function avoiding an `if let`"
-}
-
-declare_lint_pass!(RedundantPatternMatching => [REDUNDANT_PATTERN_MATCHING]);
-
-impl<'tcx> LateLintPass<'tcx> for RedundantPatternMatching {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
-            match match_source {
-                MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
-                MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
-                MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
-                _ => return,
-            }
-        }
-    }
-}
-
-fn find_sugg_for_if_let<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'_>,
-    op: &Expr<'_>,
-    arms: &[Arm<'_>],
-    keyword: &'static str,
-) {
-    fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
-        if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
-            return Some("is_ok()");
-        }
-        if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
-            return Some("is_err()");
-        }
-        if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
-            return Some("is_some()");
-        }
-        if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
-            return Some("is_none()");
-        }
-        None
-    }
-
-    let hir_id = expr.hir_id;
-    let good_method = match arms[0].pat.kind {
-        PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
-            if let PatKind::Wild = patterns[0].kind {
-                find_suggestion(cx, hir_id, path)
-            } else {
-                None
-            }
-        },
-        PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
-        _ => None,
-    };
-    let good_method = match good_method {
-        Some(method) => method,
-        None => return,
-    };
-
-    // check that `while_let_on_iterator` lint does not trigger
-    if_chain! {
-        if keyword == "while";
-        if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
-        if method_path.ident.name == sym!(next);
-        if match_trait_method(cx, op, &paths::ITERATOR);
-        then {
-            return;
-        }
-    }
-
-    span_lint_and_then(
-        cx,
-        REDUNDANT_PATTERN_MATCHING,
-        arms[0].pat.span,
-        &format!("redundant pattern matching, consider using `{}`", good_method),
-        |diag| {
-            // while let ... = ... { ... }
-            // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-            let expr_span = expr.span;
-
-            // while let ... = ... { ... }
-            //                 ^^^
-            let op_span = op.span.source_callsite();
-
-            // while let ... = ... { ... }
-            // ^^^^^^^^^^^^^^^^^^^
-            let span = expr_span.until(op_span.shrink_to_hi());
-            diag.span_suggestion(
-                span,
-                "try this",
-                format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
-                Applicability::MachineApplicable, // snippet
-            );
-        },
-    );
-}
-
-fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
-    if arms.len() == 2 {
-        let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
-
-        let hir_id = expr.hir_id;
-        let found_good_method = match node_pair {
-            (
-                PatKind::TupleStruct(ref path_left, ref patterns_left, _),
-                PatKind::TupleStruct(ref path_right, ref patterns_right, _),
-            ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
-                if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
-                    find_good_method_for_match(
-                        arms,
-                        path_left,
-                        path_right,
-                        &paths::RESULT_OK,
-                        &paths::RESULT_ERR,
-                        "is_ok()",
-                        "is_err()",
-                        || can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
-                        || can_suggest(cx, hir_id, sym!(result_type), "is_err"),
-                    )
-                } else {
-                    None
-                }
-            },
-            (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
-            | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
-                if patterns.len() == 1 =>
-            {
-                if let PatKind::Wild = patterns[0].kind {
-                    find_good_method_for_match(
-                        arms,
-                        path_left,
-                        path_right,
-                        &paths::OPTION_SOME,
-                        &paths::OPTION_NONE,
-                        "is_some()",
-                        "is_none()",
-                        || can_suggest(cx, hir_id, sym!(option_type), "is_some"),
-                        || can_suggest(cx, hir_id, sym!(option_type), "is_none"),
-                    )
-                } else {
-                    None
-                }
-            },
-            _ => None,
-        };
-
-        if let Some(good_method) = found_good_method {
-            span_lint_and_then(
-                cx,
-                REDUNDANT_PATTERN_MATCHING,
-                expr.span,
-                &format!("redundant pattern matching, consider using `{}`", good_method),
-                |diag| {
-                    let span = expr.span.to(op.span);
-                    diag.span_suggestion(
-                        span,
-                        "try this",
-                        format!("{}.{}", snippet(cx, op.span, "_"), good_method),
-                        Applicability::MaybeIncorrect, // snippet
-                    );
-                },
-            );
-        }
-    }
-}
-
-#[allow(clippy::too_many_arguments)]
-fn find_good_method_for_match<'a>(
-    arms: &[Arm<'_>],
-    path_left: &QPath<'_>,
-    path_right: &QPath<'_>,
-    expected_left: &[&str],
-    expected_right: &[&str],
-    should_be_left: &'a str,
-    should_be_right: &'a str,
-    can_suggest_left: impl Fn() -> bool,
-    can_suggest_right: impl Fn() -> bool,
-) -> Option<&'a str> {
-    let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
-        (&(*arms[0].body).kind, &(*arms[1].body).kind)
-    } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
-        (&(*arms[1].body).kind, &(*arms[0].body).kind)
-    } else {
-        return None;
-    };
-
-    match body_node_pair {
-        (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
-            _ => None,
-        },
-        _ => None,
-    }
-}
-
-fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
-    if !in_constant(cx, hir_id) {
-        return true;
-    }
-
-    // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
-    cx.tcx
-        .get_diagnostic_item(diag_item)
-        .and_then(|def_id| {
-            cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
-                cx.tcx
-                    .associated_items(*imp)
-                    .in_definition_order()
-                    .find_map(|item| match item.kind {
-                        ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
-                        _ => None,
-                    })
-            })
-        })
-        .map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
-}
index b67abad6ccb8f502e3e89ae6e4163eb43d8ef8ca..dfc158661cbf68cd0b6b2c9c1600077076d272f6 100644 (file)
@@ -1,9 +1,9 @@
 use crate::consts::{constant, Constant};
-use crate::utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_lint_and_help};
+use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help};
 use if_chain::if_chain;
 use rustc_ast::ast::{LitKind, StrStyle};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{Block, BorrowKind, Crate, Expr, ExprKind, HirId};
+use rustc_hir::{BorrowKind, Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{BytePos, Span};
     "trivial regular expressions"
 }
 
-declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `regex!(_)` which (as of now) is
-    /// usually slower than `Regex::new(_)` unless called in a loop (which is a bad
-    /// idea anyway).
-    ///
-    /// **Why is this bad?** Performance, at least for now. The macro version is
-    /// likely to catch up long-term, but for now the dynamic version is faster.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```ignore
-    /// regex!("foo|bar")
-    /// ```
-    pub REGEX_MACRO,
-    style,
-    "use of `regex!(_)` instead of `Regex::new(_)`"
-}
-
 #[derive(Clone, Default)]
 pub struct Regex {
     spans: FxHashSet<Span>,
     last: Option<HirId>,
 }
 
-impl_lint_pass!(Regex => [INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX]);
+impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
 
 impl<'tcx> LateLintPass<'tcx> for Regex {
-    fn check_crate(&mut self, _: &LateContext<'tcx>, _: &'tcx Crate<'_>) {
-        self.spans.clear();
-    }
-
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        if_chain! {
-            if self.last.is_none();
-            if let Some(ref expr) = block.expr;
-            if match_type(cx, cx.tables().expr_ty(expr), &paths::REGEX);
-            if let Some(span) = is_expn_of(expr.span, "regex");
-            then {
-                if !self.spans.contains(&span) {
-                    span_lint(
-                        cx,
-                        REGEX_MACRO,
-                        span,
-                        "`regex!(_)` found. \
-                        Please use `Regex::new(_)`, which is faster for now."
-                    );
-                    self.spans.insert(span);
-                }
-                self.last = Some(block.hir_id);
-            }
-        }
-    }
-
-    fn check_block_post(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        if self.last.map_or(false, |id| block.hir_id == id) {
-            self.last = None;
-        }
-    }
-
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let ExprKind::Call(ref fun, ref args) = expr.kind;
@@ -140,7 +89,7 @@ fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span {
 }
 
 fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
-    constant(cx, cx.tables(), e).and_then(|(c, _)| match c {
+    constant(cx, cx.typeck_results(), e).and_then(|(c, _)| match c {
         Constant::Str(s) => Some(s),
         _ => None,
     })
@@ -150,12 +99,7 @@ fn is_trivial_regex(s: &regex_syntax::hir::Hir) -> Option<&'static str> {
     use regex_syntax::hir::Anchor::{EndText, StartText};
     use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal};
 
-    let is_literal = |e: &[regex_syntax::hir::Hir]| {
-        e.iter().all(|e| match *e.kind() {
-            Literal(_) => true,
-            _ => false,
-        })
-    };
+    let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_)));
 
     match *s.kind() {
         Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"),
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
new file mode 100644 (file)
index 0000000..77c2060
--- /dev/null
@@ -0,0 +1,82 @@
+use crate::consts::{constant_context, Constant};
+use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types.
+    /// - `.to_string()` for `str`
+    /// - `.clone()` for `String`
+    /// - `.to_vec()` for `slice`
+    ///
+    /// **Why is this bad?** For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning the string is the intention behind this, `clone()` should be used.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     let x = String::from("hello world").repeat(1);
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn main() {
+    ///     let x = String::from("hello world").clone();
+    /// }
+    /// ```
+    pub REPEAT_ONCE,
+    complexity,
+    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
+}
+
+declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);
+
+impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
+        if_chain! {
+            if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
+            if path.ident.name == sym!(repeat);
+            if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&args[1]);
+            if !in_macro(args[0].span);
+            then {
+                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
+                if ty.is_str() {
+                    span_lint_and_sugg(
+                        cx,
+                        REPEAT_ONCE,
+                        expr.span,
+                        "calling `repeat(1)` on str",
+                        "consider using `.to_string()` instead",
+                        format!("{}.to_string()", snippet(cx, args[0].span, r#""...""#)),
+                        Applicability::MachineApplicable,
+                    );
+                } else if ty.builtin_index().is_some() {
+                    span_lint_and_sugg(
+                        cx,
+                        REPEAT_ONCE,
+                        expr.span,
+                        "calling `repeat(1)` on slice",
+                        "consider using `.to_vec()` instead",
+                        format!("{}.to_vec()", snippet(cx, args[0].span, r#""...""#)),
+                        Applicability::MachineApplicable,
+                    );
+                } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
+                    span_lint_and_sugg(
+                        cx,
+                        REPEAT_ONCE,
+                        expr.span,
+                        "calling `repeat(1)` on a string literal",
+                        "consider using `.clone()` instead",
+                        format!("{}.clone()", snippet(cx, args[0].span, r#""...""#)),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        }
+    }
+}
index 3c939744173562515d8419edffabca457ec08e11..faef7e724dd056a8464957cfb91a5b4e6c53f157 100644 (file)
@@ -259,15 +259,15 @@ fn is_unit_expr(expr: &ast::Expr) -> bool {
 
 fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
     let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
-        if let Some(rpos) = fn_source.rfind("->") {
-            #[allow(clippy::cast_possible_truncation)]
-            (
-                ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
-                Applicability::MachineApplicable,
-            )
-        } else {
-            (ty.span, Applicability::MaybeIncorrect)
-        }
+        fn_source
+            .rfind("->")
+            .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
+                (
+                    #[allow(clippy::cast_possible_truncation)]
+                    ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
+                    Applicability::MachineApplicable,
+                )
+            })
     } else {
         (ty.span, Applicability::MaybeIncorrect)
     };
index 7da47ee4ff94b892c3ef369ccbfb0f8c028f6b05..901c0a65d7fef93b06cd208427787235ee4bc76c 100644 (file)
@@ -164,15 +164,8 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &
 }
 
 fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool {
-    let var_ty = cx.tables().node_type_opt(pat_id);
-    if let Some(var_ty) = var_ty {
-        match var_ty.kind {
-            ty::Adt(..) => false,
-            _ => true,
-        }
-    } else {
-        false
-    }
+    let var_ty = cx.typeck_results().node_type_opt(pat_id);
+    var_ty.map_or(false, |var_ty| !matches!(var_ty.kind, ty::Adt(..)))
 }
 
 fn check_pat<'tcx>(
index 89aa6a4edd62d22880f265ca2d3a9f43110778b8..bada6fa7c522fca28060f7544026edd753a53746 100644 (file)
@@ -134,7 +134,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 }
 
 fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    is_type_diagnostic_item(cx, walk_ptrs_ty(cx.tables().expr_ty(e)), sym!(string_type))
+    is_type_diagnostic_item(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(e)), sym!(string_type))
 }
 
 fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
index eb7d35839206ba9a0494bcc115e595045a7f2039..754f87e6b55e2585f9b79b4c7993e78b6049df21 100644 (file)
@@ -194,7 +194,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<
     if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
         if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
             if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
-                let ty = walk_ptrs_ty(cx.tables().expr_ty(lhs1));
+                let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1));
 
                 if matches!(ty.kind, ty::Slice(_))
                     || matches!(ty.kind, ty::Array(_, _))
index 509bbfd27c1a5094184e4bbf775e631d89e445d2..1aeff1baa362e24a2362263c07a946e412abde46 100644 (file)
 fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match &expr.kind {
         ExprKind::Struct(..) | ExprKind::Tup(..) => true,
-        ExprKind::Path(qpath) => {
-            if let Res::Def(DefKind::Const, ..) = cx.qpath_res(qpath, expr.hir_id) {
-                true
-            } else {
-                false
-            }
-        },
+        ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)),
         _ => false,
     }
 }
index 4157103a574e12be1e2bddc64de6ee1dcd97d8db..6750452941f28a1b15dc11cb02e4ad301ed3b2bd 100644 (file)
@@ -43,7 +43,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                         if_chain! {
                             if let [char_arg, radix_arg] = &**to_digit_args;
                             if to_digits_path.ident.name.as_str() == "to_digit";
-                            let char_arg_ty = cx.tables().expr_ty_adjusted(char_arg);
+                            let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
                             if char_arg_ty.kind == ty::Char;
                             then {
                                 Some((true, char_arg, radix_arg))
index 9eb2079c3ca2dffbec32bb6adb90ac89fe7bdf40..0ef70311fb1cde5a80e9f21b20f21ed511d1093f 100644 (file)
@@ -1,19 +1,19 @@
 use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_help, SpanlessHash};
+use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::{GenericBound, Generics, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
-#[derive(Copy, Clone)]
-pub struct TraitBounds;
-
 declare_clippy_lint! {
     /// **What it does:** This lint warns about unnecessary type repetitions in trait bounds
     ///
     /// **Why is this bad?** Repeating the type for every bound makes the code
     /// less readable than combining the bounds
     ///
+    /// **Known problems:** None.
+    ///
     /// **Example:**
     /// ```rust
     /// pub fn foo<T>(t: T) where T: Copy, T: Clone {}
     "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
 }
 
+#[derive(Copy, Clone)]
+pub struct TraitBounds {
+    max_trait_bounds: u64,
+}
+
+impl TraitBounds {
+    #[must_use]
+    pub fn new(max_trait_bounds: u64) -> Self {
+        Self { max_trait_bounds }
+    }
+}
+
 impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS]);
 
 impl<'tcx> LateLintPass<'tcx> for TraitBounds {
@@ -44,9 +56,14 @@ fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
         let mut map = FxHashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
         for bound in gen.where_clause.predicates {
-            if let WherePredicate::BoundPredicate(ref p) = bound {
+            if_chain! {
+                if let WherePredicate::BoundPredicate(ref p) = bound;
+                if p.bounds.len() as u64 <= self.max_trait_bounds;
+                if !in_macro(p.span);
                 let h = hash(&p.bounded_ty);
-                if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>()) {
+                if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>());
+
+                then {
                     let mut hint_string = format!(
                         "consider combining the bounds: `{}:",
                         snippet(cx, p.bounded_ty.span, "_")
index 5f76d5c46efba4a061945801a415bb5d86fdbb30..d55eb1a0c938702386e9b25e80447a0ffa4f10ed 100644 (file)
@@ -302,8 +302,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::TRANSMUTE);
             then {
-                let from_ty = cx.tables().expr_ty(&args[0]);
-                let to_ty = cx.tables().expr_ty(e);
+                let from_ty = cx.typeck_results().expr_ty(&args[0]);
+                let to_ty = cx.typeck_results().expr_ty(e);
 
                 match (&from_ty.kind, &to_ty.kind) {
                     _ if from_ty == to_ty => span_lint(
index 2f03c6db42d99379eb3c688cd3617de861406fd9..fbf7f0b2517ac19bea082525b49467bd2898add0 100644 (file)
@@ -44,7 +44,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             then {
 
                 // Catching transmute over constants that resolve to `null`.
-                let mut const_eval_context = constant_context(cx, cx.tables());
+                let mut const_eval_context = constant_context(cx, cx.typeck_results());
                 if_chain! {
                     if let ExprKind::Path(ref _qpath) = args[0].kind;
                     let x = const_eval_context.expr(&args[0]);
index 208d248faa57d0fec568f87ad6e6f6e87305ed34..d3b351f30ef7c9c0b4f8211fd711f01e8221e972 100644 (file)
@@ -68,7 +68,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let Some(return_type) = find_err_return_type(cx, &expr.kind);
 
             then {
-                let err_type = cx.tables().expr_ty(err_arg);
+                let err_type = cx.typeck_results().expr_ty(err_arg);
                 let origin_snippet = if err_arg.span.from_expansion() {
                     snippet_with_macro_callsite(cx, err_arg.span, "_")
                 } else {
@@ -114,7 +114,7 @@ fn find_err_return_type_arm<'tcx>(cx: &LateContext<'tcx>, arm: &'tcx Arm<'_>) ->
         if match_qpath(from_error_fn, &paths::TRY_FROM_ERROR);
         if let Some(from_error_arg) = from_error_args.get(0);
         then {
-            Some(cx.tables().expr_ty(from_error_arg))
+            Some(cx.typeck_results().expr_ty(from_error_arg))
         } else {
             None
         }
index 68f51f0afdccd158a91da17f2ba0b845649dc15c..c3dea44752133bf9d8a24fee5e402c427651ef76 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckTables};
+use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckResults};
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::Span;
@@ -595,7 +595,7 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool {
 impl<'tcx> LateLintPass<'tcx> for LetUnitValue {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Local(ref local) = stmt.kind {
-            if is_unit(cx.tables().pat_ty(&local.pat)) {
+            if is_unit(cx.typeck_results().pat_ty(&local.pat)) {
                 if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
                     return;
                 }
@@ -680,7 +680,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
                     if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
                         let op = cmp.node;
-                        if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) {
+                        if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
                             let result = match &*symbol.as_str() {
                                 "assert_eq" | "debug_assert_eq" => "succeed",
                                 "assert_ne" | "debug_assert_ne" => "fail",
@@ -704,7 +704,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         }
         if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
             let op = cmp.node;
-            if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) {
+            if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) {
                 let result = match op {
                     BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true",
                     _ => "false",
@@ -774,12 +774,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 let args_to_recover = args
                     .iter()
                     .filter(|arg| {
-                        if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) {
-                            if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind {
-                                false
-                            } else {
-                                true
-                            }
+                        if is_unit(cx.typeck_results().expr_ty(arg)) && !is_unit_literal(arg) {
+                            !matches!(&arg.kind, ExprKind::Match(.., MatchSource::TryDesugar))
                         } else {
                             false
                         }
@@ -899,17 +895,11 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
 }
 
 fn is_unit(ty: Ty<'_>) -> bool {
-    match ty.kind {
-        ty::Tuple(slice) if slice.is_empty() => true,
-        _ => false,
-    }
+    matches!(ty.kind, ty::Tuple(slice) if slice.is_empty())
 }
 
 fn is_unit_literal(expr: &Expr<'_>) -> bool {
-    match expr.kind {
-        ExprKind::Tup(ref slice) if slice.is_empty() => true,
-        _ => false,
-    }
+    matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty())
 }
 
 declare_clippy_lint! {
@@ -1154,10 +1144,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
 }
 
 fn is_isize_or_usize(typ: Ty<'_>) -> bool {
-    match typ.kind {
-        ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => true,
-        _ => false,
-    }
+    matches!(typ.kind, ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
 }
 
 fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) {
@@ -1205,16 +1192,19 @@ fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast
     // has parens on the outside, they are no longer needed.
     let mut applicability = Applicability::MachineApplicable;
     let opt = snippet_opt(cx, op.span);
-    let sugg = if let Some(ref snip) = opt {
-        if should_strip_parens(op, snip) {
-            &snip[1..snip.len() - 1]
-        } else {
-            snip.as_str()
-        }
-    } else {
-        applicability = Applicability::HasPlaceholders;
-        ".."
-    };
+    let sugg = opt.as_ref().map_or_else(
+        || {
+            applicability = Applicability::HasPlaceholders;
+            ".."
+        },
+        |snip| {
+            if should_strip_parens(op, snip) {
+                &snip[1..snip.len() - 1]
+            } else {
+                snip.as_str()
+            }
+        },
+    );
 
     span_lint_and_sugg(
         cx,
@@ -1242,7 +1232,7 @@ fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast
     }
 
     // don't lint for positive constants
-    let const_val = constant(cx, &cx.tables(), op);
+    let const_val = constant(cx, &cx.typeck_results(), op);
     if_chain! {
         if let Some((const_val, _)) = const_val;
         if let Constant::Int(n) = const_val;
@@ -1408,7 +1398,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             return;
         }
         if let ExprKind::Cast(ref ex, _) = expr.kind {
-            let (cast_from, cast_to) = (cx.tables().expr_ty(ex), cx.tables().expr_ty(expr));
+            let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr));
             lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
             if let ExprKind::Lit(ref lit) = ex.kind {
                 if_chain! {
@@ -1734,10 +1724,10 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
 
             TyKind::TraitObject(ref param_bounds, _) => {
                 let has_lifetime_parameters = param_bounds.iter().any(|bound| {
-                    bound.bound_generic_params.iter().any(|gen| match gen.kind {
-                        GenericParamKind::Lifetime { .. } => true,
-                        _ => false,
-                    })
+                    bound
+                        .bound_generic_params
+                        .iter()
+                        .any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
                 });
                 if has_lifetime_parameters {
                     // complex trait bounds like A<'a, 'b>
@@ -1796,7 +1786,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Cast(e, _) = &expr.kind;
             if let ExprKind::Lit(l) = &e.kind;
             if let LitKind::Char(c) = l.node;
-            if ty::Uint(UintTy::U8) == cx.tables().expr_ty(expr).kind;
+            if ty::Uint(UintTy::U8) == cx.typeck_results().expr_ty(expr).kind;
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
@@ -1872,8 +1862,8 @@ enum AbsurdComparisonResult {
 
 fn is_cast_between_fixed_and_target<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
-        let precast_ty = cx.tables().expr_ty(cast_exp);
-        let cast_ty = cx.tables().expr_ty(expr);
+        let precast_ty = cx.typeck_results().expr_ty(cast_exp);
+        let cast_ty = cx.typeck_results().expr_ty(expr);
 
         return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
     }
@@ -1893,7 +1883,7 @@ fn detect_absurd_comparison<'tcx>(
 
     // absurd comparison only makes sense on primitive types
     // primitive types don't implement comparison operators with each other
-    if cx.tables().expr_ty(lhs) != cx.tables().expr_ty(rhs) {
+    if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) {
         return None;
     }
 
@@ -1931,9 +1921,9 @@ fn detect_absurd_comparison<'tcx>(
 fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
     use crate::types::ExtremeType::{Maximum, Minimum};
 
-    let ty = cx.tables().expr_ty(expr);
+    let ty = cx.typeck_results().expr_ty(expr);
 
-    let cv = constant(cx, cx.tables(), expr)?.0;
+    let cv = constant(cx, cx.typeck_results(), expr)?.0;
 
     let which = match (&ty.kind, cv) {
         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
@@ -2063,8 +2053,8 @@ fn cmp(&self, other: &Self) -> Ordering {
 
 fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
-        let pre_cast_ty = cx.tables().expr_ty(cast_exp);
-        let cast_ty = cx.tables().expr_ty(expr);
+        let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
+        let cast_ty = cx.typeck_results().expr_ty(expr);
         // if it's a cast from i32 to u32 wrapping will invalidate all these checks
         if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
             return None;
@@ -2094,9 +2084,9 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) ->
 }
 
 fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
-    let val = constant(cx, cx.tables(), expr)?.0;
+    let val = constant(cx, cx.typeck_results(), expr)?.0;
     if let Constant::Int(const_int) = val {
-        match cx.tables().expr_ty(expr).kind {
+        match cx.typeck_results().expr_ty(expr).kind {
             ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
             ty::Uint(_) => Some(FullInt::U(const_int)),
             _ => None,
@@ -2482,7 +2472,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 /// Looks for default-hasher-dependent constructors like `HashMap::new`.
 struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    maybe_typeck_tables: Option<&'tcx TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
     target: &'b ImplicitHasherType<'tcx>,
     suggestions: BTreeMap<Span, String>,
 }
@@ -2491,7 +2481,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
         Self {
             cx,
-            maybe_typeck_tables: cx.maybe_typeck_tables(),
+            maybe_typeck_results: cx.maybe_typeck_results(),
             target,
             suggestions: BTreeMap::new(),
         }
@@ -2502,9 +2492,9 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
     type Map = Map<'tcx>;
 
     fn visit_body(&mut self, body: &'tcx Body<'_>) {
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.cx.tcx.body_tables(body.id()));
+        let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
         walk_body(self, body);
-        self.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
@@ -2513,7 +2503,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind;
             if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
             then {
-                if !TyS::same_type(self.target.ty(), self.maybe_typeck_tables.unwrap().expr_ty(e)) {
+                if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
                     return;
                 }
 
@@ -2599,7 +2589,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind;
             if let ExprKind::Cast(e, t) = &e.kind;
             if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind;
-            if let ty::Ref(..) = cx.tables().node_type(e.hir_id).kind;
+            if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind;
             then {
                 span_lint(
                     cx,
index b9aa202b328f6aad2637a20ed45697858e3352f6..28b393b9f11f0b67a952af15e2909a6926e134df 100644 (file)
 impl LateLintPass<'_> for UnnamedAddress {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         fn is_comparison(binop: BinOpKind) -> bool {
-            match binop {
-                BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt => true,
-                _ => false,
-            }
+            matches!(
+                binop,
+                BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt
+            )
         }
 
         fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-            match cx.tables().expr_ty_adjusted(expr).kind {
+            match cx.typeck_results().expr_ty_adjusted(expr).kind {
                 ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
                 _ => false,
             }
         }
 
         fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-            if let ty::FnDef(..) = cx.tables().expr_ty(expr).kind {
-                true
-            } else {
-                false
-            }
+            matches!(cx.typeck_results().expr_ty(expr).kind, ty::FnDef(..))
         }
 
         if_chain! {
@@ -102,7 +98,7 @@ fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
             if match_def_path(cx, def_id, &paths::PTR_EQ) ||
                 match_def_path(cx, def_id, &paths::RC_PTR_EQ) ||
                 match_def_path(cx, def_id, &paths::ARC_PTR_EQ);
-            let ty_param = cx.tables().node_substs(func.hir_id).type_at(0);
+            let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
             if ty_param.is_trait();
             then {
                 span_lint_and_help(
@@ -119,8 +115,8 @@ fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         if_chain! {
             if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
             if is_comparison(binop.node);
-            if cx.tables().expr_ty_adjusted(left).is_fn_ptr() &&
-                cx.tables().expr_ty_adjusted(right).is_fn_ptr();
+            if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr() &&
+                cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr();
             if is_fn_def(cx, left) || is_fn_def(cx, right);
             then {
                 span_lint(
index d940776817ca078453e21d6a5aa46d9814bafdb4..59993d25bb4706b9b204729693ff0921cd0b5422 100644 (file)
@@ -5,24 +5,23 @@
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, subst::GenericArgKind};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Ident;
 
 declare_clippy_lint! {
     /// **What it does:**
-    /// Detects when people use `Vec::sort_by` and pass in a function
+    /// Detects uses of `Vec::sort_by` passing in a closure
     /// which compares the two arguments, either directly or indirectly.
     ///
     /// **Why is this bad?**
     /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
-    /// possible) than to use `Vec::sort_by` and and a more complicated
+    /// possible) than to use `Vec::sort_by` and a more complicated
     /// closure.
     ///
     /// **Known problems:**
-    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't
-    /// imported by a use statement in the current frame, then a `use`
-    /// statement that imports it will need to be added (which this lint
-    /// can't do).
+    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
+    /// imported by a use statement, then it will need to be added manually.
     ///
     /// **Example:**
     ///
@@ -177,7 +176,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
         if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
-        if utils::match_type(cx, &cx.tables().expr_ty(vec), &paths::VEC);
+        if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC);
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
@@ -201,28 +200,41 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
             };
             let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
             let unstable = name == "sort_unstable_by";
+
             if_chain! {
                 if let ExprKind::Path(QPath::Resolved(_, Path {
                     segments: [PathSegment { ident: left_name, .. }], ..
                 })) = &left_expr.kind;
                 if left_name == left_ident;
                 then {
-                    Some(LintTrigger::Sort(SortDetection { vec_name, unstable }))
-                }
-                else {
-                    Some(LintTrigger::SortByKey(SortByKeyDetection {
-                        vec_name,
-                        unstable,
-                        closure_arg,
-                        closure_body,
-                        reverse
-                    }))
+                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }))
+                } else {
+                    if !key_returns_borrow(cx, left_expr) {
+                        return Some(LintTrigger::SortByKey(SortByKeyDetection {
+                            vec_name,
+                            unstable,
+                            closure_arg,
+                            closure_body,
+                            reverse
+                        }))
+                    }
                 }
             }
-        } else {
-            None
         }
     }
+
+    None
+}
+
+fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(def_id) = utils::fn_def_id(cx, expr) {
+        let output = cx.tcx.fn_sig(def_id).output();
+        let ty = output.skip_binder();
+        return matches!(ty.kind, ty::Ref(..))
+            || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
+    }
+
+    false
 }
 
 impl LateLintPass<'_> for UnnecessarySortBy {
index 4d3682263f14fdedc14be9209e1806147937190d..502bf0c427954b616a817d91512586ff1f968d68 100644 (file)
@@ -72,8 +72,8 @@ fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
 }
 
 fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
-    if !cx.sess.opts.unstable_features.is_nightly_build() {
-        // User cannot do `#![feature(or_patterns)]`, so bail.
+    if !cx.sess.features_untracked().or_patterns {
+        // Do not suggest nesting the patterns if the feature `or_patterns` is not enabled.
         return;
     }
 
@@ -400,8 +400,8 @@ fn extend_with_matching(
 
 /// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`?
 fn eq_pre_post(ps1: &[P<Pat>], ps2: &[P<Pat>], idx: usize) -> bool {
-    ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`.
-        && ps1.len() == ps2.len()
+    ps1.len() == ps2.len()
+        && ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`.
         && over(&ps1[..idx], &ps2[..idx], |l, r| eq_pat(l, r))
         && over(&ps1[idx + 1..], &ps2[idx + 1..], |l, r| eq_pat(l, r))
 }
index 735800e7e74160ee079aefcdaf3a20b65189122a..154082a0fdb530b8e81d1d4e47f3abced3f96b6b 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{Ident, SymbolStr};
+use rustc_span::symbol::Ident;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for imports that remove "unsafe" from an item's
@@ -73,6 +73,6 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>,
 }
 
 #[must_use]
-fn contains_unsafe(name: &SymbolStr) -> bool {
+fn contains_unsafe(name: &str) -> bool {
     name.contains("Unsafe") || name.contains("unsafe")
 }
index 56ff62eca033a172877893eb1d5e70e8afc568fa..f2bbde28c2abc81793b852069926c0a718e85342 100644 (file)
@@ -114,7 +114,7 @@ fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str)
         if_chain! {
             if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
             if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind;
-            let ty = cx.tables().expr_ty(&args[0]);
+            let ty = cx.typeck_results().expr_ty(&args[0]);
             let name = method_name.ident.as_str();
             if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name);
             then {
index f85db1e2006e8e77327d2bc2e35d6bde02fea0a7..776c6bc57ca6f857c4d86b699d99a4d5f2351f41 100644 (file)
@@ -167,14 +167,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind;
             then {
                 let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
-                let should_check = if let Some(ref params) = *parameters {
-                    !params.parenthesized && !params.args.iter().any(|arg| match arg {
-                        GenericArg::Lifetime(_) => true,
-                        _ => false,
-                    })
-                } else {
-                    true
-                };
+                let should_check = parameters.as_ref().map_or(
+                    true,
+                    |params| !params.parenthesized
+                        &&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
+                );
 
                 if should_check {
                     let visitor = &mut UseSelfVisitor {
index 69c0b092520d86b11d069291abf848440c7bd7ab..a48ad3185e9c2f440de3f95fd5bb0b9eb40e6ae8 100644 (file)
@@ -63,8 +63,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 
             ExprKind::MethodCall(ref name, .., ref args, _) => {
                 if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
-                    let a = cx.tables().expr_ty(e);
-                    let b = cx.tables().expr_ty(&args[0]);
+                    let a = cx.typeck_results().expr_ty(e);
+                    let b = cx.typeck_results().expr_ty(&args[0]);
                     if TyS::same_type(a, b) {
                         let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
                         span_lint_and_sugg(
@@ -79,8 +79,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     }
                 }
                 if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
-                    let a = cx.tables().expr_ty(e);
-                    let b = cx.tables().expr_ty(&args[0]);
+                    let a = cx.typeck_results().expr_ty(e);
+                    let b = cx.typeck_results().expr_ty(&args[0]);
                     if TyS::same_type(a, b) {
                         let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                         span_lint_and_sugg(
@@ -96,8 +96,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 }
                 if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
                     if_chain! {
-                        let a = cx.tables().expr_ty(e);
-                        let b = cx.tables().expr_ty(&args[0]);
+                        let a = cx.typeck_results().expr_ty(e);
+                        let b = cx.typeck_results().expr_ty(&args[0]);
                         if is_type_diagnostic_item(cx, a, sym!(result_type));
                         if let ty::Adt(_, substs) = a.kind;
                         if let Some(a_type) = substs.types().next();
@@ -122,8 +122,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     if args.len() == 1;
                     if let ExprKind::Path(ref qpath) = path.kind;
                     if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
-                    let a = cx.tables().expr_ty(e);
-                    let b = cx.tables().expr_ty(&args[0]);
+                    let a = cx.typeck_results().expr_ty(e);
+                    let b = cx.typeck_results().expr_ty(&args[0]);
 
                     then {
                         if_chain! {
index e19a79dd8dad164dd40cc84a1a37f52740bb5bca..58c1103da9f7dfed78e7039b107944057e7eecb9 100755 (executable)
@@ -387,10 +387,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
 }
 
 pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
-    match (l, r) {
-        (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)) => true,
-        _ => false,
-    }
+    matches!((l, r), (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)))
 }
 
 pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool {
index 4dcf6c105ec63666a7136c876b9b04d901cfbf52..4bb4b087c5566773b5dfa9249c936a486b103f98 100644 (file)
@@ -65,42 +65,45 @@ pub fn get_attr<'a>(
         };
         let attr_segments = &attr.path.segments;
         if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" {
-            if let Some(deprecation_status) =
-                BUILTIN_ATTRIBUTES
-                    .iter()
-                    .find_map(|(builtin_name, deprecation_status)| {
-                        if *builtin_name == attr_segments[1].ident.to_string() {
-                            Some(deprecation_status)
-                        } else {
-                            None
-                        }
-                    })
-            {
-                let mut diag = sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute");
-                match *deprecation_status {
-                    DeprecationStatus::Deprecated => {
-                        diag.emit();
-                        false
-                    },
-                    DeprecationStatus::Replaced(new_name) => {
-                        diag.span_suggestion(
-                            attr_segments[1].ident.span,
-                            "consider using",
-                            new_name.to_string(),
-                            Applicability::MachineApplicable,
-                        );
-                        diag.emit();
+            BUILTIN_ATTRIBUTES
+                .iter()
+                .find_map(|(builtin_name, deprecation_status)| {
+                    if *builtin_name == attr_segments[1].ident.to_string() {
+                        Some(deprecation_status)
+                    } else {
+                        None
+                    }
+                })
+                .map_or_else(
+                    || {
+                        sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute");
                         false
                     },
-                    DeprecationStatus::None => {
-                        diag.cancel();
-                        attr_segments[1].ident.to_string() == name
+                    |deprecation_status| {
+                        let mut diag =
+                            sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute");
+                        match *deprecation_status {
+                            DeprecationStatus::Deprecated => {
+                                diag.emit();
+                                false
+                            },
+                            DeprecationStatus::Replaced(new_name) => {
+                                diag.span_suggestion(
+                                    attr_segments[1].ident.span,
+                                    "consider using",
+                                    new_name.to_string(),
+                                    Applicability::MachineApplicable,
+                                );
+                                diag.emit();
+                                false
+                            },
+                            DeprecationStatus::None => {
+                                diag.cancel();
+                                attr_segments[1].ident.to_string() == name
+                            },
+                        }
                     },
-                }
-            } else {
-                sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute");
-                false
-            }
+                )
         } else {
             false
         }
index c41befbf147b8c2e1567b86f50262ec0c9359009..de425211e38ef60b99011a5307377d6fb63c55cf 100644 (file)
@@ -156,6 +156,8 @@ fn $config() -> $Ty {
     (array_size_threshold, "array_size_threshold": u64, 512_000),
     /// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed
     (vec_box_size_threshold, "vec_box_size_threshold": u64, 4096),
+    /// Lint: TYPE_REPETITION_IN_BOUNDS. The maximum number of bounds a trait can have to be linted
+    (max_trait_bounds, "max_trait_bounds": u64, 3),
     /// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bools a struct can have
     (max_struct_bools, "max_struct_bools": u64, 3),
     /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have
index eb7ac2447e493b5390bd4bbe0d55d256cf3e087e..f81a132c7e7b4748d82dfab656c71170de8ec78d 100644 (file)
@@ -56,7 +56,7 @@ fn get_field<'c>(name: &str, fields: &'c [hir::Field<'_>]) -> Option<&'c hir::Ex
         Some(expr)
     }
 
-    let def_path = match cx.tables().expr_ty(expr).kind {
+    let def_path = match cx.typeck_results().expr_ty(expr).kind {
         ty::Adt(def, _) => cx.tcx.def_path(def.did),
         _ => return None,
     };
index ae58f0a1521e69bf3ff32f7ae4e7cdd2cb1676b2..28fb6ed12a05ac90e0616be3af474a5b344b436d 100644 (file)
@@ -9,7 +9,7 @@
 };
 use rustc_lint::LateContext;
 use rustc_middle::ich::StableHashingContextProvider;
-use rustc_middle::ty::TypeckTables;
+use rustc_middle::ty::TypeckResults;
 use rustc_span::Symbol;
 use std::hash::Hash;
 
@@ -22,7 +22,7 @@
 pub struct SpanlessEq<'a, 'tcx> {
     /// Context used to evaluate constant expressions.
     cx: &'a LateContext<'tcx>,
-    maybe_typeck_tables: Option<&'tcx TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
     /// If is true, never consider as equal expressions containing function
     /// calls.
     ignore_fn: bool,
@@ -32,7 +32,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
     pub fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
             cx,
-            maybe_typeck_tables: cx.maybe_typeck_tables(),
+            maybe_typeck_results: cx.maybe_typeck_results(),
             ignore_fn: false,
         }
     }
@@ -71,10 +71,10 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             return false;
         }
 
-        if let Some(tables) = self.maybe_typeck_tables {
+        if let Some(typeck_results) = self.maybe_typeck_results {
             if let (Some(l), Some(r)) = (
-                constant_simple(self.cx, tables, left),
-                constant_simple(self.cx, tables, right),
+                constant_simple(self.cx, typeck_results, left),
+                constant_simple(self.cx, typeck_results, right),
             ) {
                 if l == r {
                     return true;
@@ -137,9 +137,9 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
                 !self.ignore_fn && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
             (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
-                let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(ll_id.body));
+                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body));
                 let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
-                let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(rl_id.body));
+                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body));
                 let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
 
                 self.eq_expr(le, re) && ll == rl
@@ -272,18 +272,18 @@ pub fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool {
         match (left, right) {
             (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
             (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
-                let old_maybe_typeck_tables = self.maybe_typeck_tables;
+                let old_maybe_typeck_results = self.maybe_typeck_results;
 
-                let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(ll_id.body));
-                self.maybe_typeck_tables = Some(self.cx.tcx.body_tables(ll_id.body));
+                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body));
+                self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(ll_id.body));
                 let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
 
-                let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(rl_id.body));
-                self.maybe_typeck_tables = Some(self.cx.tcx.body_tables(rl_id.body));
+                let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body));
+                self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(rl_id.body));
                 let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
 
                 let eq_ty = self.eq_ty(lt, rt);
-                self.maybe_typeck_tables = old_maybe_typeck_tables;
+                self.maybe_typeck_results = old_maybe_typeck_results;
                 eq_ty && ll == rl
             },
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
@@ -348,7 +348,7 @@ pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -
 pub struct SpanlessHash<'a, 'tcx> {
     /// Context used to evaluate constant expressions.
     cx: &'a LateContext<'tcx>,
-    maybe_typeck_tables: Option<&'tcx TypeckTables<'tcx>>,
+    maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
     s: StableHasher,
 }
 
@@ -356,7 +356,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     pub fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
             cx,
-            maybe_typeck_tables: cx.maybe_typeck_tables(),
+            maybe_typeck_results: cx.maybe_typeck_results(),
             s: StableHasher::new(),
         }
     }
@@ -386,8 +386,8 @@ pub fn hash_block(&mut self, b: &Block<'_>) {
     #[allow(clippy::many_single_char_names, clippy::too_many_lines)]
     pub fn hash_expr(&mut self, e: &Expr<'_>) {
         let simple_const = self
-            .maybe_typeck_tables
-            .and_then(|tables| constant_simple(self.cx, tables, e));
+            .maybe_typeck_results
+            .and_then(|typeck_results| constant_simple(self.cx, typeck_results, e));
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
         // discriminant depending on which path we're choosing next
@@ -458,7 +458,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                     CaptureBy::Ref => 1,
                 }
                 .hash(&mut self.s);
-                // closures inherit TypeckTables
+                // closures inherit TypeckResults
                 self.hash_expr(&self.cx.tcx.hir().body(eid).value);
             },
             ExprKind::Field(ref e, ref f) => {
@@ -602,7 +602,7 @@ pub fn hash_qpath(&mut self, p: &QPath<'_>) {
                 self.hash_name(path.ident.name);
             },
         }
-        // self.maybe_typeck_tables.unwrap().qpath_res(p, id).hash(&mut self.s);
+        // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
     }
 
     pub fn hash_path(&mut self, p: &Path<'_>) {
@@ -703,6 +703,7 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
                     }
                     for segment in path.segments {
                         segment.ident.name.hash(&mut self.s);
+                        self.hash_generic_args(segment.generic_args().args);
                     }
                 },
                 QPath::TypeRelative(ref ty, ref segment) => {
@@ -711,13 +712,7 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
                 },
             },
             TyKind::OpaqueDef(_, arg_list) => {
-                for arg in *arg_list {
-                    match arg {
-                        GenericArg::Lifetime(ref l) => self.hash_lifetime(l),
-                        GenericArg::Type(ref ty) => self.hash_ty(&ty),
-                        GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
-                    }
-                }
+                self.hash_generic_args(arg_list);
             },
             TyKind::TraitObject(_, lifetime) => {
                 self.hash_lifetime(lifetime);
@@ -730,9 +725,19 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
     }
 
     pub fn hash_body(&mut self, body_id: BodyId) {
-        // swap out TypeckTables when hashing a body
-        let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.cx.tcx.body_tables(body_id));
+        // swap out TypeckResults when hashing a body
+        let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
         self.hash_expr(&self.cx.tcx.hir().body(body_id).value);
-        self.maybe_typeck_tables = old_maybe_typeck_tables;
+        self.maybe_typeck_results = old_maybe_typeck_results;
+    }
+
+    fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
+        for arg in arg_list {
+            match arg {
+                GenericArg::Lifetime(ref l) => self.hash_lifetime(l),
+                GenericArg::Type(ref ty) => self.hash_ty(&ty),
+                GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
+            }
+        }
     }
 }
index fbd103323e313fdebb08561834d1d7236af56a48..d8fa1fa278e296b8cc9c18cbb6483a88f224d706 100644 (file)
@@ -114,7 +114,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
         }
         match stmt.kind {
             hir::StmtKind::Local(ref local) => {
-                println!("local variable of type {}", cx.tables().node_type(local.hir_id));
+                println!("local variable of type {}", cx.typeck_results().node_type(local.hir_id));
                 println!("pattern:");
                 print_pat(cx, &local.pat, 0);
                 if let Some(ref e) = local.init {
@@ -144,8 +144,12 @@ fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
 fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
     let ind = "  ".repeat(indent);
     println!("{}+", ind);
-    println!("{}ty: {}", ind, cx.tables().expr_ty(expr));
-    println!("{}adjustments: {:?}", ind, cx.tables().adjustments().get(expr.hir_id));
+    println!("{}ty: {}", ind, cx.typeck_results().expr_ty(expr));
+    println!(
+        "{}adjustments: {:?}",
+        ind,
+        cx.typeck_results().adjustments().get(expr.hir_id)
+    );
     match expr.kind {
         hir::ExprKind::Box(ref e) => {
             println!("{}Box", ind);
index 38cb764adde7b16a4784f1b2f1921b3dc23b546d..6c2356799142db6b609fb6c2a77be4c00f8266a2 100644 (file)
@@ -405,7 +405,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
             let fn_name = path.ident;
             if let Some(sugg) = self.map.get(&*fn_name.as_str());
-            let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
+            let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0]));
             if match_type(cx, ty, &paths::EARLY_CONTEXT)
                 || match_type(cx, ty, &paths::LATE_CONTEXT);
             then {
@@ -438,7 +438,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             let args = arg_lists[1];
             if args.len() == 1;
             let self_arg = &args[0];
-            let self_ty = walk_ptrs_ty(cx.tables().expr_ty(self_arg));
+            let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(self_arg));
             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
             then {
                 span_lint_and_sugg(
index 99ba7d64331cd02ff6dcb6b91177ce4721b2df58..4b163fba52890a7aa341940f30d61198f732db94 100644 (file)
@@ -102,11 +102,7 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
 #[must_use]
 pub fn in_macro(span: Span) -> bool {
     if span.from_expansion() {
-        if let ExpnKind::Desugaring(..) = span.ctxt().outer_expn_data().kind {
-            false
-        } else {
-            true
-        }
+        !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
     } else {
         false
     }
@@ -127,10 +123,7 @@ pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
 
 /// Checks if given pattern is a wildcard (`_`)
 pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
-    match pat.kind {
-        PatKind::Wild => true,
-        _ => false,
-    }
+    matches!(pat.kind, PatKind::Wild)
 }
 
 /// Checks if type is struct, enum or union type with the given def path.
@@ -151,13 +144,9 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
 
 /// Checks if the method call given in `expr` belongs to the given trait.
 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
-    let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
+    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
     let trt_id = cx.tcx.trait_of_item(def_id);
-    if let Some(trt_id) = trt_id {
-        match_def_path(cx, trt_id, path)
-    } else {
-        false
-    }
+    trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 }
 
 /// Checks if an expression references a variable of the given name.
@@ -289,10 +278,8 @@ pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -
     match qpath {
         hir::QPath::Resolved(_, path) => path.res,
         hir::QPath::TypeRelative(..) => {
-            if cx.tcx.has_typeck_tables(id.owner.to_def_id()) {
-                cx.tcx
-                    .typeck_tables_of(id.owner.to_def_id().expect_local())
-                    .qpath_res(qpath, id)
+            if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
+                cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id)
             } else {
                 Res::Err
             }
@@ -600,21 +587,15 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
 /// //  ^^^^^^^^^^
 /// ```
 pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
-    if let Some(first_char_pos) = first_char_in_first_line(cx, span) {
-        span.with_lo(first_char_pos)
-    } else {
-        span
-    }
+    first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
 }
 
 fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> {
     let line_span = line_span(cx, span);
-    if let Some(snip) = snippet_opt(cx, line_span) {
+    snippet_opt(cx, line_span).and_then(|snip| {
         snip.find(|c: char| !c.is_whitespace())
             .map(|pos| line_span.lo() + BytePos::from_usize(pos))
-    } else {
-        None
-    }
+    })
 }
 
 /// Returns the indentation of the line of a span
@@ -626,11 +607,7 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
 /// //          ^^ -- will return 4
 /// ```
 pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
-    if let Some(snip) = snippet_opt(cx, line_span(cx, span)) {
-        snip.find(|c: char| !c.is_whitespace())
-    } else {
-        None
-    }
+    snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
 }
 
 /// Extends the span to the beginning of the spans line, incl. whitespaces.
@@ -738,25 +715,21 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
     let enclosing_node = map
         .get_enclosing_scope(hir_id)
         .and_then(|enclosing_id| map.find(enclosing_id));
-    if let Some(node) = enclosing_node {
-        match node {
-            Node::Block(block) => Some(block),
-            Node::Item(&Item {
-                kind: ItemKind::Fn(_, _, eid),
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Fn(_, eid),
-                ..
-            }) => match cx.tcx.hir().body(eid).value.kind {
-                ExprKind::Block(ref block, _) => Some(block),
-                _ => None,
-            },
+    enclosing_node.and_then(|node| match node {
+        Node::Block(block) => Some(block),
+        Node::Item(&Item {
+            kind: ItemKind::Fn(_, _, eid),
+            ..
+        })
+        | Node::ImplItem(&ImplItem {
+            kind: ImplItemKind::Fn(_, eid),
+            ..
+        }) => match cx.tcx.hir().body(eid).value.kind {
+            ExprKind::Block(ref block, _) => Some(block),
             _ => None,
-        }
-    } else {
-        None
-    }
+        },
+        _ => None,
+    })
 }
 
 /// Returns the base type for HIR references and pointers.
@@ -797,7 +770,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
     let parent_item = map.get_parent_item(e.hir_id);
     if let Some((Constant::Int(v), _)) = map
         .maybe_body_owned_by(parent_item)
-        .and_then(|body_id| constant(cx, cx.tcx.body_tables(body_id), e))
+        .and_then(|body_id| constant(cx, cx.tcx.typeck_body(body_id), e))
     {
         value == v
     } else {
@@ -824,7 +797,7 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
 /// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
 /// information on adjustments and coercions.
 pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    cx.tables().adjustments().get(e.hir_id).is_some()
+    cx.typeck_results().adjustments().get(e.hir_id).is_some()
 }
 
 /// Returns the pre-expansion span if is this comes from an expansion of the
@@ -941,7 +914,7 @@ fn are_refutable<'a, I: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, mut
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
         PatKind::Slice(ref head, ref middle, ref tail) => {
-            match &cx.tables().node_type(pat.hir_id).kind {
+            match &cx.typeck_results().node_type(pat.hir_id).kind {
                 ty::Slice(..) => {
                     // [..] is the only irrefutable slice pattern.
                     !head.is_empty() || middle.is_none() || !tail.is_empty()
@@ -1324,15 +1297,11 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                 None
             }
         },
-        ExprKind::MethodCall(_, _, _, _) => cx.tables().type_dependent_def_id(expr.hir_id),
+        ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
         _ => None,
     };
 
-    if let Some(did) = did {
-        must_use_attr(&cx.tcx.get_attrs(did)).is_some()
-    } else {
-        false
-    }
+    did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
 }
 
 pub fn is_no_std_crate(krate: &Crate<'_>) -> bool {
@@ -1385,6 +1354,21 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
     )
 }
 
+/// Returns the `DefId` of the callee if the given expression is a function or method call.
+pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
+    match &expr.kind {
+        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
+        ExprKind::Call(
+            Expr {
+                kind: ExprKind::Path(qpath),
+                ..
+            },
+            ..,
+        ) => cx.typeck_results().qpath_res(qpath, expr.hir_id).opt_def_id(),
+        _ => None,
+    }
+}
+
 pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bool {
     lints.iter().any(|lint| {
         matches!(
index 99413153d49bbc08f28dd38deaabef9e62239988..87cb454f654bcfb9a2a8ad70c4cceac6ccbd3253 100644 (file)
@@ -51,7 +51,7 @@ pub fn from_lit(src: &'a str, lit: &Lit) -> Option<NumericLiteral<'a>> {
     pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
         if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
             let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
-            let float = if let LitKind::Float(..) = lit_kind { true } else { false };
+            let float = matches!(lit_kind, LitKind::Float(..));
             Some(NumericLiteral::new(unsuffixed, suffix, float))
         } else {
             None
@@ -200,12 +200,10 @@ pub fn group_digits(output: &mut String, input: &str, group_size: usize, partial
 
 fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
     debug_assert!(lit_kind.is_numeric());
-    if let Some(suffix_length) = lit_suffix_length(lit_kind) {
+    lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| {
         let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
         (unsuffixed, Some(suffix))
-    } else {
-        (src, None)
-    }
+    })
 }
 
 fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
index 3b7e9739211b0520cca61321ff7498bcc90c97ef..4c3462802e9218535b8343bc10b1946a3c3adb87 100644 (file)
@@ -98,7 +98,6 @@
 pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
 pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
-pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"];
 pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
 pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
 pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
index d05e81b9505795cf979985ea5bb2dcf714143afd..0ac7714fbeb79cd9b3feb6d3665b437c72aabcd0 100644 (file)
@@ -325,22 +325,22 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
 /// parenthesis will always be added for a mix of these.
 pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
     /// Returns `true` if the operator is a shift operator `<<` or `>>`.
-    fn is_shift(op: &AssocOp) -> bool {
-        matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
+    fn is_shift(op: AssocOp) -> bool {
+        matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
     }
 
     /// Returns `true` if the operator is a arithmetic operator
     /// (i.e., `+`, `-`, `*`, `/`, `%`).
-    fn is_arith(op: &AssocOp) -> bool {
+    fn is_arith(op: AssocOp) -> bool {
         matches!(
-            *op,
+            op,
             AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus
         )
     }
 
     /// Returns `true` if the operator `op` needs parenthesis with the operator
     /// `other` in the direction `dir`.
-    fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
+    fn needs_paren(op: AssocOp, other: AssocOp, dir: Associativity) -> bool {
         other.precedence() < op.precedence()
             || (other.precedence() == op.precedence()
                 && ((op != other && associativity(op) != dir)
@@ -349,14 +349,14 @@ fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
             || is_shift(other) && is_arith(op)
     }
 
-    let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
-        needs_paren(&op, lop, Associativity::Left)
+    let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs {
+        needs_paren(op, lop, Associativity::Left)
     } else {
         false
     };
 
-    let rhs_paren = if let Sugg::BinOp(ref rop, _) = *rhs {
-        needs_paren(&op, rop, Associativity::Right)
+    let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs {
+        needs_paren(op, rop, Associativity::Right)
     } else {
         false
     };
@@ -424,13 +424,13 @@ enum Associativity {
 /// they are considered
 /// associative.
 #[must_use]
-fn associativity(op: &AssocOp) -> Associativity {
+fn associativity(op: AssocOp) -> Associativity {
     use rustc_ast::util::parser::AssocOp::{
         Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater,
         GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
     };
 
-    match *op {
+    match op {
         Assign | AssignOp(_) => Associativity::Right,
         Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both,
         Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight
@@ -492,20 +492,20 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
 /// before it on its line.
 fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
     let lo = cx.sess().source_map().lookup_char_pos(span.lo());
-    if let Some(line) = lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) {
-        if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') {
-            // We can mix char and byte positions here because we only consider `[ \t]`.
-            if lo.col == CharPos(pos) {
-                Some(line[..pos].into())
+    lo.file
+        .get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */)
+        .and_then(|line| {
+            if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') {
+                // We can mix char and byte positions here because we only consider `[ \t]`.
+                if lo.col == CharPos(pos) {
+                    Some(line[..pos].into())
+                } else {
+                    None
+                }
             } else {
                 None
             }
-        } else {
-            None
-        }
-    } else {
-        None
-    }
+        })
 }
 
 /// Convenience extension trait for `DiagnosticBuilder`.
index 53d3a241f58af673ebb5648a71e3f17a2ceba57f..4a64b935ac9b4c4c4ef5ec09b9a89934e5c382e1 100644 (file)
@@ -18,7 +18,14 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) ->
     };
     let def_id = expr.hir_id.owner.to_def_id();
     cx.tcx.infer_ctxt().enter(|infcx| {
-        ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(expr);
+        ExprUseVisitor::new(
+            &mut delegate,
+            &infcx,
+            def_id.expect_local(),
+            cx.param_env,
+            cx.typeck_results(),
+        )
+        .walk_expr(expr);
     });
 
     if delegate.skip {
index e1043c36e0a541c45653f045e17295cdddedd504..f2e76442a19bae5775d72f5343183bf10ac4066f 100644 (file)
@@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // search for `&vec![_]` expressions where the adjusted type is `&[_]`
         if_chain! {
-            if let ty::Ref(_, ty, _) = cx.tables().expr_ty_adjusted(expr).kind;
+            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind;
             if let ty::Slice(..) = ty.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
             if let Some(vec_args) = higher::vec_macro(cx, addressee);
@@ -50,7 +50,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let Some((_, arg, _)) = higher::for_loop(expr);
             if let Some(vec_args) = higher::vec_macro(cx, arg);
-            if is_copy(cx, vec_type(cx.tables().expr_ty_adjusted(arg)));
+            if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
             then {
                 // report the error around the `vec!` not inside `<std macros>:`
                 let span = arg.span
@@ -70,7 +70,7 @@ fn check_vec_macro<'tcx>(cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx
     let mut applicability = Applicability::MachineApplicable;
     let snippet = match *vec_args {
         higher::VecArgs::Repeat(elem, len) => {
-            if constant(cx, cx.tables(), len).is_some() {
+            if constant(cx, cx.typeck_results(), len).is_some() {
                 format!(
                     "&[{}; {}]",
                     snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
index cc5e21a7ca6fc876a627e6675ed54e923bc86518..ad73a1ea1acdfeda18cc022307729c2fc16ad470 100644 (file)
@@ -32,7 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for VecResizeToZero {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let hir::ExprKind::MethodCall(path_segment, _, ref args, _) = expr.kind;
-            if let Some(method_def_id) = cx.tables().type_dependent_def_id(expr.hir_id);
+            if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
             if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
             if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
             if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
index b06fe36da631b65c925f25ec867b274594f6e436..32574d9d6c9a821fcf0f5db89339ba81e4829908 100644 (file)
@@ -62,7 +62,7 @@ fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) ->
         if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind;
         if method_name.ident.as_str() == "read_to_end";
         if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.tables().expr_ty(&exprs[0]);
+        let ty = cx.typeck_results().expr_ty(&exprs[0]);
         if match_type(cx, ty, &paths::FILE);
         then {
             return true
@@ -76,7 +76,7 @@ fn is_file_read_to_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
         if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind;
         if method_name.ident.as_str() == "read_to_string";
         if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.tables().expr_ty(&exprs[0]);
+        let ty = cx.typeck_results().expr_ty(&exprs[0]);
         if match_type(cx, ty, &paths::FILE);
         then {
             return true
index cb769b5a2ce95671d9b67b222615c126f93dcfd4..063f94582b9d14cc38f138d8914e8ce178aaae66 100644 (file)
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// println!("");
+    ///
+    /// // Good
+    /// println!();
     /// ```
     pub PRINTLN_EMPTY_STRING,
     style,
@@ -32,8 +36,7 @@
 
 declare_clippy_lint! {
     /// **What it does:** This lint warns when you use `print!()` with a format
-    /// string that
-    /// ends in a newline.
+    /// string that ends in a newline.
     ///
     /// **Why is this bad?** You should use `println!()` instead, which appends the
     /// newline.
     /// ```rust
     /// # use std::fmt::Write;
     /// # let mut buf = String::new();
+    ///
+    /// // Bad
     /// writeln!(buf, "");
+    ///
+    /// // Good
+    /// writeln!(buf);
     /// ```
     pub WRITELN_EMPTY_STRING,
     style,
     /// # use std::fmt::Write;
     /// # let mut buf = String::new();
     /// # let name = "World";
+    ///
+    /// // Bad
     /// write!(buf, "Hello {}!\n", name);
+    ///
+    /// // Good
+    /// writeln!(buf, "Hello {}!", name);
     /// ```
     pub WRITE_WITH_NEWLINE,
     style,
     /// ```rust
     /// # use std::fmt::Write;
     /// # let mut buf = String::new();
+    ///
+    /// // Bad
     /// writeln!(buf, "{}", "foo");
+    ///
+    /// // Good
+    /// writeln!(buf, "foo");
     /// ```
     pub WRITE_LITERAL,
     style,
@@ -279,13 +297,13 @@ fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
             if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) {
                 if fmt_str.symbol == Symbol::intern("") {
                     let mut applicability = Applicability::MachineApplicable;
-                    let suggestion = match expr {
-                        Some(expr) => snippet_with_applicability(cx, expr.span, "v", &mut applicability),
-                        None => {
+                    let suggestion = expr.map_or_else(
+                        || {
                             applicability = Applicability::HasPlaceholders;
                             Cow::Borrowed("v")
                         },
-                    };
+                        |e| snippet_with_applicability(cx, e.span, "v", &mut Applicability::MachineApplicable),
+                    );
 
                     span_lint_and_sugg(
                         cx,
index 1e011ea9cba5e4f316b4730cf1b18f7c0f50a765..4b81a27632d8d03df056ef17a1a48b79b7f39bed 100644 (file)
@@ -36,8 +36,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             // TODO - constant_simple does not fold many operations involving floats.
             // That's probably fine for this lint - it's pretty unlikely that someone would
             // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
-            if let Some(lhs_value) = constant_simple(cx, cx.tables(), left);
-            if let Some(rhs_value) = constant_simple(cx, cx.tables(), right);
+            if let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left);
+            if let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right);
             if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value;
             if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value;
             then {
index 412ff99314d9969baa1997008b3d3d3ebbccd916..9dd4c8a5f7a703b935629d733e7b1cfa0735b8e7 100644 (file)
@@ -23,7 +23,7 @@ Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for ex
 - is it a primitive type?
 - does it implement a trait?
 
-This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct,
+This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckResults`][TypeckResults] struct,
 that gives you access to the underlying structure [`TyS`][TyS].
 
 Example of use:
@@ -31,7 +31,7 @@ Example of use:
 impl LateLintPass<'_> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         // Get type of `expr`
-        let ty = cx.tables().expr_ty(expr);
+        let ty = cx.typeck_results().expr_ty(expr);
         // Match its kind to enter its type
         match ty.kind {
             ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"),
@@ -41,14 +41,14 @@ impl LateLintPass<'_> for MyStructLint {
 }
 ```
 
-Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method
+Similarly in [`TypeckResults`][TypeckResults] methods, you have the [`pat_ty()`][pat_ty] method
 to retrieve a type from a pattern.
 
 Two noticeable items here:
 - `cx` is the lint context [`LateContext`][LateContext].
   The two most useful data structures in this context are `tcx` and `tables`,
   allowing us to jump to type definitions and other compilation stages such as HIR.
-- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step,
+- `tables` is [`TypeckResults`][TypeckResults] and is created by type checking step,
   it includes useful information such as types of expressions, ways to resolve methods and so on.
 
 # Checking if an expr is calling a specific method
@@ -87,7 +87,7 @@ impl LateLintPass<'_> for MyStructLint {
         }
 
         // 2. Using type context `TyCtxt`
-        let ty = cx.tables().expr_ty(expr);
+        let ty = cx.typeck_results().expr_ty(expr);
         if cx.tcx.lang_items()
             // we are looking for the `DefId` of `Drop` trait in lang items
             .drop_trait()
@@ -192,9 +192,9 @@ assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
 
 [TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html
 [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
-[TypeckTables]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html
-[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html#method.expr_ty
+[TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html
+[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty
 [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
 [TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
-[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckTables.html#method.pat_ty
+[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
 [paths]: ../clippy_lints/src/utils/paths.rs
index decd3a79cce180c839320dc158f5714c095150c2..47315fa64cd8019cba3c508de3d960a6c50ebcc0 100644 (file)
@@ -382,13 +382,8 @@ pub fn main() {
 
         let should_describe_lints = || {
             let args: Vec<_> = env::args().collect();
-            args.windows(2).any(|args| {
-                args[1] == "help"
-                    && match args[0].as_str() {
-                        "-W" | "-A" | "-D" | "-F" => true,
-                        _ => false,
-                    }
-            })
+            args.windows(2)
+                .any(|args| args[1] == "help" && matches!(args[0].as_str(), "-W" | "-A" | "-D" | "-F"))
         };
 
         if !wrapper_mode && should_describe_lints() {
index edceb75518008e798915dc815e52561662431a31..b89a87128626bc927db31c27665d220c452c52fd 100644 (file)
         deprecation: None,
         module: "blacklisted_name",
     },
+    Lint {
+        name: "blanket_clippy_restriction_lints",
+        group: "style",
+        desc: "enabling the complete restriction group",
+        deprecation: None,
+        module: "attrs",
+    },
     Lint {
         name: "blocks_in_if_conditions",
         group: "style",
         deprecation: None,
         module: "methods",
     },
+    Lint {
+        name: "map_identity",
+        group: "complexity",
+        desc: "using iterator.map(|x| x)",
+        deprecation: None,
+        module: "map_identity",
+    },
     Lint {
         name: "map_unwrap_or",
         group: "pedantic",
         deprecation: None,
         module: "matches",
     },
+    Lint {
+        name: "match_like_matches_macro",
+        group: "style",
+        desc: "a match that could be written with the matches! macro",
+        deprecation: None,
+        module: "matches",
+    },
     Lint {
         name: "match_on_vec_items",
         group: "pedantic",
         deprecation: None,
         module: "option_env_unwrap",
     },
+    Lint {
+        name: "option_if_let_else",
+        group: "pedantic",
+        desc: "reimplementation of Option::map_or",
+        deprecation: None,
+        module: "option_if_let_else",
+    },
     Lint {
         name: "option_map_or_none",
         group: "style",
         deprecation: None,
         module: "path_buf_push_overwrite",
     },
+    Lint {
+        name: "pattern_type_mismatch",
+        group: "restriction",
+        desc: "type of pattern does not match the expression type",
+        deprecation: None,
+        module: "pattern_type_mismatch",
+    },
     Lint {
         name: "possible_missing_comma",
         group: "correctness",
     },
     Lint {
         name: "range_minus_one",
-        group: "complexity",
+        group: "pedantic",
         desc: "`x..=(y-1)` reads better as `x..y`",
         deprecation: None,
         module: "ranges",
         group: "style",
         desc: "use the proper utility function avoiding an `if let`",
         deprecation: None,
-        module: "redundant_pattern_matching",
+        module: "matches",
     },
     Lint {
         name: "redundant_pub_crate",
         module: "reference",
     },
     Lint {
-        name: "regex_macro",
-        group: "style",
-        desc: "use of `regex!(_)` instead of `Regex::new(_)`",
+        name: "repeat_once",
+        group: "complexity",
+        desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ",
         deprecation: None,
-        module: "regex",
+        module: "repeat_once",
     },
     Lint {
         name: "rest_pat_in_fully_bound_structs",
index 368fa6a98c5d6fd7c11614a7a86846a21360c368..26a47d237065a9f0c16cc3db6638a014b9ae86b7 100644 (file)
 mod cargo;
 
 fn host_lib() -> PathBuf {
-    if let Some(path) = option_env!("HOST_LIBS") {
-        PathBuf::from(path)
-    } else {
-        cargo::CARGO_TARGET_DIR.join(env!("PROFILE"))
-    }
+    option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
 }
 
 fn clippy_driver_path() -> PathBuf {
-    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
-        PathBuf::from(path)
-    } else {
-        cargo::TARGET_LIB.join("clippy-driver")
-    }
+    option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
 }
 
 // When we'll want to use `extern crate ..` for a dependency that is used
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock
new file mode 100644 (file)
index 0000000..7e96aa3
--- /dev/null
@@ -0,0 +1,109 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "bitflags"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "ctrlc"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "653abc99aa905f693d89df4797fadc08085baee379db92be9f2496cefe8a6f2c"
+dependencies = [
+ "kernel32-sys",
+ "nix",
+ "winapi 0.2.8",
+]
+
+[[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",
+ "winapi-build",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+
+[[package]]
+name = "multiple_crate_versions"
+version = "0.1.0"
+dependencies = [
+ "ansi_term",
+ "ctrlc",
+]
+
+[[package]]
+name = "nix"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "libc",
+ "void",
+]
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[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.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "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-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
index 4f668599be950ffbae42e0af7bbd8c30f99887fa..f3113e093650221171de886a7701689239b55516 100644 (file)
@@ -1,4 +1,4 @@
-error: multiple versions for dependency `winapi`: 0.2.8, 0.3.8
+error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9
    |
    = note: `-D clippy::multiple-crate-versions` implied by `-D warnings`
 
index 53970af41079d5a952038fb4911e19bca40c4bc5..6fbba01416a8d5a27ed47c0b8ae60206ccc1f5fe 100644 (file)
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
index 91b65a43be77fa5fdb3aa2a1fe66f2227347a7cf..908d063729f45c4bcdb0a41dc6fb18bfc73c470d 100644 (file)
@@ -1,5 +1,11 @@
 #![warn(clippy::inline_always, clippy::deprecated_semver)]
 #![allow(clippy::assertions_on_constants)]
+// Test that the whole restriction group is not enabled
+#![warn(clippy::restriction)]
+#![deny(clippy::restriction)]
+#![forbid(clippy::restriction)]
+#![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)]
+
 #[inline(always)]
 fn test_attr_lint() {
     assert!(true)
index 39ddf6f226d95482da927fb934b3973c79179892..ef4b89eaa6dee41522557104579adbdca5031133 100644 (file)
@@ -1,5 +1,5 @@
 error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
-  --> $DIR/attrs.rs:3:1
+  --> $DIR/attrs.rs:9:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[inline(always)]
    = note: `-D clippy::inline-always` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:23:14
+  --> $DIR/attrs.rs:29:14
    |
 LL | #[deprecated(since = "forever")]
    |              ^^^^^^^^^^^^^^^^^
@@ -15,10 +15,35 @@ LL | #[deprecated(since = "forever")]
    = note: `-D clippy::deprecated-semver` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:26:14
+  --> $DIR/attrs.rs:32:14
    |
 LL | #[deprecated(since = "1")]
    |              ^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: restriction lints are not meant to be all enabled
+  --> $DIR/attrs.rs:4:9
+   |
+LL | #![warn(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/attrs.rs:5:9
+   |
+LL | #![deny(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/attrs.rs:6:11
+   |
+LL | #![forbid(clippy::restriction)]
+   |           ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed
new file mode 100644 (file)
index 0000000..1f0ca10
--- /dev/null
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![allow(
+    unused,
+    clippy::redundant_clone,
+    clippy::deref_addrof,
+    clippy::no_effect,
+    clippy::unnecessary_operation
+)]
+
+use std::cell::RefCell;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+fn main() {}
+
+fn is_ascii(ch: char) -> bool {
+    ch.is_ascii()
+}
+
+fn clone_on_copy() {
+    42;
+
+    vec![1].clone(); // ok, not a Copy type
+    Some(vec![1]).clone(); // ok, not a Copy type
+    *(&42);
+
+    let rc = RefCell::new(0);
+    *rc.borrow();
+
+    // Issue #4348
+    let mut x = 43;
+    let _ = &x.clone(); // ok, getting a ref
+    'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
+    is_ascii('z');
+
+    // Issue #5436
+    let mut vec = Vec::new();
+    vec.push(42);
+}
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs
new file mode 100644 (file)
index 0000000..ca39a65
--- /dev/null
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![allow(
+    unused,
+    clippy::redundant_clone,
+    clippy::deref_addrof,
+    clippy::no_effect,
+    clippy::unnecessary_operation
+)]
+
+use std::cell::RefCell;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+fn main() {}
+
+fn is_ascii(ch: char) -> bool {
+    ch.is_ascii()
+}
+
+fn clone_on_copy() {
+    42.clone();
+
+    vec![1].clone(); // ok, not a Copy type
+    Some(vec![1]).clone(); // ok, not a Copy type
+    (&42).clone();
+
+    let rc = RefCell::new(0);
+    rc.borrow().clone();
+
+    // Issue #4348
+    let mut x = 43;
+    let _ = &x.clone(); // ok, getting a ref
+    'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
+    is_ascii('z'.clone());
+
+    // Issue #5436
+    let mut vec = Vec::new();
+    vec.push(42.clone());
+}
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr
new file mode 100644 (file)
index 0000000..ec2faf4
--- /dev/null
@@ -0,0 +1,34 @@
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:22:5
+   |
+LL |     42.clone();
+   |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
+   |
+   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:26:5
+   |
+LL |     (&42).clone();
+   |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:29:5
+   |
+LL |     rc.borrow().clone();
+   |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:35:14
+   |
+LL |     is_ascii('z'.clone());
+   |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:39:14
+   |
+LL |     vec.push(42.clone());
+   |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed
new file mode 100644 (file)
index 0000000..3305ac9
--- /dev/null
@@ -0,0 +1,93 @@
+// run-rustfix
+#![allow(unused, clippy::redundant_clone)] // See #5700
+
+// Define the types in each module to avoid trait impls leaking between modules.
+macro_rules! impl_types {
+    () => {
+        #[derive(PartialEq)]
+        pub struct Owned;
+
+        pub struct Borrowed;
+
+        impl ToOwned for Borrowed {
+            type Owned = Owned;
+            fn to_owned(&self) -> Owned {
+                Owned {}
+            }
+        }
+
+        impl std::borrow::Borrow<Borrowed> for Owned {
+            fn borrow(&self) -> &Borrowed {
+                static VALUE: Borrowed = Borrowed {};
+                &VALUE
+            }
+        }
+    };
+}
+
+// Only Borrowed == Owned is implemented
+mod borrowed_eq_owned {
+    impl_types!();
+
+    impl PartialEq<Owned> for Borrowed {
+        fn eq(&self, _: &Owned) -> bool {
+            true
+        }
+    }
+
+    pub fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if borrowed == owned {}
+        if borrowed == owned {}
+    }
+}
+
+// Only Owned == Borrowed is implemented
+mod owned_eq_borrowed {
+    impl_types!();
+
+    impl PartialEq<Borrowed> for Owned {
+        fn eq(&self, _: &Borrowed) -> bool {
+            true
+        }
+    }
+
+    fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if owned == borrowed {}
+        if owned == borrowed {}
+    }
+}
+
+mod issue_4874 {
+    impl_types!();
+
+    // NOTE: PartialEq<Borrowed> for T can't be implemented due to the orphan rules
+    impl<T> PartialEq<T> for Borrowed
+    where
+        T: AsRef<str> + ?Sized,
+    {
+        fn eq(&self, _: &T) -> bool {
+            true
+        }
+    }
+
+    impl std::fmt::Display for Borrowed {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, "borrowed")
+        }
+    }
+
+    fn compare() {
+        let borrowed = Borrowed {};
+
+        if borrowed == "Hi" {}
+        if borrowed == "Hi" {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs
new file mode 100644 (file)
index 0000000..88bc2f5
--- /dev/null
@@ -0,0 +1,93 @@
+// run-rustfix
+#![allow(unused, clippy::redundant_clone)] // See #5700
+
+// Define the types in each module to avoid trait impls leaking between modules.
+macro_rules! impl_types {
+    () => {
+        #[derive(PartialEq)]
+        pub struct Owned;
+
+        pub struct Borrowed;
+
+        impl ToOwned for Borrowed {
+            type Owned = Owned;
+            fn to_owned(&self) -> Owned {
+                Owned {}
+            }
+        }
+
+        impl std::borrow::Borrow<Borrowed> for Owned {
+            fn borrow(&self) -> &Borrowed {
+                static VALUE: Borrowed = Borrowed {};
+                &VALUE
+            }
+        }
+    };
+}
+
+// Only Borrowed == Owned is implemented
+mod borrowed_eq_owned {
+    impl_types!();
+
+    impl PartialEq<Owned> for Borrowed {
+        fn eq(&self, _: &Owned) -> bool {
+            true
+        }
+    }
+
+    pub fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if borrowed.to_owned() == owned {}
+        if owned == borrowed.to_owned() {}
+    }
+}
+
+// Only Owned == Borrowed is implemented
+mod owned_eq_borrowed {
+    impl_types!();
+
+    impl PartialEq<Borrowed> for Owned {
+        fn eq(&self, _: &Borrowed) -> bool {
+            true
+        }
+    }
+
+    fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if owned == borrowed.to_owned() {}
+        if borrowed.to_owned() == owned {}
+    }
+}
+
+mod issue_4874 {
+    impl_types!();
+
+    // NOTE: PartialEq<Borrowed> for T can't be implemented due to the orphan rules
+    impl<T> PartialEq<T> for Borrowed
+    where
+        T: AsRef<str> + ?Sized,
+    {
+        fn eq(&self, _: &T) -> bool {
+            true
+        }
+    }
+
+    impl std::fmt::Display for Borrowed {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, "borrowed")
+        }
+    }
+
+    fn compare() {
+        let borrowed = Borrowed {};
+
+        if "Hi" == borrowed.to_string() {}
+        if borrowed.to_string() == "Hi" {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr
new file mode 100644 (file)
index 0000000..43bf885
--- /dev/null
@@ -0,0 +1,46 @@
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:42:12
+   |
+LL |         if borrowed.to_owned() == owned {}
+   |            ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
+   |
+   = note: `-D clippy::cmp-owned` implied by `-D warnings`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:43:21
+   |
+LL |         if owned == borrowed.to_owned() {}
+   |            ---------^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            help: try: `borrowed == owned`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:61:21
+   |
+LL |         if owned == borrowed.to_owned() {}
+   |                     ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:62:12
+   |
+LL |         if borrowed.to_owned() == owned {}
+   |            ^^^^^^^^^^^^^^^^^^^---------
+   |            |
+   |            help: try: `owned == borrowed`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:88:20
+   |
+LL |         if "Hi" == borrowed.to_string() {}
+   |            --------^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            help: try: `borrowed == "Hi"`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:89:12
+   |
+LL |         if borrowed.to_string() == "Hi" {}
+   |            ^^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
+
+error: aborting due to 6 previous errors
+
index 28048999e8ec9568a8071135f2e3612bccddae43..3d1c458879e58818efd38abb03c8935e23b852de 100644 (file)
@@ -10,7 +10,7 @@ LL | |     }
    | |_____^
    |
    = note: `-D clippy::collapsible-if` implied by `-D warnings`
-help: try
+help: collapse nested if block
    |
 LL |     } else if y == "world" {
 LL |         println!("world!")
@@ -28,7 +28,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     } else if let Some(42) = Some(42) {
 LL |         println!("world!")
@@ -48,7 +48,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     } else if y == "world" {
 LL |         println!("world")
@@ -71,7 +71,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     } else if let Some(42) = Some(42) {
 LL |         println!("world")
@@ -94,7 +94,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     } else if let Some(42) = Some(42) {
 LL |         println!("world")
@@ -117,7 +117,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     } else if x == "hello" {
 LL |         println!("world")
@@ -140,7 +140,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     } else if let Some(42) = Some(42) {
 LL |         println!("world")
index 6440ff41be81e243da433c4ac3ac7ec67b6bf55a..f56dd65b9dd26c77144b24d0763ac472b739c238 100644 (file)
@@ -9,7 +9,7 @@ LL | |     }
    | |_____^
    |
    = note: `-D clippy::collapsible-if` implied by `-D warnings`
-help: try
+help: collapse nested if block
    |
 LL |     if x == "hello" && y == "world" {
 LL |         println!("Hello world!");
@@ -26,7 +26,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
 LL |         println!("Hello world!");
@@ -43,7 +43,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     if x == "hello" && x == "world" && (y == "world" || y == "hello") {
 LL |         println!("Hello world!");
@@ -60,7 +60,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     if (x == "hello" || x == "world") && y == "world" && y == "hello" {
 LL |         println!("Hello world!");
@@ -77,7 +77,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     if x == "hello" && x == "world" && y == "world" && y == "hello" {
 LL |         println!("Hello world!");
@@ -94,7 +94,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     if 42 == 1337 && 'a' != 'A' {
 LL |         println!("world!")
@@ -111,7 +111,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: try
+help: collapse nested if block
    |
 LL |     if x == "hello" && y == "world" { // Collapsible
 LL |         println!("Hello world!");
index 188a641aa1af25db2288d2162f5b6b7edea46f5e..3eefb232780f1a9931a6040307eb67edbefeca4d 100644 (file)
@@ -7,5 +7,6 @@
 #[warn(clippy::invalid_ref)]
 #[warn(clippy::into_iter_on_array)]
 #[warn(clippy::unused_label)]
+#[warn(clippy::regex_macro)]
 
 fn main() {}
index a4efe3d15a952e100cbfb4e59c4e94cb303ac1e9..a80e2bf31feb6b37a7869bba98cef5e84b5ccdae 100644 (file)
@@ -54,11 +54,17 @@ error: lint `clippy::unused_label` has been removed: `this lint has been uplifte
 LL | #[warn(clippy::unused_label)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
+error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018`
+  --> $DIR/deprecated.rs:10:8
+   |
+LL | #[warn(clippy::regex_macro)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
 error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
   --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::str_to_string)]
    |        ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 11 previous errors
 
index c28cca144ca3f15bb6aa90c0095d7e844d1d7ea9..88d3b0e74900152d33938bf332da60dd9035f31c 100644 (file)
@@ -19,6 +19,7 @@ fn main() {
 
     let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
 
+    #[allow(clippy::match_like_matches_macro)]
     let _: Option<Flavor> = desserts_of_the_week
         .iter()
         .find(|dessert| match *dessert {
index 92f40fe6f1fb23b8a6e2b6681019c573ef5c2e2a..f279850fef8af91a0c520197efb7571f4e22b5e6 100644 (file)
@@ -8,7 +8,7 @@ LL |     let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s
    = help: this is more succinctly expressed by calling `.find_map(..)` instead
 
 error: called `find(p).map(q)` on an `Iterator`
-  --> $DIR/find_map.rs:22:29
+  --> $DIR/find_map.rs:23:29
    |
 LL |       let _: Option<Flavor> = desserts_of_the_week
    |  _____________________________^
diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.fixed b/src/tools/clippy/tests/ui/floating_point_hypot.fixed
new file mode 100644 (file)
index 0000000..bbe411b
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+#![warn(clippy::imprecise_flops)]
+
+fn main() {
+    let x = 3f32;
+    let y = 4f32;
+    let _ = x.hypot(y);
+    let _ = (x + 1f32).hypot(y);
+    let _ = x.hypot(y);
+    // Cases where the lint shouldn't be applied
+    // TODO: linting this adds some complexity, but could be done
+    let _ = x.mul_add(x, y * y).sqrt();
+    let _ = (x * 4f32 + y * y).sqrt();
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.rs b/src/tools/clippy/tests/ui/floating_point_hypot.rs
new file mode 100644 (file)
index 0000000..586fd17
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+#![warn(clippy::imprecise_flops)]
+
+fn main() {
+    let x = 3f32;
+    let y = 4f32;
+    let _ = (x * x + y * y).sqrt();
+    let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt();
+    let _ = (x.powi(2) + y.powi(2)).sqrt();
+    // Cases where the lint shouldn't be applied
+    // TODO: linting this adds some complexity, but could be done
+    let _ = x.mul_add(x, y * y).sqrt();
+    let _ = (x * 4f32 + y * y).sqrt();
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.stderr b/src/tools/clippy/tests/ui/floating_point_hypot.stderr
new file mode 100644 (file)
index 0000000..42069d9
--- /dev/null
@@ -0,0 +1,22 @@
+error: hypotenuse can be computed more accurately
+  --> $DIR/floating_point_hypot.rs:7:13
+   |
+LL |     let _ = (x * x + y * y).sqrt();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)`
+   |
+   = note: `-D clippy::imprecise-flops` implied by `-D warnings`
+
+error: hypotenuse can be computed more accurately
+  --> $DIR/floating_point_hypot.rs:8:13
+   |
+LL |     let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 1f32).hypot(y)`
+
+error: hypotenuse can be computed more accurately
+  --> $DIR/floating_point_hypot.rs:9:13
+   |
+LL |     let _ = (x.powi(2) + y.powi(2)).sqrt();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)`
+
+error: aborting due to 3 previous errors
+
index 42c5e5d2bae2418c4330959aa559382a46f4940f..7dc7ee94affc0d06c7ca21e0ad7df80a8d9903d9 100644 (file)
@@ -25,11 +25,11 @@ fn check_ln1p() {
     let _ = 2.0f32.ln_1p();
     let _ = x.ln_1p();
     let _ = (x / 2.0).ln_1p();
-    let _ = x.powi(2).ln_1p();
-    let _ = (x.powi(2) / 2.0).ln_1p();
+    let _ = x.powi(3).ln_1p();
+    let _ = (x.powi(3) / 2.0).ln_1p();
     let _ = ((std::f32::consts::E - 1.0)).ln_1p();
     let _ = x.ln_1p();
-    let _ = x.powi(2).ln_1p();
+    let _ = x.powi(3).ln_1p();
     let _ = (x + 2.0).ln_1p();
     let _ = (x / 2.0).ln_1p();
     // Cases where the lint shouldn't be applied
@@ -43,9 +43,9 @@ fn check_ln1p() {
     let _ = 2.0f64.ln_1p();
     let _ = x.ln_1p();
     let _ = (x / 2.0).ln_1p();
-    let _ = x.powi(2).ln_1p();
+    let _ = x.powi(3).ln_1p();
     let _ = x.ln_1p();
-    let _ = x.powi(2).ln_1p();
+    let _ = x.powi(3).ln_1p();
     let _ = (x + 2.0).ln_1p();
     let _ = (x / 2.0).ln_1p();
     // Cases where the lint shouldn't be applied
index 8be0d9ad56fc34fa07f120eda343a6ab61257047..01181484e7dee290c0973d60a38a93bd71062905 100644 (file)
@@ -25,11 +25,11 @@ fn check_ln1p() {
     let _ = (1f32 + 2.0).ln();
     let _ = (1.0 + x).ln();
     let _ = (1.0 + x / 2.0).ln();
-    let _ = (1.0 + x.powi(2)).ln();
-    let _ = (1.0 + x.powi(2) / 2.0).ln();
+    let _ = (1.0 + x.powi(3)).ln();
+    let _ = (1.0 + x.powi(3) / 2.0).ln();
     let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
     let _ = (x + 1.0).ln();
-    let _ = (x.powi(2) + 1.0).ln();
+    let _ = (x.powi(3) + 1.0).ln();
     let _ = (x + 2.0 + 1.0).ln();
     let _ = (x / 2.0 + 1.0).ln();
     // Cases where the lint shouldn't be applied
@@ -43,9 +43,9 @@ fn check_ln1p() {
     let _ = (1f64 + 2.0).ln();
     let _ = (1.0 + x).ln();
     let _ = (1.0 + x / 2.0).ln();
-    let _ = (1.0 + x.powi(2)).ln();
+    let _ = (1.0 + x.powi(3)).ln();
     let _ = (x + 1.0).ln();
-    let _ = (x.powi(2) + 1.0).ln();
+    let _ = (x.powi(3) + 1.0).ln();
     let _ = (x + 2.0 + 1.0).ln();
     let _ = (x / 2.0 + 1.0).ln();
     // Cases where the lint shouldn't be applied
index 943fbdb0b83232964312d49beedce567093ce20b..900dc2b79336a8bd1e67a642c54a6eb1c74966fa 100644 (file)
@@ -77,14 +77,14 @@ LL |     let _ = (1.0 + x / 2.0).ln();
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:28:13
    |
-LL |     let _ = (1.0 + x.powi(2)).ln();
-   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+LL |     let _ = (1.0 + x.powi(3)).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:29:13
    |
-LL |     let _ = (1.0 + x.powi(2) / 2.0).ln();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) / 2.0).ln_1p()`
+LL |     let _ = (1.0 + x.powi(3) / 2.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:30:13
@@ -101,8 +101,8 @@ LL |     let _ = (x + 1.0).ln();
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:32:13
    |
-LL |     let _ = (x.powi(2) + 1.0).ln();
-   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+LL |     let _ = (x.powi(3) + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:33:13
@@ -143,8 +143,8 @@ LL |     let _ = (1.0 + x / 2.0).ln();
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:46:13
    |
-LL |     let _ = (1.0 + x.powi(2)).ln();
-   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+LL |     let _ = (1.0 + x.powi(3)).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:47:13
@@ -155,8 +155,8 @@ LL |     let _ = (x + 1.0).ln();
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:48:13
    |
-LL |     let _ = (x.powi(2) + 1.0).ln();
-   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
+LL |     let _ = (x.powi(3) + 1.0).ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
   --> $DIR/floating_point_log.rs:49:13
diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.fixed b/src/tools/clippy/tests/ui/floating_point_logbase.fixed
new file mode 100644 (file)
index 0000000..13962a2
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let x = 3f32;
+    let y = 5f32;
+    let _ = x.log(y);
+    let _ = x.log(y);
+    let _ = x.log(y);
+    let _ = x.log(y);
+    // Cases where the lint shouldn't be applied
+    let _ = x.ln() / y.powf(3.2);
+    let _ = x.powf(3.2) / y.powf(3.2);
+    let _ = x.powf(3.2) / y.ln();
+    let _ = x.log(5f32) / y.log(7f32);
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.rs b/src/tools/clippy/tests/ui/floating_point_logbase.rs
new file mode 100644 (file)
index 0000000..26bc20d
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let x = 3f32;
+    let y = 5f32;
+    let _ = x.ln() / y.ln();
+    let _ = x.log2() / y.log2();
+    let _ = x.log10() / y.log10();
+    let _ = x.log(5f32) / y.log(5f32);
+    // Cases where the lint shouldn't be applied
+    let _ = x.ln() / y.powf(3.2);
+    let _ = x.powf(3.2) / y.powf(3.2);
+    let _ = x.powf(3.2) / y.ln();
+    let _ = x.log(5f32) / y.log(7f32);
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.stderr b/src/tools/clippy/tests/ui/floating_point_logbase.stderr
new file mode 100644 (file)
index 0000000..78354c2
--- /dev/null
@@ -0,0 +1,28 @@
+error: log base can be expressed more clearly
+  --> $DIR/floating_point_logbase.rs:7:13
+   |
+LL |     let _ = x.ln() / y.ln();
+   |             ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
+error: log base can be expressed more clearly
+  --> $DIR/floating_point_logbase.rs:8:13
+   |
+LL |     let _ = x.log2() / y.log2();
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
+
+error: log base can be expressed more clearly
+  --> $DIR/floating_point_logbase.rs:9:13
+   |
+LL |     let _ = x.log10() / y.log10();
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
+
+error: log base can be expressed more clearly
+  --> $DIR/floating_point_logbase.rs:10:13
+   |
+LL |     let _ = x.log(5f32) / y.log(5f32);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
+
+error: aborting due to 4 previous errors
+
index e343c37740da5f8207c5999238b2f48655914e35..911700bab0040e2e4a33439c537b73cbbeb69721 100644 (file)
@@ -18,4 +18,9 @@ fn main() {
 
     let _ = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c;
     let _ = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64);
+
+    let _ = a.mul_add(a, b).sqrt();
+
+    // Cases where the lint shouldn't be applied
+    let _ = (a * a + b * b).sqrt();
 }
index 810f929c8568b9bc1573e6c0ad976ac55933a785..d202385fc8ae76a0ee0f169852b1d410b3a76f77 100644 (file)
@@ -18,4 +18,9 @@ fn main() {
 
     let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c;
     let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64;
+
+    let _ = (a * a + b).sqrt();
+
+    // Cases where the lint shouldn't be applied
+    let _ = (a * a + b * b).sqrt();
 }
index 2dfbf562d15fc0c6a16bc2960ae02488870fad3f..ac8d0c0cae068cf87162396380ce510e075d3477 100644 (file)
@@ -54,5 +54,11 @@ error: multiply and add expressions can be calculated more efficiently and accur
 LL |     let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)`
 
-error: aborting due to 9 previous errors
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_mul_add.rs:22:13
+   |
+LL |     let _ = (a * a + b).sqrt();
+   |             ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)`
+
+error: aborting due to 10 previous errors
 
index 78a9d44829bb1ab708b1b39ed2fabffe2b3e24e4..b0641a100cdc810b4a3c7d3d045928970dfe1272 100644 (file)
@@ -11,7 +11,7 @@ fn main() {
     let _ = (-3.1f32).exp();
     let _ = x.sqrt();
     let _ = x.cbrt();
-    let _ = x.powi(2);
+    let _ = x.powi(3);
     let _ = x.powi(-2);
     let _ = x.powi(16_777_215);
     let _ = x.powi(-16_777_215);
@@ -30,7 +30,7 @@ fn main() {
     let _ = (-3.1f64).exp();
     let _ = x.sqrt();
     let _ = x.cbrt();
-    let _ = x.powi(2);
+    let _ = x.powi(3);
     let _ = x.powi(-2);
     let _ = x.powi(-2_147_483_648);
     let _ = x.powi(2_147_483_647);
index dbc1cac5cb4315cb03ceb516542e15b4aa8e21a9..a0a2c973900f4b7ba943f29a7bb90dcecaf6a8ce 100644 (file)
@@ -11,7 +11,7 @@ fn main() {
     let _ = std::f32::consts::E.powf(-3.1);
     let _ = x.powf(1.0 / 2.0);
     let _ = x.powf(1.0 / 3.0);
-    let _ = x.powf(2.0);
+    let _ = x.powf(3.0);
     let _ = x.powf(-2.0);
     let _ = x.powf(16_777_215.0);
     let _ = x.powf(-16_777_215.0);
@@ -30,7 +30,7 @@ fn main() {
     let _ = std::f64::consts::E.powf(-3.1);
     let _ = x.powf(1.0 / 2.0);
     let _ = x.powf(1.0 / 3.0);
-    let _ = x.powf(2.0);
+    let _ = x.powf(3.0);
     let _ = x.powf(-2.0);
     let _ = x.powf(-2_147_483_648.0);
     let _ = x.powf(2_147_483_647.0);
index ad5163f0079be937ae34e629eaa5a5148c17190a..2422eb911e90a7041dedbecccf2fa2677a12710d 100644 (file)
@@ -53,8 +53,8 @@ LL |     let _ = x.powf(1.0 / 3.0);
 error: exponentiation with integer powers can be computed more efficiently
   --> $DIR/floating_point_powf.rs:14:13
    |
-LL |     let _ = x.powf(2.0);
-   |             ^^^^^^^^^^^ help: consider using: `x.powi(2)`
+LL |     let _ = x.powf(3.0);
+   |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
   --> $DIR/floating_point_powf.rs:15:13
@@ -125,8 +125,8 @@ LL |     let _ = x.powf(1.0 / 3.0);
 error: exponentiation with integer powers can be computed more efficiently
   --> $DIR/floating_point_powf.rs:33:13
    |
-LL |     let _ = x.powf(2.0);
-   |             ^^^^^^^^^^^ help: consider using: `x.powi(2)`
+LL |     let _ = x.powf(3.0);
+   |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
   --> $DIR/floating_point_powf.rs:34:13
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed
new file mode 100644 (file)
index 0000000..5676240
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let one = 1;
+    let x = 3f32;
+    let _ = x * x;
+    let _ = x * x;
+
+    let y = 4f32;
+    let _ = x.mul_add(x, y);
+    let _ = y.mul_add(y, x);
+    let _ = x.mul_add(x, y).sqrt();
+    let _ = y.mul_add(y, x).sqrt();
+    // Cases where the lint shouldn't be applied
+    let _ = x.powi(3);
+    let _ = x.powi(one + 1);
+    let _ = (x.powi(2) + y.powi(2)).sqrt();
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs
new file mode 100644 (file)
index 0000000..1f800e4
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let one = 1;
+    let x = 3f32;
+    let _ = x.powi(2);
+    let _ = x.powi(1 + 1);
+
+    let y = 4f32;
+    let _ = x.powi(2) + y;
+    let _ = x + y.powi(2);
+    let _ = (x.powi(2) + y).sqrt();
+    let _ = (x + y.powi(2)).sqrt();
+    // Cases where the lint shouldn't be applied
+    let _ = x.powi(3);
+    let _ = x.powi(one + 1);
+    let _ = (x.powi(2) + y.powi(2)).sqrt();
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr
new file mode 100644 (file)
index 0000000..d5a5f1b
--- /dev/null
@@ -0,0 +1,40 @@
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:7:13
+   |
+LL |     let _ = x.powi(2);
+   |             ^^^^^^^^^ help: consider using: `x * x`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:8:13
+   |
+LL |     let _ = x.powi(1 + 1);
+   |             ^^^^^^^^^^^^^ help: consider using: `x * x`
+
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:11:13
+   |
+LL |     let _ = x.powi(2) + y;
+   |             ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
+
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:12:13
+   |
+LL |     let _ = x + y.powi(2);
+   |             ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
+
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:13:13
+   |
+LL |     let _ = (x.powi(2) + y).sqrt();
+   |             ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
+
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:14:13
+   |
+LL |     let _ = (x + y.powi(2)).sqrt();
+   |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed
new file mode 100644 (file)
index 0000000..92480c5
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let x = 3f32;
+    let _ = x.to_degrees();
+    let _ = x.to_radians();
+    // Cases where the lint shouldn't be applied
+    let _ = x * 90f32 / std::f32::consts::PI;
+    let _ = x * std::f32::consts::PI / 90f32;
+    let _ = x * 180f32 / std::f32::consts::E;
+    let _ = x * std::f32::consts::E / 180f32;
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs
new file mode 100644 (file)
index 0000000..062e7c3
--- /dev/null
@@ -0,0 +1,13 @@
+// run-rustfix
+#![warn(clippy::suboptimal_flops)]
+
+fn main() {
+    let x = 3f32;
+    let _ = x * 180f32 / std::f32::consts::PI;
+    let _ = x * std::f32::consts::PI / 180f32;
+    // Cases where the lint shouldn't be applied
+    let _ = x * 90f32 / std::f32::consts::PI;
+    let _ = x * std::f32::consts::PI / 90f32;
+    let _ = x * 180f32 / std::f32::consts::E;
+    let _ = x * std::f32::consts::E / 180f32;
+}
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr
new file mode 100644 (file)
index 0000000..a6ffdca
--- /dev/null
@@ -0,0 +1,16 @@
+error: conversion to degrees can be done more accurately
+  --> $DIR/floating_point_rad.rs:6:13
+   |
+LL |     let _ = x * 180f32 / std::f32::consts::PI;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
+error: conversion to radians can be done more accurately
+  --> $DIR/floating_point_rad.rs:7:13
+   |
+LL |     let _ = x * std::f32::consts::PI / 180f32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()`
+
+error: aborting due to 2 previous errors
+
index 7ac368878ab7ea341ea7c71c4896eb7be5cf6813..4171d80f48a3f51826fe8c59870e75ebdd2e488b 100644 (file)
@@ -2,6 +2,7 @@
 
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::map_identity)]
 
 fn main() {
     let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();
index a608601039ce783c80e3dfa2a3abdc4d94ea5dc5..16a0fd090ad04533e0fc1fde345d8c11ea930b5d 100644 (file)
@@ -2,6 +2,7 @@
 
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::map_identity)]
 
 fn main() {
     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
index 3cf2abd5b6d85a506a47e9fda694420c36bc3aff..00bc41c15e9b8d892ee6eb4ee30d3a5ad62a81eb 100644 (file)
@@ -1,5 +1,5 @@
 error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)`
-  --> $DIR/map_flatten.rs:7:21
+  --> $DIR/map_flatten.rs:8:21
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)`
@@ -7,7 +7,7 @@ LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().colle
    = note: `-D clippy::map-flatten` implied by `-D warnings`
 
 error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)`
-  --> $DIR/map_flatten.rs:8:24
+  --> $DIR/map_flatten.rs:9:24
    |
 LL |     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)`
diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed
new file mode 100644 (file)
index 0000000..4a1452b
--- /dev/null
@@ -0,0 +1,23 @@
+// run-rustfix
+#![warn(clippy::map_identity)]
+#![allow(clippy::needless_return)]
+
+fn main() {
+    let x: [u16; 3] = [1, 2, 3];
+    // should lint
+    let _: Vec<_> = x.iter().map(not_identity).collect();
+    let _: Vec<_> = x.iter().collect();
+    let _: Option<u8> = Some(3);
+    let _: Result<i8, f32> = Ok(-3);
+    // should not lint
+    let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
+    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
+    let _: Option<u8> = None.map(|x: u8| x - 1);
+    let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
+        return x + 3;
+    });
+}
+
+fn not_identity(x: &u16) -> u16 {
+    *x
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs
new file mode 100644 (file)
index 0000000..65c7e6e
--- /dev/null
@@ -0,0 +1,25 @@
+// run-rustfix
+#![warn(clippy::map_identity)]
+#![allow(clippy::needless_return)]
+
+fn main() {
+    let x: [u16; 3] = [1, 2, 3];
+    // should lint
+    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
+    let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
+    let _: Option<u8> = Some(3).map(|x| x);
+    let _: Result<i8, f32> = Ok(-3).map(|x| {
+        return x;
+    });
+    // should not lint
+    let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
+    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
+    let _: Option<u8> = None.map(|x: u8| x - 1);
+    let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
+        return x + 3;
+    });
+}
+
+fn not_identity(x: &u16) -> u16 {
+    *x
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr
new file mode 100644 (file)
index 0000000..e4a0320
--- /dev/null
@@ -0,0 +1,37 @@
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:8:47
+   |
+LL |     let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
+   |                                               ^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+   |
+   = note: `-D clippy::map-identity` implied by `-D warnings`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:9:57
+   |
+LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
+   |                                                         ^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:9:29
+   |
+LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:10:32
+   |
+LL |     let _: Option<u8> = Some(3).map(|x| x);
+   |                                ^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:11:36
+   |
+LL |       let _: Result<i8, f32> = Ok(-3).map(|x| {
+   |  ____________________________________^
+LL | |         return x;
+LL | |     });
+   | |______^ help: remove the call to `map`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
new file mode 100644 (file)
index 0000000..f3e1909
--- /dev/null
@@ -0,0 +1,36 @@
+// run-rustfix
+
+#![warn(clippy::match_like_matches_macro)]
+#![allow(unreachable_patterns)]
+
+fn main() {
+    let x = Some(5);
+
+    // Lint
+    let _y = matches!(x, Some(0));
+
+    // Lint
+    let _w = matches!(x, Some(_));
+
+    // Turn into is_none
+    let _z = x.is_none();
+
+    // Lint
+    let _zz = !matches!(x, Some(r) if r == 0);
+
+    // Lint
+    let _zzz = matches!(x, Some(5));
+
+    // No lint
+    let _a = match x {
+        Some(_) => false,
+        _ => false,
+    };
+
+    // No lint
+    let _ab = match x {
+        Some(0) => false,
+        _ => true,
+        None => false,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
new file mode 100644 (file)
index 0000000..fbae7c1
--- /dev/null
@@ -0,0 +1,48 @@
+// run-rustfix
+
+#![warn(clippy::match_like_matches_macro)]
+#![allow(unreachable_patterns)]
+
+fn main() {
+    let x = Some(5);
+
+    // Lint
+    let _y = match x {
+        Some(0) => true,
+        _ => false,
+    };
+
+    // Lint
+    let _w = match x {
+        Some(_) => true,
+        _ => false,
+    };
+
+    // Turn into is_none
+    let _z = match x {
+        Some(_) => false,
+        None => true,
+    };
+
+    // Lint
+    let _zz = match x {
+        Some(r) if r == 0 => false,
+        _ => true,
+    };
+
+    // Lint
+    let _zzz = if let Some(5) = x { true } else { false };
+
+    // No lint
+    let _a = match x {
+        Some(_) => false,
+        _ => false,
+    };
+
+    // No lint
+    let _ab = match x {
+        Some(0) => false,
+        _ => true,
+        None => false,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
new file mode 100644 (file)
index 0000000..4668f85
--- /dev/null
@@ -0,0 +1,52 @@
+error: match expression looks like `matches!` macro
+  --> $DIR/match_expr_like_matches_macro.rs:10:14
+   |
+LL |       let _y = match x {
+   |  ______________^
+LL | |         Some(0) => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `matches!(x, Some(0))`
+   |
+   = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
+
+error: match expression looks like `matches!` macro
+  --> $DIR/match_expr_like_matches_macro.rs:16:14
+   |
+LL |       let _w = match x {
+   |  ______________^
+LL | |         Some(_) => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `matches!(x, Some(_))`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/match_expr_like_matches_macro.rs:22:14
+   |
+LL |       let _z = match x {
+   |  ______________^
+LL | |         Some(_) => false,
+LL | |         None => true,
+LL | |     };
+   | |_____^ help: try this: `x.is_none()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: match expression looks like `matches!` macro
+  --> $DIR/match_expr_like_matches_macro.rs:28:15
+   |
+LL |       let _zz = match x {
+   |  _______________^
+LL | |         Some(r) if r == 0 => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `!matches!(x, Some(r) if r == 0)`
+
+error: if let .. else expression looks like `matches!` macro
+  --> $DIR/match_expr_like_matches_macro.rs:34:16
+   |
+LL |     let _zzz = if let Some(5) = x { true } else { false };
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))`
+
+error: aborting due to 5 previous errors
+
index 0b471195272473cdd4d971c8fb91cf9826f7dbe0..2d392c593b3e7e58cc2d160067f48eb43b1f7a1c 100644 (file)
@@ -4,7 +4,7 @@
 
 use std::cmp::Ordering;
 
-#[allow(clippy::unnested_or_patterns)]
+#[allow(clippy::unnested_or_patterns, clippy::match_like_matches_macro)]
 #[warn(clippy::neg_cmp_op_on_partial_ord)]
 fn main() {
     let a_value = 1.0;
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
new file mode 100644 (file)
index 0000000..695a460
--- /dev/null
@@ -0,0 +1,74 @@
+// run-rustfix
+#![warn(clippy::option_if_let_else)]
+
+fn bad1(string: Option<&str>) -> (bool, &str) {
+    string.map_or((false, "hello"), |x| (true, x))
+}
+
+fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
+    if string.is_none() {
+        None
+    } else { string.map_or(Some((false, "")), |x| Some((true, x))) }
+}
+
+fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
+    let _ = string.map_or(0, |s| s.len());
+    let _ = num.as_ref().map_or(&0, |s| s);
+    let _ = num.as_mut().map_or(&mut 0, |s| {
+        *s += 1;
+        s
+    });
+    let _ = num.as_ref().map_or(&0, |s| s);
+    let _ = num.map_or(0, |mut s| {
+        s += 1;
+        s
+    });
+    let _ = num.as_mut().map_or(&mut 0, |s| {
+        *s += 1;
+        s
+    });
+}
+
+fn longer_body(arg: Option<u32>) -> u32 {
+    arg.map_or(13, |x| {
+        let y = x * x;
+        y * y
+    })
+}
+
+fn test_map_or_else(arg: Option<u32>) {
+    let _ = arg.map_or_else(|| {
+        let mut y = 1;
+        y = (y + 2 / y) / 2;
+        y = (y + 2 / y) / 2;
+        y
+    }, |x| x * x * x * x);
+}
+
+fn negative_tests(arg: Option<u32>) -> u32 {
+    let _ = if let Some(13) = arg { "unlucky" } else { "lucky" };
+    for _ in 0..10 {
+        let _ = if let Some(x) = arg {
+            x
+        } else {
+            continue;
+        };
+    }
+    let _ = if let Some(x) = arg {
+        return x;
+    } else {
+        5
+    };
+    7
+}
+
+fn main() {
+    let optional = Some(5);
+    let _ = optional.map_or(5, |x| x + 2);
+    let _ = bad1(None);
+    let _ = else_if_option(None);
+    unop_bad(&None, None);
+    let _ = longer_body(None);
+    test_map_or_else(None);
+    let _ = negative_tests(None);
+}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
new file mode 100644 (file)
index 0000000..dee80d2
--- /dev/null
@@ -0,0 +1,92 @@
+// run-rustfix
+#![warn(clippy::option_if_let_else)]
+
+fn bad1(string: Option<&str>) -> (bool, &str) {
+    if let Some(x) = string {
+        (true, x)
+    } else {
+        (false, "hello")
+    }
+}
+
+fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
+    if string.is_none() {
+        None
+    } else if let Some(x) = string {
+        Some((true, x))
+    } else {
+        Some((false, ""))
+    }
+}
+
+fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
+    let _ = if let Some(s) = *string { s.len() } else { 0 };
+    let _ = if let Some(s) = &num { s } else { &0 };
+    let _ = if let Some(s) = &mut num {
+        *s += 1;
+        s
+    } else {
+        &mut 0
+    };
+    let _ = if let Some(ref s) = num { s } else { &0 };
+    let _ = if let Some(mut s) = num {
+        s += 1;
+        s
+    } else {
+        0
+    };
+    let _ = if let Some(ref mut s) = num {
+        *s += 1;
+        s
+    } else {
+        &mut 0
+    };
+}
+
+fn longer_body(arg: Option<u32>) -> u32 {
+    if let Some(x) = arg {
+        let y = x * x;
+        y * y
+    } else {
+        13
+    }
+}
+
+fn test_map_or_else(arg: Option<u32>) {
+    let _ = if let Some(x) = arg {
+        x * x * x * x
+    } else {
+        let mut y = 1;
+        y = (y + 2 / y) / 2;
+        y = (y + 2 / y) / 2;
+        y
+    };
+}
+
+fn negative_tests(arg: Option<u32>) -> u32 {
+    let _ = if let Some(13) = arg { "unlucky" } else { "lucky" };
+    for _ in 0..10 {
+        let _ = if let Some(x) = arg {
+            x
+        } else {
+            continue;
+        };
+    }
+    let _ = if let Some(x) = arg {
+        return x;
+    } else {
+        5
+    };
+    7
+}
+
+fn main() {
+    let optional = Some(5);
+    let _ = if let Some(x) = optional { x + 2 } else { 5 };
+    let _ = bad1(None);
+    let _ = else_if_option(None);
+    unop_bad(&None, None);
+    let _ = longer_body(None);
+    test_map_or_else(None);
+    let _ = negative_tests(None);
+}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
new file mode 100644 (file)
index 0000000..7005850
--- /dev/null
@@ -0,0 +1,151 @@
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:5:5
+   |
+LL | /     if let Some(x) = string {
+LL | |         (true, x)
+LL | |     } else {
+LL | |         (false, "hello")
+LL | |     }
+   | |_____^ help: try: `string.map_or((false, "hello"), |x| (true, x))`
+   |
+   = note: `-D clippy::option-if-let-else` implied by `-D warnings`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:15:12
+   |
+LL |       } else if let Some(x) = string {
+   |  ____________^
+LL | |         Some((true, x))
+LL | |     } else {
+LL | |         Some((false, ""))
+LL | |     }
+   | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:23:13
+   |
+LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:24:13
+   |
+LL |     let _ = if let Some(s) = &num { s } else { &0 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:25:13
+   |
+LL |       let _ = if let Some(s) = &mut num {
+   |  _____________^
+LL | |         *s += 1;
+LL | |         s
+LL | |     } else {
+LL | |         &mut 0
+LL | |     };
+   | |_____^
+   |
+help: try
+   |
+LL |     let _ = num.as_mut().map_or(&mut 0, |s| {
+LL |         *s += 1;
+LL |         s
+LL |     });
+   |
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:31:13
+   |
+LL |     let _ = if let Some(ref s) = num { s } else { &0 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:32:13
+   |
+LL |       let _ = if let Some(mut s) = num {
+   |  _____________^
+LL | |         s += 1;
+LL | |         s
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^
+   |
+help: try
+   |
+LL |     let _ = num.map_or(0, |mut s| {
+LL |         s += 1;
+LL |         s
+LL |     });
+   |
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:38:13
+   |
+LL |       let _ = if let Some(ref mut s) = num {
+   |  _____________^
+LL | |         *s += 1;
+LL | |         s
+LL | |     } else {
+LL | |         &mut 0
+LL | |     };
+   | |_____^
+   |
+help: try
+   |
+LL |     let _ = num.as_mut().map_or(&mut 0, |s| {
+LL |         *s += 1;
+LL |         s
+LL |     });
+   |
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:47:5
+   |
+LL | /     if let Some(x) = arg {
+LL | |         let y = x * x;
+LL | |         y * y
+LL | |     } else {
+LL | |         13
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL |     arg.map_or(13, |x| {
+LL |         let y = x * x;
+LL |         y * y
+LL |     })
+   |
+
+error: use Option::map_or_else instead of an if let/else
+  --> $DIR/option_if_let_else.rs:56:13
+   |
+LL |       let _ = if let Some(x) = arg {
+   |  _____________^
+LL | |         x * x * x * x
+LL | |     } else {
+LL | |         let mut y = 1;
+...  |
+LL | |         y
+LL | |     };
+   | |_____^
+   |
+help: try
+   |
+LL |     let _ = arg.map_or_else(|| {
+LL |         let mut y = 1;
+LL |         y = (y + 2 / y) / 2;
+LL |         y = (y + 2 / y) / 2;
+LL |         y
+LL |     }, |x| x * x * x * x);
+   |
+
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:85:13
+   |
+LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs
new file mode 100644 (file)
index 0000000..9b4f2f1
--- /dev/null
@@ -0,0 +1,40 @@
+#![allow(clippy::all)]
+#![warn(clippy::pattern_type_mismatch)]
+
+fn main() {}
+
+fn should_lint() {
+    let value = &Some(23);
+    match value {
+        Some(_) => (),
+        _ => (),
+    }
+
+    let value = &mut Some(23);
+    match value {
+        Some(_) => (),
+        _ => (),
+    }
+}
+
+fn should_not_lint() {
+    let value = &Some(23);
+    match value {
+        &Some(_) => (),
+        _ => (),
+    }
+    match *value {
+        Some(_) => (),
+        _ => (),
+    }
+
+    let value = &mut Some(23);
+    match value {
+        &mut Some(_) => (),
+        _ => (),
+    }
+    match *value {
+        Some(_) => (),
+        _ => (),
+    }
+}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr
new file mode 100644 (file)
index 0000000..3421d56
--- /dev/null
@@ -0,0 +1,19 @@
+error: type of pattern does not match the expression type
+  --> $DIR/mutability.rs:9:9
+   |
+LL |         Some(_) => (),
+   |         ^^^^^^^
+   |
+   = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/mutability.rs:15:9
+   |
+LL |         Some(_) => (),
+   |         ^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&mut _` pattern and adjust the enclosed variable bindings
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs
new file mode 100644 (file)
index 0000000..065ea9f
--- /dev/null
@@ -0,0 +1,24 @@
+#![allow(clippy::all)]
+#![warn(clippy::pattern_type_mismatch)]
+
+fn main() {}
+
+fn alternatives() {
+    enum Value<'a> {
+        Unused,
+        A(&'a Option<i32>),
+        B,
+    }
+    let ref_value = &Value::A(&Some(23));
+
+    // not ok
+    if let Value::B | Value::A(_) = ref_value {}
+    if let &Value::B | &Value::A(Some(_)) = ref_value {}
+    if let Value::B | Value::A(Some(_)) = *ref_value {}
+
+    // ok
+    if let &Value::B | &Value::A(_) = ref_value {}
+    if let Value::B | Value::A(_) = *ref_value {}
+    if let &Value::B | &Value::A(&Some(_)) = ref_value {}
+    if let Value::B | Value::A(&Some(_)) = *ref_value {}
+}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr
new file mode 100644 (file)
index 0000000..d285c93
--- /dev/null
@@ -0,0 +1,27 @@
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_alternatives.rs:15:12
+   |
+LL |     if let Value::B | Value::A(_) = ref_value {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_alternatives.rs:16:34
+   |
+LL |     if let &Value::B | &Value::A(Some(_)) = ref_value {}
+   |                                  ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_alternatives.rs:17:32
+   |
+LL |     if let Value::B | Value::A(Some(_)) = *ref_value {}
+   |                                ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs
new file mode 100644 (file)
index 0000000..417b1c1
--- /dev/null
@@ -0,0 +1,45 @@
+#![allow(clippy::all)]
+#![warn(clippy::pattern_type_mismatch)]
+
+fn main() {}
+
+fn struct_types() {
+    struct Struct<'a> {
+        ref_inner: &'a Option<i32>,
+    }
+    let ref_value = &Struct { ref_inner: &Some(42) };
+
+    // not ok
+    let Struct { .. } = ref_value;
+    if let &Struct { ref_inner: Some(_) } = ref_value {}
+    if let Struct { ref_inner: Some(_) } = *ref_value {}
+
+    // ok
+    let &Struct { .. } = ref_value;
+    let Struct { .. } = *ref_value;
+    if let &Struct { ref_inner: &Some(_) } = ref_value {}
+    if let Struct { ref_inner: &Some(_) } = *ref_value {}
+}
+
+fn struct_enum_variants() {
+    enum StructEnum<'a> {
+        Empty,
+        Var { inner_ref: &'a Option<i32> },
+    }
+    let ref_value = &StructEnum::Var { inner_ref: &Some(42) };
+
+    // not ok
+    if let StructEnum::Var { .. } = ref_value {}
+    if let StructEnum::Var { inner_ref: Some(_) } = ref_value {}
+    if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {}
+    if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {}
+    if let StructEnum::Empty = ref_value {}
+
+    // ok
+    if let &StructEnum::Var { .. } = ref_value {}
+    if let StructEnum::Var { .. } = *ref_value {}
+    if let &StructEnum::Var { inner_ref: &Some(_) } = ref_value {}
+    if let StructEnum::Var { inner_ref: &Some(_) } = *ref_value {}
+    if let &StructEnum::Empty = ref_value {}
+    if let StructEnum::Empty = *ref_value {}
+}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr
new file mode 100644 (file)
index 0000000..d428e85
--- /dev/null
@@ -0,0 +1,67 @@
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:13:9
+   |
+LL |     let Struct { .. } = ref_value;
+   |         ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:14:33
+   |
+LL |     if let &Struct { ref_inner: Some(_) } = ref_value {}
+   |                                 ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:15:32
+   |
+LL |     if let Struct { ref_inner: Some(_) } = *ref_value {}
+   |                                ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:32:12
+   |
+LL |     if let StructEnum::Var { .. } = ref_value {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:33:12
+   |
+LL |     if let StructEnum::Var { inner_ref: Some(_) } = ref_value {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:34:42
+   |
+LL |     if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {}
+   |                                          ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:35:41
+   |
+LL |     if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {}
+   |                                         ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_structs.rs:36:12
+   |
+LL |     if let StructEnum::Empty = ref_value {}
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs
new file mode 100644 (file)
index 0000000..19504a0
--- /dev/null
@@ -0,0 +1,57 @@
+#![allow(clippy::all)]
+#![warn(clippy::pattern_type_mismatch)]
+
+fn main() {}
+
+fn tuple_types() {
+    struct TupleStruct<'a>(&'a Option<i32>);
+    let ref_value = &TupleStruct(&Some(42));
+
+    // not ok
+    let TupleStruct(_) = ref_value;
+    if let &TupleStruct(Some(_)) = ref_value {}
+    if let TupleStruct(Some(_)) = *ref_value {}
+
+    // ok
+    let &TupleStruct(_) = ref_value;
+    let TupleStruct(_) = *ref_value;
+    if let &TupleStruct(&Some(_)) = ref_value {}
+    if let TupleStruct(&Some(_)) = *ref_value {}
+}
+
+fn tuple_enum_variants() {
+    enum TupleEnum<'a> {
+        Empty,
+        Var(&'a Option<i32>),
+    }
+    let ref_value = &TupleEnum::Var(&Some(42));
+
+    // not ok
+    if let TupleEnum::Var(_) = ref_value {}
+    if let &TupleEnum::Var(Some(_)) = ref_value {}
+    if let TupleEnum::Var(Some(_)) = *ref_value {}
+    if let TupleEnum::Empty = ref_value {}
+
+    // ok
+    if let &TupleEnum::Var(_) = ref_value {}
+    if let TupleEnum::Var(_) = *ref_value {}
+    if let &TupleEnum::Var(&Some(_)) = ref_value {}
+    if let TupleEnum::Var(&Some(_)) = *ref_value {}
+    if let &TupleEnum::Empty = ref_value {}
+    if let TupleEnum::Empty = *ref_value {}
+}
+
+fn plain_tuples() {
+    let ref_value = &(&Some(23), &Some(42));
+
+    // not ok
+    let (_a, _b) = ref_value;
+    if let &(_a, Some(_)) = ref_value {}
+    if let (_a, Some(_)) = *ref_value {}
+
+    // ok
+    let &(_a, _b) = ref_value;
+    let (_a, _b) = *ref_value;
+    if let &(_a, &Some(_)) = ref_value {}
+    if let (_a, &Some(_)) = *ref_value {}
+}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr
new file mode 100644 (file)
index 0000000..edd0074
--- /dev/null
@@ -0,0 +1,83 @@
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:11:9
+   |
+LL |     let TupleStruct(_) = ref_value;
+   |         ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:12:25
+   |
+LL |     if let &TupleStruct(Some(_)) = ref_value {}
+   |                         ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:13:24
+   |
+LL |     if let TupleStruct(Some(_)) = *ref_value {}
+   |                        ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:30:12
+   |
+LL |     if let TupleEnum::Var(_) = ref_value {}
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:31:28
+   |
+LL |     if let &TupleEnum::Var(Some(_)) = ref_value {}
+   |                            ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:32:27
+   |
+LL |     if let TupleEnum::Var(Some(_)) = *ref_value {}
+   |                           ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:33:12
+   |
+LL |     if let TupleEnum::Empty = ref_value {}
+   |            ^^^^^^^^^^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:48:9
+   |
+LL |     let (_a, _b) = ref_value;
+   |         ^^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:49:18
+   |
+LL |     if let &(_a, Some(_)) = ref_value {}
+   |                  ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/pattern_tuples.rs:50:17
+   |
+LL |     if let (_a, Some(_)) = *ref_value {}
+   |                 ^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs
new file mode 100644 (file)
index 0000000..e89917c
--- /dev/null
@@ -0,0 +1,146 @@
+#![allow(clippy::all)]
+#![warn(clippy::pattern_type_mismatch)]
+
+fn main() {}
+
+fn syntax_match() {
+    let ref_value = &Some(&Some(42));
+
+    // not ok
+    match ref_value {
+        Some(_) => (),
+        None => (),
+    }
+
+    // ok
+    match ref_value {
+        &Some(_) => (),
+        &None => (),
+    }
+    match *ref_value {
+        Some(_) => (),
+        None => (),
+    }
+}
+
+fn syntax_if_let() {
+    let ref_value = &Some(42);
+
+    // not ok
+    if let Some(_) = ref_value {}
+
+    // ok
+    if let &Some(_) = ref_value {}
+    if let Some(_) = *ref_value {}
+}
+
+fn syntax_while_let() {
+    let ref_value = &Some(42);
+
+    // not ok
+    while let Some(_) = ref_value {
+        break;
+    }
+
+    // ok
+    while let &Some(_) = ref_value {
+        break;
+    }
+    while let Some(_) = *ref_value {
+        break;
+    }
+}
+
+fn syntax_for() {
+    let ref_value = &Some(23);
+    let slice = &[(2, 3), (4, 2)];
+
+    // not ok
+    for (_a, _b) in slice.iter() {}
+
+    // ok
+    for &(_a, _b) in slice.iter() {}
+}
+
+fn syntax_let() {
+    let ref_value = &(2, 3);
+
+    // not ok
+    let (_n, _m) = ref_value;
+
+    // ok
+    let &(_n, _m) = ref_value;
+    let (_n, _m) = *ref_value;
+}
+
+fn syntax_fn() {
+    // not ok
+    fn foo((_a, _b): &(i32, i32)) {}
+
+    // ok
+    fn foo_ok_1(&(_a, _b): &(i32, i32)) {}
+}
+
+fn syntax_closure() {
+    fn foo<F>(f: F)
+    where
+        F: FnOnce(&(i32, i32)),
+    {
+    }
+
+    // not ok
+    foo(|(_a, _b)| ());
+
+    // ok
+    foo(|&(_a, _b)| ());
+}
+
+fn macro_with_expression() {
+    macro_rules! matching_macro {
+        ($e:expr) => {
+            $e
+        };
+    }
+    let value = &Some(23);
+
+    // not ok
+    matching_macro!(match value {
+        Some(_) => (),
+        _ => (),
+    });
+
+    // ok
+    matching_macro!(match value {
+        &Some(_) => (),
+        _ => (),
+    });
+    matching_macro!(match *value {
+        Some(_) => (),
+        _ => (),
+    });
+}
+
+fn macro_expansion() {
+    macro_rules! matching_macro {
+        ($e:expr) => {
+            // not ok
+            match $e {
+                Some(_) => (),
+                _ => (),
+            }
+
+            // ok
+            match $e {
+                &Some(_) => (),
+                _ => (),
+            }
+            match *$e {
+                Some(_) => (),
+                _ => (),
+            }
+        };
+    }
+
+    let value = &Some(23);
+    matching_macro!(value);
+}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr
new file mode 100644 (file)
index 0000000..5a5186b
--- /dev/null
@@ -0,0 +1,79 @@
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:11:9
+   |
+LL |         Some(_) => (),
+   |         ^^^^^^^
+   |
+   = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:30:12
+   |
+LL |     if let Some(_) = ref_value {}
+   |            ^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:41:15
+   |
+LL |     while let Some(_) = ref_value {
+   |               ^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:59:9
+   |
+LL |     for (_a, _b) in slice.iter() {}
+   |         ^^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:69:9
+   |
+LL |     let (_n, _m) = ref_value;
+   |         ^^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:78:12
+   |
+LL |     fn foo((_a, _b): &(i32, i32)) {}
+   |            ^^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:92:10
+   |
+LL |     foo(|(_a, _b)| ());
+   |          ^^^^^^^^
+   |
+   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:108:9
+   |
+LL |         Some(_) => (),
+   |         ^^^^^^^
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+
+error: type of pattern does not match the expression type
+  --> $DIR/syntax.rs:128:17
+   |
+LL |                 Some(_) => (),
+   |                 ^^^^^^^
+...
+LL |     matching_macro!(value);
+   |     ----------------------- in this macro invocation
+   |
+   = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 9 previous errors
+
index 6b40211409974089e974b5e7b6ee6ce71c229a69..19b253b0fe2c6b94c1c43c9cfd4e736b438967b5 100644 (file)
@@ -7,6 +7,7 @@ fn f() -> usize {
 }
 
 #[warn(clippy::range_plus_one)]
+#[warn(clippy::range_minus_one)]
 fn main() {
     for _ in 0..2 {}
     for _ in 0..=2 {}
index 3cfed4125b35c7434dda2950b72e243cbed6e2d5..7d034117547caf87990d1c824b99b872471eefe8 100644 (file)
@@ -7,6 +7,7 @@ fn f() -> usize {
 }
 
 #[warn(clippy::range_plus_one)]
+#[warn(clippy::range_minus_one)]
 fn main() {
     for _ in 0..2 {}
     for _ in 0..=2 {}
index f72943a04f252af9b471324f225ed12a3d79fd4d..fb4f1658597a585de8f220e9255e0f5c57388ad5 100644 (file)
@@ -1,5 +1,5 @@
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:14:14
+  --> $DIR/range_plus_minus_one.rs:15:14
    |
 LL |     for _ in 0..3 + 1 {}
    |              ^^^^^^^^ help: use: `0..=3`
@@ -7,25 +7,25 @@ LL |     for _ in 0..3 + 1 {}
    = note: `-D clippy::range-plus-one` implied by `-D warnings`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:17:14
+  --> $DIR/range_plus_minus_one.rs:18:14
    |
 LL |     for _ in 0..1 + 5 {}
    |              ^^^^^^^^ help: use: `0..=5`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:20:14
+  --> $DIR/range_plus_minus_one.rs:21:14
    |
 LL |     for _ in 1..1 + 1 {}
    |              ^^^^^^^^ help: use: `1..=1`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:26:14
+  --> $DIR/range_plus_minus_one.rs:27:14
    |
 LL |     for _ in 0..(1 + f()) {}
    |              ^^^^^^^^^^^^ help: use: `0..=f()`
 
 error: an exclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:30:13
+  --> $DIR/range_plus_minus_one.rs:31:13
    |
 LL |     let _ = ..=11 - 1;
    |             ^^^^^^^^^ help: use: `..11`
@@ -33,25 +33,25 @@ LL |     let _ = ..=11 - 1;
    = note: `-D clippy::range-minus-one` implied by `-D warnings`
 
 error: an exclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:31:13
+  --> $DIR/range_plus_minus_one.rs:32:13
    |
 LL |     let _ = ..=(11 - 1);
    |             ^^^^^^^^^^^ help: use: `..11`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:32:13
+  --> $DIR/range_plus_minus_one.rs:33:13
    |
 LL |     let _ = (1..11 + 1);
    |             ^^^^^^^^^^^ help: use: `(1..=11)`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:33:13
+  --> $DIR/range_plus_minus_one.rs:34:13
    |
 LL |     let _ = (f() + 1)..(f() + 1);
    |             ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:37:14
+  --> $DIR/range_plus_minus_one.rs:38:14
    |
 LL |     for _ in 1..ONE + ONE {}
    |              ^^^^^^^^^^^^ help: use: `1..=ONE`
index 8b4e2d21331cd9e6ca0ff31fa88601ac8c7d3148..ce8582d2b221cd21c891bfd38af0d20bfd073ec4 100644 (file)
@@ -2,7 +2,13 @@
 
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
+#![allow(
+    clippy::unit_arg,
+    unused_must_use,
+    clippy::needless_bool,
+    clippy::match_like_matches_macro,
+    deprecated
+)]
 
 fn main() {
     if Ok::<i32, i32>(42).is_ok() {}
index b0904e41b6f43d976137e46fd8205e55e779dcd9..a3a9aa40e3b9c8ec7fd2b7a708c34bf5d93377ab 100644 (file)
@@ -2,7 +2,13 @@
 
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
+#![allow(
+    clippy::unit_arg,
+    unused_must_use,
+    clippy::needless_bool,
+    clippy::match_like_matches_macro,
+    deprecated
+)]
 
 fn main() {
     if let Ok(_) = Ok::<i32, i32>(42) {}
index 51a6f4350d32c3f4daaf15fdcd0b95034dabb029..25d1476062e7f599e7fe37dfddab9c1ce80bc1c0 100644 (file)
@@ -1,5 +1,5 @@
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:8:12
+  --> $DIR/redundant_pattern_matching.rs:14:12
    |
 LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
@@ -7,67 +7,67 @@ LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:10:12
+  --> $DIR/redundant_pattern_matching.rs:16:12
    |
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:12:12
+  --> $DIR/redundant_pattern_matching.rs:18:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:14:12
+  --> $DIR/redundant_pattern_matching.rs:20:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:16:12
+  --> $DIR/redundant_pattern_matching.rs:22:12
    |
 LL |     if let Some(_) = Some(42) {
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:22:15
+  --> $DIR/redundant_pattern_matching.rs:28:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:24:15
+  --> $DIR/redundant_pattern_matching.rs:30:15
    |
 LL |     while let None = Some(42) {}
    |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:26:15
+  --> $DIR/redundant_pattern_matching.rs:32:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:28:15
+  --> $DIR/redundant_pattern_matching.rs:34:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:30:15
+  --> $DIR/redundant_pattern_matching.rs:36:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:33:15
+  --> $DIR/redundant_pattern_matching.rs:39:15
    |
 LL |     while let Some(_) = v.pop() {
    |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:49:5
+  --> $DIR/redundant_pattern_matching.rs:55:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -76,7 +76,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:54:5
+  --> $DIR/redundant_pattern_matching.rs:60:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -85,7 +85,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:59:5
+  --> $DIR/redundant_pattern_matching.rs:65:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -94,7 +94,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:64:5
+  --> $DIR/redundant_pattern_matching.rs:70:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -103,7 +103,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:69:5
+  --> $DIR/redundant_pattern_matching.rs:75:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -112,7 +112,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:74:5
+  --> $DIR/redundant_pattern_matching.rs:80:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -121,7 +121,7 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:79:13
+  --> $DIR/redundant_pattern_matching.rs:85:13
    |
 LL |       let _ = match None::<()> {
    |  _____________^
@@ -131,61 +131,61 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:84:20
+  --> $DIR/redundant_pattern_matching.rs:90:20
    |
 LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
    |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:87:20
+  --> $DIR/redundant_pattern_matching.rs:93:20
    |
 LL |     let x = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:93:20
+  --> $DIR/redundant_pattern_matching.rs:99:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:95:19
+  --> $DIR/redundant_pattern_matching.rs:101:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:97:19
+  --> $DIR/redundant_pattern_matching.rs:103:19
    |
 LL |     } else if let Ok(_) = gen_res() {
    |            -------^^^^^------------ help: try this: `if gen_res().is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:99:19
+  --> $DIR/redundant_pattern_matching.rs:105:19
    |
 LL |     } else if let Err(_) = gen_res() {
    |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:132:19
+  --> $DIR/redundant_pattern_matching.rs:138:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
    |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:133:16
+  --> $DIR/redundant_pattern_matching.rs:139:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
    |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:139:12
+  --> $DIR/redundant_pattern_matching.rs:145:12
    |
 LL |     if let Some(_) = m!() {}
    |     -------^^^^^^^------- help: try this: `if m!().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:140:15
+  --> $DIR/redundant_pattern_matching.rs:146:15
    |
 LL |     while let Some(_) = m!() {}
    |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
index 8a81e92f04a7321f7e579fbafbad134a6be7c49b..de3fe00d5fa689b81591706e9acd4693f1073053 100644 (file)
@@ -2,7 +2,7 @@
 
 #![feature(const_result)]
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(unused)]
+#![allow(clippy::match_like_matches_macro, unused)]
 
 // Test that results are linted with the feature enabled.
 
index 1cd515441d13a5e1f6c6989f2631510fb8a69cbe..b77969d53d92df3def12d657c545d7c62e5ee39d 100644 (file)
@@ -2,7 +2,7 @@
 
 #![feature(const_result)]
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(unused)]
+#![allow(clippy::match_like_matches_macro, unused)]
 
 // Test that results are linted with the feature enabled.
 
index b523fa5b711ae68e611aa3580ea59e9ccc2a7dc9..9767e5bf76a85ca7953b01ee53068b67925b282a 100644 (file)
@@ -1,5 +1,5 @@
 #![allow(unused)]
-#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_macro)]
+#![warn(clippy::invalid_regex, clippy::trivial_regex)]
 
 extern crate regex;
 
diff --git a/src/tools/clippy/tests/ui/repeat_once.fixed b/src/tools/clippy/tests/ui/repeat_once.fixed
new file mode 100644 (file)
index 0000000..a637c22
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+#![warn(clippy::repeat_once)]
+#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
+fn main() {
+    const N: usize = 1;
+    let s = "str";
+    let string = "String".to_string();
+    let slice = [1; 5];
+
+    let a = [1; 5].to_vec();
+    let b = slice.to_vec();
+    let c = "hello".to_string();
+    let d = "hi".to_string();
+    let e = s.to_string();
+    let f = string.clone();
+}
diff --git a/src/tools/clippy/tests/ui/repeat_once.rs b/src/tools/clippy/tests/ui/repeat_once.rs
new file mode 100644 (file)
index 0000000..d99ca1b
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+#![warn(clippy::repeat_once)]
+#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
+fn main() {
+    const N: usize = 1;
+    let s = "str";
+    let string = "String".to_string();
+    let slice = [1; 5];
+
+    let a = [1; 5].repeat(1);
+    let b = slice.repeat(1);
+    let c = "hello".repeat(N);
+    let d = "hi".repeat(1);
+    let e = s.repeat(1);
+    let f = string.repeat(1);
+}
diff --git a/src/tools/clippy/tests/ui/repeat_once.stderr b/src/tools/clippy/tests/ui/repeat_once.stderr
new file mode 100644 (file)
index 0000000..915eea3
--- /dev/null
@@ -0,0 +1,40 @@
+error: calling `repeat(1)` on slice
+  --> $DIR/repeat_once.rs:10:13
+   |
+LL |     let a = [1; 5].repeat(1);
+   |             ^^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `[1; 5].to_vec()`
+   |
+   = note: `-D clippy::repeat-once` implied by `-D warnings`
+
+error: calling `repeat(1)` on slice
+  --> $DIR/repeat_once.rs:11:13
+   |
+LL |     let b = slice.repeat(1);
+   |             ^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `slice.to_vec()`
+
+error: calling `repeat(1)` on str
+  --> $DIR/repeat_once.rs:12:13
+   |
+LL |     let c = "hello".repeat(N);
+   |             ^^^^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hello".to_string()`
+
+error: calling `repeat(1)` on str
+  --> $DIR/repeat_once.rs:13:13
+   |
+LL |     let d = "hi".repeat(1);
+   |             ^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hi".to_string()`
+
+error: calling `repeat(1)` on str
+  --> $DIR/repeat_once.rs:14:13
+   |
+LL |     let e = s.repeat(1);
+   |             ^^^^^^^^^^^ help: consider using `.to_string()` instead: `s.to_string()`
+
+error: calling `repeat(1)` on a string literal
+  --> $DIR/repeat_once.rs:15:13
+   |
+LL |     let f = string.repeat(1);
+   |             ^^^^^^^^^^^^^^^^ help: consider using `.clone()` instead: `string.clone()`
+
+error: aborting due to 6 previous errors
+
index 34193be0b75e40b978ae7661c3ab944fe1fd5b90..b624a41a29b2da10375b212d321afbabac572c6a 100644 (file)
@@ -1,4 +1,6 @@
 #![warn(clippy::single_match_else)]
+#![allow(clippy::needless_return)]
+#![allow(clippy::no_effect)]
 
 enum ExprNode {
     ExprAddrOf,
@@ -30,6 +32,55 @@ macro_rules! unwrap_addr {
     };
 }
 
+#[rustfmt::skip]
 fn main() {
     unwrap_addr!(ExprNode::Unicorns);
+
+    //
+    // don't lint single exprs/statements
+    //
+
+    // don't lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => return,
+    }
+
+    // don't lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => {
+            return
+        },
+    }
+
+    // don't lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => {
+            return;
+        },
+    }
+
+    //
+    // lint multiple exprs/statements "else" blocks
+    //
+
+    // lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => {
+            println!("else block");
+            return
+        },
+    }
+
+    // lint here
+    match Some(1) {
+        Some(a) => println!("${:?}", a),
+        None => {
+            println!("else block");
+            return;
+        },
+    }
 }
index 59861d46eb34cf5383bec85151672e023308e719..3a07c2ec5426278848e9b2e5e3910ea03a01ba31 100644 (file)
@@ -1,5 +1,5 @@
 error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match_else.rs:12:5
+  --> $DIR/single_match_else.rs:14:5
    |
 LL | /     match ExprNode::Butterflies {
 LL | |         ExprNode::ExprAddrOf => Some(&NODE),
@@ -19,5 +19,45 @@ LL |         None
 LL |     }
    |
 
-error: aborting due to previous error
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:70:5
+   |
+LL | /     match Some(1) {
+LL | |         Some(a) => println!("${:?}", a),
+LL | |         None => {
+LL | |             println!("else block");
+LL | |             return
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL |     if let Some(a) = Some(1) { println!("${:?}", a) } else {
+LL |         println!("else block");
+LL |         return
+LL |     }
+   |
+
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:79:5
+   |
+LL | /     match Some(1) {
+LL | |         Some(a) => println!("${:?}", a),
+LL | |         None => {
+LL | |             println!("else block");
+LL | |             return;
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+help: try this
+   |
+LL |     if let Some(a) = Some(1) { println!("${:?}", a) } else {
+LL |         println!("else block");
+LL |         return;
+LL |     }
+   |
+
+error: aborting due to 3 previous errors
 
index 8b538be762b0c3bb9821171388e33c85c99f1fea..766190f209977fcec1a70bd9f5ae9a4ec467c603 100644 (file)
@@ -1,4 +1,6 @@
-#[deny(clippy::type_repetition_in_bounds)]
+#![deny(clippy::type_repetition_in_bounds)]
+
+use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
 
 pub fn foo<T>(_t: T)
 where
@@ -16,4 +18,55 @@ pub fn bar<T, U>(_t: T, _u: U)
     unimplemented!();
 }
 
+// Threshold test (see #4380)
+trait LintBounds
+where
+    Self: Clone,
+    Self: Copy + Default + Ord,
+    Self: Add<Output = Self> + AddAssign + Sub<Output = Self> + SubAssign,
+    Self: Mul<Output = Self> + MulAssign + Div<Output = Self> + DivAssign,
+{
+}
+
+trait LotsOfBounds
+where
+    Self: Clone + Copy + Default + Ord,
+    Self: Add<Output = Self> + AddAssign + Sub<Output = Self> + SubAssign,
+    Self: Mul<Output = Self> + MulAssign + Div<Output = Self> + DivAssign,
+{
+}
+
+// Generic distinction (see #4323)
+mod issue4323 {
+    pub struct Foo<A>(A);
+    pub struct Bar<A, B> {
+        a: Foo<A>,
+        b: Foo<B>,
+    }
+
+    impl<A, B> Unpin for Bar<A, B>
+    where
+        Foo<A>: Unpin,
+        Foo<B>: Unpin,
+    {
+    }
+}
+
+// Extern macros shouldn't lint (see #4326)
+extern crate serde;
+mod issue4326 {
+    use serde::{Deserialize, Serialize};
+
+    trait Foo {}
+    impl Foo for String {}
+
+    #[derive(Debug, Serialize, Deserialize)]
+    struct Bar<S>
+    where
+        S: Foo,
+    {
+        foo: S,
+    }
+}
+
 fn main() {}
index 4264e2e10bf17ebe8978e02132323f502ab0d2e9..148c19c7d0701dc2910de718d175a03122d26e03 100644 (file)
@@ -1,15 +1,23 @@
 error: this type has already been used as a bound predicate
-  --> $DIR/type_repetition_in_bounds.rs:6:5
+  --> $DIR/type_repetition_in_bounds.rs:8:5
    |
 LL |     T: Clone,
    |     ^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/type_repetition_in_bounds.rs:1:8
+  --> $DIR/type_repetition_in_bounds.rs:1:9
    |
-LL | #[deny(clippy::type_repetition_in_bounds)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(clippy::type_repetition_in_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: consider combining the bounds: `T: Copy + Clone`
 
-error: aborting due to previous error
+error: this type has already been used as a bound predicate
+  --> $DIR/type_repetition_in_bounds.rs:25:5
+   |
+LL |     Self: Copy + Default + Ord,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord`
+
+error: aborting due to 2 previous errors
 
index f1cc5b564c1dca66329e21bf9b3c02cc22c7ce4d..2c9d4d39e6c7d9e7d18c8c7daf59fbe075b18b32 100644 (file)
@@ -13,31 +13,6 @@ impl SomeTrait for SomeImpl {}
 
 fn main() {}
 
-fn is_ascii(ch: char) -> bool {
-    ch.is_ascii()
-}
-
-fn clone_on_copy() {
-    42.clone();
-
-    vec![1].clone(); // ok, not a Copy type
-    Some(vec![1]).clone(); // ok, not a Copy type
-    (&42).clone();
-
-    let rc = RefCell::new(0);
-    rc.borrow().clone();
-
-    // Issue #4348
-    let mut x = 43;
-    let _ = &x.clone(); // ok, getting a ref
-    'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
-    is_ascii('z'.clone());
-
-    // Issue #5436
-    let mut vec = Vec::new();
-    vec.push(42.clone());
-}
-
 fn clone_on_ref_ptr() {
     let rc = Rc::new(true);
     let arc = Arc::new(true);
index 6176a2bc4647987a44a5a60c0197dd50c83c2e2d..113fab6900954c891b2610517dd728148aa3994b 100644 (file)
@@ -1,37 +1,5 @@
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:21:5
-   |
-LL |     42.clone();
-   |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
-   |
-   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:25:5
-   |
-LL |     (&42).clone();
-   |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:28:5
-   |
-LL |     rc.borrow().clone();
-   |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:34:14
-   |
-LL |     is_ascii('z'.clone());
-   |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:38:14
-   |
-LL |     vec.push(42.clone());
-   |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
-
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:48:5
+  --> $DIR/unnecessary_clone.rs:23:5
    |
 LL |     rc.clone();
    |     ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)`
@@ -39,43 +7,45 @@ LL |     rc.clone();
    = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:51:5
+  --> $DIR/unnecessary_clone.rs:26:5
    |
 LL |     arc.clone();
    |     ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:54:5
+  --> $DIR/unnecessary_clone.rs:29:5
    |
 LL |     rcweak.clone();
    |     ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:57:5
+  --> $DIR/unnecessary_clone.rs:32:5
    |
 LL |     arc_weak.clone();
    |     ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:61:33
+  --> $DIR/unnecessary_clone.rs:36:33
    |
 LL |     let _: Arc<dyn SomeTrait> = x.clone();
    |                                 ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)`
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:65:5
+  --> $DIR/unnecessary_clone.rs:40:5
    |
 LL |     t.clone();
    |     ^^^^^^^^^ help: try removing the `clone` call: `t`
+   |
+   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:67:5
+  --> $DIR/unnecessary_clone.rs:42:5
    |
 LL |     Some(t).clone();
    |     ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
 
 error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
-  --> $DIR/unnecessary_clone.rs:73:22
+  --> $DIR/unnecessary_clone.rs:48:22
    |
 LL |     let z: &Vec<_> = y.clone();
    |                      ^^^^^^^^^
@@ -91,13 +61,13 @@ LL |     let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:109:20
+  --> $DIR/unnecessary_clone.rs:84:20
    |
 LL |         let _: E = a.clone();
    |                    ^^^^^^^^^ help: try dereferencing it: `*****a`
 
 error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
-  --> $DIR/unnecessary_clone.rs:114:22
+  --> $DIR/unnecessary_clone.rs:89:22
    |
 LL |         let _ = &mut encoded.clone();
    |                      ^^^^^^^^^^^^^^^
@@ -112,7 +82,7 @@ LL |         let _ = &mut <&[u8]>::clone(encoded);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
-  --> $DIR/unnecessary_clone.rs:115:18
+  --> $DIR/unnecessary_clone.rs:90:18
    |
 LL |         let _ = &encoded.clone();
    |                  ^^^^^^^^^^^^^^^
@@ -126,5 +96,5 @@ help: or try being explicit if you are sure, that you want to clone a reference
 LL |         let _ = &<&[u8]>::clone(encoded);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 16 previous errors
+error: aborting due to 11 previous errors
 
index 779fd57707ad4f517e9ec9e6b235c728f5996008..c017d1cf9a468bc03ddc55829e277442dfe87734 100644 (file)
@@ -2,11 +2,11 @@
 
 use std::cmp::Reverse;
 
-fn id(x: isize) -> isize {
-    x
-}
+fn unnecessary_sort_by() {
+    fn id(x: isize) -> isize {
+        x
+    }
 
-fn main() {
     let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5];
     // Forward examples
     vec.sort();
@@ -24,3 +24,41 @@ fn main() {
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
 }
+
+// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
+mod issue_5754 {
+    struct Test(String);
+
+    #[derive(PartialOrd, Ord, PartialEq, Eq)]
+    struct Wrapper<'a>(&'a str);
+
+    impl Test {
+        fn name(&self) -> &str {
+            &self.0
+        }
+
+        fn wrapped(&self) -> Wrapper<'_> {
+            Wrapper(&self.0)
+        }
+    }
+
+    pub fn test() {
+        let mut args: Vec<Test> = vec![];
+
+        // Forward
+        args.sort_by(|a, b| a.name().cmp(b.name()));
+        args.sort_by(|a, b| a.wrapped().cmp(&b.wrapped()));
+        args.sort_unstable_by(|a, b| a.name().cmp(b.name()));
+        args.sort_unstable_by(|a, b| a.wrapped().cmp(&b.wrapped()));
+        // Reverse
+        args.sort_by(|a, b| b.name().cmp(a.name()));
+        args.sort_by(|a, b| b.wrapped().cmp(&a.wrapped()));
+        args.sort_unstable_by(|a, b| b.name().cmp(a.name()));
+        args.sort_unstable_by(|a, b| b.wrapped().cmp(&a.wrapped()));
+    }
+}
+
+fn main() {
+    unnecessary_sort_by();
+    issue_5754::test();
+}
index 0485a5630afef682c80e9729bbf2855c9d782b62..1929c72b2f2cd3737194c2c52eba6aaa309b3380 100644 (file)
@@ -2,11 +2,11 @@
 
 use std::cmp::Reverse;
 
-fn id(x: isize) -> isize {
-    x
-}
+fn unnecessary_sort_by() {
+    fn id(x: isize) -> isize {
+        x
+    }
 
-fn main() {
     let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5];
     // Forward examples
     vec.sort_by(|a, b| a.cmp(b));
@@ -24,3 +24,41 @@ fn main() {
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
 }
+
+// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162
+mod issue_5754 {
+    struct Test(String);
+
+    #[derive(PartialOrd, Ord, PartialEq, Eq)]
+    struct Wrapper<'a>(&'a str);
+
+    impl Test {
+        fn name(&self) -> &str {
+            &self.0
+        }
+
+        fn wrapped(&self) -> Wrapper<'_> {
+            Wrapper(&self.0)
+        }
+    }
+
+    pub fn test() {
+        let mut args: Vec<Test> = vec![];
+
+        // Forward
+        args.sort_by(|a, b| a.name().cmp(b.name()));
+        args.sort_by(|a, b| a.wrapped().cmp(&b.wrapped()));
+        args.sort_unstable_by(|a, b| a.name().cmp(b.name()));
+        args.sort_unstable_by(|a, b| a.wrapped().cmp(&b.wrapped()));
+        // Reverse
+        args.sort_by(|a, b| b.name().cmp(a.name()));
+        args.sort_by(|a, b| b.wrapped().cmp(&a.wrapped()));
+        args.sort_unstable_by(|a, b| b.name().cmp(a.name()));
+        args.sort_unstable_by(|a, b| b.wrapped().cmp(&a.wrapped()));
+    }
+}
+
+fn main() {
+    unnecessary_sort_by();
+    issue_5754::test();
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns3.rs b/src/tools/clippy/tests/ui/unnested_or_patterns3.rs
new file mode 100644 (file)
index 0000000..6bd3505
--- /dev/null
@@ -0,0 +1,6 @@
+#![warn(clippy::unnested_or_patterns)]
+
+// Test that `unnested_or_patterns` does not trigger without enabling `or_patterns`
+fn main() {
+    if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {}
+}
index 703b87634cec37042e95db4d6428a3eccb47e187..5f7373be6594636540e3ba6845bbd5e8a4505cf8 100644 (file)
@@ -186,6 +186,9 @@ pub struct Config {
     /// The rustdoc executable.
     pub rustdoc_path: Option<PathBuf>,
 
+    /// The rust-demangler executable.
+    pub rust_demangler_path: Option<PathBuf>,
+
     /// The Python executable to use for LLDB.
     pub lldb_python: String,
 
index 571e7a59113ada60bbe3af9097f4f36c99acbc2b..d6e28e93c96676aaf5ba632d17916e40d06c4b2f 100644 (file)
@@ -867,6 +867,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
             &self.target == name ||                             // triple
             util::matches_os(&self.target, name) ||             // target
             util::matches_env(&self.target, name) ||            // env
+            self.target.ends_with(name) ||                      // target and env
             name == util::get_arch(&self.target) ||             // architecture
             name == util::get_pointer_width(&self.target) ||    // pointer width
             name == self.stage_id.split('-').next().unwrap() || // stage
index 97272f1a9c1b6e342f08adfcbc456fd3a14f9574..07eba22c6eeb3a048f0a0322bfd492217ce389d2 100644 (file)
@@ -53,6 +53,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         .reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
         .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
         .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
+        .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH")
         .reqopt("", "lldb-python", "path to python to use for doc tests", "PATH")
         .reqopt("", "docck-python", "path to python to use for doc tests", "PATH")
         .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
@@ -182,6 +183,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
         rustc_path: opt_path(matches, "rustc-path"),
         rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
+        rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from),
         lldb_python: matches.opt_str("lldb-python").unwrap(),
         docck_python: matches.opt_str("docck-python").unwrap(),
         valgrind_path: matches.opt_str("valgrind-path"),
@@ -246,6 +248,7 @@ pub fn log_config(config: &Config) {
     logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
     logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
     logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
+    logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path));
     logv(c, format!("src_base: {:?}", config.src_base.display()));
     logv(c, format!("build_base: {:?}", config.build_base.display()));
     logv(c, format!("stage_id: {}", config.stage_id));
@@ -479,6 +482,8 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
         stamp.add_path(&rustdoc_path);
         stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));
     }
+    // FIXME(richkadel): Do I need to add an `if let Some(rust_demangler_path) contribution to the
+    // stamp here as well?
 
     // Compiletest itself.
     stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/"));
index dd0c68ecd4965121ec723ecdf0c0166399be8c92..f09f7621aa170ebc453b0508ee89f0fddaae0acf 100644 (file)
@@ -2739,6 +2739,10 @@ fn run_rmake_test(&self) {
             cmd.env("RUSTDOC", cwd.join(rustdoc));
         }
 
+        if let Some(ref rust_demangler) = self.config.rust_demangler_path {
+            cmd.env("RUST_DEMANGLER", cwd.join(rust_demangler));
+        }
+
         if let Some(ref node) = self.config.nodejs {
             cmd.env("NODE", node);
         }
index 9aea859999ceab51fadcc53249641f777aabc311..c4292d041d0511db7711167e0185196e0b42a9b1 100644 (file)
@@ -127,7 +127,7 @@ fn error_code_block(
                         DEFAULT_EDITION,
                         &Some(playground)
                     )
-                    .to_string()
+                    .into_string()
                 )?
             }
             None => write!(output, "<p>No description.</p>\n")?,
index eee22ffddab20f51e1866bcbe4c5a69a90bdd260..515287f114b546a72d4a1fe8ffe1dbc20dedf13d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit eee22ffddab20f51e1866bcbe4c5a69a90bdd260
+Subproject commit 515287f114b546a72d4a1fe8ffe1dbc20dedf13d
diff --git a/src/tools/rust-demangler/Cargo.toml b/src/tools/rust-demangler/Cargo.toml
new file mode 100644 (file)
index 0000000..0b8d974
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rust-demangler"
+version = "0.0.0"
+edition = "2018"
+
+[dependencies]
+rustc-demangle = "0.1"
+
+[[bin]]
+name = "rust-demangler"
+path = "main.rs"
diff --git a/src/tools/rust-demangler/main.rs b/src/tools/rust-demangler/main.rs
new file mode 100644 (file)
index 0000000..a9f1011
--- /dev/null
@@ -0,0 +1,39 @@
+//! Demangles rustc mangled names.
+//!
+//! This tool uses https://crates.io/crates/rustc-demangle to convert an input buffer of
+//! newline-separated mangled names into their demangled translations.
+//!
+//! This tool can be leveraged by other applications that support third-party demanglers.
+//! It takes a list of mangled names (one per line) on standard input, and prints a corresponding
+//! list of demangled names. The tool is designed to support other programs that can leverage a
+//! third-party demangler, such as `llvm-cov`, via the `-Xdemangler=<path-to-demangler>` option.
+//!
+//! To use `rust-demangler`, first build the tool with:
+//!
+//! ```shell
+//! $ ./x.py build rust-demangler
+//! ```
+//!
+//! Then, with `llvm-cov` for example, add the `-Xdemangler=...` option:
+//!
+//! ```shell
+//! $ TARGET="${PWD}/build/x86_64-unknown-linux-gnu"
+//! $ "${TARGET}"/llvm/bin/llvm-cov show --Xdemangler="${TARGET}"/stage0-tools-bin/rust-demangler \
+//!   --instr-profile=main.profdata ./main --show-line-counts-or-regions
+//! ```
+
+use rustc_demangle::demangle;
+use std::io::{self, Read, Write};
+
+fn main() -> io::Result<()> {
+    let mut buffer = String::new();
+    io::stdin().read_to_string(&mut buffer)?;
+    let lines = buffer.lines();
+    let mut demangled = Vec::new();
+    for mangled in lines {
+        demangled.push(demangle(mangled).to_string());
+    }
+    demangled.push("".to_string());
+    io::stdout().write_all(demangled.join("\n").as_bytes())?;
+    Ok(())
+}
index f40d09cafbb4791f5d0c8d835c1250804c1a2669..1e955c61ac85f1bb7f717c1d77b5fad3b5c1e4b3 100644 (file)
@@ -1 +1,2 @@
+#![feature(restricted_std)]
 pub use std::*;
index b7d3d428cd28340aa3ace9124f6c08885fd061a8..36bd1ab6c1078b686fea8bc215651f99720386d1 100644 (file)
@@ -17,6 +17,7 @@
     "MIT",
     "Unlicense/MIT",
     "Unlicense OR MIT",
+    "0BSD OR MIT OR Apache-2.0", // adler license
 ];
 
 /// These are exceptions to Rust's permissive licensing policy, and
@@ -36,7 +37,6 @@
     ("ryu", "Apache-2.0 OR BSL-1.0"),       // rls/cargo/... (because of serde)
     ("bytesize", "Apache-2.0"),             // cargo
     ("im-rc", "MPL-2.0+"),                  // cargo
-    ("adler32", "BSD-3-Clause AND Zlib"),   // cargo dep that isn't used
     ("constant_time_eq", "CC0-1.0"),        // rustfmt
     ("sized-chunks", "MPL-2.0+"),           // cargo via im-rc
     ("bitmaps", "MPL-2.0+"),                // cargo via im-rc
@@ -57,7 +57,8 @@
 /// This list is here to provide a speed-bump to adding a new dependency to
 /// rustc. Please check with the compiler team before adding an entry.
 const PERMITTED_DEPENDENCIES: &[&str] = &[
-    "adler32",
+    "addr2line",
+    "adler",
     "aho-corasick",
     "annotate-snippets",
     "ansi_term",
@@ -65,7 +66,6 @@
     "atty",
     "autocfg",
     "backtrace",
-    "backtrace-sys",
     "bitflags",
     "block-buffer",
     "block-padding",
@@ -98,6 +98,7 @@
     "generic-array",
     "getopts",
     "getrandom",
+    "gimli",
     "hashbrown",
     "hermit-abi",
     "humantime",
     "miniz_oxide",
     "nodrop",
     "num_cpus",
+    "object",
     "once_cell",
     "opaque-debug",
     "parking_lot",
     "parking_lot_core",
+    "pathdiff",
     "pkg-config",
     "polonius-engine",
     "ppv-lite86",
index 3af71f69d2457c162a6bd183f0609852b599fc90..51f135d37616125ad1b2e4a18aacf28631327c30 100644 (file)
@@ -8,11 +8,11 @@
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0456",
-    "E0461", "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479",
-    "E0480", "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489",
-    "E0514", "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717",
-    "E0727", "E0729",
+    "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461",
+    "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480",
+    "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514",
+    "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727",
+    "E0729",
 ];
 
 // Some error codes don't have any tests apparently...
index b4aafb815fc6b6b169a0caa91aa21de9a8c5b8dc..c0671596e19f1b365a990243d3b02ad7a1b51389 100644 (file)
@@ -60,6 +60,7 @@ fn filter_dirs(path: &Path) -> bool {
         "src/tools/rust-installer",
         "src/tools/rustfmt",
         "src/doc/book",
+        "src/backtrace",
         // Filter RLS output directories
         "target/rls",
     ];
index 396d6c0cfcdeff81e0235650780c7b418df721d5..470fab496a442fa6dc65328896c3af6713d7593b 100644 (file)
@@ -119,6 +119,7 @@ fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) ->
     // Update `can_contain` when changing this
     if contents.contains(&format!("// ignore-tidy-{}", check))
         || contents.contains(&format!("# ignore-tidy-{}", check))
+        || contents.contains(&format!("/* ignore-tidy-{} */", check))
     {
         Directive::Ignore(false)
     } else {
@@ -136,15 +137,37 @@ macro_rules! suppressible_tidy_err {
     };
 }
 
+pub fn is_in(full_path: &Path, parent_folder_to_find: &str, folder_to_find: &str) -> bool {
+    if let Some(parent) = full_path.parent() {
+        if parent.file_name().map_or_else(
+            || false,
+            |f| {
+                f.to_string_lossy() == folder_to_find
+                    && parent
+                        .parent()
+                        .and_then(|f| f.file_name())
+                        .map_or_else(|| false, |f| f == parent_folder_to_find)
+            },
+        ) {
+            true
+        } else {
+            is_in(parent, parent_folder_to_find, folder_to_find)
+        }
+    } else {
+        false
+    }
+}
+
 pub fn check(path: &Path, bad: &mut bool) {
     super::walk(path, &mut super::filter_dirs, &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap().to_string_lossy();
-        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md"];
+        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css"];
         if extensions.iter().all(|e| !filename.ends_with(e)) || filename.starts_with(".#") {
             return;
         }
 
+        let is_style_file = filename.ends_with(".css");
         let under_rustfmt = filename.ends_with(".rs") &&
             // This list should ideally be sourced from rustfmt.toml but we don't want to add a toml
             // parser to tidy.
@@ -161,6 +184,10 @@ pub fn check(path: &Path, bad: &mut bool) {
             // currently), just the long error code explanation ones.
             return;
         }
+        if is_style_file && !is_in(file, "src", "librustdoc") {
+            // We only check CSS files in rustdoc.
+            return;
+        }
 
         if contents.is_empty() {
             tidy_error!(bad, "{}: empty file", file.display());
@@ -172,8 +199,9 @@ pub fn check(path: &Path, bad: &mut bool) {
             COLS
         };
 
-        let can_contain =
-            contents.contains("// ignore-tidy-") || contents.contains("# ignore-tidy-");
+        let can_contain = contents.contains("// ignore-tidy-")
+            || contents.contains("# ignore-tidy-")
+            || contents.contains("/* ignore-tidy-");
         // Enable testing ICE's that require specific (untidy)
         // file formats easily eg. `issue-1234-ignore-tidy.rs`
         if filename.contains("ignore-tidy") {
@@ -208,12 +236,15 @@ pub fn check(path: &Path, bad: &mut bool) {
                     &format!("line longer than {} chars", max_columns)
                 );
             }
-            if line.contains('\t') {
+            if !is_style_file && line.contains('\t') {
                 suppressible_tidy_err!(err, skip_tab, "tab character");
             }
             if line.ends_with(' ') || line.ends_with('\t') {
                 suppressible_tidy_err!(err, skip_end_whitespace, "trailing whitespace");
             }
+            if is_style_file && line.starts_with(' ') {
+                err("CSS files use tabs for indent");
+            }
             if line.contains('\r') {
                 suppressible_tidy_err!(err, skip_cr, "CR character");
             }