]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #67989 - ollie27:rustdoc_unstable, r=GuillaumeGomez
authorYuki Okushi <huyuumi.dev@gmail.com>
Tue, 14 Jan 2020 05:02:18 +0000 (14:02 +0900)
committerGitHub <noreply@github.com>
Tue, 14 Jan 2020 05:02:18 +0000 (14:02 +0900)
rustdoc: Don't allow `#![feature(...)]` on stable or beta

Fixes #67647

r? @GuillaumeGomez

1248 files changed:
Cargo.lock
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/flags.rs
src/bootstrap/native.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/build_helper/lib.rs
src/ci/docker/x86_64-gnu-debug/Dockerfile
src/ci/docker/x86_64-gnu/Dockerfile
src/ci/publish_toolstate.sh
src/ci/scripts/install-clang.sh
src/ci/scripts/install-msys2-packages.sh
src/ci/shared.sh
src/doc/unstable-book/src/compiler-flags/sanitizer.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md [deleted file]
src/liballoc/boxed.rs
src/liballoc/collections/btree/node.rs
src/liballoc/collections/btree/search.rs
src/liballoc/tests/lib.rs
src/liballoc/vec.rs
src/libcore/alloc.rs
src/libcore/cmp.rs
src/libcore/iter/traits/iterator.rs
src/libcore/lib.rs
src/libcore/num/mod.rs
src/libcore/option.rs
src/libcore/pin.rs
src/libcore/ptr/mut_ptr.rs
src/libcore/result.rs
src/libcore/str/pattern.rs
src/libcore/sync/atomic.rs
src/libcore/task/poll.rs
src/libcore/tests/lib.rs
src/libcore/tests/result.rs
src/libpanic_unwind/emcc.rs
src/libproc_macro/lib.rs
src/libprofiler_builtins/build.rs
src/librustc/Cargo.toml
src/librustc/dep_graph/graph.rs
src/librustc/hir/check_attr.rs
src/librustc/hir/intravisit.rs [deleted file]
src/librustc/hir/map/blocks.rs
src/librustc/hir/map/collector.rs
src/librustc/hir/map/definitions.rs
src/librustc/hir/map/hir_id_validator.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/hir/upvars.rs
src/librustc/infer/canonical/query_response.rs
src/librustc/infer/error_reporting/mod.rs
src/librustc/infer/error_reporting/need_type_info.rs
src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs
src/librustc/infer/error_reporting/nice_region_error/mod.rs
src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs
src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs
src/librustc/infer/error_reporting/note.rs
src/librustc/infer/lexical_region_resolve/mod.rs
src/librustc/infer/mod.rs
src/librustc/infer/opaque_types/mod.rs
src/librustc/infer/outlives/env.rs
src/librustc/infer/outlives/free_region_map.rs [deleted file]
src/librustc/infer/outlives/mod.rs
src/librustc/infer/outlives/verify.rs
src/librustc/lib.rs
src/librustc/lint.rs [new file with mode: 0644]
src/librustc/lint/builtin.rs [deleted file]
src/librustc/lint/context.rs [deleted file]
src/librustc/lint/internal.rs [deleted file]
src/librustc/lint/levels.rs [deleted file]
src/librustc/lint/mod.rs [deleted file]
src/librustc/middle/cstore.rs
src/librustc/middle/free_region.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/stability.rs
src/librustc/middle/weak_lang_items.rs
src/librustc/mir/interpret/error.rs
src/librustc/mir/interpret/queries.rs
src/librustc/mir/mod.rs
src/librustc/mir/query.rs [new file with mode: 0644]
src/librustc/mir/tcx.rs
src/librustc/mir/visit.rs
src/librustc/query/mod.rs
src/librustc/traits/codegen/mod.rs
src/librustc/traits/coherence.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/fulfill.rs
src/librustc/traits/misc.rs [new file with mode: 0644]
src/librustc/traits/mod.rs
src/librustc/traits/object_safety.rs
src/librustc/traits/on_unimplemented.rs
src/librustc/traits/project.rs
src/librustc/traits/query/dropck_outlives.rs
src/librustc/traits/query/mod.rs
src/librustc/traits/query/normalize_erasing_regions.rs [deleted file]
src/librustc/traits/select.rs
src/librustc/traits/specialize/mod.rs
src/librustc/traits/structural_match.rs [new file with mode: 0644]
src/librustc/traits/util.rs
src/librustc/traits/wf.rs [new file with mode: 0644]
src/librustc/ty/codec.rs
src/librustc/ty/constness.rs [deleted file]
src/librustc/ty/context.rs
src/librustc/ty/error.rs
src/librustc/ty/flags.rs
src/librustc/ty/free_region_map.rs [new file with mode: 0644]
src/librustc/ty/inhabitedness/mod.rs
src/librustc/ty/instance.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc/ty/normalize_erasing_regions.rs [new file with mode: 0644]
src/librustc/ty/outlives.rs
src/librustc/ty/print/pretty.rs
src/librustc/ty/query/config.rs
src/librustc/ty/query/keys.rs
src/librustc/ty/query/mod.rs
src/librustc/ty/query/on_disk_cache.rs
src/librustc/ty/query/plumbing.rs
src/librustc/ty/query/profiling_support.rs [new file with mode: 0644]
src/librustc/ty/relate.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/structural_match.rs [deleted file]
src/librustc/ty/sty.rs
src/librustc/ty/util.rs
src/librustc/ty/walk.rs
src/librustc/ty/wf.rs [deleted file]
src/librustc/util/captures.rs [deleted file]
src/librustc/util/common.rs
src/librustc_asan/Cargo.toml [deleted file]
src/librustc_asan/build.rs [deleted file]
src/librustc_asan/lib.rs [deleted file]
src/librustc_ast_lowering/expr.rs
src/librustc_ast_lowering/item.rs
src/librustc_ast_lowering/lib.rs
src/librustc_ast_lowering/pat.rs [new file with mode: 0644]
src/librustc_ast_lowering/path.rs [new file with mode: 0644]
src/librustc_ast_passes/Cargo.toml [new file with mode: 0644]
src/librustc_ast_passes/ast_validation.rs [new file with mode: 0644]
src/librustc_ast_passes/feature_gate.rs [new file with mode: 0644]
src/librustc_ast_passes/lib.rs [new file with mode: 0644]
src/librustc_ast_passes/show_span.rs [new file with mode: 0644]
src/librustc_builtin_macros/Cargo.toml
src/librustc_builtin_macros/asm.rs
src/librustc_builtin_macros/assert.rs
src/librustc_builtin_macros/cfg.rs
src/librustc_builtin_macros/deriving/default.rs
src/librustc_builtin_macros/format.rs
src/librustc_builtin_macros/global_asm.rs
src/librustc_builtin_macros/proc_macro_harness.rs
src/librustc_builtin_macros/source_util.rs
src/librustc_builtin_macros/test_harness.rs
src/librustc_codegen_llvm/Cargo.toml
src/librustc_codegen_llvm/back/lto.rs
src/librustc_codegen_llvm/back/write.rs
src/librustc_codegen_llvm/base.rs
src/librustc_codegen_llvm/context.rs
src/librustc_codegen_llvm/debuginfo/metadata.rs
src/librustc_codegen_llvm/lib.rs
src/librustc_codegen_llvm/llvm_util.rs
src/librustc_codegen_ssa/back/link.rs
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/back/write.rs
src/librustc_codegen_ssa/base.rs
src/librustc_codegen_ssa/common.rs
src/librustc_codegen_ssa/lib.rs
src/librustc_codegen_ssa/mir/analyze.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_codegen_ssa/mir/constant.rs
src/librustc_codegen_ssa/mir/debuginfo.rs
src/librustc_codegen_ssa/mir/operand.rs
src/librustc_codegen_ssa/mir/place.rs
src/librustc_codegen_ssa/mir/statement.rs
src/librustc_codegen_ssa/traits/backend.rs
src/librustc_data_structures/Cargo.toml
src/librustc_data_structures/binary_search_util/mod.rs
src/librustc_data_structures/captures.rs [new file with mode: 0644]
src/librustc_data_structures/lib.rs
src/librustc_data_structures/profiling.rs
src/librustc_driver/Cargo.toml
src/librustc_driver/lib.rs
src/librustc_error_codes/error_codes/E0038.md
src/librustc_error_codes/error_codes/E0084.md
src/librustc_error_codes/error_codes/E0184.md
src/librustc_error_codes/error_codes/E0185.md
src/librustc_error_codes/error_codes/E0186.md
src/librustc_error_codes/error_codes/E0307.md
src/librustc_error_codes/error_codes/E0373.md
src/librustc_error_codes/error_codes/E0426.md
src/librustc_error_codes/error_codes/E0445.md
src/librustc_error_codes/error_codes/E0446.md
src/librustc_error_codes/error_codes/E0491.md
src/librustc_error_codes/error_codes/E0566.md
src/librustc_errors/diagnostic_builder.rs
src/librustc_errors/lib.rs
src/librustc_expand/Cargo.toml
src/librustc_expand/base.rs
src/librustc_expand/build.rs
src/librustc_expand/expand.rs
src/librustc_expand/lib.rs
src/librustc_expand/mbe/macro_check.rs
src/librustc_expand/mbe/macro_parser.rs
src/librustc_expand/mbe/macro_rules.rs
src/librustc_expand/mbe/transcribe.rs
src/librustc_expand/parse/lexer/tests.rs
src/librustc_expand/parse/tests.rs
src/librustc_expand/proc_macro.rs
src/librustc_expand/proc_macro_server.rs
src/librustc_expand/tests.rs
src/librustc_feature/active.rs
src/librustc_feature/builtin_attrs.rs
src/librustc_feature/lib.rs
src/librustc_feature/removed.rs
src/librustc_hir/hir.rs
src/librustc_hir/intravisit.rs [new file with mode: 0644]
src/librustc_hir/lib.rs
src/librustc_hir/print.rs
src/librustc_incremental/assert_dep_graph.rs
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_incremental/persist/fs.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/save.rs
src/librustc_interface/Cargo.toml
src/librustc_interface/interface.rs
src/librustc_interface/passes.rs
src/librustc_interface/queries.rs
src/librustc_interface/tests.rs
src/librustc_interface/util.rs
src/librustc_lint/Cargo.toml
src/librustc_lint/array_into_iter.rs
src/librustc_lint/builtin.rs
src/librustc_lint/context.rs [new file with mode: 0644]
src/librustc_lint/early.rs
src/librustc_lint/internal.rs [new file with mode: 0644]
src/librustc_lint/late.rs
src/librustc_lint/levels.rs
src/librustc_lint/lib.rs
src/librustc_lint/non_ascii_idents.rs
src/librustc_lint/nonstandard_style.rs
src/librustc_lint/passes.rs [new file with mode: 0644]
src/librustc_lint/redundant_semicolon.rs
src/librustc_lint/types.rs
src/librustc_lint/unused.rs
src/librustc_lsan/Cargo.toml [deleted file]
src/librustc_lsan/build.rs [deleted file]
src/librustc_lsan/lib.rs [deleted file]
src/librustc_metadata/Cargo.toml
src/librustc_metadata/creader.rs
src/librustc_metadata/locator.rs
src/librustc_metadata/native_libs.rs
src/librustc_metadata/rmeta/decoder.rs
src/librustc_metadata/rmeta/decoder/cstore_impl.rs
src/librustc_metadata/rmeta/encoder.rs
src/librustc_metadata/rmeta/mod.rs
src/librustc_mir/Cargo.toml
src/librustc_mir/borrow_check/borrow_set.rs
src/librustc_mir/borrow_check/constraint_generation.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/diagnostics/region_errors.rs
src/librustc_mir/borrow_check/invalidation.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll.rs
src/librustc_mir/borrow_check/path_utils.rs
src/librustc_mir/borrow_check/place_ext.rs
src/librustc_mir/borrow_check/places_conflict.rs
src/librustc_mir/borrow_check/prefixes.rs
src/librustc_mir/borrow_check/type_check/free_region_relations.rs
src/librustc_mir/borrow_check/type_check/mod.rs
src/librustc_mir/borrow_check/used_muts.rs
src/librustc_mir/build/block.rs [deleted file]
src/librustc_mir/build/cfg.rs [deleted file]
src/librustc_mir/build/expr/as_constant.rs [deleted file]
src/librustc_mir/build/expr/as_operand.rs [deleted file]
src/librustc_mir/build/expr/as_place.rs [deleted file]
src/librustc_mir/build/expr/as_rvalue.rs [deleted file]
src/librustc_mir/build/expr/as_temp.rs [deleted file]
src/librustc_mir/build/expr/category.rs [deleted file]
src/librustc_mir/build/expr/into.rs [deleted file]
src/librustc_mir/build/expr/mod.rs [deleted file]
src/librustc_mir/build/expr/stmt.rs [deleted file]
src/librustc_mir/build/into.rs [deleted file]
src/librustc_mir/build/matches/mod.rs [deleted file]
src/librustc_mir/build/matches/simplify.rs [deleted file]
src/librustc_mir/build/matches/test.rs [deleted file]
src/librustc_mir/build/matches/util.rs [deleted file]
src/librustc_mir/build/misc.rs [deleted file]
src/librustc_mir/build/mod.rs [deleted file]
src/librustc_mir/build/scope.rs [deleted file]
src/librustc_mir/const_eval.rs
src/librustc_mir/const_eval/eval_queries.rs
src/librustc_mir/const_eval/fn_queries.rs [new file with mode: 0644]
src/librustc_mir/dataflow/impls/borrowed_locals.rs
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/impls/indirect_mutation.rs
src/librustc_mir/dataflow/impls/storage_liveness.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/dataflow/move_paths/mod.rs
src/librustc_mir/hair/constant.rs [deleted file]
src/librustc_mir/hair/cx/block.rs [deleted file]
src/librustc_mir/hair/cx/expr.rs [deleted file]
src/librustc_mir/hair/cx/mod.rs [deleted file]
src/librustc_mir/hair/cx/to_ref.rs [deleted file]
src/librustc_mir/hair/mod.rs [deleted file]
src/librustc_mir/hair/pattern/_match.rs [deleted file]
src/librustc_mir/hair/pattern/check_match.rs [deleted file]
src/librustc_mir/hair/pattern/const_to_pat.rs [deleted file]
src/librustc_mir/hair/pattern/mod.rs [deleted file]
src/librustc_mir/hair/util.rs [deleted file]
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/intern.rs
src/librustc_mir/interpret/machine.rs
src/librustc_mir/interpret/mod.rs
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/interpret/snapshot.rs
src/librustc_mir/interpret/terminator.rs
src/librustc_mir/interpret/validity.rs
src/librustc_mir/interpret/visitor.rs
src/librustc_mir/lib.rs
src/librustc_mir/lints.rs [deleted file]
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/monomorphize/partitioning.rs
src/librustc_mir/transform/check_consts/ops.rs
src/librustc_mir/transform/check_consts/qualifs.rs
src/librustc_mir/transform/check_consts/resolver.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/elaborate_drops.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/instcombine.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_min_const_fn.rs
src/librustc_mir/transform/simplify.rs
src/librustc_mir/transform/simplify_try.rs
src/librustc_mir/util/alignment.rs
src/librustc_mir/util/borrowck_errors.rs
src/librustc_mir_build/Cargo.toml [new file with mode: 0644]
src/librustc_mir_build/build/block.rs [new file with mode: 0644]
src/librustc_mir_build/build/cfg.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/as_constant.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/as_operand.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/as_place.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/as_rvalue.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/as_temp.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/category.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/into.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/mod.rs [new file with mode: 0644]
src/librustc_mir_build/build/expr/stmt.rs [new file with mode: 0644]
src/librustc_mir_build/build/into.rs [new file with mode: 0644]
src/librustc_mir_build/build/matches/mod.rs [new file with mode: 0644]
src/librustc_mir_build/build/matches/simplify.rs [new file with mode: 0644]
src/librustc_mir_build/build/matches/test.rs [new file with mode: 0644]
src/librustc_mir_build/build/matches/util.rs [new file with mode: 0644]
src/librustc_mir_build/build/misc.rs [new file with mode: 0644]
src/librustc_mir_build/build/mod.rs [new file with mode: 0644]
src/librustc_mir_build/build/scope.rs [new file with mode: 0644]
src/librustc_mir_build/hair/constant.rs [new file with mode: 0644]
src/librustc_mir_build/hair/cx/block.rs [new file with mode: 0644]
src/librustc_mir_build/hair/cx/expr.rs [new file with mode: 0644]
src/librustc_mir_build/hair/cx/mod.rs [new file with mode: 0644]
src/librustc_mir_build/hair/cx/to_ref.rs [new file with mode: 0644]
src/librustc_mir_build/hair/mod.rs [new file with mode: 0644]
src/librustc_mir_build/hair/pattern/_match.rs [new file with mode: 0644]
src/librustc_mir_build/hair/pattern/check_match.rs [new file with mode: 0644]
src/librustc_mir_build/hair/pattern/const_to_pat.rs [new file with mode: 0644]
src/librustc_mir_build/hair/pattern/mod.rs [new file with mode: 0644]
src/librustc_mir_build/hair/util.rs [new file with mode: 0644]
src/librustc_mir_build/lib.rs [new file with mode: 0644]
src/librustc_mir_build/lints.rs [new file with mode: 0644]
src/librustc_msan/Cargo.toml [deleted file]
src/librustc_msan/build.rs [deleted file]
src/librustc_msan/lib.rs [deleted file]
src/librustc_parse/Cargo.toml
src/librustc_parse/config.rs
src/librustc_parse/lexer/unescape_error_reporting.rs
src/librustc_parse/parser/diagnostics.rs
src/librustc_parse/parser/expr.rs
src/librustc_parse/parser/generics.rs
src/librustc_parse/parser/item.rs
src/librustc_parse/parser/mod.rs
src/librustc_parse/parser/module.rs
src/librustc_parse/parser/pat.rs
src/librustc_parse/parser/ty.rs
src/librustc_parse/validate_attr.rs
src/librustc_passes/Cargo.toml
src/librustc_passes/ast_validation.rs [deleted file]
src/librustc_passes/check_const.rs
src/librustc_passes/dead.rs
src/librustc_passes/diagnostic_items.rs
src/librustc_passes/entry.rs
src/librustc_passes/hir_stats.rs
src/librustc_passes/intrinsicck.rs
src/librustc_passes/lib.rs
src/librustc_passes/lib_features.rs
src/librustc_passes/liveness.rs
src/librustc_passes/loops.rs
src/librustc_passes/reachable.rs
src/librustc_passes/region.rs
src/librustc_passes/stability.rs
src/librustc_plugin_impl/Cargo.toml
src/librustc_plugin_impl/lib.rs
src/librustc_plugin_impl/load.rs
src/librustc_privacy/Cargo.toml
src/librustc_privacy/lib.rs
src/librustc_resolve/Cargo.toml
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/check_unused.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/lib.rs
src/librustc_resolve/lifetimes.rs
src/librustc_resolve/macros.rs
src/librustc_session/Cargo.toml
src/librustc_session/lint.rs
src/librustc_session/lint/builtin.rs [new file with mode: 0644]
src/librustc_session/options.rs
src/librustc_session/parse.rs
src/librustc_session/session.rs
src/librustc_session/utils.rs
src/librustc_span/lib.rs
src/librustc_span/source_map.rs
src/librustc_span/symbol.rs
src/librustc_target/spec/i386_apple_ios.rs
src/librustc_target/spec/i686_apple_darwin.rs
src/librustc_target/spec/i686_linux_android.rs
src/librustc_target/spec/i686_pc_windows_gnu.rs
src/librustc_target/spec/i686_pc_windows_msvc.rs
src/librustc_target/spec/i686_unknown_cloudabi.rs
src/librustc_target/spec/i686_unknown_freebsd.rs
src/librustc_target/spec/i686_unknown_haiku.rs
src/librustc_target/spec/i686_unknown_linux_gnu.rs
src/librustc_target/spec/i686_unknown_linux_musl.rs
src/librustc_target/spec/i686_unknown_netbsd.rs
src/librustc_target/spec/i686_unknown_openbsd.rs
src/librustc_target/spec/i686_unknown_uefi.rs
src/librustc_target/spec/i686_uwp_windows_gnu.rs
src/librustc_target/spec/i686_uwp_windows_msvc.rs
src/librustc_target/spec/i686_wrs_vxworks.rs
src/librustc_target/spec/mod.rs
src/librustc_target/spec/x86_64_apple_darwin.rs
src/librustc_target/spec/x86_64_apple_ios.rs
src/librustc_target/spec/x86_64_apple_ios_macabi.rs
src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
src/librustc_target/spec/x86_64_fuchsia.rs
src/librustc_target/spec/x86_64_linux_android.rs
src/librustc_target/spec/x86_64_linux_kernel.rs
src/librustc_target/spec/x86_64_pc_windows_gnu.rs
src/librustc_target/spec/x86_64_pc_windows_msvc.rs
src/librustc_target/spec/x86_64_rumprun_netbsd.rs
src/librustc_target/spec/x86_64_sun_solaris.rs
src/librustc_target/spec/x86_64_unknown_cloudabi.rs
src/librustc_target/spec/x86_64_unknown_dragonfly.rs
src/librustc_target/spec/x86_64_unknown_freebsd.rs
src/librustc_target/spec/x86_64_unknown_haiku.rs
src/librustc_target/spec/x86_64_unknown_hermit.rs
src/librustc_target/spec/x86_64_unknown_hermit_kernel.rs
src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs
src/librustc_target/spec/x86_64_unknown_linux_gnu.rs
src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs
src/librustc_target/spec/x86_64_unknown_linux_musl.rs
src/librustc_target/spec/x86_64_unknown_netbsd.rs
src/librustc_target/spec/x86_64_unknown_openbsd.rs
src/librustc_target/spec/x86_64_unknown_redox.rs
src/librustc_target/spec/x86_64_unknown_uefi.rs
src/librustc_target/spec/x86_64_uwp_windows_gnu.rs
src/librustc_target/spec/x86_64_uwp_windows_msvc.rs
src/librustc_target/spec/x86_64_wrs_vxworks.rs
src/librustc_traits/implied_outlives_bounds.rs
src/librustc_traits/lowering/mod.rs
src/librustc_tsan/Cargo.toml [deleted file]
src/librustc_tsan/build.rs [deleted file]
src/librustc_tsan/lib.rs [deleted file]
src/librustc_typeck/Cargo.toml
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/dropck.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/regionck.rs
src/librustc_typeck/check/upvar.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/check_unused.rs
src/librustc_typeck/coherence/builtin.rs
src/librustc_typeck/coherence/inherent_impls.rs
src/librustc_typeck/coherence/inherent_impls_overlap.rs
src/librustc_typeck/coherence/mod.rs
src/librustc_typeck/coherence/orphan.rs
src/librustc_typeck/coherence/unsafety.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/impl_wf_check.rs
src/librustc_typeck/lib.rs
src/librustc_typeck/outlives/test.rs
src/librustc_typeck/structured_errors.rs
src/librustc_typeck/variance/test.rs
src/librustdoc/clean/cfg.rs
src/librustdoc/clean/cfg/tests.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/docfs.rs
src/librustdoc/externalfiles.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/lib.rs
src/librustdoc/markdown.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/check_code_block_syntax.rs
src/librustdoc/passes/collapse_docs.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/mod.rs
src/librustdoc/passes/private_items_doc_tests.rs
src/librustdoc/passes/propagate_doc_cfg.rs
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/passes/strip_priv_imports.rs
src/librustdoc/passes/strip_private.rs
src/librustdoc/passes/unindent_comments.rs
src/librustdoc/test.rs
src/librustdoc/theme.rs
src/libstd/Cargo.toml
src/libstd/collections/hash/set.rs
src/libstd/error.rs
src/libstd/ffi/c_str.rs
src/libstd/ffi/os_str.rs
src/libstd/net/addr.rs
src/libstd/net/ip.rs
src/libstd/path.rs
src/libstd/sync/barrier.rs
src/libstd/sync/mpsc/oneshot.rs
src/libstd/sys/hermit/os.rs
src/libstd/sys/hermit/thread_local.rs
src/libstd/sys/sgx/abi/tls.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/vxworks/mod.rs
src/libstd/sys/vxworks/os.rs
src/libstd/sys/vxworks/weak.rs [deleted file]
src/libstd/sys/wasi/os.rs
src/libstd/sys/windows/os.rs
src/libstd/sys_common/os_str_bytes.rs
src/libstd/time.rs
src/libsyntax/Cargo.toml
src/libsyntax/ast.rs
src/libsyntax/attr/builtin.rs
src/libsyntax/attr/mod.rs
src/libsyntax/diagnostics/macros.rs [deleted file]
src/libsyntax/early_buffered_lints.rs [deleted file]
src/libsyntax/feature_gate/check.rs [deleted file]
src/libsyntax/lib.rs
src/libsyntax/mut_visit.rs
src/libsyntax/print/pprust.rs
src/libsyntax/show_span.rs [deleted file]
src/libsyntax/util/lev_distance.rs
src/libsyntax/util/lev_distance/tests.rs
src/libsyntax/visit.rs
src/libtest/cli.rs
src/rustc/Cargo.toml
src/rustllvm/ArchiveWrapper.cpp
src/rustllvm/Linker.cpp
src/rustllvm/PassWrapper.cpp
src/rustllvm/RustWrapper.cpp
src/test/codegen/abi-main-signature-32bit-c-int.rs
src/test/codegen/bool-cmp.rs
src/test/codegen/consts.rs
src/test/codegen/function-arguments.rs
src/test/codegen/intrinsics/prefetch.rs
src/test/codegen/naked-functions.rs
src/test/codegen/repeat-trusted-len.rs
src/test/codegen/repr-transparent-sysv64.rs
src/test/codegen/union-abi.rs
src/test/compile-fail/consts/const-fn-error.rs
src/test/compile-fail/issue-52443.rs
src/test/debuginfo/borrowed-enum-legacy.rs [deleted file]
src/test/debuginfo/generic-enum-with-different-disr-sizes-legacy.rs [deleted file]
src/test/debuginfo/generic-struct-style-enum-legacy.rs [deleted file]
src/test/debuginfo/generic-tuple-style-enum-legacy.rs [deleted file]
src/test/debuginfo/recursive-struct-legacy.rs [deleted file]
src/test/debuginfo/struct-style-enum-legacy.rs [deleted file]
src/test/debuginfo/tuple-style-enum-legacy.rs [deleted file]
src/test/debuginfo/unique-enum-legacy.rs [deleted file]
src/test/mir-opt/const-promotion-extern-static.rs [new file with mode: 0644]
src/test/mir-opt/const_prop/ref_deref.rs
src/test/mir-opt/const_prop/ref_deref_project.rs [new file with mode: 0644]
src/test/mir-opt/const_prop/slice_len.rs
src/test/mir-opt/inline/inline-retag.rs
src/test/mir-opt/match_false_edges.rs
src/test/run-make-fulldeps/sanitizer-address/Makefile
src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile [deleted file]
src/test/run-make-fulldeps/sanitizer-invalid-cratetype/hello.rs [deleted file]
src/test/run-make-fulldeps/sanitizer-invalid-target/Makefile
src/test/run-make-fulldeps/sanitizer-leak/Makefile
src/test/run-make-fulldeps/sanitizer-memory/Makefile
src/test/run-make-fulldeps/simd-ffi/simd.rs
src/test/run-make/wasm-export-all-symbols/bar.rs
src/test/run-make/wasm-export-all-symbols/verify.js
src/test/rustdoc/duplicate-cfg.rs
src/test/rustdoc/issue-46380.rs [deleted file]
src/test/rustdoc/issue-67851-both.rs [new file with mode: 0644]
src/test/rustdoc/issue-67851-hidden.rs [new file with mode: 0644]
src/test/rustdoc/issue-67851-neither.rs [new file with mode: 0644]
src/test/rustdoc/issue-67851-private.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
src/test/ui-fulldeps/lint-plugin-forbid-attrs.rs
src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr
src/test/ui-fulldeps/lint-plugin-forbid-cmdline.rs
src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr
src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr
src/test/ui-fulldeps/lint-tool-test.rs
src/test/ui-fulldeps/lint-tool-test.stderr
src/test/ui/associated-const/associated-const-no-item.rs
src/test/ui/associated-const/issue-63496.stderr
src/test/ui/associated-item/associated-item-enum.stderr
src/test/ui/associated-item/issue-48027.stderr
src/test/ui/associated-type-bounds/duplicate.rs
src/test/ui/associated-type-bounds/duplicate.stderr
src/test/ui/async-await/dont-suggest-missing-await.stderr
src/test/ui/async-await/issue-64130-3-other.stderr
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr
src/test/ui/async-await/suggest-missing-await-closure.stderr
src/test/ui/async-await/suggest-missing-await.stderr
src/test/ui/async-await/unresolved_type_param.rs
src/test/ui/async-await/unresolved_type_param.stderr
src/test/ui/attributes/register-attr-tool-import.rs
src/test/ui/attributes/register-attr-tool-import.stderr
src/test/ui/auto-ref-slice-plus-ref.stderr
src/test/ui/block-result/issue-3563.rs
src/test/ui/block-result/issue-3563.stderr
src/test/ui/bogus-tag.stderr
src/test/ui/borrowck/borrowck-move-out-from-array-match.rs [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-from-array-use-match.rs [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs [new file with mode: 0644]
src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr [new file with mode: 0644]
src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs
src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
src/test/ui/class-cast-to-trait.stderr
src/test/ui/closures/closure-reform-bad.stderr
src/test/ui/coherence/coherence_inherent.stderr
src/test/ui/coherence/coherence_inherent_cc.stderr
src/test/ui/conflicting-repr-hints.rs
src/test/ui/conflicting-repr-hints.stderr
src/test/ui/confuse-field-and-method/issue-18343.stderr
src/test/ui/confuse-field-and-method/issue-2392.stderr
src/test/ui/confuse-field-and-method/issue-32128.stderr
src/test/ui/confuse-field-and-method/issue-33784.stderr
src/test/ui/confuse-field-and-method/private-field.stderr
src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
src/test/ui/consts/array-literal-index-oob.rs
src/test/ui/consts/array-literal-index-oob.stderr
src/test/ui/consts/const-eval/conditional_array_execution.rs
src/test/ui/consts/const-eval/conditional_array_execution.stderr
src/test/ui/consts/const-eval/const-eval-overflow-2.rs
src/test/ui/consts/const-eval/const-eval-overflow-2.stderr
src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
src/test/ui/consts/const-eval/issue-43197.rs
src/test/ui/consts/const-eval/issue-43197.stderr
src/test/ui/consts/const-eval/issue-44578.rs
src/test/ui/consts/const-eval/issue-50814.rs
src/test/ui/consts/const-eval/issue-50814.stderr
src/test/ui/consts/const-eval/promoted_errors.rs
src/test/ui/consts/const-eval/promoted_errors.stderr
src/test/ui/consts/const-eval/promoted_errors2.rs
src/test/ui/consts/const-eval/promoted_errors2.stderr
src/test/ui/consts/const-eval/ref_to_int_match.rs
src/test/ui/consts/const-eval/ref_to_int_match.stderr
src/test/ui/consts/const-eval/ub-nonnull.stderr
src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr [new file with mode: 0644]
src/test/ui/consts/const-fn-not-safe-for-const.stderr
src/test/ui/consts/const-mut-refs/const_mut_refs.rs
src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
src/test/ui/consts/control-flow/short-circuit-let.rs
src/test/ui/consts/control-flow/single_variant_match_ice.rs
src/test/ui/consts/enum-discr-type-err.rs
src/test/ui/consts/enum-discr-type-err.stderr
src/test/ui/consts/match_ice.rs
src/test/ui/consts/match_ice.stderr
src/test/ui/consts/miri_unleashed/const_refers_to_static.rs
src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr
src/test/ui/consts/miri_unleashed/mutable_const2.stderr
src/test/ui/consts/miri_unleashed/non_const_fn.rs
src/test/ui/consts/miri_unleashed/non_const_fn.stderr
src/test/ui/consts/too_generic_eval_ice.stderr
src/test/ui/consts/transmute-size-mismatch-before-typeck.rs
src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr
src/test/ui/consts/zst_no_llvm_alloc.rs
src/test/ui/copy-a-resource.stderr
src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs
src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
src/test/ui/deduplicate-diagnostics-2.deduplicate.stderr [new file with mode: 0644]
src/test/ui/deduplicate-diagnostics-2.duplicate.stderr [new file with mode: 0644]
src/test/ui/deduplicate-diagnostics-2.rs [new file with mode: 0644]
src/test/ui/deduplicate-diagnostics.deduplicate.stderr
src/test/ui/deduplicate-diagnostics.duplicate.stderr
src/test/ui/deduplicate-diagnostics.rs
src/test/ui/derives/derive-assoc-type-not-impl.stderr
src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.rs
src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr
src/test/ui/derives/derives-span-PartialOrd-enum.rs
src/test/ui/derives/derives-span-PartialOrd-enum.stderr
src/test/ui/derives/derives-span-PartialOrd-struct.rs
src/test/ui/derives/derives-span-PartialOrd-struct.stderr
src/test/ui/derives/derives-span-PartialOrd-tuple-struct.rs
src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr
src/test/ui/derives/deriving-bounds.rs
src/test/ui/derives/deriving-bounds.stderr
src/test/ui/derives/deriving-meta-unknown-trait.rs
src/test/ui/derives/deriving-meta-unknown-trait.stderr
src/test/ui/derives/deriving-primitive.rs
src/test/ui/derives/deriving-primitive.stderr
src/test/ui/did_you_mean/bad-assoc-pat.rs
src/test/ui/did_you_mean/bad-assoc-pat.stderr
src/test/ui/did_you_mean/issue-40006.rs
src/test/ui/did_you_mean/issue-40006.stderr
src/test/ui/did_you_mean/issue-40396.rs
src/test/ui/did_you_mean/issue-40396.stderr
src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs
src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr
src/test/ui/dont-suggest-private-trait-method.rs
src/test/ui/dont-suggest-private-trait-method.stderr
src/test/ui/empty/empty-struct-braces-expr.rs
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/empty/empty-struct-tuple-pat.stderr
src/test/ui/empty/empty-struct-unit-pat.stderr
src/test/ui/error-codes/E0030.rs
src/test/ui/error-codes/E0030.stderr
src/test/ui/error-codes/E0452.rs
src/test/ui/error-codes/E0452.stderr
src/test/ui/error-codes/E0453.rs
src/test/ui/error-codes/E0453.stderr
src/test/ui/error-codes/E0565.rs
src/test/ui/error-codes/E0565.stderr
src/test/ui/error-codes/E0586.stderr
src/test/ui/error-codes/E0599.stderr
src/test/ui/error-codes/E0602.stderr
src/test/ui/error-festival.stderr
src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.rs [deleted file]
src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr [deleted file]
src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.rs [deleted file]
src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr [deleted file]
src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs [deleted file]
src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr [deleted file]
src/test/ui/extern/extern-types-distinct-types.stderr
src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
src/test/ui/feature-gate/issue-43106-gating-of-derive-2.rs
src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr
src/test/ui/feature-gate/issue-43106-gating-of-rustc_deprecated.rs
src/test/ui/feature-gate/issue-43106-gating-of-rustc_deprecated.stderr
src/test/ui/feature-gate/issue-43106-gating-of-stable.rs
src/test/ui/feature-gate/issue-43106-gating-of-stable.stderr
src/test/ui/feature-gate/issue-43106-gating-of-unstable.rs
src/test/ui/feature-gate/issue-43106-gating-of-unstable.stderr
src/test/ui/feature-gates/feature-gate-external_doc.rs
src/test/ui/feature-gates/feature-gate-external_doc.stderr
src/test/ui/feature-gates/feature-gate-lint-reasons.rs
src/test/ui/feature-gates/feature-gate-lint-reasons.stderr
src/test/ui/feature-gates/feature-gate-repr-simd.rs
src/test/ui/feature-gates/feature-gate-repr-simd.stderr
src/test/ui/feature-gates/feature-gate-sanitizer-runtime.rs [deleted file]
src/test/ui/feature-gates/feature-gate-sanitizer-runtime.stderr [deleted file]
src/test/ui/generator/auto-trait-regions.nll.stderr
src/test/ui/generator/auto-trait-regions.rs
src/test/ui/generator/auto-trait-regions.stderr
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-semantics.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/pat-tuple-4.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/pat-tuple-5.rs [new file with mode: 0644]
src/test/ui/half-open-range-patterns/pat-tuple-5.stderr [new file with mode: 0644]
src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr
src/test/ui/hrtb/hrtb-perfect-forwarding.rs
src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
src/test/ui/hrtb/issue-30786.nll.stderr
src/test/ui/hrtb/issue-30786.rs
src/test/ui/hygiene/no_implicit_prelude.stderr
src/test/ui/hygiene/trait_items.rs
src/test/ui/hygiene/trait_items.stderr
src/test/ui/impl-trait/auto-trait-leak.rs
src/test/ui/impl-trait/auto-trait-leak.stderr
src/test/ui/impl-trait/auto-trait-leak2.stderr
src/test/ui/impl-trait/bindings-opaque.stderr
src/test/ui/impl-trait/equality2.stderr
src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs
src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr
src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
src/test/ui/impl-trait/no-method-suggested-traits.rs
src/test/ui/impl-trait/no-method-suggested-traits.stderr
src/test/ui/imports/issue-55457.rs
src/test/ui/imports/issue-55457.stderr
src/test/ui/imports/local-modularized-tricky-fail-1.rs
src/test/ui/imports/local-modularized-tricky-fail-1.stderr
src/test/ui/imports/macros.rs
src/test/ui/imports/macros.stderr
src/test/ui/impossible_range.rs
src/test/ui/impossible_range.stderr
src/test/ui/infinite/infinite-autoderef.stderr
src/test/ui/internal/internal-unstable-const.rs [new file with mode: 0644]
src/test/ui/internal/internal-unstable-const.stderr [new file with mode: 0644]
src/test/ui/invalid_const_promotion.rs [deleted file]
src/test/ui/issues/issue-10465.stderr
src/test/ui/issues/issue-13853.stderr
src/test/ui/issues/issue-14221.stderr
src/test/ui/issues/issue-17546.rs
src/test/ui/issues/issue-17546.stderr
src/test/ui/issues/issue-17718-const-bad-values.rs
src/test/ui/issues/issue-17718-const-bad-values.stderr
src/test/ui/issues/issue-17718-references.stderr
src/test/ui/issues/issue-18118-2.rs
src/test/ui/issues/issue-18118-2.stderr
src/test/ui/issues/issue-19100.stderr
src/test/ui/issues/issue-19521.stderr
src/test/ui/issues/issue-19692.stderr
src/test/ui/issues/issue-20831-debruijn.rs
src/test/ui/issues/issue-20831-debruijn.stderr
src/test/ui/issues/issue-21596.stderr
src/test/ui/issues/issue-22933-2.rs
src/test/ui/issues/issue-22933-2.stderr
src/test/ui/issues/issue-22933-3.rs
src/test/ui/issues/issue-23173.rs
src/test/ui/issues/issue-23173.stderr
src/test/ui/issues/issue-23217.rs
src/test/ui/issues/issue-23217.stderr
src/test/ui/issues/issue-24036.stderr
src/test/ui/issues/issue-25385.rs
src/test/ui/issues/issue-2823.stderr
src/test/ui/issues/issue-28344.stderr
src/test/ui/issues/issue-28586.rs
src/test/ui/issues/issue-28837.rs
src/test/ui/issues/issue-28837.stderr
src/test/ui/issues/issue-28971.rs
src/test/ui/issues/issue-28971.stderr
src/test/ui/issues/issue-29124.rs
src/test/ui/issues/issue-29124.stderr
src/test/ui/issues/issue-30123.rs
src/test/ui/issues/issue-30123.stderr
src/test/ui/issues/issue-30302.stderr
src/test/ui/issues/issue-31173.stderr
src/test/ui/issues/issue-32963.rs
src/test/ui/issues/issue-32963.stderr
src/test/ui/issues/issue-33571.rs
src/test/ui/issues/issue-33571.stderr
src/test/ui/issues/issue-33575.rs
src/test/ui/issues/issue-33575.stderr
src/test/ui/issues/issue-34209.rs
src/test/ui/issues/issue-34209.stderr
src/test/ui/issues/issue-34229.rs
src/test/ui/issues/issue-34229.stderr
src/test/ui/issues/issue-34334.rs
src/test/ui/issues/issue-34334.stderr
src/test/ui/issues/issue-35677.stderr
src/test/ui/issues/issue-36617.rs
src/test/ui/issues/issue-36617.stderr
src/test/ui/issues/issue-3707.rs
src/test/ui/issues/issue-3707.stderr
src/test/ui/issues/issue-38919.rs
src/test/ui/issues/issue-38919.stderr
src/test/ui/issues/issue-39175.stderr
src/test/ui/issues/issue-39559.rs
src/test/ui/issues/issue-39559.stderr
src/test/ui/issues/issue-39720.rs
src/test/ui/issues/issue-39720.stderr [deleted file]
src/test/ui/issues/issue-3973.rs
src/test/ui/issues/issue-3973.stderr
src/test/ui/issues/issue-41255.rs
src/test/ui/issues/issue-41255.stderr
src/test/ui/issues/issue-41880.rs
src/test/ui/issues/issue-41880.stderr
src/test/ui/issues/issue-42880.stderr
src/test/ui/issues/issue-43105.rs
src/test/ui/issues/issue-43105.stderr
src/test/ui/issues/issue-43189.rs
src/test/ui/issues/issue-43189.stderr
src/test/ui/issues/issue-46101.rs
src/test/ui/issues/issue-46101.stderr
src/test/ui/issues/issue-47094.rs
src/test/ui/issues/issue-47094.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.rs [deleted file]
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.stderr [deleted file]
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.rs [deleted file]
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.stderr [deleted file]
src/test/ui/issues/issue-50480.rs
src/test/ui/issues/issue-50480.stderr
src/test/ui/issues/issue-5153.rs
src/test/ui/issues/issue-5153.stderr
src/test/ui/issues/issue-52060.stderr
src/test/ui/issues/issue-53251.rs
src/test/ui/issues/issue-53251.stderr
src/test/ui/issues/issue-54062.stderr
src/test/ui/issues/issue-57362-1.stderr
src/test/ui/issues/issue-57362-2.stderr
src/test/ui/issues/issue-58022.stderr
src/test/ui/issues/issue-58734.rs
src/test/ui/issues/issue-58734.stderr
src/test/ui/issues/issue-59029-1.rs
src/test/ui/issues/issue-59029-1.stderr
src/test/ui/issues/issue-62554.rs
src/test/ui/issues/issue-62554.stderr
src/test/ui/issues/issue-64430.stderr
src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs
src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr
src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.rs [new file with mode: 0644]
src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.stderr [new file with mode: 0644]
src/test/ui/issues/issue-6804.rs
src/test/ui/issues/issue-6804.stderr
src/test/ui/issues/issue-68091-unicode-ident-after-if.rs [new file with mode: 0644]
src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr [new file with mode: 0644]
src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs [new file with mode: 0644]
src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr [new file with mode: 0644]
src/test/ui/issues/issue-68103.rs [new file with mode: 0644]
src/test/ui/issues/issue-7607-1.rs
src/test/ui/issues/issue-7607-1.stderr
src/test/ui/issues/issue-7950.rs
src/test/ui/issues/issue-7950.stderr
src/test/ui/kindck/kindck-nonsendable-1.stderr
src/test/ui/lexical-scopes.stderr
src/test/ui/lint/lint-forbid-attr.rs
src/test/ui/lint/lint-forbid-attr.stderr
src/test/ui/lint/lint-forbid-cmdline.rs
src/test/ui/lint/lint-forbid-cmdline.stderr
src/test/ui/lint/lint-malformed.rs
src/test/ui/lint/lint-malformed.stderr
src/test/ui/lint/lint-removed-cmdline.stderr
src/test/ui/lint/lint-renamed-cmdline.stderr
src/test/ui/lint/lint-stability-deprecated.rs
src/test/ui/lint/lint-stability-deprecated.stderr
src/test/ui/lint/lint-unexported-no-mangle.stderr
src/test/ui/lint/lint-unknown-lint-cmdline.stderr
src/test/ui/lint/lint-uppercase-variables.stderr
src/test/ui/lint/outer-forbid.rs
src/test/ui/lint/outer-forbid.stderr
src/test/ui/lint/reasons-erroneous.rs
src/test/ui/lint/reasons-erroneous.stderr
src/test/ui/lint/reasons-forbidden.rs
src/test/ui/lint/reasons-forbidden.stderr
src/test/ui/macros/builtin-std-paths-fail.rs
src/test/ui/macros/builtin-std-paths-fail.stderr
src/test/ui/macros/issue-68058.rs [new file with mode: 0644]
src/test/ui/macros/macro-name-typo.rs
src/test/ui/macros/macro-name-typo.stderr
src/test/ui/macros/macro-path-prelude-fail-3.rs
src/test/ui/macros/macro-path-prelude-fail-3.stderr
src/test/ui/macros/macro-use-wrong-name.stderr
src/test/ui/macros/meta-item-absolute-path.rs
src/test/ui/macros/meta-item-absolute-path.stderr
src/test/ui/match/match-range-fail-2.rs
src/test/ui/match/match-range-fail-2.stderr
src/test/ui/methods/method-call-err-msg.rs
src/test/ui/methods/method-call-err-msg.stderr
src/test/ui/mir/issue-67947.rs [new file with mode: 0644]
src/test/ui/mir/issue-67947.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-36053-2.stderr
src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs
src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/never_type/issue-2149.rs
src/test/ui/never_type/issue-2149.stderr
src/test/ui/no-send-res-ports.stderr
src/test/ui/non-copyable-void.stderr
src/test/ui/non-ice-error-on-worker-io-fail.rs [new file with mode: 0644]
src/test/ui/non-ice-error-on-worker-io-fail.stderr [new file with mode: 0644]
src/test/ui/noncopyable-class.stderr
src/test/ui/not-clone-closure.stderr
src/test/ui/object-pointer-types.stderr
src/test/ui/parse-error-correct.rs
src/test/ui/parse-error-correct.stderr
src/test/ui/parser-recovery-1.rs
src/test/ui/parser-recovery-1.stderr
src/test/ui/parser-recovery-2.rs
src/test/ui/parser-recovery-2.stderr
src/test/ui/parser/ascii-only-character-escape.rs
src/test/ui/parser/ascii-only-character-escape.stderr
src/test/ui/parser/attr-stmt-expr-attr-bad.rs
src/test/ui/parser/attr-stmt-expr-attr-bad.stderr
src/test/ui/parser/bad-char-literals.rs
src/test/ui/parser/bad-char-literals.stderr
src/test/ui/parser/bounds-type.rs
src/test/ui/parser/bounds-type.stderr
src/test/ui/parser/byte-literals.rs
src/test/ui/parser/byte-literals.stderr
src/test/ui/parser/byte-string-literals.rs
src/test/ui/parser/byte-string-literals.stderr
src/test/ui/parser/chained-comparison-suggestion.rs [new file with mode: 0644]
src/test/ui/parser/chained-comparison-suggestion.stderr [new file with mode: 0644]
src/test/ui/parser/impl-parsing.rs
src/test/ui/parser/impl-parsing.stderr
src/test/ui/parser/issue-23620-invalid-escapes.rs
src/test/ui/parser/issue-23620-invalid-escapes.stderr
src/test/ui/parser/issue-62913.rs
src/test/ui/parser/issue-62913.stderr
src/test/ui/parser/issue-62973.rs
src/test/ui/parser/issue-62973.stderr
src/test/ui/parser/issue-63115-range-pat-interpolated.rs
src/test/ui/parser/issue-63135.rs
src/test/ui/parser/issue-63135.stderr
src/test/ui/parser/issue-66357-unexpected-unreachable.rs
src/test/ui/parser/issue-66357-unexpected-unreachable.stderr
src/test/ui/parser/lex-bad-char-literals-1.rs
src/test/ui/parser/lex-bad-char-literals-1.stderr
src/test/ui/parser/lex-bad-char-literals-7.rs
src/test/ui/parser/lex-bad-char-literals-7.stderr
src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.rs
src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr
src/test/ui/parser/missing_right_paren.rs
src/test/ui/parser/missing_right_paren.stderr
src/test/ui/parser/pat-tuple-4.rs [deleted file]
src/test/ui/parser/pat-tuple-4.stderr [deleted file]
src/test/ui/parser/pat-tuple-5.rs [deleted file]
src/test/ui/parser/pat-tuple-5.stderr [deleted file]
src/test/ui/parser/range_inclusive.rs
src/test/ui/parser/range_inclusive.stderr
src/test/ui/parser/raw-byte-string-literals.rs
src/test/ui/parser/recover-range-pats.rs
src/test/ui/parser/recover-range-pats.stderr
src/test/ui/parser/require-parens-for-chained-comparison.rs
src/test/ui/parser/require-parens-for-chained-comparison.stderr
src/test/ui/parser/type-parameters-in-field-exprs.rs
src/test/ui/parser/type-parameters-in-field-exprs.stderr
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
src/test/ui/pattern/const-pat-ice.stderr
src/test/ui/pattern/issue-67776-match-same-name-enum-variant-refs.stderr
src/test/ui/pattern/patkind-litrange-no-expr.rs
src/test/ui/pattern/patkind-litrange-no-expr.stderr
src/test/ui/pattern/usefulness/match-range-fail-dominate.rs
src/test/ui/pattern/usefulness/match-range-fail-dominate.stderr
src/test/ui/privacy/privacy1.rs
src/test/ui/privacy/privacy1.stderr
src/test/ui/privacy/private-in-public-assoc-ty.rs
src/test/ui/privacy/private-in-public-assoc-ty.stderr
src/test/ui/proc-macro/issue-50493.rs
src/test/ui/proc-macro/issue-50493.stderr
src/test/ui/proc-macro/macro-namespace-reserved-2.rs
src/test/ui/proc-macro/macro-namespace-reserved-2.stderr
src/test/ui/proc-macro/parent-source-spans.rs
src/test/ui/proc-macro/parent-source-spans.stderr
src/test/ui/proc-macro/resolve-error.rs
src/test/ui/proc-macro/resolve-error.stderr
src/test/ui/range/range_traits-1.rs
src/test/ui/range/range_traits-1.stderr
src/test/ui/regions/regions-close-object-into-object-5.rs
src/test/ui/regions/regions-close-object-into-object-5.stderr
src/test/ui/regions/regions-normalize-in-where-clause-list.rs
src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
src/test/ui/repr/repr-align-assign.fixed
src/test/ui/repr/repr-align-assign.rs
src/test/ui/repr/repr-align-assign.stderr
src/test/ui/repr/repr-align.rs
src/test/ui/repr/repr-align.stderr
src/test/ui/resolve/levenshtein.rs
src/test/ui/resolve/levenshtein.stderr
src/test/ui/rfc-2091-track-caller/std-panic-locations.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/syntax.rs [new file with mode: 0644]
src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs
src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr
src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs
src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr
src/test/ui/rfc1445/match-forbidden-without-eq.rs
src/test/ui/rfc1445/match-forbidden-without-eq.stderr
src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs
src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr
src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs
src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr
src/test/ui/rust-2018/uniform-paths/cross-crate.rs
src/test/ui/rust-2018/uniform-paths/cross-crate.stderr
src/test/ui/rust-2018/uniform-paths/prelude-fail-2.rs
src/test/ui/rust-2018/uniform-paths/prelude-fail-2.stderr
src/test/ui/self/point-at-arbitrary-self-type-method.stderr
src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
src/test/ui/self/suggest-self-2.rs
src/test/ui/self/suggest-self-2.stderr
src/test/ui/shadowed/shadowed-trait-methods.stderr
src/test/ui/span/issue-43927-non-ADT-derive.rs
src/test/ui/span/issue-43927-non-ADT-derive.stderr
src/test/ui/span/issue-7575.rs
src/test/ui/span/issue-7575.stderr
src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs
src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
src/test/ui/suffixed-literal-meta.rs
src/test/ui/suffixed-literal-meta.stderr
src/test/ui/suggestions/attribute-typos.rs
src/test/ui/suggestions/attribute-typos.stderr
src/test/ui/suggestions/constrain-trait.fixed
src/test/ui/suggestions/constrain-trait.rs
src/test/ui/suggestions/constrain-trait.stderr
src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
src/test/ui/suggestions/issue-21673.stderr
src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr [new file with mode: 0644]
src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
src/test/ui/suggestions/opaque-type-error.stderr
src/test/ui/suggestions/remove-as_str.rs
src/test/ui/suggestions/remove-as_str.stderr
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.rs
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs
src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr
src/test/ui/suggestions/suggest-methods.stderr
src/test/ui/suggestions/suggest-variants.rs
src/test/ui/suggestions/suggest-variants.stderr
src/test/ui/symbol-names/impl1.legacy.stderr
src/test/ui/tool-attributes/tool-attributes-misplaced-1.rs
src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
src/test/ui/tool_lints.rs
src/test/ui/tool_lints.stderr
src/test/ui/traits/trait-impl-1.rs
src/test/ui/traits/trait-impl-1.stderr
src/test/ui/traits/trait-item-privacy.rs
src/test/ui/traits/trait-item-privacy.stderr
src/test/ui/tuple/tuple-struct-fields/test2.rs
src/test/ui/tuple/tuple-struct-fields/test2.stderr
src/test/ui/tuple/tuple-struct-fields/test3.rs
src/test/ui/tuple/tuple-struct-fields/test3.stderr
src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr
src/test/ui/typeck/typeck_type_placeholder_item.rs
src/test/ui/typeck/typeck_type_placeholder_item.stderr
src/test/ui/ufcs/ufcs-partially-resolved.rs
src/test/ui/ufcs/ufcs-partially-resolved.stderr
src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
src/test/ui/underscore-imports/hygiene.stderr
src/test/ui/underscore-imports/shadow.stderr
src/test/ui/union/union-const-pat.rs
src/test/ui/union/union-const-pat.stderr
src/test/ui/union/union-derive-clone.rs
src/test/ui/union/union-derive-clone.stderr
src/test/ui/unique-object-noncopyable.stderr
src/test/ui/unique-pinned-nocopy.stderr
src/test/ui/unknown-lint-tool-name.rs
src/test/ui/unknown-lint-tool-name.stderr
src/test/ui/unspecified-self-in-trait-ref.stderr
src/test/ui/use/use-super-global-path.rs
src/test/ui/use/use-super-global-path.stderr
src/tools/clippy
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs

index 274c1eefbfb52b8e6da17c812495e7b959e5a393..4836e15cd799a698a0d7c0003ec23dfc877aa443 100644 (file)
@@ -1995,9 +1995,9 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "0.5.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c420bbc064623934620b5ab2dc0cf96451b34163329e82f95e7fa1b7b99a6ac8"
+checksum = "fef709d3257013bba7cff14fc504e07e80631d3fe0f6d38ce63b8f6510ccb932"
 dependencies = [
  "byteorder",
  "memmap",
@@ -3080,7 +3080,6 @@ dependencies = [
  "jobserver",
  "log",
  "measureme",
- "num_cpus",
  "parking_lot",
  "polonius-engine",
  "rustc-rayon",
@@ -3090,7 +3089,6 @@ dependencies = [
  "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
- "rustc_fs_util",
  "rustc_hir",
  "rustc_index",
  "rustc_macros",
@@ -3278,7 +3276,6 @@ dependencies = [
  "jemalloc-sys",
  "rustc_codegen_ssa",
  "rustc_driver",
- "rustc_target",
 ]
 
 [[package]]
@@ -3348,17 +3345,6 @@ dependencies = [
  "smallvec 1.0.0",
 ]
 
-[[package]]
-name = "rustc_asan"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "build_helper",
- "cmake",
- "compiler_builtins",
- "core",
-]
-
 [[package]]
 name = "rustc_ast_lowering"
 version = "0.0.0"
@@ -3377,6 +3363,21 @@ dependencies = [
  "syntax",
 ]
 
+[[package]]
+name = "rustc_ast_passes"
+version = "0.0.0"
+dependencies = [
+ "log",
+ "rustc_data_structures",
+ "rustc_error_codes",
+ "rustc_errors",
+ "rustc_feature",
+ "rustc_parse",
+ "rustc_session",
+ "rustc_span",
+ "syntax",
+]
+
 [[package]]
 name = "rustc_builtin_macros"
 version = "0.0.0"
@@ -3389,6 +3390,7 @@ dependencies = [
  "rustc_expand",
  "rustc_feature",
  "rustc_parse",
+ "rustc_session",
  "rustc_span",
  "rustc_target",
  "smallvec 1.0.0",
@@ -3409,7 +3411,6 @@ dependencies = [
  "rustc_codegen_utils",
  "rustc_data_structures",
  "rustc_errors",
- "rustc_expand",
  "rustc_feature",
  "rustc_fs_util",
  "rustc_hir",
@@ -3497,7 +3498,6 @@ name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
  "env_logger 0.7.1",
- "graphviz",
  "lazy_static 1.3.0",
  "log",
  "rustc",
@@ -3513,7 +3513,6 @@ dependencies = [
  "rustc_mir",
  "rustc_parse",
  "rustc_plugin_impl",
- "rustc_resolve",
  "rustc_save_analysis",
  "rustc_span",
  "rustc_target",
@@ -3545,11 +3544,13 @@ name = "rustc_expand"
 version = "0.0.0"
 dependencies = [
  "log",
+ "rustc_ast_passes",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_feature",
  "rustc_lexer",
  "rustc_parse",
+ "rustc_session",
  "rustc_span",
  "serialize",
  "smallvec 1.0.0",
@@ -3619,6 +3620,7 @@ dependencies = [
  "rustc",
  "rustc-rayon",
  "rustc_ast_lowering",
+ "rustc_ast_passes",
  "rustc_builtin_macros",
  "rustc_codegen_llvm",
  "rustc_codegen_ssa",
@@ -3631,11 +3633,13 @@ dependencies = [
  "rustc_lint",
  "rustc_metadata",
  "rustc_mir",
+ "rustc_mir_build",
  "rustc_parse",
  "rustc_passes",
  "rustc_plugin_impl",
  "rustc_privacy",
  "rustc_resolve",
+ "rustc_session",
  "rustc_span",
  "rustc_target",
  "rustc_traits",
@@ -3661,6 +3665,7 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_error_codes",
+ "rustc_errors",
  "rustc_feature",
  "rustc_hir",
  "rustc_index",
@@ -3680,17 +3685,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "rustc_lsan"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "build_helper",
- "cmake",
- "compiler_builtins",
- "core",
-]
-
 [[package]]
 name = "rustc_macros"
 version = "0.1.0"
@@ -3729,7 +3723,6 @@ dependencies = [
 name = "rustc_mir"
 version = "0.0.0"
 dependencies = [
- "arena",
  "either",
  "graphviz",
  "itertools 0.8.0",
@@ -3753,14 +3746,25 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustc_msan"
+name = "rustc_mir_build"
 version = "0.0.0"
 dependencies = [
- "alloc",
- "build_helper",
- "cmake",
- "compiler_builtins",
- "core",
+ "arena",
+ "itertools 0.8.0",
+ "log",
+ "rustc",
+ "rustc_apfloat",
+ "rustc_data_structures",
+ "rustc_error_codes",
+ "rustc_errors",
+ "rustc_hir",
+ "rustc_index",
+ "rustc_macros",
+ "rustc_span",
+ "rustc_target",
+ "serialize",
+ "smallvec 1.0.0",
+ "syntax",
 ]
 
 [[package]]
@@ -3774,6 +3778,7 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_lexer",
+ "rustc_session",
  "rustc_span",
  "smallvec 1.0.0",
  "syntax",
@@ -3792,7 +3797,7 @@ dependencies = [
  "rustc_feature",
  "rustc_hir",
  "rustc_index",
- "rustc_parse",
+ "rustc_session",
  "rustc_span",
  "rustc_target",
  "syntax",
@@ -3804,7 +3809,9 @@ version = "0.0.0"
 dependencies = [
  "rustc",
  "rustc_error_codes",
+ "rustc_errors",
  "rustc_hir",
+ "rustc_lint",
  "rustc_metadata",
  "rustc_span",
  "syntax",
@@ -3818,6 +3825,7 @@ dependencies = [
  "rustc",
  "rustc_data_structures",
  "rustc_error_codes",
+ "rustc_errors",
  "rustc_hir",
  "rustc_span",
  "rustc_typeck",
@@ -3870,6 +3878,7 @@ dependencies = [
  "log",
  "num_cpus",
  "rustc_data_structures",
+ "rustc_error_codes",
  "rustc_errors",
  "rustc_feature",
  "rustc_fs_util",
@@ -3933,17 +3942,6 @@ dependencies = [
  "syntax",
 ]
 
-[[package]]
-name = "rustc_tsan"
-version = "0.0.0"
-dependencies = [
- "alloc",
- "build_helper",
- "cmake",
- "compiler_builtins",
- "core",
-]
-
 [[package]]
 name = "rustc_typeck"
 version = "0.0.0"
@@ -4305,10 +4303,6 @@ dependencies = [
  "panic_unwind",
  "profiler_builtins",
  "rand 0.7.0",
- "rustc_asan",
- "rustc_lsan",
- "rustc_msan",
- "rustc_tsan",
  "unwind",
  "wasi 0.9.0+wasi-snapshot-preview1",
 ]
@@ -4462,8 +4456,6 @@ dependencies = [
 name = "syntax"
 version = "0.0.0"
 dependencies = [
- "bitflags",
- "lazy_static 1.3.0",
  "log",
  "rustc_data_structures",
  "rustc_error_codes",
index f7d8daa75ecb5fb95fb5bdb5ff382075cb096674..00c8e72a8f6851c82c68a4f0cd2925d8fd3ed584 100644 (file)
@@ -343,6 +343,7 @@ macro_rules! describe {
                 tool::Rustdoc,
                 tool::Clippy,
                 native::Llvm,
+                native::Sanitizers,
                 tool::Rustfmt,
                 tool::Miri,
                 native::Lld
@@ -726,7 +727,7 @@ pub fn cargo(
             self.clear_if_dirty(&my_out, &rustdoc);
         }
 
-        cargo.env("CARGO_TARGET_DIR", out_dir).arg(cmd).arg("-Zconfig-profile");
+        cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd).arg("-Zconfig-profile");
 
         let profile_var = |name: &str| {
             let profile = if self.config.rust_optimize { "RELEASE" } else { "DEV" };
@@ -865,6 +866,18 @@ pub fn cargo(
         let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot };
         let libdir = self.rustc_libdir(compiler);
 
+        // Clear the output directory if the real rustc we're using has changed;
+        // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
+        //
+        // Avoid doing this during dry run as that usually means the relevant
+        // compiler is not yet linked/copied properly.
+        //
+        // Only clear out the directory if we're compiling std; otherwise, we
+        // should let Cargo take care of things for us (via depdep info)
+        if !self.config.dry_run && mode == Mode::ToolStd && cmd == "build" {
+            self.clear_if_dirty(&out_dir, &self.rustc(compiler));
+        }
+
         // Customize the compiler we're running. Specify the compiler to cargo
         // as our shim and then pass it some various options used to configure
         // how the actual compiler itself is called.
index d4016f16fa9d3fe10b908fae38da240d47f40303..b76515763fbdb19a18d6049418ac28ee6d8165ab 100644 (file)
@@ -45,7 +45,7 @@ fn run(self, builder: &Builder<'_>) {
         let compiler = builder.compiler(0, builder.config.build);
 
         let mut cargo = builder.cargo(compiler, Mode::Std, target, cargo_subcommand(builder.kind));
-        std_cargo(builder, &compiler, target, &mut cargo);
+        std_cargo(builder, target, &mut cargo);
 
         builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
         run_cargo(
index 2d60024a22ac4ec6cedf3518fd97c200605c40ee..eced03506ab9ff64fcdcf91acf072556ea74c8d8 100644 (file)
@@ -87,7 +87,7 @@ fn run(self, builder: &Builder<'_>) {
         target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter());
 
         let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
-        std_cargo(builder, &compiler, target, &mut cargo);
+        std_cargo(builder, target, &mut cargo);
 
         builder.info(&format!(
             "Building stage{} std artifacts ({} -> {})",
@@ -153,17 +153,18 @@ fn copy_third_party_objects(
         copy_and_stamp(Path::new(&src), "libunwind.a");
     }
 
+    if builder.config.sanitizers && compiler.stage != 0 {
+        // The sanitizers are only copied in stage1 or above,
+        // to avoid creating dependency on LLVM.
+        target_deps.extend(copy_sanitizers(builder, &compiler, target));
+    }
+
     target_deps
 }
 
 /// Configure cargo to compile the standard library, adding appropriate env vars
 /// and such.
-pub fn std_cargo(
-    builder: &Builder<'_>,
-    compiler: &Compiler,
-    target: Interned<String>,
-    cargo: &mut Cargo,
-) {
+pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, cargo: &mut Cargo) {
     if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
         cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
     }
@@ -206,19 +207,6 @@ pub fn std_cargo(
         let mut features = builder.std_features();
         features.push_str(&compiler_builtins_c_feature);
 
-        if compiler.stage != 0 && builder.config.sanitizers {
-            // This variable is used by the sanitizer runtime crates, e.g.
-            // rustc_lsan, to build the sanitizer runtime from C code
-            // When this variable is missing, those crates won't compile the C code,
-            // so we don't set this variable during stage0 where llvm-config is
-            // missing
-            // We also only build the runtimes when --enable-sanitizers (or its
-            // config.toml equivalent) is used
-            let llvm_config = builder.ensure(native::Llvm { target: builder.config.build });
-            cargo.env("LLVM_CONFIG", llvm_config);
-            cargo.env("RUSTC_BUILD_SANITIZERS", "1");
-        }
-
         cargo
             .arg("--features")
             .arg(features)
@@ -276,31 +264,43 @@ fn run(self, builder: &Builder<'_>) {
         let libdir = builder.sysroot_libdir(target_compiler, target);
         let hostdir = builder.sysroot_libdir(target_compiler, compiler.host);
         add_to_sysroot(builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
-
-        if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
-            // The sanitizers are only built in stage1 or above, so the dylibs will
-            // be missing in stage0 and causes panic. See the `std()` function above
-            // for reason why the sanitizers are not built in stage0.
-            copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir);
-        }
     }
 }
 
-fn copy_apple_sanitizer_dylibs(
+/// Copies sanitizer runtime libraries into target libdir.
+fn copy_sanitizers(
     builder: &Builder<'_>,
-    native_dir: &Path,
-    platform: &str,
-    into: &Path,
-) {
-    for &sanitizer in &["asan", "tsan"] {
-        let filename = format!("lib__rustc__clang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
-        let mut src_path = native_dir.join(sanitizer);
-        src_path.push("build");
-        src_path.push("lib");
-        src_path.push("darwin");
-        src_path.push(&filename);
-        builder.copy(&src_path, &into.join(filename));
+    compiler: &Compiler,
+    target: Interned<String>,
+) -> Vec<PathBuf> {
+    let runtimes: Vec<native::SanitizerRuntime> = builder.ensure(native::Sanitizers { target });
+
+    if builder.config.dry_run {
+        return Vec::new();
+    }
+
+    let mut target_deps = Vec::new();
+    let libdir = builder.sysroot_libdir(*compiler, target);
+
+    for runtime in &runtimes {
+        let dst = libdir.join(&runtime.name);
+        builder.copy(&runtime.path, &dst);
+
+        if target == "x86_64-apple-darwin" {
+            // Update the library install name reflect the fact it has been renamed.
+            let status = Command::new("install_name_tool")
+                .arg("-id")
+                .arg(format!("@rpath/{}", runtime.name))
+                .arg(&dst)
+                .status()
+                .expect("failed to execute `install_name_tool`");
+            assert!(status.success());
+        }
+
+        target_deps.push(dst);
     }
+
+    target_deps
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -776,7 +776,6 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
         let bindir = sysroot.join("bin");
         t!(fs::create_dir_all(&bindir));
         let compiler = builder.rustc(target_compiler);
-        let _ = fs::remove_file(&compiler);
         builder.copy(&rustc, &compiler);
 
         target_compiler
index 944df66431fe8f39c00a0571d31a8446ed1617f1..110c8b844d54c6d68357b3161e753fda23c7d2a1 100644 (file)
@@ -493,9 +493,13 @@ pub fn parse(args: &[String]) -> Config {
             config.mandir = install.mandir.clone().map(PathBuf::from);
         }
 
+        // We want the llvm-skip-rebuild flag to take precedence over the
+        // skip-rebuild config.toml option so we store it separately
+        // so that we can infer the right value
+        let mut llvm_skip_rebuild = flags.llvm_skip_rebuild;
+
         // Store off these values as options because if they're not provided
         // we'll infer default values for them later
-        let mut llvm_skip_rebuild = None;
         let mut llvm_assertions = None;
         let mut debug = None;
         let mut debug_assertions = None;
@@ -517,7 +521,7 @@ pub fn parse(args: &[String]) -> Config {
             }
             set(&mut config.ninja, llvm.ninja);
             llvm_assertions = llvm.assertions;
-            llvm_skip_rebuild = llvm.skip_rebuild;
+            llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild);
             set(&mut config.llvm_optimize, llvm.optimize);
             set(&mut config.llvm_thin_lto, llvm.thin_lto);
             set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
index e64d4c8637d5527c1b0c4142b7b789fd9042d7e9..8d13df3ee21a49e2f179a68ae999d8cb041dca59 100644 (file)
@@ -984,10 +984,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             "src/libcore",
             "src/libpanic_abort",
             "src/libpanic_unwind",
-            "src/librustc_asan",
-            "src/librustc_lsan",
-            "src/librustc_msan",
-            "src/librustc_tsan",
             "src/libstd",
             "src/libunwind",
             "src/libtest",
index 8cd7fc2c172571b13035d725a7c54383b1523061..204056598d9004882914c0cc1f8cf4980f8f235f 100644 (file)
@@ -49,7 +49,7 @@ fn run(self, builder: &Builder<'_>) {
                 builder.ensure(RustbookSrc {
                     target: self.target,
                     name: INTERNER.intern_str($book_name),
-                    src: doc_src(builder),
+                    src: INTERNER.intern_path(builder.src.join($path)),
                 })
             }
         }
@@ -60,6 +60,7 @@ fn run(self, builder: &Builder<'_>) {
 // NOTE: When adding a book here, make sure to ALSO build the book by
 // adding a build step in `src/bootstrap/builder.rs`!
 book!(
+    CargoBook, "src/tools/cargo/src/doc", "cargo";
     EditionGuide, "src/doc/edition-guide", "edition-guide";
     EmbeddedBook, "src/doc/embedded-book", "embedded-book";
     Nomicon, "src/doc/nomicon", "nomicon";
@@ -69,10 +70,6 @@ fn run(self, builder: &Builder<'_>) {
     RustdocBook, "src/doc/rustdoc", "rustdoc";
 );
 
-fn doc_src(builder: &Builder<'_>) -> Interned<PathBuf> {
-    INTERNER.intern_path(builder.src.join("src/doc"))
-}
-
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBook {
     target: Interned<String>,
@@ -96,48 +93,11 @@ fn run(self, builder: &Builder<'_>) {
         builder.ensure(RustbookSrc {
             target: self.target,
             name: INTERNER.intern_str("unstable-book"),
-            src: builder.md_doc_out(self.target),
+            src: INTERNER.intern_path(builder.md_doc_out(self.target).join("unstable-book")),
         })
     }
 }
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct CargoBook {
-    target: Interned<String>,
-    name: Interned<String>,
-}
-
-impl Step for CargoBook {
-    type Output = ();
-    const DEFAULT: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        let builder = run.builder;
-        run.path("src/tools/cargo/src/doc/book").default_condition(builder.config.docs)
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(CargoBook { target: run.target, name: INTERNER.intern_str("cargo") });
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        let target = self.target;
-        let name = self.name;
-        let src = builder.src.join("src/tools/cargo/src/doc");
-
-        let out = builder.doc_out(target);
-        t!(fs::create_dir_all(&out));
-
-        let out = out.join(name);
-
-        builder.info(&format!("Cargo Book ({}) - {}", target, name));
-
-        let _ = fs::remove_dir_all(&out);
-
-        builder.run(builder.tool_cmd(Tool::Rustbook).arg("build").arg(&src).arg("-d").arg(out));
-    }
-}
-
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 struct RustbookSrc {
     target: Interned<String>,
@@ -164,7 +124,6 @@ fn run(self, builder: &Builder<'_>) {
         t!(fs::create_dir_all(&out));
 
         let out = out.join(name);
-        let src = src.join(name);
         let index = out.join("index.html");
         let rustbook = builder.tool_exe(Tool::Rustbook);
         let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
@@ -182,7 +141,6 @@ fn run(self, builder: &Builder<'_>) {
 pub struct TheBook {
     compiler: Compiler,
     target: Interned<String>,
-    name: &'static str,
 }
 
 impl Step for TheBook {
@@ -198,7 +156,6 @@ fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(TheBook {
             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
             target: run.target,
-            name: "book",
         });
     }
 
@@ -206,45 +163,30 @@ fn make_run(run: RunConfig<'_>) {
     ///
     /// We need to build:
     ///
-    /// * Book (first edition)
-    /// * Book (second edition)
+    /// * Book
+    /// * Older edition redirects
     /// * Version info and CSS
     /// * Index page
     /// * Redirect pages
     fn run(self, builder: &Builder<'_>) {
         let compiler = self.compiler;
         let target = self.target;
-        let name = self.name;
 
         // build book
         builder.ensure(RustbookSrc {
             target,
-            name: INTERNER.intern_string(name.to_string()),
-            src: doc_src(builder),
+            name: INTERNER.intern_str("book"),
+            src: INTERNER.intern_path(builder.src.join("src/doc/book")),
         });
 
         // building older edition redirects
-
-        let source_name = format!("{}/first-edition", name);
-        builder.ensure(RustbookSrc {
-            target,
-            name: INTERNER.intern_string(source_name),
-            src: doc_src(builder),
-        });
-
-        let source_name = format!("{}/second-edition", name);
-        builder.ensure(RustbookSrc {
-            target,
-            name: INTERNER.intern_string(source_name),
-            src: doc_src(builder),
-        });
-
-        let source_name = format!("{}/2018-edition", name);
-        builder.ensure(RustbookSrc {
-            target,
-            name: INTERNER.intern_string(source_name),
-            src: doc_src(builder),
-        });
+        for edition in &["first-edition", "second-edition", "2018-edition"] {
+            builder.ensure(RustbookSrc {
+                target,
+                name: INTERNER.intern_string(format!("book/{}", edition)),
+                src: INTERNER.intern_path(builder.src.join("src/doc/book").join(edition)),
+            });
+        }
 
         // build the version info page and CSS
         builder.ensure(Standalone { compiler, target });
@@ -449,7 +391,7 @@ fn run(self, builder: &Builder<'_>) {
 
         let run_cargo_rustdoc_for = |package: &str| {
             let mut cargo = builder.cargo(compiler, Mode::Std, target, "rustdoc");
-            compile::std_cargo(builder, &compiler, target, &mut cargo);
+            compile::std_cargo(builder, target, &mut cargo);
 
             // Keep a whitelist so we do not build internal stdlib crates, these will be
             // build by the rustc step later if enabled.
@@ -531,7 +473,7 @@ fn run(self, builder: &Builder<'_>) {
 
         // Build cargo command.
         let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
-        cargo.env("RUSTDOCFLAGS", "--document-private-items --passes strip-hidden");
+        cargo.env("RUSTDOCFLAGS", "--document-private-items");
         compile::rustc_cargo(builder, &mut cargo, target);
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
index ffc24367db6e9cf214479ee779ddbd3fb097cb02..1fbdd50a51133d4636c7b1bf5069c887a32dfcb0 100644 (file)
@@ -38,6 +38,8 @@ pub struct Flags {
     //
     // true => deny, false => warn
     pub deny_warnings: Option<bool>,
+
+    pub llvm_skip_rebuild: Option<bool>,
 }
 
 pub enum Subcommand {
@@ -150,6 +152,14 @@ pub fn parse(args: &[String]) -> Flags {
             "VALUE",
         );
         opts.optopt("", "error-format", "rustc error format", "FORMAT");
+        opts.optopt(
+            "",
+            "llvm-skip-rebuild",
+            "whether rebuilding llvm should be skipped \
+             a VALUE of TRUE indicates that llvm will not be rebuilt \
+             VALUE overrides the skip-rebuild option in config.toml.",
+            "VALUE",
+        );
 
         // fn usage()
         let usage =
@@ -487,6 +497,9 @@ pub fn parse(args: &[String]) -> Flags {
                 .map(|p| p.into())
                 .collect::<Vec<_>>(),
             deny_warnings: parse_deny_warnings(&matches),
+            llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map(
+                |s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"),
+            ),
         }
     }
 }
index 2a4e9903e5527d4a4c801c0c53000499e453253c..ce977f1bbc44e5c0eda159230ba65cda643746d1 100644 (file)
@@ -546,3 +546,118 @@ fn run(self, builder: &Builder<'_>) {
             .compile("rust_test_helpers");
     }
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Sanitizers {
+    pub target: Interned<String>,
+}
+
+impl Step for Sanitizers {
+    type Output = Vec<SanitizerRuntime>;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/llvm-project/compiler-rt").path("src/sanitizers")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Sanitizers { target: run.target });
+    }
+
+    /// Builds sanitizer runtime libraries.
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let compiler_rt_dir = builder.src.join("src/llvm-project/compiler-rt");
+        if !compiler_rt_dir.exists() {
+            return Vec::new();
+        }
+
+        let out_dir = builder.native_dir(self.target).join("sanitizers");
+        let runtimes = supported_sanitizers(&out_dir, self.target);
+        if runtimes.is_empty() {
+            return runtimes;
+        }
+
+        let llvm_config = builder.ensure(Llvm { target: builder.config.build });
+        if builder.config.dry_run {
+            return runtimes;
+        }
+
+        let done_stamp = out_dir.join("sanitizers-finished-building");
+        if done_stamp.exists() {
+            builder.info(&format!(
+                "Assuming that sanitizers rebuild is not necessary. \
+                To force a rebuild, remove the file `{}`",
+                done_stamp.display()
+            ));
+            return runtimes;
+        }
+
+        builder.info(&format!("Building sanitizers for {}", self.target));
+        let _time = util::timeit(&builder);
+
+        let mut cfg = cmake::Config::new(&compiler_rt_dir);
+        cfg.target(&self.target);
+        cfg.host(&builder.config.build);
+        cfg.profile("Release");
+
+        cfg.define("CMAKE_C_COMPILER_TARGET", self.target);
+        cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF");
+        cfg.define("COMPILER_RT_BUILD_CRT", "OFF");
+        cfg.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF");
+        cfg.define("COMPILER_RT_BUILD_PROFILE", "OFF");
+        cfg.define("COMPILER_RT_BUILD_SANITIZERS", "ON");
+        cfg.define("COMPILER_RT_BUILD_XRAY", "OFF");
+        cfg.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON");
+        cfg.define("COMPILER_RT_USE_LIBCXX", "OFF");
+        cfg.define("LLVM_CONFIG_PATH", &llvm_config);
+
+        t!(fs::create_dir_all(&out_dir));
+        cfg.out_dir(out_dir);
+
+        for runtime in &runtimes {
+            cfg.build_target(&runtime.cmake_target);
+            cfg.build();
+        }
+
+        t!(fs::write(&done_stamp, b""));
+
+        runtimes
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct SanitizerRuntime {
+    /// CMake target used to build the runtime.
+    pub cmake_target: String,
+    /// Path to the built runtime library.
+    pub path: PathBuf,
+    /// Library filename that will be used rustc.
+    pub name: String,
+}
+
+/// Returns sanitizers available on a given target.
+fn supported_sanitizers(out_dir: &Path, target: Interned<String>) -> Vec<SanitizerRuntime> {
+    let mut result = Vec::new();
+    match &*target {
+        "x86_64-apple-darwin" => {
+            for s in &["asan", "lsan", "tsan"] {
+                result.push(SanitizerRuntime {
+                    cmake_target: format!("clang_rt.{}_osx_dynamic", s),
+                    path: out_dir
+                        .join(&format!("build/lib/darwin/libclang_rt.{}_osx_dynamic.dylib", s)),
+                    name: format!("librustc_rt.{}.dylib", s),
+                });
+            }
+        }
+        "x86_64-unknown-linux-gnu" => {
+            for s in &["asan", "lsan", "msan", "tsan"] {
+                result.push(SanitizerRuntime {
+                    cmake_target: format!("clang_rt.{}-x86_64", s),
+                    path: out_dir.join(&format!("build/lib/linux/libclang_rt.{}-x86_64.a", s)),
+                    name: format!("librustc_rt.{}.a", s),
+                });
+            }
+        }
+        _ => {}
+    }
+    result
+}
index b5c8de057d017b6b174853ea62b399f23270dc68..10e07489e1212ce76f804a177b1fa8cc5c7ee8cf 100644 (file)
@@ -1659,7 +1659,7 @@ fn run(self, builder: &Builder<'_>) {
         let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
         match mode {
             Mode::Std => {
-                compile::std_cargo(builder, &compiler, target, &mut cargo);
+                compile::std_cargo(builder, target, &mut cargo);
             }
             Mode::Rustc => {
                 builder.ensure(compile::Rustc { compiler, target });
index 9fd20386e367bd815c7cb872f1ca9aec4272913b..7f24768a4f10e54cce459ab65dc2af4f46134f0f 100644 (file)
@@ -289,8 +289,8 @@ fn rustbook_features() -> Vec<String> {
 macro_rules! bootstrap_tool {
     ($(
         $name:ident, $path:expr, $tool_name:expr
-        $(,llvm_tools = $llvm:expr)*
         $(,is_external_tool = $external:expr)*
+        $(,is_unstable_tool = $unstable:expr)*
         $(,features = $features:expr)*
         ;
     )+) => {
@@ -301,15 +301,6 @@ pub enum Tool {
             )+
         }
 
-        impl Tool {
-            /// Whether this tool requires LLVM to run
-            pub fn uses_llvm_tools(&self) -> bool {
-                match self {
-                    $(Tool::$name => false $(|| $llvm)*,)+
-                }
-            }
-        }
-
         impl<'a> Builder<'a> {
             pub fn tool_exe(&self, tool: Tool) -> PathBuf {
                 match tool {
@@ -350,7 +341,12 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                     compiler: self.compiler,
                     target: self.target,
                     tool: $tool_name,
-                    mode: Mode::ToolBootstrap,
+                    mode: if false $(|| $unstable)* {
+                        // use in-tree libraries for unstable features
+                        Mode::ToolStd
+                    } else {
+                        Mode::ToolBootstrap
+                    },
                     path: $path,
                     is_optional_tool: false,
                     source_type: if false $(|| $external)* {
@@ -377,7 +373,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
     Tidy, "src/tools/tidy", "tidy";
     Linkchecker, "src/tools/linkchecker", "linkchecker";
     CargoTest, "src/tools/cargotest", "cargotest";
-    Compiletest, "src/tools/compiletest", "compiletest", llvm_tools = true;
+    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";
     RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
index 3f42533238a89dc0cfcba06e016f63dee2d209e1..43c3c5773ce5b2d45cd32ee1157cf2d8ce0dc1b2 100644 (file)
@@ -1,7 +1,5 @@
-use std::fs::File;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
-use std::thread;
 use std::time::{SystemTime, UNIX_EPOCH};
 use std::{env, fs};
 
@@ -181,108 +179,6 @@ pub fn up_to_date(src: &Path, dst: &Path) -> bool {
     }
 }
 
-#[must_use]
-pub struct NativeLibBoilerplate {
-    pub src_dir: PathBuf,
-    pub out_dir: PathBuf,
-}
-
-impl NativeLibBoilerplate {
-    /// On macOS we don't want to ship the exact filename that compiler-rt builds.
-    /// This conflicts with the system and ours is likely a wildly different
-    /// version, so they can't be substituted.
-    ///
-    /// As a result, we rename it here but we need to also use
-    /// `install_name_tool` on macOS to rename the commands listed inside of it to
-    /// ensure it's linked against correctly.
-    pub fn fixup_sanitizer_lib_name(&self, sanitizer_name: &str) {
-        if env::var("TARGET").unwrap() != "x86_64-apple-darwin" {
-            return;
-        }
-
-        let dir = self.out_dir.join("build/lib/darwin");
-        let name = format!("clang_rt.{}_osx_dynamic", sanitizer_name);
-        let src = dir.join(&format!("lib{}.dylib", name));
-        let new_name = format!("lib__rustc__{}.dylib", name);
-        let dst = dir.join(&new_name);
-
-        println!("{} => {}", src.display(), dst.display());
-        fs::rename(&src, &dst).unwrap();
-        let status = Command::new("install_name_tool")
-            .arg("-id")
-            .arg(format!("@rpath/{}", new_name))
-            .arg(&dst)
-            .status()
-            .expect("failed to execute `install_name_tool`");
-        assert!(status.success());
-    }
-}
-
-impl Drop for NativeLibBoilerplate {
-    fn drop(&mut self) {
-        if !thread::panicking() {
-            t!(File::create(self.out_dir.join("rustbuild.timestamp")));
-        }
-    }
-}
-
-// Perform standard preparations for native libraries that are build only once for all stages.
-// Emit rerun-if-changed and linking attributes for Cargo, check if any source files are
-// updated, calculate paths used later in actual build with CMake/make or C/C++ compiler.
-// If Err is returned, then everything is up-to-date and further build actions can be skipped.
-// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
-// of scope, so all the build actions should be completed until then.
-pub fn native_lib_boilerplate(
-    src_dir: &Path,
-    out_name: &str,
-    link_name: &str,
-    search_subdir: &str,
-) -> Result<NativeLibBoilerplate, ()> {
-    rerun_if_changed_anything_in_dir(src_dir);
-
-    let out_dir =
-        env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or_else(|| env::var_os("OUT_DIR").unwrap());
-    let out_dir = PathBuf::from(out_dir).join(out_name);
-    t!(fs::create_dir_all(&out_dir));
-    if link_name.contains('=') {
-        println!("cargo:rustc-link-lib={}", link_name);
-    } else {
-        println!("cargo:rustc-link-lib=static={}", link_name);
-    }
-    println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display());
-
-    let timestamp = out_dir.join("rustbuild.timestamp");
-    if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(src_dir, &timestamp) {
-        Ok(NativeLibBoilerplate { src_dir: src_dir.to_path_buf(), out_dir })
-    } else {
-        Err(())
-    }
-}
-
-pub fn sanitizer_lib_boilerplate(
-    sanitizer_name: &str,
-) -> Result<(NativeLibBoilerplate, String), ()> {
-    let (link_name, search_path, apple) = match &*env::var("TARGET").unwrap() {
-        "x86_64-unknown-linux-gnu" => {
-            (format!("clang_rt.{}-x86_64", sanitizer_name), "build/lib/linux", false)
-        }
-        "x86_64-apple-darwin" => {
-            (format!("clang_rt.{}_osx_dynamic", sanitizer_name), "build/lib/darwin", true)
-        }
-        _ => return Err(()),
-    };
-    let to_link = if apple {
-        format!("dylib=__rustc__{}", link_name)
-    } else {
-        format!("static={}", link_name)
-    };
-    // This env var is provided by rustbuild to tell us where `compiler-rt`
-    // lives.
-    let dir = env::var_os("RUST_COMPILER_RT_ROOT").unwrap();
-    let lib = native_lib_boilerplate(dir.as_ref(), sanitizer_name, &to_link, search_path)?;
-    Ok((lib, link_name))
-}
-
 fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
     t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
         let meta = t!(e.metadata());
index b2748d9c2ab79696791838f8d063e08f2619fc51..890e13232c3fd35055fbd279b74bd78fd936b497 100644 (file)
@@ -1,4 +1,4 @@
-FROM ubuntu:19.04
+FROM ubuntu:19.10
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
index 4ec4364721393691ced50f59359f95aa82e2bb20..b864c09ea8c45bd1a1b13c39549d34089d8ed059 100644 (file)
@@ -1,4 +1,4 @@
-FROM ubuntu:19.04
+FROM ubuntu:19.10
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
index 4c047069571bd4ad02ca00aa6f231b31540d43f0..7c43d034d8b7f70118010289502c920696548be5 100755 (executable)
@@ -1,6 +1,9 @@
-#!/bin/sh
+#!/bin/bash
 
-set -eu
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/shared.sh"
 
 # The following lines are also found in src/bootstrap/toolstate.rs,
 # so if updating here, please also update that file.
@@ -21,7 +24,7 @@ cd rust-toolstate
 FAILURE=1
 for RETRY_COUNT in 1 2 3 4 5; do
     #  The purpose is to publish the new "current" toolstate in the toolstate repo.
-    "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$GIT_COMMIT" \
+    "$(ciCheckoutPath)/src/tools/publish_toolstate.py" "$GIT_COMMIT" \
         "$GIT_COMMIT_MSG" \
         "$MESSAGE_FILE" \
         "$TOOLSTATE_REPO_ACCESS_TOKEN"
index f0179994e8e4cb5c44d2c0feea09793c487dd0fe..e16a4814197b31159b53040c4c950b59d222cf18 100755 (executable)
@@ -14,6 +14,15 @@ if isMacOS; then
     ciCommandSetEnv CC "$(pwd)/clang+llvm-9.0.0-x86_64-darwin-apple/bin/clang"
     ciCommandSetEnv CXX "$(pwd)/clang+llvm-9.0.0-x86_64-darwin-apple/bin/clang++"
 
+    # macOS 10.15 onwards doesn't have libraries in /usr/include anymore: those
+    # are now located deep into the filesystem, under Xcode's own files. The
+    # native clang is configured to use the correct path, but our custom one
+    # doesn't. This sets the SDKROOT environment variable to the SDK so that
+    # our own clang can figure out the correct include path on its own.
+    if ! [[ -d "/usr/include" ]]; then
+        ciCommandSetEnv SDKROOT "$(xcrun --sdk macosx --show-sdk-path)"
+    fi
+
     # Configure `AR` specifically so rustbuild doesn't try to infer it as
     # `clang-ar` by accident.
     ciCommandSetEnv AR "ar"
index 36d9202f7a2d30e61fb7f8c8afd6d6538d9fc8cb..843a2bf2d5e55a488e8c97ca952bb1ae0e9edc71 100755 (executable)
@@ -6,7 +6,8 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 if isWindows; then
-    pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar
+    pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar \
+        binutils
 
     # Make sure we use the native python interpreter instead of some msys equivalent
     # one way or another. The msys interpreters seem to have weird path conversions
index 98120f5dff95dafb63b62f2a8ac64221b88b73bb..206065d7072451b9aa4297e722817ca8a2be39be 100644 (file)
@@ -80,7 +80,7 @@ function ciCommit {
 
 function ciCheckoutPath {
     if isAzurePipelines; then
-        echo "${SYSTEM_WORKFOLDER}"
+        echo "${BUILD_SOURCESDIRECTORY}"
     elif isGitHubActions; then
         echo "${GITHUB_WORKSPACE}"
     else
@@ -99,7 +99,7 @@ function ciCommandAddPath {
     if isAzurePipelines; then
         echo "##vso[task.prependpath]${path}"
     elif isGitHubActions; then
-        echo "::add-path::${value}"
+        echo "::add-path::${path}"
     else
         echo "ciCommandAddPath only works inside CI!"
         exit 1
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
new file mode 100644 (file)
index 0000000..cbb90bd
--- /dev/null
@@ -0,0 +1,163 @@
+# `sanitizer`
+
+The tracking issue for this feature is: [#39699](https://github.com/rust-lang/rust/issues/39699).
+
+------------------------
+
+This feature allows for use of one of following sanitizers:
+
+* [AddressSanitizer][clang-asan] a faster memory error detector. Can
+  detect out-of-bounds access to heap, stack, and globals, use after free, use
+  after return, double free, invalid free, memory leaks.
+* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
+* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
+* [ThreadSanitizer][clang-tsan] a fast data race detector.
+
+To enable a sanitizer compile with `-Zsanitizer=...` option, where value is one
+of `address`, `leak`, `memory` or `thread`.
+
+# Examples
+
+This sections show various issues that can be detected with sanitizers.  For
+simplicity, the examples are prepared under assumption that optimization level
+used is zero.
+
+## AddressSanitizer
+
+Stack buffer overflow:
+
+```shell
+$ cat a.rs
+fn main() {
+    let xs = [0, 1, 2, 3];
+    let _y = unsafe { *xs.as_ptr().offset(4) };
+}
+$ rustc -Zsanitizer=address a.rs
+$ ./a
+=================================================================
+==10029==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcc15f43d0 at pc 0x55f77dc015c5 bp 0x7ffcc15f4390 sp 0x7ffcc15f4388
+READ of size 4 at 0x7ffcc15f43d0 thread T0
+    #0 0x55f77dc015c4 in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa5c4)
+    #1 0x55f77dc01cdb in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::haa8c76d1faa7b7ca (/tmp/a+0xacdb)
+    #2 0x55f77dc90f02 in std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::hfeb9a1aef9ac820d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:48:12
+    #3 0x55f77dc90f02 in std::panicking::try::do_call::h12f0919717b8e0a6 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:288:39
+    #4 0x55f77dc926c9 in __rust_maybe_catch_panic /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libpanic_unwind/lib.rs:80:7
+    #5 0x55f77dc9197c in std::panicking::try::h413b21cdcd6cfd86 /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panicking.rs:267:12
+    #6 0x55f77dc9197c in std::panic::catch_unwind::hc5cc8ef2fd73424d /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/panic.rs:396:8
+    #7 0x55f77dc9197c in std::rt::lang_start_internal::h2039f418ab92218f /rustc/c27f7568bc74c418996892028a629eed5a7f5f00/src/libstd/rt.rs:47:24
+    #8 0x55f77dc01c61 in std::rt::lang_start::ha905d28f6b61d691 (/tmp/a+0xac61)
+    #9 0x55f77dc0163a in main (/tmp/a+0xa63a)
+    #10 0x7f9b3cf5bbba in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26bba)
+    #11 0x55f77dc01289 in _start (/tmp/a+0xa289)
+
+Address 0x7ffcc15f43d0 is located in stack of thread T0 at offset 48 in frame
+    #0 0x55f77dc0135f in a::main::hab3bd2a745c2d0ac (/tmp/a+0xa35f)
+
+  This frame has 1 object(s):
+    [32, 48) 'xs' <== Memory access at offset 48 overflows this variable
+HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
+      (longjmp and C++ exceptions *are* supported)
+SUMMARY: AddressSanitizer: stack-buffer-overflow (/tmp/a+0xa5c4) in a::main::hab3bd2a745c2d0ac
+Shadow bytes around the buggy address:
+  0x1000182b6820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b6830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b6840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b6850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b6860: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+=>0x1000182b6870: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
+  0x1000182b6880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b6890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b68a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b68b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  0x1000182b68c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+Shadow byte legend (one shadow byte represents 8 application bytes):
+  Addressable:           00
+  Partially addressable: 01 02 03 04 05 06 07 
+  Heap left redzone:       fa
+  Freed heap region:       fd
+  Stack left redzone:      f1
+  Stack mid redzone:       f2
+  Stack right redzone:     f3
+  Stack after return:      f5
+  Stack use after scope:   f8
+  Global redzone:          f9
+  Global init order:       f6
+  Poisoned by user:        f7
+  Container overflow:      fc
+  Array cookie:            ac
+  Intra object redzone:    bb
+  ASan internal:           fe
+  Left alloca redzone:     ca
+  Right alloca redzone:    cb
+  Shadow gap:              cc
+==10029==ABORTING
+```
+
+## MemorySanitizer
+
+Use of uninitialized memory. Note that we are using `-Zbuild-std` to instrument
+standard library, and passing `-msan-track-origins=2` to the LLVM to track
+origins of uninitialized memory:
+
+```shell
+$ cat src/main.rs
+use std::mem::MaybeUninit;
+
+fn main() {
+    unsafe {
+        let a = MaybeUninit::<[usize; 4]>::uninit();
+        let a = a.assume_init();
+        println!("{}", a[2]);
+    }
+}
+
+$ env RUSTFLAGS="-Zsanitizer=memory -Cllvm-args=-msan-track-origins=2" cargo -Zbuild-std run --target x86_64-unknown-linux-gnu
+==9416==WARNING: MemorySanitizer: use-of-uninitialized-value
+    #0 0x560c04f7488a in core::fmt::num::imp::fmt_u64::haa293b0b098501ca $RUST/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/src/libcore/fmt/num.rs:202:16
+...
+  Uninitialized value was stored to memory at
+    #0 0x560c04ae898a in __msan_memcpy.part.0 $RUST/src/llvm-project/compiler-rt/lib/msan/msan_interceptors.cc:1558:3
+    #1 0x560c04b2bf88 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:6:16
+
+  Uninitialized value was created by an allocation of 'a' in the stack frame of function '_ZN6memory4main17hd2333c1899d997f5E'
+    #0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3
+```
+
+
+# Instrumentation of external dependencies and std
+
+The sanitizers to varying degrees work correctly with partially instrumented
+code. On the one extreme is LeakSanitizer that doesn't use any compile time
+instrumentation, on the other is MemorySanitizer that requires that all program
+code to be instrumented (failing to achieve that will inevitably result in
+false positives).
+
+It is strongly recommended to combine sanitizers with recompiled and
+instrumented standard library, for example using [cargo `-Zbuild-std`
+functionality][build-std].
+
+[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
+
+# Build scripts and procedural macros
+
+Use of sanitizers together with build scripts and procedural macros is
+technically possible, but in almost all cases it would be best avoided.  This
+is especially true for procedural macros which would require an instrumented
+version of rustc.
+
+In more practical terms when using cargo always remember to pass `--target`
+flag, so that rustflags will not be applied to build scripts and procedural
+macros.
+
+# Additional Information
+
+* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
+* [AddressSanitizer in Clang][clang-asan]
+* [LeakSanitizer in Clang][clang-lsan]
+* [MemorySanitizer in Clang][clang-msan]
+* [ThreadSanitizer in Clang][clang-tsan]
+
+[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
+[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
+[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
+[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
diff --git a/src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md b/src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md
deleted file mode 100644 (file)
index 82ae67f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# `sanitizer_runtime_lib`
-
-This feature is internal to the Rust compiler and is not intended for general use.
-
-------------------------
index cc01de08cafb76bb50b25c96310721f2fdf05b83..87a4924f9becc4edb6afb14019668ebc2228a52d 100644 (file)
@@ -1046,48 +1046,7 @@ fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl<T: Clone> Clone for Box<[T]> {
     fn clone(&self) -> Self {
-        let mut new = BoxBuilder { data: RawVec::with_capacity(self.len()), len: 0 };
-
-        let mut target = new.data.ptr();
-
-        for item in self.iter() {
-            unsafe {
-                ptr::write(target, item.clone());
-                target = target.offset(1);
-            };
-
-            new.len += 1;
-        }
-
-        return unsafe { new.into_box() };
-
-        // Helper type for responding to panics correctly.
-        struct BoxBuilder<T> {
-            data: RawVec<T>,
-            len: usize,
-        }
-
-        impl<T> BoxBuilder<T> {
-            unsafe fn into_box(self) -> Box<[T]> {
-                let raw = ptr::read(&self.data);
-                mem::forget(self);
-                raw.into_box()
-            }
-        }
-
-        impl<T> Drop for BoxBuilder<T> {
-            fn drop(&mut self) {
-                let mut data = self.data.ptr();
-                let max = unsafe { data.add(self.len) };
-
-                while data != max {
-                    unsafe {
-                        ptr::read(data);
-                        data = data.offset(1);
-                    }
-                }
-            }
-        }
+        self.to_vec().into_boxed_slice()
     }
 }
 
index 260e51d635dbbc87a0801932847a2aea668b393e..f40e0b0c30479ae5a5b7fd3faa36faf8481631a7 100644 (file)
@@ -397,6 +397,7 @@ pub fn keys(&self) -> &[K] {
 
     /// Borrows a view into the values stored in the node.
     /// The caller must ensure that the node is not the shared root.
+    /// This function is not public, so doesn't have to support shared roots like `keys` does.
     fn vals(&self) -> &[V] {
         self.reborrow().into_val_slice()
     }
@@ -514,6 +515,7 @@ fn as_leaf_mut(&mut self) -> *mut LeafNode<K, V> {
     }
 
     /// The caller must ensure that the node is not the shared root.
+    /// This function is not public, so doesn't have to support shared roots like `keys` does.
     fn keys_mut(&mut self) -> &mut [K] {
         unsafe { self.reborrow_mut().into_key_slice_mut() }
     }
@@ -589,20 +591,15 @@ pub fn into_root_mut(self) -> &'a mut Root<K, V> {
         unsafe { &mut *(self.root as *mut Root<K, V>) }
     }
 
+    /// The caller must ensure that the node is not the shared root.
     fn into_key_slice_mut(mut self) -> &'a mut [K] {
-        // Same as for `into_key_slice` above, we try to avoid a run-time check.
-        if (mem::align_of::<NodeHeader<K, V, K>>() > mem::align_of::<NodeHeader<K, V>>()
-            || mem::size_of::<NodeHeader<K, V, K>>() != mem::size_of::<NodeHeader<K, V>>())
-            && self.is_shared_root()
-        {
-            &mut []
-        } else {
-            unsafe {
-                slice::from_raw_parts_mut(
-                    MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).keys),
-                    self.len(),
-                )
-            }
+        debug_assert!(!self.is_shared_root());
+        // We cannot be the shared root, so `as_leaf_mut` is okay.
+        unsafe {
+            slice::from_raw_parts_mut(
+                MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).keys),
+                self.len(),
+            )
         }
     }
 
index 3f3c49a2ef875246600f87cf976b1b4ea538d370..48cbf67eea2542afa0805698048011bd3db6d9c5 100644 (file)
@@ -46,6 +46,11 @@ pub fn search_node<BorrowType, K, V, Type, Q: ?Sized>(
     }
 }
 
+/// Returns the index in the node at which the key (or an equivalent) exists
+/// or could exist, and whether it exists in the node itself. If it doesn't
+/// exist in the node itself, it may exist in the subtree with that index
+/// (if the node has subtrees). If the key doesn't exist in node or subtree,
+/// the returned index is the position or subtree to insert at.
 pub fn search_linear<BorrowType, K, V, Type, Q: ?Sized>(
     node: &NodeRef<BorrowType, K, V, Type>,
     key: &Q,
@@ -54,6 +59,12 @@ pub fn search_linear<BorrowType, K, V, Type, Q: ?Sized>(
     Q: Ord,
     K: Borrow<Q>,
 {
+    // This function is defined over all borrow types (immutable, mutable, owned),
+    // and may be called on the shared root in each case.
+    // Crucially, we use `keys()` here, i.e., we work with immutable data.
+    // `keys_mut()` does not support the shared root, so we cannot use it.
+    // Using `keys()` is fine here even if BorrowType is mutable, as all we return
+    // is an index -- not a reference.
     for (i, k) in node.keys().iter().enumerate() {
         match key.cmp(k.borrow()) {
             Ordering::Greater => {}
index 3fdee8bbfdf107c96dadc3cd809504df7b6edbf3..c1ae67a1a339f9ae46c5c0e67abadf1fc3bdaef5 100644 (file)
@@ -11,6 +11,7 @@
 #![feature(associated_type_bounds)]
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(binary_heap_drain_sorted)]
+#![feature(vec_remove_item)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
index f5f8d88829f5f3b62e368d5558c5558821d94a31..e9cbf627846b5a3d4b624e3b9723b305c21f1e08 100644 (file)
@@ -1696,13 +1696,14 @@ impl<T> Vec<T> {
     /// # Examples
     ///
     /// ```
+    /// # #![feature(vec_remove_item)]
     /// let mut vec = vec![1, 2, 3, 1];
     ///
     /// vec.remove_item(&1);
     ///
     /// assert_eq!(vec, vec![2, 3, 1]);
     /// ```
-    #[stable(feature = "vec_remove_item", since = "1.42.0")]
+    #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
     pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
     where
         T: PartialEq<V>,
index b2d4b1b5fb91604ed310171da3dde8812a359a65..4354e1c7b5f695c1455f5e24f4bb7d165d5758b4 100644 (file)
@@ -17,7 +17,7 @@
 #[derive(Debug)]
 pub struct Excess(pub NonNull<u8>, pub usize);
 
-fn size_align<T>() -> (usize, usize) {
+const fn size_align<T>() -> (usize, usize) {
     (mem::size_of::<T>(), mem::align_of::<T>())
 }
 
@@ -64,8 +64,9 @@ impl Layout {
     ///    must not overflow (i.e., the rounded value must be less than
     ///    `usize::MAX`).
     #[stable(feature = "alloc_layout", since = "1.28.0")]
+    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
     #[inline]
-    pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
+    pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
         if !align.is_power_of_two() {
             return Err(LayoutErr { private: () });
         }
@@ -106,28 +107,30 @@ pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
 
     /// The minimum size in bytes for a memory block of this layout.
     #[stable(feature = "alloc_layout", since = "1.28.0")]
+    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
     #[inline]
-    pub fn size(&self) -> usize {
+    pub const fn size(&self) -> usize {
         self.size_
     }
 
     /// The minimum byte alignment for a memory block of this layout.
     #[stable(feature = "alloc_layout", since = "1.28.0")]
+    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
     #[inline]
-    pub fn align(&self) -> usize {
+    pub const fn align(&self) -> usize {
         self.align_.get()
     }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
     #[stable(feature = "alloc_layout", since = "1.28.0")]
+    #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
     #[inline]
-    pub fn new<T>() -> Self {
+    pub const fn new<T>() -> Self {
         let (size, align) = size_align::<T>();
         // Note that the align is guaranteed by rustc to be a power of two and
         // the size+align combo is guaranteed to fit in our address space. As a
         // result use the unchecked constructor here to avoid inserting code
         // that panics if it isn't optimized well enough.
-        debug_assert!(Layout::from_size_align(size, align).is_ok());
         unsafe { Layout::from_size_align_unchecked(size, align) }
     }
 
@@ -181,8 +184,9 @@ pub fn align_to(&self, align: usize) -> Result<Self, LayoutErr> {
     /// address for the whole allocated block of memory. One way to
     /// satisfy this constraint is to ensure `align <= self.align()`.
     #[unstable(feature = "alloc_layout_extra", issue = "55724")]
+    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
     #[inline]
-    pub fn padding_needed_for(&self, align: usize) -> usize {
+    pub const fn padding_needed_for(&self, align: usize) -> usize {
         let len = self.size();
 
         // Rounded up value is:
index 06e7e45c7014e796b125174d0a8d302b74f07b2f..3ea4baa57b49efb1acf3de276ced9d3e1150b07d 100644 (file)
@@ -821,10 +821,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn lt(&self, other: &Rhs) -> bool {
-        match self.partial_cmp(other) {
-            Some(Less) => true,
-            _ => false,
-        }
+        matches!(self.partial_cmp(other), Some(Less))
     }
 
     /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=`
@@ -843,10 +840,7 @@ fn lt(&self, other: &Rhs) -> bool {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn le(&self, other: &Rhs) -> bool {
-        match self.partial_cmp(other) {
-            Some(Less) | Some(Equal) => true,
-            _ => false,
-        }
+        matches!(self.partial_cmp(other), Some(Less) | Some(Equal))
     }
 
     /// This method tests greater than (for `self` and `other`) and is used by the `>` operator.
@@ -864,10 +858,7 @@ fn le(&self, other: &Rhs) -> bool {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn gt(&self, other: &Rhs) -> bool {
-        match self.partial_cmp(other) {
-            Some(Greater) => true,
-            _ => false,
-        }
+        matches!(self.partial_cmp(other), Some(Greater))
     }
 
     /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=`
@@ -886,10 +877,7 @@ fn gt(&self, other: &Rhs) -> bool {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn ge(&self, other: &Rhs) -> bool {
-        match self.partial_cmp(other) {
-            Some(Greater) | Some(Equal) => true,
-            _ => false,
-        }
+        matches!(self.partial_cmp(other), Some(Greater) | Some(Equal))
     }
 }
 
index c958289b2c935172a89a91a9c7df77c6ca5e5ff2..21a569867b17830626cf0f595b6512025becce77 100644 (file)
@@ -2968,10 +2968,7 @@ fn le<I>(self, other: I) -> bool
         Self::Item: PartialOrd<I::Item>,
         Self: Sized,
     {
-        match self.partial_cmp(other) {
-            Some(Ordering::Less) | Some(Ordering::Equal) => true,
-            _ => false,
-        }
+        matches!(self.partial_cmp(other), Some(Ordering::Less) | Some(Ordering::Equal))
     }
 
     /// Determines if the elements of this `Iterator` are lexicographically
@@ -3011,10 +3008,7 @@ fn ge<I>(self, other: I) -> bool
         Self::Item: PartialOrd<I::Item>,
         Self: Sized,
     {
-        match self.partial_cmp(other) {
-            Some(Ordering::Greater) | Some(Ordering::Equal) => true,
-            _ => false,
-        }
+        matches!(self.partial_cmp(other), Some(Ordering::Greater) | Some(Ordering::Equal))
     }
 
     /// Checks if the elements of this iterator are sorted.
index 6f1d69821f56ce8a916efeca2c563ce870936a3d..95ffe4f438f5f608d69ea683989a974000846b04 100644 (file)
@@ -70,7 +70,7 @@
 #![feature(bound_cloned)]
 #![feature(cfg_target_has_atomic)]
 #![feature(concat_idents)]
-#![feature(const_fn)]
+#![feature(const_alloc_layout)]
 #![feature(const_if_match)]
 #![feature(const_panic)]
 #![feature(const_fn_union)]
index b6b4a46e0b81227ee9d041788e79e0faeea74c4d..072966abf2c40226d928c51e7d16bc41aac76d1d 100644 (file)
@@ -1416,6 +1416,7 @@ 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)]
             #[allow_internal_unstable(const_if_match)]
             #[inline]
             pub const fn wrapping_abs(self) -> Self {
@@ -1709,6 +1710,7 @@ pub fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
             #[inline]
             #[stable(feature = "wrapping", since = "1.7.0")]
             #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
+            #[allow(unused_attributes)]
             #[allow_internal_unstable(const_if_match)]
             pub const fn overflowing_neg(self) -> (Self, bool) {
                 if self == Self::min_value() {
@@ -1997,6 +1999,7 @@ pub 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)]
             #[allow_internal_unstable(const_if_match)]
             #[inline]
             #[rustc_inherit_overflow_checks]
@@ -4283,10 +4286,7 @@ pub fn make_ascii_lowercase(&mut self) {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_alphabetic(&self) -> bool {
-        match *self {
-            b'A'..=b'Z' | b'a'..=b'z' => true,
-            _ => false,
-        }
+        matches!(*self, b'A'..=b'Z' | b'a'..=b'z')
     }
 
     /// Checks if the value is an ASCII uppercase character:
@@ -4318,10 +4318,7 @@ pub fn is_ascii_alphabetic(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_uppercase(&self) -> bool {
-        match *self {
-            b'A'..=b'Z' => true,
-            _ => false,
-        }
+        matches!(*self, b'A'..=b'Z')
     }
 
     /// Checks if the value is an ASCII lowercase character:
@@ -4353,10 +4350,7 @@ pub fn is_ascii_uppercase(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_lowercase(&self) -> bool {
-        match *self {
-            b'a'..=b'z' => true,
-            _ => false,
-        }
+        matches!(*self, b'a'..=b'z')
     }
 
     /// Checks if the value is an ASCII alphanumeric character:
@@ -4391,10 +4385,7 @@ pub fn is_ascii_lowercase(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_alphanumeric(&self) -> bool {
-        match *self {
-            b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' => true,
-            _ => false,
-        }
+        matches!(*self, b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z')
     }
 
     /// Checks if the value is an ASCII decimal digit:
@@ -4426,10 +4417,7 @@ pub fn is_ascii_alphanumeric(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_digit(&self) -> bool {
-        match *self {
-            b'0'..=b'9' => true,
-            _ => false,
-        }
+        matches!(*self, b'0'..=b'9')
     }
 
     /// Checks if the value is an ASCII hexadecimal digit:
@@ -4464,10 +4452,7 @@ pub fn is_ascii_digit(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_hexdigit(&self) -> bool {
-        match *self {
-            b'0'..=b'9' | b'A'..=b'F' | b'a'..=b'f' => true,
-            _ => false,
-        }
+        matches!(*self, b'0'..=b'9' | b'A'..=b'F' | b'a'..=b'f')
     }
 
     /// Checks if the value is an ASCII punctuation character:
@@ -4503,10 +4488,7 @@ pub fn is_ascii_hexdigit(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_punctuation(&self) -> bool {
-        match *self {
-            b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~' => true,
-            _ => false,
-        }
+        matches!(*self, b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~')
     }
 
     /// Checks if the value is an ASCII graphic character:
@@ -4538,10 +4520,7 @@ pub fn is_ascii_punctuation(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_graphic(&self) -> bool {
-        match *self {
-            b'!'..=b'~' => true,
-            _ => false,
-        }
+        matches!(*self, b'!'..=b'~')
     }
 
     /// Checks if the value is an ASCII whitespace character:
@@ -4590,10 +4569,7 @@ pub fn is_ascii_graphic(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_whitespace(&self) -> bool {
-        match *self {
-            b'\t' | b'\n' | b'\x0C' | b'\r' | b' ' => true,
-            _ => false,
-        }
+        matches!(*self, b'\t' | b'\n' | b'\x0C' | b'\r' | b' ')
     }
 
     /// Checks if the value is an ASCII control character:
@@ -4627,10 +4603,7 @@ pub fn is_ascii_whitespace(&self) -> bool {
     #[stable(feature = "ascii_ctype_on_intrinsics", since = "1.24.0")]
     #[inline]
     pub fn is_ascii_control(&self) -> bool {
-        match *self {
-            b'\0'..=b'\x1F' | b'\x7F' => true,
-            _ => false,
-        }
+        matches!(*self, b'\0'..=b'\x1F' | b'\x7F')
     }
 }
 
index 2066a484dac8091a3a294227c15093dca5e4d403..a471b174534aa4e11d16781ecb1d1731d00ace64 100644 (file)
@@ -187,10 +187,7 @@ impl<T> Option<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_some(&self) -> bool {
-        match *self {
-            Some(_) => true,
-            None => false,
-        }
+        matches!(*self, Some(_))
     }
 
     /// Returns `true` if the option is a [`None`] value.
@@ -341,6 +338,7 @@ pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
     /// x.expect("the world is ending"); // panics with `the world is ending`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn expect(self, msg: &str) -> T {
         match self {
@@ -374,6 +372,7 @@ pub fn expect(self, msg: &str) -> T {
     /// assert_eq!(x.unwrap(), "air"); // fails
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn unwrap(self) -> T {
         match self {
@@ -1015,6 +1014,7 @@ impl<T: fmt::Debug> Option<T> {
     /// }
     /// ```
     #[inline]
+    #[track_caller]
     #[unstable(feature = "option_expect_none", reason = "newly added", issue = "62633")]
     pub fn expect_none(self, msg: &str) {
         if let Some(val) = self {
@@ -1057,6 +1057,7 @@ pub fn expect_none(self, msg: &str) {
     /// }
     /// ```
     #[inline]
+    #[track_caller]
     #[unstable(feature = "option_unwrap_none", reason = "newly added", issue = "62633")]
     pub fn unwrap_none(self) {
         if let Some(val) = self {
@@ -1184,6 +1185,7 @@ pub fn transpose(self) -> Result<Option<T>, E> {
 // This is a separate function to reduce the code size of .expect() itself.
 #[inline(never)]
 #[cold]
+#[track_caller]
 fn expect_failed(msg: &str) -> ! {
     panic!("{}", msg)
 }
@@ -1191,6 +1193,7 @@ fn expect_failed(msg: &str) -> ! {
 // This is a separate function to reduce the code size of .expect_none() itself.
 #[inline(never)]
 #[cold]
+#[track_caller]
 fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! {
     panic!("{}: {:?}", msg, value)
 }
index aca6fb201388177004801487ff47b002506a06d8..676d2c784acee2143bf2b72efd441193fac2fffd 100644 (file)
@@ -672,6 +672,7 @@ impl<'a, T: ?Sized> Pin<&'a T> {
     #[stable(feature = "pin", since = "1.33.0")]
     pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U>
     where
+        U: ?Sized,
         F: FnOnce(&T) -> &U,
     {
         let pointer = &*self.pointer;
@@ -763,6 +764,7 @@ pub unsafe fn get_unchecked_mut(self) -> &'a mut T {
     #[stable(feature = "pin", since = "1.33.0")]
     pub unsafe fn map_unchecked_mut<U, F>(self, func: F) -> Pin<&'a mut U>
     where
+        U: ?Sized,
         F: FnOnce(&mut T) -> &mut U,
     {
         let pointer = Pin::get_unchecked_mut(self);
index b3bb2f179b17e291949363f176ca1c2179cf5463..4bc0a3e9faa607dd93efe45742f92a040a3a5ecb 100644 (file)
@@ -250,6 +250,20 @@ pub fn wrapping_offset(self, count: isize) -> *mut T
     /// *first_value = 4;
     /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
     /// ```
+    ///
+    /// # Null-unchecked version
+    ///
+    /// If you are sure the pointer can never be null and are looking for some kind of
+    /// `as_mut_unchecked` that returns the `&mut T` instead of `Option<&mut T>`, know that
+    /// you can dereference the pointer directly.
+    ///
+    /// ```
+    /// let mut s = [1, 2, 3];
+    /// let ptr: *mut u32 = s.as_mut_ptr();
+    /// let first_value = unsafe { &mut *ptr };
+    /// *first_value = 4;
+    /// println!("{:?}", s); // It'll print: "[4, 2, 3]".
+    /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
     pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
index 5cfc81097dd44a3b9b7a5e3381c5e08ab34bbe7c..c657ce33f60adccb380b82001affb7dfd59606ae 100644 (file)
@@ -282,10 +282,7 @@ impl<T, E> Result<T, E> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const fn is_ok(&self) -> bool {
-        match *self {
-            Ok(_) => true,
-            Err(_) => false,
-        }
+        matches!(*self, Ok(_))
     }
 
     /// Returns `true` if the result is [`Err`].
@@ -957,6 +954,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
     /// x.unwrap(); // panics with `emergency failure`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn unwrap(self) -> T {
         match self {
@@ -984,6 +982,7 @@ pub fn unwrap(self) -> T {
     /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "result_expect", since = "1.4.0")]
     pub fn expect(self, msg: &str) -> T {
         match self {
@@ -1017,6 +1016,7 @@ impl<T: fmt::Debug, E> Result<T, E> {
     /// assert_eq!(x.unwrap_err(), "emergency failure");
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn unwrap_err(self) -> E {
         match self {
@@ -1044,6 +1044,7 @@ pub fn unwrap_err(self) -> E {
     /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "result_expect_err", since = "1.17.0")]
     pub fn expect_err(self, msg: &str) -> E {
         match self {
@@ -1091,13 +1092,51 @@ pub fn unwrap_or_default(self) -> T {
     }
 }
 
+#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
+impl<T, E: Into<!>> Result<T, E> {
+    /// Unwraps a result that can never be an [`Err`], yielding the content of the [`Ok`].
+    ///
+    /// Unlike [`unwrap`], this method is known to never panic on the
+    /// result types it is implemented for. Therefore, it can be used
+    /// instead of `unwrap` as a maintainability safeguard that will fail
+    /// to compile if the error type of the `Result` is later changed
+    /// to an error that can actually occur.
+    ///
+    /// [`Ok`]: enum.Result.html#variant.Ok
+    /// [`Err`]: enum.Result.html#variant.Err
+    /// [`unwrap`]: enum.Result.html#method.unwrap
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(never_type)]
+    /// # #![feature(unwrap_infallible)]
+    ///
+    /// fn only_good_news() -> Result<String, !> {
+    ///     Ok("this is fine".into())
+    /// }
+    ///
+    /// let s: String = only_good_news().into_ok();
+    /// println!("{}", s);
+    /// ```
+    #[inline]
+    pub fn into_ok(self) -> T {
+        match self {
+            Ok(x) => x,
+            Err(e) => e.into(),
+        }
+    }
+}
+
 #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
 impl<T: Deref, E> Result<T, E> {
     /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E>`.
     ///
     /// Leaves the original `Result` in-place, creating a new one containing a reference to the
     /// `Ok` type's `Deref::Target` type.
-    pub fn as_deref_ok(&self) -> Result<&T::Target, &E> {
+    pub fn as_deref(&self) -> Result<&T::Target, &E> {
         self.as_ref().map(|t| t.deref())
     }
 }
@@ -1113,24 +1152,13 @@ pub fn as_deref_err(&self) -> Result<&T, &E::Target> {
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
-impl<T: Deref, E: Deref> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E::Target>`.
-    ///
-    /// Leaves the original `Result` in-place, creating a new one containing a reference to both
-    /// the `Ok` and `Err` types' `Deref::Target` types.
-    pub fn as_deref(&self) -> Result<&T::Target, &E::Target> {
-        self.as_ref().map(|t| t.deref()).map_err(|e| e.deref())
-    }
-}
-
 #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
 impl<T: DerefMut, E> Result<T, E> {
     /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T::Target, &mut E>`.
     ///
     /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
     /// the `Ok` type's `Deref::Target` type.
-    pub fn as_deref_mut_ok(&mut self) -> Result<&mut T::Target, &mut E> {
+    pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {
         self.as_mut().map(|t| t.deref_mut())
     }
 }
@@ -1146,18 +1174,6 @@ pub fn as_deref_mut_err(&mut self) -> Result<&mut T, &mut E::Target> {
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
-impl<T: DerefMut, E: DerefMut> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to
-    /// `Result<&mut T::Target, &mut E::Target>`.
-    ///
-    /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
-    /// both the `Ok` and `Err` types' `Deref::Target` types.
-    pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E::Target> {
-        self.as_mut().map(|t| t.deref_mut()).map_err(|e| e.deref_mut())
-    }
-}
-
 impl<T, E> Result<Option<T>, E> {
     /// Transposes a `Result` of an `Option` into an `Option` of a `Result`.
     ///
@@ -1188,6 +1204,7 @@ pub fn transpose(self) -> Option<Result<T, E>> {
 // This is a separate function to reduce the code size of the methods
 #[inline(never)]
 #[cold]
+#[track_caller]
 fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
     panic!("{}: {:?}", msg, error)
 }
index 2cbdeb2e4eed82015eb733bb4d0d073371a8813e..46d9499394a381c33eb8450ecb16a57b5739247e 100644 (file)
@@ -46,10 +46,7 @@ fn is_contained_in(self, haystack: &'a str) -> bool {
     /// Checks whether the pattern matches at the front of the haystack
     #[inline]
     fn is_prefix_of(self, haystack: &'a str) -> bool {
-        match self.into_searcher(haystack).next() {
-            SearchStep::Match(0, _) => true,
-            _ => false,
-        }
+        matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _))
     }
 
     /// Checks whether the pattern matches at the back of the haystack
@@ -58,10 +55,7 @@ fn is_suffix_of(self, haystack: &'a str) -> bool
     where
         Self::Searcher: ReverseSearcher<'a>,
     {
-        match self.into_searcher(haystack).next_back() {
-            SearchStep::Match(_, j) if haystack.len() == j => true,
-            _ => false,
-        }
+        matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j)
     }
 }
 
index a2352c08e7316083c8ee73afb41fe38dfc3443b6..fae95ca5cdb36ba4182343e308d7c53f05bf810d 100644 (file)
 /// This function is different from [`std::thread::yield_now`] which directly yields to the
 /// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system.
 ///
-/// Spin locks can be very efficient for short lock durations because they do not involve context
-/// switches or interaction with the operating system. For long lock durations they become wasteful
-/// however because they use CPU cycles for the entire lock duration, and using a
-/// [`std::sync::Mutex`] is likely the better approach. If actively spinning for a long time is
-/// required, e.g. because code polls a non-blocking API, calling [`std::thread::yield_now`]
-/// or [`std::thread::sleep`] may be the best option.
-///
-/// **Note**: Spin locks are based on the underlying assumption that another thread will release
-/// the lock 'soon'. In order for this to work, that other thread must run on a different CPU or
-/// core (at least potentially). Spin locks do not work efficiently on single CPU / core platforms.
+/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS
+/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly
+/// recommended that the spin loop is terminated after a finite amount of iterations and an
+/// appropriate blocking syscall is made.
 ///
 /// **Note**: On platforms that do not support receiving spin-loop hints this function does not
 /// do anything at all.
index d567ae545774ef56726de81f2a55c2ac3bb3be96..b3a4bd20b8f042fabf7d818fab9eda88a0bd861b 100644 (file)
@@ -39,10 +39,7 @@ pub fn map<U, F>(self, f: F) -> Poll<U>
     #[inline]
     #[stable(feature = "futures_api", since = "1.36.0")]
     pub fn is_ready(&self) -> bool {
-        match *self {
-            Poll::Ready(_) => true,
-            Poll::Pending => false,
-        }
+        matches!(*self, Poll::Ready(_))
     }
 
     /// Returns `true` if this is `Poll::Pending`
index 39f6133f2a689fe9b6af7d6ea38804081551f56c..86cf6fc104c8390bc19e5a3baa4c6bfabd94763d 100644 (file)
@@ -31,7 +31,6 @@
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
 #![feature(int_error_matching)]
-#![feature(const_fn)]
 #![feature(array_value_iter)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_is_partitioned)]
@@ -40,6 +39,8 @@
 #![feature(slice_from_raw_parts)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_raw_ptr_deref)]
+#![feature(never_type)]
+#![feature(unwrap_infallible)]
 
 extern crate test;
 
index 499a5613bd2fe3eeb88852ae064cb8b5f2931534..c835313aae7037cd59860781dee296bc37fc3149 100644 (file)
@@ -183,6 +183,28 @@ pub fn test_unwrap_or_default() {
     assert_eq!(op2().unwrap_or_default(), 0);
 }
 
+#[test]
+pub fn test_into_ok() {
+    fn infallible_op() -> Result<isize, !> {
+        Ok(666)
+    }
+
+    assert_eq!(infallible_op().into_ok(), 666);
+
+    enum MyNeverToken {}
+    impl From<MyNeverToken> for ! {
+        fn from(never: MyNeverToken) -> ! {
+            match never {}
+        }
+    }
+
+    fn infallible_op2() -> Result<isize, MyNeverToken> {
+        Ok(667)
+    }
+
+    assert_eq!(infallible_op2().into_ok(), 667);
+}
+
 #[test]
 fn test_try() {
     fn try_result_some() -> Option<u8> {
@@ -214,31 +236,17 @@ fn try_result_err() -> Result<u8, u8> {
 
 #[test]
 fn test_result_as_deref() {
-    // &Result<T: Deref, E>::Ok(T).as_deref_ok() ->
+    // &Result<T: Deref, E>::Ok(T).as_deref() ->
     //      Result<&T::Deref::Target, &E>::Ok(&*T)
     let ref_ok = &Result::Ok::<&i32, u8>(&42);
     let expected_result = Result::Ok::<&i32, &u8>(&42);
-    assert_eq!(ref_ok.as_deref_ok(), expected_result);
-
-    let ref_ok = &Result::Ok::<String, u32>(String::from("a result"));
-    let expected_result = Result::Ok::<&str, &u32>("a result");
-    assert_eq!(ref_ok.as_deref_ok(), expected_result);
-
-    let ref_ok = &Result::Ok::<Vec<i32>, u32>(vec![1, 2, 3, 4, 5]);
-    let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice());
-    assert_eq!(ref_ok.as_deref_ok(), expected_result);
-
-    // &Result<T: Deref, E: Deref>::Ok(T).as_deref() ->
-    //      Result<&T::Deref::Target, &E::Deref::Target>::Ok(&*T)
-    let ref_ok = &Result::Ok::<&i32, &u8>(&42);
-    let expected_result = Result::Ok::<&i32, &u8>(&42);
     assert_eq!(ref_ok.as_deref(), expected_result);
 
-    let ref_ok = &Result::Ok::<String, &u32>(String::from("a result"));
+    let ref_ok = &Result::Ok::<String, u32>(String::from("a result"));
     let expected_result = Result::Ok::<&str, &u32>("a result");
     assert_eq!(ref_ok.as_deref(), expected_result);
 
-    let ref_ok = &Result::Ok::<Vec<i32>, &u32>(vec![1, 2, 3, 4, 5]);
+    let ref_ok = &Result::Ok::<Vec<i32>, u32>(vec![1, 2, 3, 4, 5]);
     let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice());
     assert_eq!(ref_ok.as_deref(), expected_result);
 
@@ -259,19 +267,21 @@ fn test_result_as_deref() {
     // &Result<T: Deref, E: Deref>::Err(T).as_deref_err() ->
     //      Result<&T, &E::Deref::Target>::Err(&*E)
     let ref_err = &Result::Err::<&u8, &i32>(&41);
-    let expected_result = Result::Err::<&u8, &i32>(&41);
+    let expected_result = Result::Err::<&u8, &&i32>(&&41);
     assert_eq!(ref_err.as_deref(), expected_result);
 
-    let ref_err = &Result::Err::<&u32, String>(String::from("an error"));
-    let expected_result = Result::Err::<&u32, &str>("an error");
+    let s = String::from("an error");
+    let ref_err = &Result::Err::<&u32, String>(s.clone());
+    let expected_result = Result::Err::<&u32, &String>(&s);
     assert_eq!(ref_err.as_deref(), expected_result);
 
-    let ref_err = &Result::Err::<&u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
-    let expected_result = Result::Err::<&u32, &[i32]>([5, 4, 3, 2, 1].as_slice());
+    let v = vec![5, 4, 3, 2, 1];
+    let ref_err = &Result::Err::<&u32, Vec<i32>>(v.clone());
+    let expected_result = Result::Err::<&u32, &Vec<i32>>(&v);
     assert_eq!(ref_err.as_deref(), expected_result);
 
     // The following cases test calling `as_deref_*` with the wrong variant (i.e.
-    // `as_deref_ok()` with a `Result::Err()`, or `as_deref_err()` with a `Result::Ok()`.
+    // `as_deref()` with a `Result::Err()`, or `as_deref_err()` with a `Result::Ok()`.
     // While uncommon, these cases are supported to ensure that an `as_deref_*`
     // call can still be made even when one of the Result types does not implement
     // `Deref` (for example, std::io::Error).
@@ -290,56 +300,38 @@ fn test_result_as_deref() {
     let expected_result = Result::Ok::<&[i32; 5], &u32>(&[1, 2, 3, 4, 5]);
     assert_eq!(ref_ok.as_deref_err(), expected_result);
 
-    // &Result<T: Deref, E>::Err(E).as_deref_ok() ->
+    // &Result<T: Deref, E>::Err(E).as_deref() ->
     //      Result<&T::Deref::Target, &E>::Err(&E)
     let ref_err = &Result::Err::<&u8, i32>(41);
     let expected_result = Result::Err::<&u8, &i32>(&41);
-    assert_eq!(ref_err.as_deref_ok(), expected_result);
+    assert_eq!(ref_err.as_deref(), expected_result);
 
     let ref_err = &Result::Err::<&u32, &str>("an error");
     let expected_result = Result::Err::<&u32, &&str>(&"an error");
-    assert_eq!(ref_err.as_deref_ok(), expected_result);
+    assert_eq!(ref_err.as_deref(), expected_result);
 
     let ref_err = &Result::Err::<&u32, [i32; 5]>([5, 4, 3, 2, 1]);
     let expected_result = Result::Err::<&u32, &[i32; 5]>(&[5, 4, 3, 2, 1]);
-    assert_eq!(ref_err.as_deref_ok(), expected_result);
+    assert_eq!(ref_err.as_deref(), expected_result);
 }
 
 #[test]
 fn test_result_as_deref_mut() {
-    // &mut Result<T: Deref, E>::Ok(T).as_deref_mut_ok() ->
+    // &mut Result<T: Deref, E>::Ok(T).as_deref_mut() ->
     //      Result<&mut T::Deref::Target, &mut E>::Ok(&mut *T)
     let mut val = 42;
     let mut expected_val = 42;
     let mut_ok = &mut Result::Ok::<&mut i32, u8>(&mut val);
     let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
-    assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
-
-    let mut expected_string = String::from("a result");
-    let mut_ok = &mut Result::Ok::<String, u32>(expected_string.clone());
-    let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut());
-    assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
-
-    let mut expected_vec = vec![1, 2, 3, 4, 5];
-    let mut_ok = &mut Result::Ok::<Vec<i32>, u32>(expected_vec.clone());
-    let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice());
-    assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
-
-    // &mut Result<T: Deref, E: Deref>::Ok(T).as_deref_mut() ->
-    //      Result<&mut T::Deref::Target, &mut E::Deref::Target>::Ok(&mut *T)
-    let mut val = 42;
-    let mut expected_val = 42;
-    let mut_ok = &mut Result::Ok::<&mut i32, &mut u8>(&mut val);
-    let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
     assert_eq!(mut_ok.as_deref_mut(), expected_result);
 
     let mut expected_string = String::from("a result");
-    let mut_ok = &mut Result::Ok::<String, &mut u32>(expected_string.clone());
+    let mut_ok = &mut Result::Ok::<String, u32>(expected_string.clone());
     let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut());
     assert_eq!(mut_ok.as_deref_mut(), expected_result);
 
     let mut expected_vec = vec![1, 2, 3, 4, 5];
-    let mut_ok = &mut Result::Ok::<Vec<i32>, &mut u32>(expected_vec.clone());
+    let mut_ok = &mut Result::Ok::<Vec<i32>, u32>(expected_vec.clone());
     let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice());
     assert_eq!(mut_ok.as_deref_mut(), expected_result);
 
@@ -364,23 +356,22 @@ fn test_result_as_deref_mut() {
     // &mut Result<T: Deref, E: Deref>::Err(T).as_deref_mut_err() ->
     //      Result<&mut T, &mut E::Deref::Target>::Err(&mut *E)
     let mut val = 41;
-    let mut expected_val = 41;
-    let mut_err = &mut Result::Err::<&mut u8, &mut i32>(&mut val);
-    let expected_result = Result::Err::<&mut u8, &mut i32>(&mut expected_val);
+    let mut_err = &mut Result::Err::<&mut u8, i32>(val);
+    let expected_result = Result::Err::<&mut u8, &mut i32>(&mut val);
     assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let mut expected_string = String::from("an error");
     let mut_err = &mut Result::Err::<&mut u32, String>(expected_string.clone());
-    let expected_result = Result::Err::<&mut u32, &mut str>(expected_string.as_mut_str());
+    let expected_result = Result::Err::<&mut u32, &mut String>(&mut expected_string);
     assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let mut expected_vec = vec![5, 4, 3, 2, 1];
     let mut_err = &mut Result::Err::<&mut u32, Vec<i32>>(expected_vec.clone());
-    let expected_result = Result::Err::<&mut u32, &mut [i32]>(expected_vec.as_mut_slice());
+    let expected_result = Result::Err::<&mut u32, &mut Vec<i32>>(&mut expected_vec);
     assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     // The following cases test calling `as_deref_mut_*` with the wrong variant (i.e.
-    // `as_deref_mut_ok()` with a `Result::Err()`, or `as_deref_mut_err()` with a `Result::Ok()`.
+    // `as_deref_mut()` with a `Result::Err()`, or `as_deref_mut_err()` with a `Result::Ok()`.
     // While uncommon, these cases are supported to ensure that an `as_deref_mut_*`
     // call can still be made even when one of the Result types does not implement
     // `Deref` (for example, std::io::Error).
@@ -404,22 +395,22 @@ fn test_result_as_deref_mut() {
     let expected_result = Result::Ok::<&mut [i32; 5], &mut u32>(&mut expected_arr);
     assert_eq!(mut_ok.as_deref_mut_err(), expected_result);
 
-    // &mut Result<T: Deref, E>::Err(E).as_deref_mut_ok() ->
+    // &mut Result<T: Deref, E>::Err(E).as_deref_mut() ->
     //      Result<&mut T::Deref::Target, &mut E>::Err(&mut E)
     let mut expected_val = 41;
     let mut_err = &mut Result::Err::<&mut u8, i32>(expected_val.clone());
     let expected_result = Result::Err::<&mut u8, &mut i32>(&mut expected_val);
-    assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let string = String::from("an error");
     let expected_string = string.clone();
     let mut ref_str = expected_string.as_ref();
     let mut_err = &mut Result::Err::<&mut u32, &str>(string.as_str());
     let expected_result = Result::Err::<&mut u32, &mut &str>(&mut ref_str);
-    assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_err.as_deref_mut(), expected_result);
 
     let mut expected_arr = [5, 4, 3, 2, 1];
     let mut_err = &mut Result::Err::<&mut u32, [i32; 5]>(expected_arr.clone());
     let expected_result = Result::Err::<&mut u32, &mut [i32; 5]>(&mut expected_arr);
-    assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
+    assert_eq!(mut_err.as_deref_mut(), expected_result);
 }
index 2098404ee1b9d6cbb7b908c5a8094739b601fcd5..9d3fe5254f8a9de7b254d930bd133f031097dedb 100644 (file)
@@ -63,7 +63,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
 pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     let sz = mem::size_of_val(&data);
     let exception = __cxa_allocate_exception(sz);
-    if exception == ptr::null_mut() {
+    if exception.is_null() {
         return uw::_URC_FATAL_PHASE1_ERROR as u32;
     }
     ptr::write(exception as *mut _, data);
index 0b74a104da44bd510eb2bb18bdadb0176b666918..c51db695a5b1581efd9e7bdd7c81bcffe34edfb6 100644 (file)
@@ -21,7 +21,6 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(allow_internal_unstable)]
-#![feature(const_fn)]
 #![feature(decl_macro)]
 #![feature(extern_types)]
 #![feature(in_band_lifetimes)]
index 04cd2efe00093d80a859bf56b64a553abdcd9be4..8adcff67800fe2dc757395c6c0589f0b2f1ecbb9 100644 (file)
@@ -21,7 +21,6 @@ fn main() {
         "InstrProfilingPlatformLinux.c",
         "InstrProfilingPlatformOther.c",
         "InstrProfilingPlatformWindows.c",
-        "InstrProfilingRuntime.cc",
         "InstrProfilingUtil.c",
         "InstrProfilingValue.c",
         "InstrProfilingWriter.c",
@@ -68,10 +67,17 @@ fn main() {
     let root = env::var_os("RUST_COMPILER_RT_ROOT").unwrap();
     let root = Path::new(&root);
 
+    let src_root = root.join("lib").join("profile");
     for src in profile_sources {
-        cfg.file(root.join("lib").join("profile").join(src));
+        cfg.file(src_root.join(src));
     }
 
+    // The file was renamed in LLVM 10.
+    let old_runtime_path = src_root.join("InstrProfilingRuntime.cc");
+    let new_runtime_path = src_root.join("InstrProfilingRuntime.cpp");
+    cfg.file(if old_runtime_path.exists() { old_runtime_path } else { new_runtime_path });
+
+    cfg.include(root.join("include"));
     cfg.warnings(false);
     cfg.compile("profiler-rt");
 }
index 2e882cfdafdf3a57f4d25fe17a701bd24bc1afcb..323ce3b6cbb6dc8a82a4f90379c60f02a2c61d79 100644 (file)
@@ -15,7 +15,6 @@ bitflags = "1.2.1"
 fmt_macros = { path = "../libfmt_macros" }
 graphviz = { path = "../libgraphviz" }
 jobserver = "0.1"
-num_cpus = "1.0"
 scoped-tls = "1.0"
 log = { version = "0.4", features = ["release_max_level_info", "std"] }
 rustc-rayon = "0.3.0"
@@ -27,8 +26,8 @@ rustc_hir = { path = "../librustc_hir" }
 rustc_target = { path = "../librustc_target" }
 rustc_macros = { path = "../librustc_macros" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_index = { path = "../librustc_index" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
@@ -36,8 +35,7 @@ backtrace = "0.3.40"
 parking_lot = "0.9"
 byteorder = { version = "1.3" }
 chalk-engine = { version = "0.9.0", default-features=false }
-rustc_fs_util = { path = "../librustc_fs_util" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
-measureme = "0.5"
+measureme = "0.7.1"
 rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_session = { path = "../librustc_session" }
index 0d03c834e0f7bf433ba730f628fed3567840f7d8..8d1efc7bc048d8510a514b7029945b4f49ec021b 100644 (file)
@@ -1,17 +1,18 @@
 use crate::ty::{self, TyCtxt};
-use errors::Diagnostic;
 use parking_lot::{Condvar, Mutex};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::profiling::QueryInvocationId;
 use rustc_data_structures::sharded::{self, Sharded};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
+use rustc_errors::Diagnostic;
 use rustc_index::vec::{Idx, IndexVec};
 use smallvec::SmallVec;
 use std::collections::hash_map::Entry;
 use std::env;
 use std::hash::Hash;
 use std::mem;
-use std::sync::atomic::Ordering::SeqCst;
+use std::sync::atomic::Ordering::Relaxed;
 
 use crate::ich::{Fingerprint, StableHashingContext, StableHashingContextProvider};
 
 #[derive(Clone)]
 pub struct DepGraph {
     data: Option<Lrc<DepGraphData>>,
+
+    /// This field is used for assigning DepNodeIndices when running in
+    /// non-incremental mode. Even in non-incremental mode we make sure that
+    /// each task has a `DepNodeIndex` that uniquely identifies it. This unique
+    /// ID is used for self-profiling.
+    virtual_dep_node_index: Lrc<AtomicU32>,
 }
 
 rustc_index::newtype_index! {
@@ -35,6 +42,13 @@ impl DepNodeIndex {
     pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
 }
 
+impl std::convert::From<DepNodeIndex> for QueryInvocationId {
+    #[inline]
+    fn from(dep_node_index: DepNodeIndex) -> Self {
+        QueryInvocationId(dep_node_index.as_u32())
+    }
+}
+
 #[derive(PartialEq)]
 pub enum DepNodeColor {
     Red,
@@ -105,11 +119,12 @@ pub fn new(
                 previous: prev_graph,
                 colors: DepNodeColorMap::new(prev_graph_node_count),
             })),
+            virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
         }
     }
 
     pub fn new_disabled() -> DepGraph {
-        DepGraph { data: None }
+        DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
     }
 
     /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise.
@@ -322,7 +337,7 @@ fn with_task_impl<'a, C, A, R>(
 
             (result, dep_node_index)
         } else {
-            (task(cx, arg), DepNodeIndex::INVALID)
+            (task(cx, arg), self.next_virtual_depnode_index())
         }
     }
 
@@ -352,7 +367,7 @@ pub fn with_anon_task<OP, R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeInd
             let dep_node_index = data.current.complete_anon_task(dep_kind, task_deps);
             (result, dep_node_index)
         } else {
-            (op(), DepNodeIndex::INVALID)
+            (op(), self.next_virtual_depnode_index())
         }
     }
 
@@ -478,8 +493,8 @@ pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> {
             let current_dep_graph = &self.data.as_ref().unwrap().current;
 
             Some((
-                current_dep_graph.total_read_count.load(SeqCst),
-                current_dep_graph.total_duplicate_read_count.load(SeqCst),
+                current_dep_graph.total_read_count.load(Relaxed),
+                current_dep_graph.total_duplicate_read_count.load(Relaxed),
             ))
         } else {
             None
@@ -877,6 +892,11 @@ pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) {
             }
         }
     }
+
+    fn next_virtual_depnode_index(&self) -> DepNodeIndex {
+        let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
+        DepNodeIndex::from_u32(index)
+    }
 }
 
 /// A "work product" is an intermediate result that we save into the
@@ -1087,7 +1107,7 @@ fn read_index(&self, source: DepNodeIndex) {
             if let Some(task_deps) = icx.task_deps {
                 let mut task_deps = task_deps.lock();
                 if cfg!(debug_assertions) {
-                    self.current.total_read_count.fetch_add(1, SeqCst);
+                    self.current.total_read_count.fetch_add(1, Relaxed);
                 }
                 if task_deps.read_set.insert(source) {
                     task_deps.reads.push(source);
@@ -1105,7 +1125,7 @@ fn read_index(&self, source: DepNodeIndex) {
                         }
                     }
                 } else if cfg!(debug_assertions) {
-                    self.current.total_duplicate_read_count.fetch_add(1, SeqCst);
+                    self.current.total_duplicate_read_count.fetch_add(1, Relaxed);
                 }
             }
         })
index 7395b03c4eb80b688752f83e129ed2ddc7d71b90..5a99e7965538b2ff243d6763fe42886715964e05 100644 (file)
@@ -4,15 +4,18 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
-use crate::lint::builtin::UNUSED_ATTRIBUTES;
+use crate::hir::map::Map;
 use crate::ty::query::Providers;
 use crate::ty::TyCtxt;
+
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::DUMMY_HIR_ID;
 use rustc_hir::{self, HirId, Item, ItemKind, TraitItem, TraitItemKind};
+use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use syntax::ast::Attribute;
@@ -430,21 +433,27 @@ fn check_repr(
         // Error on repr(transparent, <anything else>).
         if is_transparent && hints.len() > 1 {
             let hint_spans: Vec<_> = hint_spans.clone().collect();
-            span_err!(
+            struct_span_err!(
                 self.tcx.sess,
                 hint_spans,
                 E0692,
                 "transparent {} cannot have other repr hints",
                 target
-            );
+            )
+            .emit();
         }
         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
         if (int_reprs > 1)
             || (is_simd && is_c)
             || (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item)))
         {
-            let hint_spans: Vec<_> = hint_spans.collect();
-            span_warn!(self.tcx.sess, hint_spans, E0566, "conflicting representation hints");
+            struct_span_err!(
+                self.tcx.sess,
+                hint_spans.collect::<Vec<Span>>(),
+                E0566,
+                "conflicting representation hints",
+            )
+            .emit();
         }
     }
 
@@ -511,7 +520,9 @@ fn check_used(&self, attrs: &'hir [Attribute], target: Target) {
 }
 
 impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
deleted file mode 100644 (file)
index edecfd3..0000000
+++ /dev/null
@@ -1,1181 +0,0 @@
-//! HIR walker for walking the contents of nodes.
-//!
-//! **For an overview of the visitor strategy, see the docs on the
-//! `super::itemlikevisit::ItemLikeVisitor` trait.**
-//!
-//! If you have decided to use this visitor, here are some general
-//! notes on how to do so:
-//!
-//! Each overridden visit method has full control over what
-//! happens with its node, it can do its own traversal of the node's children,
-//! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent
-//! deeper traversal by doing nothing.
-//!
-//! When visiting the HIR, the contents of nested items are NOT visited
-//! by default. This is different from the AST visitor, which does a deep walk.
-//! Hence this module is called `intravisit`; see the method `visit_nested_item`
-//! for more details.
-//!
-//! Note: it is an important invariant that the default visitor walks
-//! the body of a function in "execution order" - more concretely, if
-//! we consider the reverse post-order (RPO) of the CFG implied by the HIR,
-//! then a pre-order traversal of the HIR is consistent with the CFG RPO
-//! on the *initial CFG point* of each HIR node, while a post-order traversal
-//! of the HIR is consistent with the CFG RPO on each *final CFG point* of
-//! each CFG node.
-//!
-//! One thing that follows is that if HIR node A always starts/ends executing
-//! before HIR node B, then A appears in traversal pre/postorder before B,
-//! respectively. (This follows from RPO respecting CFG domination).
-//!
-//! This order consistency is required in a few places in rustc, for
-//! example generator inference, and possibly also HIR borrowck.
-
-use crate::hir::map::Map;
-
-use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
-use rustc_hir::*;
-use rustc_span::Span;
-use syntax::ast::{Attribute, Ident, Label, Name};
-
-pub struct DeepVisitor<'v, V> {
-    visitor: &'v mut V,
-}
-
-impl<'v, 'hir, V> DeepVisitor<'v, V>
-where
-    V: Visitor<'hir> + 'v,
-{
-    pub fn new(base: &'v mut V) -> Self {
-        DeepVisitor { visitor: base }
-    }
-}
-
-impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
-where
-    V: Visitor<'hir>,
-{
-    fn visit_item(&mut self, item: &'hir Item<'hir>) {
-        self.visitor.visit_item(item);
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>) {
-        self.visitor.visit_trait_item(trait_item);
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) {
-        self.visitor.visit_impl_item(impl_item);
-    }
-}
-
-pub trait IntoVisitor<'hir> {
-    type Visitor: Visitor<'hir>;
-    fn into_visitor(&self) -> Self::Visitor;
-}
-
-pub struct ParDeepVisitor<V>(pub V);
-
-impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor<V>
-where
-    V: IntoVisitor<'hir>,
-{
-    fn visit_item(&self, item: &'hir Item<'hir>) {
-        self.0.into_visitor().visit_item(item);
-    }
-
-    fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>) {
-        self.0.into_visitor().visit_trait_item(trait_item);
-    }
-
-    fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>) {
-        self.0.into_visitor().visit_impl_item(impl_item);
-    }
-}
-
-#[derive(Copy, Clone)]
-pub enum FnKind<'a> {
-    /// `#[xxx] pub async/const/extern "Abi" fn foo()`
-    ItemFn(Ident, &'a Generics<'a>, FnHeader, &'a Visibility<'a>, &'a [Attribute]),
-
-    /// `fn foo(&self)`
-    Method(Ident, &'a FnSig<'a>, Option<&'a Visibility<'a>>, &'a [Attribute]),
-
-    /// `|x, y| {}`
-    Closure(&'a [Attribute]),
-}
-
-impl<'a> FnKind<'a> {
-    pub fn attrs(&self) -> &'a [Attribute] {
-        match *self {
-            FnKind::ItemFn(.., attrs) => attrs,
-            FnKind::Method(.., attrs) => attrs,
-            FnKind::Closure(attrs) => attrs,
-        }
-    }
-
-    pub fn header(&self) -> Option<&FnHeader> {
-        match *self {
-            FnKind::ItemFn(_, _, ref header, _, _) => Some(header),
-            FnKind::Method(_, ref sig, _, _) => Some(&sig.header),
-            FnKind::Closure(_) => None,
-        }
-    }
-}
-
-/// Specifies what nested things a visitor wants to visit. The most
-/// common choice is `OnlyBodies`, which will cause the visitor to
-/// visit fn bodies for fns that it encounters, but skip over nested
-/// item-like things.
-///
-/// See the comments on `ItemLikeVisitor` for more details on the overall
-/// visit strategy.
-pub enum NestedVisitorMap<'this, 'tcx> {
-    /// Do not visit any nested things. When you add a new
-    /// "non-nested" thing, you will want to audit such uses to see if
-    /// they remain valid.
-    ///
-    /// Use this if you are only walking some particular kind of tree
-    /// (i.e., a type, or fn signature) and you don't want to thread a
-    /// HIR map around.
-    None,
-
-    /// Do not visit nested item-like things, but visit nested things
-    /// that are inside of an item-like.
-    ///
-    /// **This is the most common choice.** A very common pattern is
-    /// to use `visit_all_item_likes()` as an outer loop,
-    /// and to have the visitor that visits the contents of each item
-    /// using this setting.
-    OnlyBodies(&'this Map<'tcx>),
-
-    /// Visits all nested things, including item-likes.
-    ///
-    /// **This is an unusual choice.** It is used when you want to
-    /// process everything within their lexical context. Typically you
-    /// kick off the visit by doing `walk_krate()`.
-    All(&'this Map<'tcx>),
-}
-
-impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> {
-    /// Returns the map to use for an "intra item-like" thing (if any).
-    /// E.g., function body.
-    pub fn intra(self) -> Option<&'this Map<'tcx>> {
-        match self {
-            NestedVisitorMap::None => None,
-            NestedVisitorMap::OnlyBodies(map) => Some(map),
-            NestedVisitorMap::All(map) => Some(map),
-        }
-    }
-
-    /// Returns the map to use for an "item-like" thing (if any).
-    /// E.g., item, impl-item.
-    pub fn inter(self) -> Option<&'this Map<'tcx>> {
-        match self {
-            NestedVisitorMap::None => None,
-            NestedVisitorMap::OnlyBodies(_) => None,
-            NestedVisitorMap::All(map) => Some(map),
-        }
-    }
-}
-
-/// Each method of the Visitor trait is a hook to be potentially
-/// overridden. Each method's default implementation recursively visits
-/// the substructure of the input via the corresponding `walk` method;
-/// e.g., the `visit_mod` method by default calls `intravisit::walk_mod`.
-///
-/// Note that this visitor does NOT visit nested items by default
-/// (this is why the module is called `intravisit`, to distinguish it
-/// from the AST's `visit` module, which acts differently). If you
-/// simply want to visit all items in the crate in some order, you
-/// should call `Crate::visit_all_items`. Otherwise, see the comment
-/// on `visit_nested_item` for details on how to visit nested items.
-///
-/// If you want to ensure that your code handles every variant
-/// explicitly, you need to override each method. (And you also need
-/// to monitor future changes to `Visitor` in case a new method with a
-/// new default implementation gets introduced.)
-pub trait Visitor<'v>: Sized {
-    ///////////////////////////////////////////////////////////////////////////
-    // Nested items.
-
-    /// The default versions of the `visit_nested_XXX` routines invoke
-    /// this method to get a map to use. By selecting an enum variant,
-    /// you control which kinds of nested HIR are visited; see
-    /// `NestedVisitorMap` for details. By "nested HIR", we are
-    /// referring to bits of HIR that are not directly embedded within
-    /// one another but rather indirectly, through a table in the
-    /// crate. This is done to control dependencies during incremental
-    /// compilation: the non-inline bits of HIR can be tracked and
-    /// hashed separately.
-    ///
-    /// **If for some reason you want the nested behavior, but don't
-    /// have a `Map` at your disposal:** then you should override the
-    /// `visit_nested_XXX` methods, and override this method to
-    /// `panic!()`. This way, if a new `visit_nested_XXX` variant is
-    /// added in the future, we will see the panic in your code and
-    /// fix it appropriately.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
-
-    /// Invoked when a nested item is encountered. By default does
-    /// nothing unless you override `nested_visit_map` to return other than
-    /// `None`, in which case it will walk the item. **You probably
-    /// don't want to override this method** -- instead, override
-    /// `nested_visit_map` or use the "shallow" or "deep" visit
-    /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only
-    /// reason to override this method is if you want a nested pattern
-    /// but cannot supply a `Map`; see `nested_visit_map` for advice.
-    #[allow(unused_variables)]
-    fn visit_nested_item(&mut self, id: ItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.expect_item(id.id));
-        if let Some(item) = opt_item {
-            self.visit_item(item);
-        }
-    }
-
-    /// Like `visit_nested_item()`, but for trait items. See
-    /// `visit_nested_item()` for advice on when to override this
-    /// method.
-    #[allow(unused_variables)]
-    fn visit_nested_trait_item(&mut self, id: TraitItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
-        if let Some(item) = opt_item {
-            self.visit_trait_item(item);
-        }
-    }
-
-    /// Like `visit_nested_item()`, but for impl items. See
-    /// `visit_nested_item()` for advice on when to override this
-    /// method.
-    #[allow(unused_variables)]
-    fn visit_nested_impl_item(&mut self, id: ImplItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id));
-        if let Some(item) = opt_item {
-            self.visit_impl_item(item);
-        }
-    }
-
-    /// Invoked to visit the body of a function, method or closure. Like
-    /// visit_nested_item, does nothing by default unless you override
-    /// `nested_visit_map` to return other than `None`, in which case it will walk
-    /// the body.
-    fn visit_nested_body(&mut self, id: BodyId) {
-        let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
-        if let Some(body) = opt_body {
-            self.visit_body(body);
-        }
-    }
-
-    fn visit_param(&mut self, param: &'v Param<'v>) {
-        walk_param(self, param)
-    }
-
-    /// Visits the top-level item and (optionally) nested items / impl items. See
-    /// `visit_nested_item` for details.
-    fn visit_item(&mut self, i: &'v Item<'v>) {
-        walk_item(self, i)
-    }
-
-    fn visit_body(&mut self, b: &'v Body<'v>) {
-        walk_body(self, b);
-    }
-
-    /// When invoking `visit_all_item_likes()`, you need to supply an
-    /// item-like visitor. This method converts a "intra-visit"
-    /// visitor into an item-like visitor that walks the entire tree.
-    /// If you use this, you probably don't want to process the
-    /// contents of nested item-like things, since the outer loop will
-    /// visit them as well.
-    fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> {
-        DeepVisitor::new(self)
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-
-    fn visit_id(&mut self, _hir_id: HirId) {
-        // Nothing to do.
-    }
-    fn visit_name(&mut self, _span: Span, _name: Name) {
-        // Nothing to do.
-    }
-    fn visit_ident(&mut self, ident: Ident) {
-        walk_ident(self, ident)
-    }
-    fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) {
-        walk_mod(self, m, n)
-    }
-    fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) {
-        walk_foreign_item(self, i)
-    }
-    fn visit_local(&mut self, l: &'v Local<'v>) {
-        walk_local(self, l)
-    }
-    fn visit_block(&mut self, b: &'v Block<'v>) {
-        walk_block(self, b)
-    }
-    fn visit_stmt(&mut self, s: &'v Stmt<'v>) {
-        walk_stmt(self, s)
-    }
-    fn visit_arm(&mut self, a: &'v Arm<'v>) {
-        walk_arm(self, a)
-    }
-    fn visit_pat(&mut self, p: &'v Pat<'v>) {
-        walk_pat(self, p)
-    }
-    fn visit_anon_const(&mut self, c: &'v AnonConst) {
-        walk_anon_const(self, c)
-    }
-    fn visit_expr(&mut self, ex: &'v Expr<'v>) {
-        walk_expr(self, ex)
-    }
-    fn visit_ty(&mut self, t: &'v Ty<'v>) {
-        walk_ty(self, t)
-    }
-    fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) {
-        walk_generic_param(self, p)
-    }
-    fn visit_generics(&mut self, g: &'v Generics<'v>) {
-        walk_generics(self, g)
-    }
-    fn visit_where_predicate(&mut self, predicate: &'v WherePredicate<'v>) {
-        walk_where_predicate(self, predicate)
-    }
-    fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) {
-        walk_fn_decl(self, fd)
-    }
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, s: Span, id: HirId) {
-        walk_fn(self, fk, fd, b, s, id)
-    }
-    fn visit_use(&mut self, path: &'v Path<'v>, hir_id: HirId) {
-        walk_use(self, path, hir_id)
-    }
-    fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) {
-        walk_trait_item(self, ti)
-    }
-    fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) {
-        walk_trait_item_ref(self, ii)
-    }
-    fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) {
-        walk_impl_item(self, ii)
-    }
-    fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef<'v>) {
-        walk_impl_item_ref(self, ii)
-    }
-    fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) {
-        walk_trait_ref(self, t)
-    }
-    fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) {
-        walk_param_bound(self, bounds)
-    }
-    fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>, m: TraitBoundModifier) {
-        walk_poly_trait_ref(self, t, m)
-    }
-    fn visit_variant_data(
-        &mut self,
-        s: &'v VariantData<'v>,
-        _: Name,
-        _: &'v Generics<'v>,
-        _parent_id: HirId,
-        _: Span,
-    ) {
-        walk_struct_def(self, s)
-    }
-    fn visit_struct_field(&mut self, s: &'v StructField<'v>) {
-        walk_struct_field(self, s)
-    }
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'v EnumDef<'v>,
-        generics: &'v Generics<'v>,
-        item_id: HirId,
-        _: Span,
-    ) {
-        walk_enum_def(self, enum_definition, generics, item_id)
-    }
-    fn visit_variant(&mut self, v: &'v Variant<'v>, g: &'v Generics<'v>, item_id: HirId) {
-        walk_variant(self, v, g, item_id)
-    }
-    fn visit_label(&mut self, label: &'v Label) {
-        walk_label(self, label)
-    }
-    fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) {
-        match generic_arg {
-            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
-            GenericArg::Type(ty) => self.visit_ty(ty),
-            GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
-        }
-    }
-    fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
-        walk_lifetime(self, lifetime)
-    }
-    fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, span: Span) {
-        walk_qpath(self, qpath, id, span)
-    }
-    fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) {
-        walk_path(self, path)
-    }
-    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment<'v>) {
-        walk_path_segment(self, path_span, path_segment)
-    }
-    fn visit_generic_args(&mut self, path_span: Span, generic_args: &'v GenericArgs<'v>) {
-        walk_generic_args(self, path_span, generic_args)
-    }
-    fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding<'v>) {
-        walk_assoc_type_binding(self, type_binding)
-    }
-    fn visit_attribute(&mut self, _attr: &'v Attribute) {}
-    fn visit_macro_def(&mut self, macro_def: &'v MacroDef<'v>) {
-        walk_macro_def(self, macro_def)
-    }
-    fn visit_vis(&mut self, vis: &'v Visibility<'v>) {
-        walk_vis(self, vis)
-    }
-    fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) {
-        walk_associated_item_kind(self, kind);
-    }
-    fn visit_defaultness(&mut self, defaultness: &'v Defaultness) {
-        walk_defaultness(self, defaultness);
-    }
-}
-
-/// Walks the contents of a crate. See also `Crate::visit_all_items`.
-pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) {
-    visitor.visit_mod(&krate.module, krate.span, CRATE_HIR_ID);
-    walk_list!(visitor, visit_attribute, krate.attrs);
-    walk_list!(visitor, visit_macro_def, krate.exported_macros);
-}
-
-pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef<'v>) {
-    visitor.visit_id(macro_def.hir_id);
-    visitor.visit_name(macro_def.span, macro_def.name);
-    walk_list!(visitor, visit_attribute, macro_def.attrs);
-}
-
-pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
-    visitor.visit_id(mod_hir_id);
-    for &item_id in module.item_ids {
-        visitor.visit_nested_item(item_id);
-    }
-}
-
-pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
-    walk_list!(visitor, visit_param, body.params);
-    visitor.visit_expr(&body.value);
-}
-
-pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
-    // Intentionally visiting the expr first - the initialization expr
-    // dominates the local's definition.
-    walk_list!(visitor, visit_expr, &local.init);
-    walk_list!(visitor, visit_attribute, local.attrs.iter());
-    visitor.visit_id(local.hir_id);
-    visitor.visit_pat(&local.pat);
-    walk_list!(visitor, visit_ty, &local.ty);
-}
-
-pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) {
-    visitor.visit_name(ident.span, ident.name);
-}
-
-pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
-    visitor.visit_ident(label.ident);
-}
-
-pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
-    visitor.visit_id(lifetime.hir_id);
-    match lifetime.name {
-        LifetimeName::Param(ParamName::Plain(ident)) => {
-            visitor.visit_ident(ident);
-        }
-        LifetimeName::Param(ParamName::Fresh(_))
-        | LifetimeName::Param(ParamName::Error)
-        | LifetimeName::Static
-        | LifetimeName::Error
-        | LifetimeName::Implicit
-        | LifetimeName::ImplicitObjectLifetimeDefault
-        | LifetimeName::Underscore => {}
-    }
-}
-
-pub fn walk_poly_trait_ref<'v, V>(
-    visitor: &mut V,
-    trait_ref: &'v PolyTraitRef<'v>,
-    _modifier: TraitBoundModifier,
-) where
-    V: Visitor<'v>,
-{
-    walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
-    visitor.visit_trait_ref(&trait_ref.trait_ref);
-}
-
-pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef<'v>)
-where
-    V: Visitor<'v>,
-{
-    visitor.visit_id(trait_ref.hir_ref_id);
-    visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
-}
-
-pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) {
-    visitor.visit_id(param.hir_id);
-    visitor.visit_pat(&param.pat);
-    walk_list!(visitor, visit_attribute, param.attrs);
-}
-
-pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
-    visitor.visit_vis(&item.vis);
-    visitor.visit_ident(item.ident);
-    match item.kind {
-        ItemKind::ExternCrate(orig_name) => {
-            visitor.visit_id(item.hir_id);
-            if let Some(orig_name) = orig_name {
-                visitor.visit_name(item.span, orig_name);
-            }
-        }
-        ItemKind::Use(ref path, _) => {
-            visitor.visit_use(path, item.hir_id);
-        }
-        ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => {
-            visitor.visit_id(item.hir_id);
-            visitor.visit_ty(typ);
-            visitor.visit_nested_body(body);
-        }
-        ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn(
-            FnKind::ItemFn(item.ident, generics, sig.header, &item.vis, &item.attrs),
-            &sig.decl,
-            body_id,
-            item.span,
-            item.hir_id,
-        ),
-        ItemKind::Mod(ref module) => {
-            // `visit_mod()` takes care of visiting the `Item`'s `HirId`.
-            visitor.visit_mod(module, item.span, item.hir_id)
-        }
-        ItemKind::ForeignMod(ref foreign_module) => {
-            visitor.visit_id(item.hir_id);
-            walk_list!(visitor, visit_foreign_item, foreign_module.items);
-        }
-        ItemKind::GlobalAsm(_) => {
-            visitor.visit_id(item.hir_id);
-        }
-        ItemKind::TyAlias(ref ty, ref generics) => {
-            visitor.visit_id(item.hir_id);
-            visitor.visit_ty(ty);
-            visitor.visit_generics(generics)
-        }
-        ItemKind::OpaqueTy(OpaqueTy { ref generics, bounds, .. }) => {
-            visitor.visit_id(item.hir_id);
-            walk_generics(visitor, generics);
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
-        ItemKind::Enum(ref enum_definition, ref generics) => {
-            visitor.visit_generics(generics);
-            // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
-            visitor.visit_enum_def(enum_definition, generics, item.hir_id, item.span)
-        }
-        ItemKind::Impl(.., ref generics, ref opt_trait_reference, ref typ, impl_item_refs) => {
-            visitor.visit_id(item.hir_id);
-            visitor.visit_generics(generics);
-            walk_list!(visitor, visit_trait_ref, opt_trait_reference);
-            visitor.visit_ty(typ);
-            walk_list!(visitor, visit_impl_item_ref, impl_item_refs);
-        }
-        ItemKind::Struct(ref struct_definition, ref generics)
-        | ItemKind::Union(ref struct_definition, ref generics) => {
-            visitor.visit_generics(generics);
-            visitor.visit_id(item.hir_id);
-            visitor.visit_variant_data(
-                struct_definition,
-                item.ident.name,
-                generics,
-                item.hir_id,
-                item.span,
-            );
-        }
-        ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
-            visitor.visit_id(item.hir_id);
-            visitor.visit_generics(generics);
-            walk_list!(visitor, visit_param_bound, bounds);
-            walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
-        }
-        ItemKind::TraitAlias(ref generics, bounds) => {
-            visitor.visit_id(item.hir_id);
-            visitor.visit_generics(generics);
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
-    }
-    walk_list!(visitor, visit_attribute, item.attrs);
-}
-
-pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
-    visitor.visit_id(hir_id);
-    visitor.visit_path(path, hir_id);
-}
-
-pub fn walk_enum_def<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    enum_definition: &'v EnumDef<'v>,
-    generics: &'v Generics<'v>,
-    item_id: HirId,
-) {
-    visitor.visit_id(item_id);
-    walk_list!(visitor, visit_variant, enum_definition.variants, generics, item_id);
-}
-
-pub fn walk_variant<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    variant: &'v Variant<'v>,
-    generics: &'v Generics<'v>,
-    parent_item_id: HirId,
-) {
-    visitor.visit_ident(variant.ident);
-    visitor.visit_id(variant.id);
-    visitor.visit_variant_data(
-        &variant.data,
-        variant.ident.name,
-        generics,
-        parent_item_id,
-        variant.span,
-    );
-    walk_list!(visitor, visit_anon_const, &variant.disr_expr);
-    walk_list!(visitor, visit_attribute, variant.attrs);
-}
-
-pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
-    visitor.visit_id(typ.hir_id);
-
-    match typ.kind {
-        TyKind::Slice(ref ty) => visitor.visit_ty(ty),
-        TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
-        TyKind::Rptr(ref lifetime, ref mutable_type) => {
-            visitor.visit_lifetime(lifetime);
-            visitor.visit_ty(&mutable_type.ty)
-        }
-        TyKind::Never => {}
-        TyKind::Tup(tuple_element_types) => {
-            walk_list!(visitor, visit_ty, tuple_element_types);
-        }
-        TyKind::BareFn(ref function_declaration) => {
-            walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
-            visitor.visit_fn_decl(&function_declaration.decl);
-        }
-        TyKind::Path(ref qpath) => {
-            visitor.visit_qpath(qpath, typ.hir_id, typ.span);
-        }
-        TyKind::Def(item_id, lifetimes) => {
-            visitor.visit_nested_item(item_id);
-            walk_list!(visitor, visit_generic_arg, lifetimes);
-        }
-        TyKind::Array(ref ty, ref length) => {
-            visitor.visit_ty(ty);
-            visitor.visit_anon_const(length)
-        }
-        TyKind::TraitObject(bounds, ref lifetime) => {
-            for bound in bounds {
-                visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None);
-            }
-            visitor.visit_lifetime(lifetime);
-        }
-        TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
-        TyKind::Infer | TyKind::Err => {}
-    }
-}
-
-pub fn walk_qpath<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    qpath: &'v QPath<'v>,
-    id: HirId,
-    span: Span,
-) {
-    match *qpath {
-        QPath::Resolved(ref maybe_qself, ref path) => {
-            if let Some(ref qself) = *maybe_qself {
-                visitor.visit_ty(qself);
-            }
-            visitor.visit_path(path, id)
-        }
-        QPath::TypeRelative(ref qself, ref segment) => {
-            visitor.visit_ty(qself);
-            visitor.visit_path_segment(span, segment);
-        }
-    }
-}
-
-pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) {
-    for segment in path.segments {
-        visitor.visit_path_segment(path.span, segment);
-    }
-}
-
-pub fn walk_path_segment<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    path_span: Span,
-    segment: &'v PathSegment<'v>,
-) {
-    visitor.visit_ident(segment.ident);
-    if let Some(id) = segment.hir_id {
-        visitor.visit_id(id);
-    }
-    if let Some(ref args) = segment.args {
-        visitor.visit_generic_args(path_span, args);
-    }
-}
-
-pub fn walk_generic_args<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    _path_span: Span,
-    generic_args: &'v GenericArgs<'v>,
-) {
-    walk_list!(visitor, visit_generic_arg, generic_args.args);
-    walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings);
-}
-
-pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    type_binding: &'v TypeBinding<'v>,
-) {
-    visitor.visit_id(type_binding.hir_id);
-    visitor.visit_ident(type_binding.ident);
-    match type_binding.kind {
-        TypeBindingKind::Equality { ref ty } => {
-            visitor.visit_ty(ty);
-        }
-        TypeBindingKind::Constraint { bounds } => {
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
-    }
-}
-
-pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
-    visitor.visit_id(pattern.hir_id);
-    match pattern.kind {
-        PatKind::TupleStruct(ref qpath, children, _) => {
-            visitor.visit_qpath(qpath, pattern.hir_id, pattern.span);
-            walk_list!(visitor, visit_pat, children);
-        }
-        PatKind::Path(ref qpath) => {
-            visitor.visit_qpath(qpath, pattern.hir_id, pattern.span);
-        }
-        PatKind::Struct(ref qpath, fields, _) => {
-            visitor.visit_qpath(qpath, pattern.hir_id, pattern.span);
-            for field in fields {
-                visitor.visit_id(field.hir_id);
-                visitor.visit_ident(field.ident);
-                visitor.visit_pat(&field.pat)
-            }
-        }
-        PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats),
-        PatKind::Tuple(tuple_elements, _) => {
-            walk_list!(visitor, visit_pat, tuple_elements);
-        }
-        PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) => {
-            visitor.visit_pat(subpattern)
-        }
-        PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
-            visitor.visit_ident(ident);
-            walk_list!(visitor, visit_pat, optional_subpattern);
-        }
-        PatKind::Lit(ref expression) => visitor.visit_expr(expression),
-        PatKind::Range(ref lower_bound, ref upper_bound, _) => {
-            visitor.visit_expr(lower_bound);
-            visitor.visit_expr(upper_bound)
-        }
-        PatKind::Wild => (),
-        PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
-            walk_list!(visitor, visit_pat, prepatterns);
-            walk_list!(visitor, visit_pat, slice_pattern);
-            walk_list!(visitor, visit_pat, postpatterns);
-        }
-    }
-}
-
-pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
-    visitor.visit_id(foreign_item.hir_id);
-    visitor.visit_vis(&foreign_item.vis);
-    visitor.visit_ident(foreign_item.ident);
-
-    match foreign_item.kind {
-        ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => {
-            visitor.visit_generics(generics);
-            visitor.visit_fn_decl(function_declaration);
-            for &param_name in param_names {
-                visitor.visit_ident(param_name);
-            }
-        }
-        ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
-        ForeignItemKind::Type => (),
-    }
-
-    walk_list!(visitor, visit_attribute, foreign_item.attrs);
-}
-
-pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) {
-    match *bound {
-        GenericBound::Trait(ref typ, modifier) => {
-            visitor.visit_poly_trait_ref(typ, modifier);
-        }
-        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
-    }
-}
-
-pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam<'v>) {
-    visitor.visit_id(param.hir_id);
-    walk_list!(visitor, visit_attribute, param.attrs);
-    match param.name {
-        ParamName::Plain(ident) => visitor.visit_ident(ident),
-        ParamName::Error | ParamName::Fresh(_) => {}
-    }
-    match param.kind {
-        GenericParamKind::Lifetime { .. } => {}
-        GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
-        GenericParamKind::Const { ref ty } => visitor.visit_ty(ty),
-    }
-    walk_list!(visitor, visit_param_bound, param.bounds);
-}
-
-pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) {
-    walk_list!(visitor, visit_generic_param, generics.params);
-    walk_list!(visitor, visit_where_predicate, generics.where_clause.predicates);
-}
-
-pub fn walk_where_predicate<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    predicate: &'v WherePredicate<'v>,
-) {
-    match predicate {
-        &WherePredicate::BoundPredicate(WhereBoundPredicate {
-            ref bounded_ty,
-            bounds,
-            bound_generic_params,
-            ..
-        }) => {
-            visitor.visit_ty(bounded_ty);
-            walk_list!(visitor, visit_param_bound, bounds);
-            walk_list!(visitor, visit_generic_param, bound_generic_params);
-        }
-        &WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, bounds, .. }) => {
-            visitor.visit_lifetime(lifetime);
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
-        &WherePredicate::EqPredicate(WhereEqPredicate {
-            hir_id, ref lhs_ty, ref rhs_ty, ..
-        }) => {
-            visitor.visit_id(hir_id);
-            visitor.visit_ty(lhs_ty);
-            visitor.visit_ty(rhs_ty);
-        }
-    }
-}
-
-pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy<'v>) {
-    if let FunctionRetTy::Return(ref output_ty) = *ret_ty {
-        visitor.visit_ty(output_ty)
-    }
-}
-
-pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl<'v>) {
-    for ty in function_declaration.inputs {
-        visitor.visit_ty(ty)
-    }
-    walk_fn_ret_ty(visitor, &function_declaration.output)
-}
-
-pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
-    match function_kind {
-        FnKind::ItemFn(_, generics, ..) => {
-            visitor.visit_generics(generics);
-        }
-        FnKind::Method(..) | FnKind::Closure(_) => {}
-    }
-}
-
-pub fn walk_fn<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    function_kind: FnKind<'v>,
-    function_declaration: &'v FnDecl<'v>,
-    body_id: BodyId,
-    _span: Span,
-    id: HirId,
-) {
-    visitor.visit_id(id);
-    visitor.visit_fn_decl(function_declaration);
-    walk_fn_kind(visitor, function_kind);
-    visitor.visit_nested_body(body_id)
-}
-
-pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
-    visitor.visit_ident(trait_item.ident);
-    walk_list!(visitor, visit_attribute, trait_item.attrs);
-    visitor.visit_generics(&trait_item.generics);
-    match trait_item.kind {
-        TraitItemKind::Const(ref ty, default) => {
-            visitor.visit_id(trait_item.hir_id);
-            visitor.visit_ty(ty);
-            walk_list!(visitor, visit_nested_body, default);
-        }
-        TraitItemKind::Method(ref sig, TraitMethod::Required(param_names)) => {
-            visitor.visit_id(trait_item.hir_id);
-            visitor.visit_fn_decl(&sig.decl);
-            for &param_name in param_names {
-                visitor.visit_ident(param_name);
-            }
-        }
-        TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => {
-            visitor.visit_fn(
-                FnKind::Method(trait_item.ident, sig, None, &trait_item.attrs),
-                &sig.decl,
-                body_id,
-                trait_item.span,
-                trait_item.hir_id,
-            );
-        }
-        TraitItemKind::Type(bounds, ref default) => {
-            visitor.visit_id(trait_item.hir_id);
-            walk_list!(visitor, visit_param_bound, bounds);
-            walk_list!(visitor, visit_ty, default);
-        }
-    }
-}
-
-pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
-    // N.B., deliberately force a compilation error if/when new fields are added.
-    let TraitItemRef { id, ident, ref kind, span: _, ref defaultness } = *trait_item_ref;
-    visitor.visit_nested_trait_item(id);
-    visitor.visit_ident(ident);
-    visitor.visit_associated_item_kind(kind);
-    visitor.visit_defaultness(defaultness);
-}
-
-pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
-    // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItem {
-        hir_id: _,
-        ident,
-        ref vis,
-        ref defaultness,
-        attrs,
-        ref generics,
-        ref kind,
-        span: _,
-    } = *impl_item;
-
-    visitor.visit_ident(ident);
-    visitor.visit_vis(vis);
-    visitor.visit_defaultness(defaultness);
-    walk_list!(visitor, visit_attribute, attrs);
-    visitor.visit_generics(generics);
-    match *kind {
-        ImplItemKind::Const(ref ty, body) => {
-            visitor.visit_id(impl_item.hir_id);
-            visitor.visit_ty(ty);
-            visitor.visit_nested_body(body);
-        }
-        ImplItemKind::Method(ref sig, body_id) => {
-            visitor.visit_fn(
-                FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), &impl_item.attrs),
-                &sig.decl,
-                body_id,
-                impl_item.span,
-                impl_item.hir_id,
-            );
-        }
-        ImplItemKind::TyAlias(ref ty) => {
-            visitor.visit_id(impl_item.hir_id);
-            visitor.visit_ty(ty);
-        }
-        ImplItemKind::OpaqueTy(bounds) => {
-            visitor.visit_id(impl_item.hir_id);
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
-    }
-}
-
-pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef<'v>) {
-    // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItemRef { id, ident, ref kind, span: _, ref vis, ref defaultness } = *impl_item_ref;
-    visitor.visit_nested_impl_item(id);
-    visitor.visit_ident(ident);
-    visitor.visit_associated_item_kind(kind);
-    visitor.visit_vis(vis);
-    visitor.visit_defaultness(defaultness);
-}
-
-pub fn walk_struct_def<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    struct_definition: &'v VariantData<'v>,
-) {
-    if let Some(ctor_hir_id) = struct_definition.ctor_hir_id() {
-        visitor.visit_id(ctor_hir_id);
-    }
-    walk_list!(visitor, visit_struct_field, struct_definition.fields());
-}
-
-pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField<'v>) {
-    visitor.visit_id(struct_field.hir_id);
-    visitor.visit_vis(&struct_field.vis);
-    visitor.visit_ident(struct_field.ident);
-    visitor.visit_ty(&struct_field.ty);
-    walk_list!(visitor, visit_attribute, struct_field.attrs);
-}
-
-pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
-    visitor.visit_id(block.hir_id);
-    walk_list!(visitor, visit_stmt, block.stmts);
-    walk_list!(visitor, visit_expr, &block.expr);
-}
-
-pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
-    visitor.visit_id(statement.hir_id);
-    match statement.kind {
-        StmtKind::Local(ref local) => visitor.visit_local(local),
-        StmtKind::Item(item) => visitor.visit_nested_item(item),
-        StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
-            visitor.visit_expr(expression)
-        }
-    }
-}
-
-pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
-    visitor.visit_id(constant.hir_id);
-    visitor.visit_nested_body(constant.body);
-}
-
-pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
-    visitor.visit_id(expression.hir_id);
-    walk_list!(visitor, visit_attribute, expression.attrs.iter());
-    match expression.kind {
-        ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
-        ExprKind::Array(subexpressions) => {
-            walk_list!(visitor, visit_expr, subexpressions);
-        }
-        ExprKind::Repeat(ref element, ref count) => {
-            visitor.visit_expr(element);
-            visitor.visit_anon_const(count)
-        }
-        ExprKind::Struct(ref qpath, fields, ref optional_base) => {
-            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
-            for field in fields {
-                visitor.visit_id(field.hir_id);
-                visitor.visit_ident(field.ident);
-                visitor.visit_expr(&field.expr)
-            }
-            walk_list!(visitor, visit_expr, optional_base);
-        }
-        ExprKind::Tup(subexpressions) => {
-            walk_list!(visitor, visit_expr, subexpressions);
-        }
-        ExprKind::Call(ref callee_expression, arguments) => {
-            visitor.visit_expr(callee_expression);
-            walk_list!(visitor, visit_expr, arguments);
-        }
-        ExprKind::MethodCall(ref segment, _, arguments) => {
-            visitor.visit_path_segment(expression.span, segment);
-            walk_list!(visitor, visit_expr, arguments);
-        }
-        ExprKind::Binary(_, ref left_expression, ref right_expression) => {
-            visitor.visit_expr(left_expression);
-            visitor.visit_expr(right_expression)
-        }
-        ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
-            visitor.visit_expr(subexpression)
-        }
-        ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
-            visitor.visit_expr(subexpression);
-            visitor.visit_ty(typ)
-        }
-        ExprKind::DropTemps(ref subexpression) => {
-            visitor.visit_expr(subexpression);
-        }
-        ExprKind::Loop(ref block, ref opt_label, _) => {
-            walk_list!(visitor, visit_label, opt_label);
-            visitor.visit_block(block);
-        }
-        ExprKind::Match(ref subexpression, arms, _) => {
-            visitor.visit_expr(subexpression);
-            walk_list!(visitor, visit_arm, arms);
-        }
-        ExprKind::Closure(_, ref function_declaration, body, _fn_decl_span, _gen) => visitor
-            .visit_fn(
-                FnKind::Closure(&expression.attrs),
-                function_declaration,
-                body,
-                expression.span,
-                expression.hir_id,
-            ),
-        ExprKind::Block(ref block, ref opt_label) => {
-            walk_list!(visitor, visit_label, opt_label);
-            visitor.visit_block(block);
-        }
-        ExprKind::Assign(ref lhs, ref rhs, _) => {
-            visitor.visit_expr(rhs);
-            visitor.visit_expr(lhs)
-        }
-        ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
-            visitor.visit_expr(right_expression);
-            visitor.visit_expr(left_expression);
-        }
-        ExprKind::Field(ref subexpression, ident) => {
-            visitor.visit_expr(subexpression);
-            visitor.visit_ident(ident);
-        }
-        ExprKind::Index(ref main_expression, ref index_expression) => {
-            visitor.visit_expr(main_expression);
-            visitor.visit_expr(index_expression)
-        }
-        ExprKind::Path(ref qpath) => {
-            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
-        }
-        ExprKind::Break(ref destination, ref opt_expr) => {
-            if let Some(ref label) = destination.label {
-                visitor.visit_label(label);
-            }
-            walk_list!(visitor, visit_expr, opt_expr);
-        }
-        ExprKind::Continue(ref destination) => {
-            if let Some(ref label) = destination.label {
-                visitor.visit_label(label);
-            }
-        }
-        ExprKind::Ret(ref optional_expression) => {
-            walk_list!(visitor, visit_expr, optional_expression);
-        }
-        ExprKind::InlineAsm(ref asm) => {
-            walk_list!(visitor, visit_expr, asm.outputs_exprs);
-            walk_list!(visitor, visit_expr, asm.inputs_exprs);
-        }
-        ExprKind::Yield(ref subexpression, _) => {
-            visitor.visit_expr(subexpression);
-        }
-        ExprKind::Lit(_) | ExprKind::Err => {}
-    }
-}
-
-pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
-    visitor.visit_id(arm.hir_id);
-    visitor.visit_pat(&arm.pat);
-    if let Some(ref g) = arm.guard {
-        match g {
-            Guard::If(ref e) => visitor.visit_expr(e),
-        }
-    }
-    visitor.visit_expr(&arm.body);
-    walk_list!(visitor, visit_attribute, arm.attrs);
-}
-
-pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility<'v>) {
-    if let VisibilityKind::Restricted { ref path, hir_id } = vis.node {
-        visitor.visit_id(hir_id);
-        visitor.visit_path(path, hir_id)
-    }
-}
-
-pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) {
-    // No visitable content here: this fn exists so you can call it if
-    // the right thing to do, should content be added in the future,
-    // would be to walk it.
-}
-
-pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) {
-    // No visitable content here: this fn exists so you can call it if
-    // the right thing to do, should content be added in the future,
-    // would be to walk it.
-}
index 2cd44770b02cba6d23957fe22ff20ca3cb94f804..016fc939a7a172bfb17d2230b9368efd46704879 100644 (file)
@@ -11,9 +11,9 @@
 //! nested within a uniquely determined `FnLike`), and users can ask
 //! for the `Code` associated with a particular NodeId.
 
-use crate::hir::intravisit::FnKind;
-use crate::hir::map;
-use rustc_hir as ast;
+use crate::hir::map::Map;
+use rustc_hir as hir;
+use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Expr, FnDecl, Node};
 use rustc_span::Span;
 use syntax::ast::{Attribute, Ident};
@@ -39,37 +39,37 @@ trait MaybeFnLike {
     fn is_fn_like(&self) -> bool;
 }
 
-impl MaybeFnLike for ast::Item<'_> {
+impl MaybeFnLike for hir::Item<'_> {
     fn is_fn_like(&self) -> bool {
         match self.kind {
-            ast::ItemKind::Fn(..) => true,
+            hir::ItemKind::Fn(..) => true,
             _ => false,
         }
     }
 }
 
-impl MaybeFnLike for ast::ImplItem<'_> {
+impl MaybeFnLike for hir::ImplItem<'_> {
     fn is_fn_like(&self) -> bool {
         match self.kind {
-            ast::ImplItemKind::Method(..) => true,
+            hir::ImplItemKind::Method(..) => true,
             _ => false,
         }
     }
 }
 
-impl MaybeFnLike for ast::TraitItem<'_> {
+impl MaybeFnLike for hir::TraitItem<'_> {
     fn is_fn_like(&self) -> bool {
         match self.kind {
-            ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
             _ => false,
         }
     }
 }
 
-impl MaybeFnLike for ast::Expr<'_> {
+impl MaybeFnLike for hir::Expr<'_> {
     fn is_fn_like(&self) -> bool {
         match self.kind {
-            ast::ExprKind::Closure(..) => true,
+            hir::ExprKind::Closure(..) => true,
             _ => false,
         }
     }
@@ -85,7 +85,7 @@ pub enum Code<'a> {
 }
 
 impl<'a> Code<'a> {
-    pub fn id(&self) -> ast::HirId {
+    pub fn id(&self) -> hir::HirId {
         match *self {
             Code::FnLike(node) => node.id(),
             Code::Expr(block) => block.hir_id,
@@ -93,13 +93,13 @@ pub fn id(&self) -> ast::HirId {
     }
 
     /// Attempts to construct a Code from presumed FnLike or Expr node input.
-    pub fn from_node(map: &map::Map<'a>, id: ast::HirId) -> Option<Code<'a>> {
+    pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> {
         match map.get(id) {
-            map::Node::Block(_) => {
+            Node::Block(_) => {
                 //  Use the parent, hopefully an expression node.
                 Code::from_node(map, map.get_parent_node(id))
             }
-            map::Node::Expr(expr) => Some(Code::Expr(expr)),
+            Node::Expr(expr) => Some(Code::Expr(expr)),
             node => FnLikeNode::from_node(node).map(Code::FnLike),
         }
     }
@@ -109,12 +109,12 @@ pub fn from_node(map: &map::Map<'a>, id: ast::HirId) -> Option<Code<'a>> {
 /// use when implementing FnLikeNode operations.
 struct ItemFnParts<'a> {
     ident: Ident,
-    decl: &'a ast::FnDecl<'a>,
-    header: ast::FnHeader,
-    vis: &'a ast::Visibility<'a>,
-    generics: &'a ast::Generics<'a>,
-    body: ast::BodyId,
-    id: ast::HirId,
+    decl: &'a hir::FnDecl<'a>,
+    header: hir::FnHeader,
+    vis: &'a hir::Visibility<'a>,
+    generics: &'a hir::Generics<'a>,
+    body: hir::BodyId,
+    id: hir::HirId,
     span: Span,
     attrs: &'a [Attribute],
 }
@@ -123,8 +123,8 @@ struct ItemFnParts<'a> {
 /// for use when implementing FnLikeNode operations.
 struct ClosureParts<'a> {
     decl: &'a FnDecl<'a>,
-    body: ast::BodyId,
-    id: ast::HirId,
+    body: hir::BodyId,
+    id: hir::HirId,
     span: Span,
     attrs: &'a [Attribute],
 }
@@ -132,8 +132,8 @@ struct ClosureParts<'a> {
 impl<'a> ClosureParts<'a> {
     fn new(
         d: &'a FnDecl<'a>,
-        b: ast::BodyId,
-        id: ast::HirId,
+        b: hir::BodyId,
+        id: hir::HirId,
         s: Span,
         attrs: &'a [Attribute],
     ) -> Self {
@@ -145,19 +145,19 @@ impl<'a> FnLikeNode<'a> {
     /// Attempts to construct a FnLikeNode from presumed FnLike node input.
     pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
         let fn_like = match node {
-            map::Node::Item(item) => item.is_fn_like(),
-            map::Node::TraitItem(tm) => tm.is_fn_like(),
-            map::Node::ImplItem(it) => it.is_fn_like(),
-            map::Node::Expr(e) => e.is_fn_like(),
+            Node::Item(item) => item.is_fn_like(),
+            Node::TraitItem(tm) => tm.is_fn_like(),
+            Node::ImplItem(it) => it.is_fn_like(),
+            Node::Expr(e) => e.is_fn_like(),
             _ => false,
         };
         fn_like.then_some(FnLikeNode { node })
     }
 
-    pub fn body(self) -> ast::BodyId {
+    pub fn body(self) -> hir::BodyId {
         self.handle(
             |i: ItemFnParts<'a>| i.body,
-            |_, _, _: &'a ast::FnSig<'a>, _, body: ast::BodyId, _, _| body,
+            |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _, _| body,
             |c: ClosureParts<'a>| c.body,
         )
     }
@@ -165,7 +165,7 @@ pub fn body(self) -> ast::BodyId {
     pub fn decl(self) -> &'a FnDecl<'a> {
         self.handle(
             |i: ItemFnParts<'a>| &*i.decl,
-            |_, _, sig: &'a ast::FnSig<'a>, _, _, _, _| &sig.decl,
+            |_, _, sig: &'a hir::FnSig<'a>, _, _, _, _| &sig.decl,
             |c: ClosureParts<'a>| c.decl,
         )
     }
@@ -173,29 +173,29 @@ pub fn decl(self) -> &'a FnDecl<'a> {
     pub fn span(self) -> Span {
         self.handle(
             |i: ItemFnParts<'_>| i.span,
-            |_, _, _: &'a ast::FnSig<'a>, _, _, span, _| span,
+            |_, _, _: &'a hir::FnSig<'a>, _, _, span, _| span,
             |c: ClosureParts<'_>| c.span,
         )
     }
 
-    pub fn id(self) -> ast::HirId {
+    pub fn id(self) -> hir::HirId {
         self.handle(
             |i: ItemFnParts<'_>| i.id,
-            |id, _, _: &'a ast::FnSig<'a>, _, _, _, _| id,
+            |id, _, _: &'a hir::FnSig<'a>, _, _, _, _| id,
             |c: ClosureParts<'_>| c.id,
         )
     }
 
-    pub fn constness(self) -> ast::Constness {
-        self.kind().header().map_or(ast::Constness::NotConst, |header| header.constness)
+    pub fn constness(self) -> hir::Constness {
+        self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness)
     }
 
-    pub fn asyncness(self) -> ast::IsAsync {
-        self.kind().header().map_or(ast::IsAsync::NotAsync, |header| header.asyncness)
+    pub fn asyncness(self) -> hir::IsAsync {
+        self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness)
     }
 
-    pub fn unsafety(self) -> ast::Unsafety {
-        self.kind().header().map_or(ast::Unsafety::Normal, |header| header.unsafety)
+    pub fn unsafety(self) -> hir::Unsafety {
+        self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety)
     }
 
     pub fn kind(self) -> FnKind<'a> {
@@ -203,7 +203,7 @@ pub fn kind(self) -> FnKind<'a> {
             FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs)
         };
         let closure = |c: ClosureParts<'a>| FnKind::Closure(c.attrs);
-        let method = |_, ident: Ident, sig: &'a ast::FnSig<'a>, vis, _, _, attrs| {
+        let method = |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _, attrs| {
             FnKind::Method(ident, sig, vis, attrs)
         };
         self.handle(item, method, closure)
@@ -213,19 +213,19 @@ fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
     where
         I: FnOnce(ItemFnParts<'a>) -> A,
         M: FnOnce(
-            ast::HirId,
+            hir::HirId,
             Ident,
-            &'a ast::FnSig<'a>,
-            Option<&'a ast::Visibility<'a>>,
-            ast::BodyId,
+            &'a hir::FnSig<'a>,
+            Option<&'a hir::Visibility<'a>>,
+            hir::BodyId,
             Span,
             &'a [Attribute],
         ) -> A,
         C: FnOnce(ClosureParts<'a>) -> A,
     {
         match self.node {
-            map::Node::Item(i) => match i.kind {
-                ast::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
+            Node::Item(i) => match i.kind {
+                hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
                     id: i.hir_id,
                     ident: i.ident,
                     decl: &sig.decl,
@@ -238,20 +238,20 @@ fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
                 }),
                 _ => bug!("item FnLikeNode that is not fn-like"),
             },
-            map::Node::TraitItem(ti) => match ti.kind {
-                ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
+            Node::TraitItem(ti) => match ti.kind {
+                hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
                     method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs)
                 }
                 _ => bug!("trait method FnLikeNode that is not fn-like"),
             },
-            map::Node::ImplItem(ii) => match ii.kind {
-                ast::ImplItemKind::Method(ref sig, body) => {
+            Node::ImplItem(ii) => match ii.kind {
+                hir::ImplItemKind::Method(ref sig, body) => {
                     method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
                 }
                 _ => bug!("impl method FnLikeNode that is not fn-like"),
             },
-            map::Node::Expr(e) => match e.kind {
-                ast::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
+            Node::Expr(e) => match e.kind {
+                hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
                     closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs))
                 }
                 _ => bug!("expr FnLikeNode that is not fn-like"),
index 6879e8fd76348b0261a4787098c273ec1893222f..b6be4bb00199656f8948306b21d37a200f56271b 100644 (file)
@@ -1,22 +1,24 @@
-use super::*;
-use crate::dep_graph::{DepGraph, DepKind, DepNodeIndex};
-use crate::hir::intravisit::{NestedVisitorMap, Visitor};
-use crate::hir::map::HirEntryMap;
-use crate::ich::Fingerprint;
+use crate::dep_graph::{DepGraph, DepKind, DepNode, DepNodeIndex};
+use crate::hir::map::definitions::{self, DefPathHash};
+use crate::hir::map::{Entry, HirEntryMap, Map};
+use crate::ich::StableHashingContext;
 use crate::middle::cstore::CrateStore;
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
+use rustc_hir::def_id::CRATE_DEF_INDEX;
 use rustc_hir::def_id::{CrateNum, DefIndex, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::*;
 use rustc_index::vec::IndexVec;
 use rustc_session::{CrateDisambiguator, Session};
 use rustc_span::source_map::SourceMap;
-use rustc_span::Span;
-use std::iter::repeat;
+use rustc_span::{Span, Symbol, DUMMY_SP};
 use syntax::ast::NodeId;
 
-use crate::ich::StableHashingContext;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use std::iter::repeat;
 
 /// A visitor that walks over the HIR and collects `Node`s into a HIR map.
 pub(super) struct NodeCollector<'a, 'hir> {
@@ -49,15 +51,12 @@ pub(super) struct NodeCollector<'a, 'hir> {
     hir_body_nodes: Vec<(DefPathHash, Fingerprint)>,
 }
 
-fn input_dep_node_and_hash<I>(
+fn input_dep_node_and_hash(
     dep_graph: &DepGraph,
     hcx: &mut StableHashingContext<'_>,
     dep_node: DepNode,
-    input: I,
-) -> (DepNodeIndex, Fingerprint)
-where
-    I: for<'a> HashStable<StableHashingContext<'a>>,
-{
+    input: impl for<'a> HashStable<StableHashingContext<'a>>,
+) -> (DepNodeIndex, Fingerprint) {
     let dep_node_index = dep_graph.input_task(dep_node, &mut *hcx, &input).1;
 
     let hash = if dep_graph.is_fully_enabled() {
@@ -71,16 +70,13 @@ fn input_dep_node_and_hash<I>(
     (dep_node_index, hash)
 }
 
-fn alloc_hir_dep_nodes<I>(
+fn alloc_hir_dep_nodes(
     dep_graph: &DepGraph,
     hcx: &mut StableHashingContext<'_>,
     def_path_hash: DefPathHash,
-    item_like: I,
+    item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
     hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>,
-) -> (DepNodeIndex, DepNodeIndex)
-where
-    I: for<'a> HashStable<StableHashingContext<'a>>,
-{
+) -> (DepNodeIndex, DepNodeIndex) {
     let sig = dep_graph
         .input_task(
             def_path_hash.to_dep_node(DepKind::Hir),
@@ -98,6 +94,21 @@ fn alloc_hir_dep_nodes<I>(
     (sig, full)
 }
 
+fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
+    let mut upstream_crates: Vec<_> = cstore
+        .crates_untracked()
+        .iter()
+        .map(|&cnum| {
+            let name = cstore.crate_name_untracked(cnum);
+            let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
+            let hash = cstore.crate_hash_untracked(cnum);
+            (name, disambiguator, hash)
+        })
+        .collect();
+    upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
+    upstream_crates
+}
+
 impl<'a, 'hir> NodeCollector<'a, 'hir> {
     pub(super) fn root(
         sess: &'a Session,
@@ -190,18 +201,7 @@ pub(super) fn finalize_and_compute_crate_hash(
             },
         );
 
-        let mut upstream_crates: Vec<_> = cstore
-            .crates_untracked()
-            .iter()
-            .map(|&cnum| {
-                let name = cstore.crate_name_untracked(cnum);
-                let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
-                let hash = cstore.crate_hash_untracked(cnum);
-                (name, disambiguator, hash)
-            })
-            .collect();
-
-        upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
+        let upstream_crates = upstream_crates(cstore);
 
         // We hash the final, remapped names of all local source files so we
         // don't have to include the path prefix remapping commandline args.
@@ -336,11 +336,13 @@ fn with_dep_node_owner<
 }
 
 impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
+    type Map = Map<'hir>;
+
     /// Because we want to track parent items and so forth, enable
     /// deep walking so that we walk nested items in the context of
     /// their outer items.
 
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         panic!("`visit_nested_xxx` must be manually implemented in this visitor");
     }
 
index 67d29b38db2a584b031d217e82e62eafd32a1ad9..ac2d7a9a8dc2a953dd1a9c3b75be09068739e55e 100644 (file)
@@ -4,7 +4,7 @@
 //! There are also some rather random cases (like const initializer
 //! expressions) that are mostly just leftovers.
 
-use crate::ich::Fingerprint;
+use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_hir as hir;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
+use syntax::ast;
+
 use std::borrow::Borrow;
 use std::fmt::Write;
 use std::hash::Hash;
-use syntax::ast;
 
 /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa.
 /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
index 63299707592033f04f0e65b83918461fd80fd9e6..76e42b8af2874a674a2a4fbd8af6abfd9f6c8a24 100644 (file)
@@ -1,9 +1,9 @@
-use crate::hir::intravisit;
 use crate::hir::map::Map;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ItemLocalId};
 
@@ -133,7 +133,9 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, wal
 }
 
 impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
-    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'hir> {
+    type Map = Map<'hir>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> {
         intravisit::NestedVisitorMap::OnlyBodies(self.hir_map)
     }
 
index 0a165accb7d52df9c2d6f3c7b827ee2e245d3d71..46c5ee272d2352a97077189607f01f44b5710e7d 100644 (file)
@@ -4,13 +4,13 @@
 };
 
 use crate::dep_graph::{DepGraph, DepKind, DepNode, DepNodeIndex};
-use crate::hir::intravisit;
 use crate::middle::cstore::CrateStoreDyn;
 use crate::ty::query::Providers;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::print::Nested;
 use rustc_hir::*;
@@ -18,7 +18,7 @@
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::kw;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 use syntax::ast::{self, Name, NodeId};
 
@@ -186,12 +186,12 @@ struct ParentHirIterator<'map, 'hir> {
 }
 
 impl<'map, 'hir> ParentHirIterator<'map, 'hir> {
-    fn new(current_id: HirId, map: &'map Map<'hir>) -> ParentHirIterator<'map, 'hir> {
-        ParentHirIterator { current_id, map }
+    fn new(current_id: HirId, map: &'map Map<'hir>) -> Self {
+        Self { current_id, map }
     }
 }
 
-impl<'map, 'hir> Iterator for ParentHirIterator<'map, 'hir> {
+impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
     type Item = (HirId, Node<'hir>);
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -405,6 +405,14 @@ pub fn krate(&self) -> &'hir Crate<'hir> {
         self.forest.krate()
     }
 
+    pub fn item(&self, id: HirId) -> &'hir Item<'hir> {
+        self.read(id);
+
+        // N.B., intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.item(id)
+    }
+
     pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
         self.read(id.hir_id);
 
@@ -1085,6 +1093,24 @@ pub fn hir_to_pretty_string(&self, id: HirId) -> String {
     }
 }
 
+impl<'hir> intravisit::Map<'hir> for Map<'hir> {
+    fn body(&self, id: BodyId) -> &'hir Body<'hir> {
+        self.body(id)
+    }
+
+    fn item(&self, id: HirId) -> &'hir Item<'hir> {
+        self.item(id)
+    }
+
+    fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
+        self.trait_item(id)
+    }
+
+    fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
+        self.impl_item(id)
+    }
+}
+
 pub struct NodesMatchingSuffix<'a> {
     map: &'a Map<'a>,
     item_name: &'a String,
@@ -1244,7 +1270,7 @@ pub fn map_crate<'hir>(
         definitions,
     };
 
-    sess.time("validate HIR map", || {
+    sess.time("validate_HIR_map", || {
         hir_id_validator::check_crate(&map);
     });
 
index 3087fc3c1f2e6c0bd1577fdad6b8e05e9d8b1c20..97c14dd7e00541f180cbc407dc07d0ed11eca243 100644 (file)
@@ -4,7 +4,6 @@
 
 pub mod check_attr;
 pub mod exports;
-pub mod intravisit;
 pub mod map;
 pub mod upvars;
 
index df02a79ef4cc2b0da07921125469ee0cdcaaeea3..4ca294f48615536a01498979d659079c165fe092 100644 (file)
@@ -1,11 +1,12 @@
 //! Upvar (closure capture) collection from cross-body HIR uses of `Res::Local`s.
 
-use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use crate::hir::map::Map;
 use crate::ty::query::Providers;
 use crate::ty::TyCtxt;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{self, HirId};
 use rustc_span::Span;
 
@@ -43,7 +44,9 @@ struct LocalCollector {
 }
 
 impl Visitor<'tcx> for LocalCollector {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         NestedVisitorMap::None
     }
 
@@ -70,7 +73,9 @@ fn visit_local_use(&mut self, var_id: HirId, span: Span) {
 }
 
 impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         NestedVisitorMap::None
     }
 
index 5e402dc79a1adb703ad4b3ae39ea5221b6eafc41..012900f8af51b1ec19e6a094c226feb01d23582f 100644 (file)
@@ -22,7 +22,7 @@
 use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::{self, BoundVar, Ty, TyCtxt};
-use crate::util::captures::Captures;
+use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 use rustc_index::vec::IndexVec;
 use rustc_span::DUMMY_SP;
index 90f546113c1bc58e8248e5a5327f68ecb09d68bd..c52d4335ea184fed6496b5e1d47dfa4be0bbb5c1 100644 (file)
@@ -53,6 +53,8 @@
 use crate::infer::opaque_types;
 use crate::infer::{self, SuppressRegionErrors};
 use crate::middle::region;
+use crate::traits::error_reporting::report_object_safety_error;
+use crate::traits::object_safety_violations;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
 };
     subst::{Subst, SubstsRef},
     Region, Ty, TyCtxt, TypeFoldable,
 };
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_error_codes::*;
+use rustc_errors::{pluralize, struct_span_err};
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Node;
-
-use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
-use rustc_error_codes::*;
-use rustc_span::{Pos, Span};
+use rustc_span::{DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::{cmp, fmt};
 
 
 pub mod nice_region_error;
 
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn note_and_explain_region(
-        self,
-        region_scope_tree: &region::ScopeTree,
-        err: &mut DiagnosticBuilder<'_>,
-        prefix: &str,
-        region: ty::Region<'tcx>,
-        suffix: &str,
-    ) {
-        let (description, span) = match *region {
-            ty::ReScope(scope) => {
-                let new_string;
-                let unknown_scope = || {
-                    format!("{}unknown scope: {:?}{}.  Please report a bug.", prefix, scope, suffix)
-                };
-                let span = scope.span(self, region_scope_tree);
-                let tag = match self.hir().find(scope.hir_id(region_scope_tree)) {
-                    Some(Node::Block(_)) => "block",
-                    Some(Node::Expr(expr)) => match expr.kind {
-                        hir::ExprKind::Call(..) => "call",
-                        hir::ExprKind::MethodCall(..) => "method call",
-                        hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
-                        hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
-                        hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
-                        hir::ExprKind::Match(..) => "match",
-                        _ => "expression",
-                    },
-                    Some(Node::Stmt(_)) => "statement",
-                    Some(Node::Item(it)) => Self::item_scope_tag(&it),
-                    Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
-                    Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
-                    Some(_) | None => {
-                        err.span_note(span, &unknown_scope());
-                        return;
-                    }
-                };
-                let scope_decorated_tag = match scope.data {
-                    region::ScopeData::Node => tag,
-                    region::ScopeData::CallSite => "scope of call-site for function",
-                    region::ScopeData::Arguments => "scope of function body",
-                    region::ScopeData::Destruction => {
-                        new_string = format!("destruction scope surrounding {}", tag);
-                        &new_string[..]
-                    }
-                    region::ScopeData::Remainder(first_statement_index) => {
-                        new_string = format!(
-                            "block suffix following statement {}",
-                            first_statement_index.index()
-                        );
-                        &new_string[..]
-                    }
-                };
-                self.explain_span(scope_decorated_tag, span)
-            }
+pub(super) fn note_and_explain_region(
+    tcx: TyCtxt<'tcx>,
+    region_scope_tree: &region::ScopeTree,
+    err: &mut DiagnosticBuilder<'_>,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+) {
+    let (description, span) = match *region {
+        ty::ReScope(scope) => {
+            let new_string;
+            let unknown_scope =
+                || format!("{}unknown scope: {:?}{}.  Please report a bug.", prefix, scope, suffix);
+            let span = scope.span(tcx, region_scope_tree);
+            let tag = match tcx.hir().find(scope.hir_id(region_scope_tree)) {
+                Some(Node::Block(_)) => "block",
+                Some(Node::Expr(expr)) => match expr.kind {
+                    hir::ExprKind::Call(..) => "call",
+                    hir::ExprKind::MethodCall(..) => "method call",
+                    hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
+                    hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let",
+                    hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for",
+                    hir::ExprKind::Match(..) => "match",
+                    _ => "expression",
+                },
+                Some(Node::Stmt(_)) => "statement",
+                Some(Node::Item(it)) => item_scope_tag(&it),
+                Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
+                Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
+                Some(_) | None => {
+                    err.span_note(span, &unknown_scope());
+                    return;
+                }
+            };
+            let scope_decorated_tag = match scope.data {
+                region::ScopeData::Node => tag,
+                region::ScopeData::CallSite => "scope of call-site for function",
+                region::ScopeData::Arguments => "scope of function body",
+                region::ScopeData::Destruction => {
+                    new_string = format!("destruction scope surrounding {}", tag);
+                    &new_string[..]
+                }
+                region::ScopeData::Remainder(first_statement_index) => {
+                    new_string = format!(
+                        "block suffix following statement {}",
+                        first_statement_index.index()
+                    );
+                    &new_string[..]
+                }
+            };
+            explain_span(tcx, scope_decorated_tag, span)
+        }
 
-            ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
-                self.msg_span_from_free_region(region)
-            }
+        ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
+            msg_span_from_free_region(tcx, region)
+        }
 
-            ty::ReEmpty => ("the empty lifetime".to_owned(), None),
+        ty::ReEmpty => ("the empty lifetime".to_owned(), None),
 
-            ty::RePlaceholder(_) => (format!("any other region"), None),
+        ty::RePlaceholder(_) => (format!("any other region"), None),
 
-            // FIXME(#13998) RePlaceholder should probably print like
-            // ReFree rather than dumping Debug output on the user.
-            //
-            // We shouldn't really be having unification failures with ReVar
-            // and ReLateBound though.
-            ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
-                (format!("lifetime {:?}", region), None)
-            }
+        // FIXME(#13998) RePlaceholder should probably print like
+        // ReFree rather than dumping Debug output on the user.
+        //
+        // We shouldn't really be having unification failures with ReVar
+        // and ReLateBound though.
+        ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+            (format!("lifetime {:?}", region), None)
+        }
 
-            // We shouldn't encounter an error message with ReClosureBound.
-            ty::ReClosureBound(..) => {
-                bug!("encountered unexpected ReClosureBound: {:?}", region,);
-            }
-        };
+        // We shouldn't encounter an error message with ReClosureBound.
+        ty::ReClosureBound(..) => {
+            bug!("encountered unexpected ReClosureBound: {:?}", region,);
+        }
+    };
 
-        TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
-    }
+    emit_msg_span(err, prefix, description, span, suffix);
+}
 
-    pub fn note_and_explain_free_region(
-        self,
-        err: &mut DiagnosticBuilder<'_>,
-        prefix: &str,
-        region: ty::Region<'tcx>,
-        suffix: &str,
-    ) {
-        let (description, span) = self.msg_span_from_free_region(region);
+pub(super) fn note_and_explain_free_region(
+    tcx: TyCtxt<'tcx>,
+    err: &mut DiagnosticBuilder<'_>,
+    prefix: &str,
+    region: ty::Region<'tcx>,
+    suffix: &str,
+) {
+    let (description, span) = msg_span_from_free_region(tcx, region);
 
-        TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
-    }
+    emit_msg_span(err, prefix, description, span, suffix);
+}
 
-    fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
-        match *region {
-            ty::ReEarlyBound(_) | ty::ReFree(_) => {
-                self.msg_span_from_early_bound_and_free_regions(region)
-            }
-            ty::ReStatic => ("the static lifetime".to_owned(), None),
-            ty::ReEmpty => ("an empty lifetime".to_owned(), None),
-            _ => bug!("{:?}", region),
+fn msg_span_from_free_region(
+    tcx: TyCtxt<'tcx>,
+    region: ty::Region<'tcx>,
+) -> (String, Option<Span>) {
+    match *region {
+        ty::ReEarlyBound(_) | ty::ReFree(_) => {
+            msg_span_from_early_bound_and_free_regions(tcx, region)
         }
+        ty::ReStatic => ("the static lifetime".to_owned(), None),
+        ty::ReEmpty => ("an empty lifetime".to_owned(), None),
+        _ => bug!("{:?}", region),
     }
+}
 
-    fn msg_span_from_early_bound_and_free_regions(
-        self,
-        region: ty::Region<'tcx>,
-    ) -> (String, Option<Span>) {
-        let cm = self.sess.source_map();
-
-        let scope = region.free_region_binding_scope(self);
-        let node = self.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
-        let tag = match self.hir().find(node) {
-            Some(Node::Block(_)) | Some(Node::Expr(_)) => "body",
-            Some(Node::Item(it)) => Self::item_scope_tag(&it),
-            Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
-            Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
-            _ => unreachable!(),
-        };
-        let (prefix, span) = match *region {
-            ty::ReEarlyBound(ref br) => {
-                let mut sp = cm.def_span(self.hir().span(node));
-                if let Some(param) =
-                    self.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
-                {
-                    sp = param.span;
-                }
-                (format!("the lifetime `{}` as defined on", br.name), sp)
-            }
-            ty::ReFree(ty::FreeRegion {
-                bound_region: ty::BoundRegion::BrNamed(_, name), ..
-            }) => {
-                let mut sp = cm.def_span(self.hir().span(node));
-                if let Some(param) =
-                    self.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
-                {
-                    sp = param.span;
-                }
-                (format!("the lifetime `{}` as defined on", name), sp)
-            }
-            ty::ReFree(ref fr) => match fr.bound_region {
-                ty::BrAnon(idx) => (
-                    format!("the anonymous lifetime #{} defined on", idx + 1),
-                    self.hir().span(node),
-                ),
-                _ => (
-                    format!("the lifetime `{}` as defined on", region),
-                    cm.def_span(self.hir().span(node)),
-                ),
-            },
-            _ => bug!(),
-        };
-        let (msg, opt_span) = self.explain_span(tag, span);
-        (format!("{} {}", prefix, msg), opt_span)
-    }
-
-    fn emit_msg_span(
-        err: &mut DiagnosticBuilder<'_>,
-        prefix: &str,
-        description: String,
-        span: Option<Span>,
-        suffix: &str,
-    ) {
-        let message = format!("{}{}{}", prefix, description, suffix);
-
-        if let Some(span) = span {
-            err.span_note(span, &message);
-        } else {
-            err.note(&message);
+fn msg_span_from_early_bound_and_free_regions(
+    tcx: TyCtxt<'tcx>,
+    region: ty::Region<'tcx>,
+) -> (String, Option<Span>) {
+    let cm = tcx.sess.source_map();
+
+    let scope = region.free_region_binding_scope(tcx);
+    let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
+    let tag = match tcx.hir().find(node) {
+        Some(Node::Block(_)) | Some(Node::Expr(_)) => "body",
+        Some(Node::Item(it)) => item_scope_tag(&it),
+        Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
+        Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
+        _ => unreachable!(),
+    };
+    let (prefix, span) = match *region {
+        ty::ReEarlyBound(ref br) => {
+            let mut sp = cm.def_span(tcx.hir().span(node));
+            if let Some(param) =
+                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+            {
+                sp = param.span;
+            }
+            (format!("the lifetime `{}` as defined on", br.name), sp)
         }
-    }
-
-    fn item_scope_tag(item: &hir::Item<'_>) -> &'static str {
-        match item.kind {
-            hir::ItemKind::Impl(..) => "impl",
-            hir::ItemKind::Struct(..) => "struct",
-            hir::ItemKind::Union(..) => "union",
-            hir::ItemKind::Enum(..) => "enum",
-            hir::ItemKind::Trait(..) => "trait",
-            hir::ItemKind::Fn(..) => "function body",
-            _ => "item",
+        ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => {
+            let mut sp = cm.def_span(tcx.hir().span(node));
+            if let Some(param) =
+                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+            {
+                sp = param.span;
+            }
+            (format!("the lifetime `{}` as defined on", name), sp)
         }
+        ty::ReFree(ref fr) => match fr.bound_region {
+            ty::BrAnon(idx) => {
+                (format!("the anonymous lifetime #{} defined on", idx + 1), tcx.hir().span(node))
+            }
+            _ => (
+                format!("the lifetime `{}` as defined on", region),
+                cm.def_span(tcx.hir().span(node)),
+            ),
+        },
+        _ => bug!(),
+    };
+    let (msg, opt_span) = explain_span(tcx, tag, span);
+    (format!("{} {}", prefix, msg), opt_span)
+}
+
+fn emit_msg_span(
+    err: &mut DiagnosticBuilder<'_>,
+    prefix: &str,
+    description: String,
+    span: Option<Span>,
+    suffix: &str,
+) {
+    let message = format!("{}{}{}", prefix, description, suffix);
+
+    if let Some(span) = span {
+        err.span_note(span, &message);
+    } else {
+        err.note(&message);
     }
+}
 
-    fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str {
-        match item.kind {
-            hir::TraitItemKind::Method(..) => "method body",
-            hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
-        }
+fn item_scope_tag(item: &hir::Item<'_>) -> &'static str {
+    match item.kind {
+        hir::ItemKind::Impl(..) => "impl",
+        hir::ItemKind::Struct(..) => "struct",
+        hir::ItemKind::Union(..) => "union",
+        hir::ItemKind::Enum(..) => "enum",
+        hir::ItemKind::Trait(..) => "trait",
+        hir::ItemKind::Fn(..) => "function body",
+        _ => "item",
     }
+}
 
-    fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str {
-        match item.kind {
-            hir::ImplItemKind::Method(..) => "method body",
-            hir::ImplItemKind::Const(..)
-            | hir::ImplItemKind::OpaqueTy(..)
-            | hir::ImplItemKind::TyAlias(..) => "associated item",
-        }
+fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str {
+    match item.kind {
+        hir::TraitItemKind::Method(..) => "method body",
+        hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
     }
+}
 
-    fn explain_span(self, heading: &str, span: Span) -> (String, Option<Span>) {
-        let lo = self.sess.source_map().lookup_char_pos(span.lo());
-        (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
+fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str {
+    match item.kind {
+        hir::ImplItemKind::Method(..) => "method body",
+        hir::ImplItemKind::Const(..)
+        | hir::ImplItemKind::OpaqueTy(..)
+        | hir::ImplItemKind::TyAlias(..) => "associated item",
     }
 }
 
+fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) {
+    let lo = tcx.sess.source_map().lookup_char_pos(span.lo());
+    (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn report_region_errors(
         &self,
@@ -1290,6 +1290,8 @@ pub fn note_type_err(
         mut values: Option<ValuePairs<'tcx>>,
         terr: &TypeError<'tcx>,
     ) {
+        let span = cause.span(self.tcx);
+
         // For some types of errors, expected-found does not make
         // sense, so just ignore the values we were given.
         match terr {
@@ -1299,6 +1301,100 @@ pub fn note_type_err(
             _ => {}
         }
 
+        struct OpaqueTypesVisitor<'tcx> {
+            types: FxHashMap<TyCategory, FxHashSet<Span>>,
+            expected: FxHashMap<TyCategory, FxHashSet<Span>>,
+            found: FxHashMap<TyCategory, FxHashSet<Span>>,
+            ignore_span: Span,
+            tcx: TyCtxt<'tcx>,
+        }
+
+        impl<'tcx> OpaqueTypesVisitor<'tcx> {
+            fn visit_expected_found(
+                tcx: TyCtxt<'tcx>,
+                expected: Ty<'tcx>,
+                found: Ty<'tcx>,
+                ignore_span: Span,
+            ) -> Self {
+                let mut types_visitor = OpaqueTypesVisitor {
+                    types: Default::default(),
+                    expected: Default::default(),
+                    found: Default::default(),
+                    ignore_span,
+                    tcx,
+                };
+                // The visitor puts all the relevant encountered types in `self.types`, but in
+                // here we want to visit two separate types with no relation to each other, so we
+                // move the results from `types` to `expected` or `found` as appropriate.
+                expected.visit_with(&mut types_visitor);
+                std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types);
+                found.visit_with(&mut types_visitor);
+                std::mem::swap(&mut types_visitor.found, &mut types_visitor.types);
+                types_visitor
+            }
+
+            fn report(&self, err: &mut DiagnosticBuilder<'_>) {
+                self.add_labels_for_types(err, "expected", &self.expected);
+                self.add_labels_for_types(err, "found", &self.found);
+            }
+
+            fn add_labels_for_types(
+                &self,
+                err: &mut DiagnosticBuilder<'_>,
+                target: &str,
+                types: &FxHashMap<TyCategory, FxHashSet<Span>>,
+            ) {
+                for (key, values) in types.iter() {
+                    let count = values.len();
+                    let kind = key.descr();
+                    for sp in values {
+                        err.span_label(
+                            *sp,
+                            format!(
+                                "{}{}{} {}{}",
+                                if sp.is_desugaring(DesugaringKind::Async) {
+                                    "the `Output` of this `async fn`'s "
+                                } else if count == 1 {
+                                    "the "
+                                } else {
+                                    ""
+                                },
+                                if count > 1 { "one of the " } else { "" },
+                                target,
+                                kind,
+                                pluralize!(count),
+                            ),
+                        );
+                    }
+                }
+            }
+        }
+
+        impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
+            fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+                if let Some((kind, def_id)) = TyCategory::from_ty(t) {
+                    let span = self.tcx.def_span(def_id);
+                    // Avoid cluttering the output when the "found" and error span overlap:
+                    //
+                    // error[E0308]: mismatched types
+                    //   --> $DIR/issue-20862.rs:2:5
+                    //    |
+                    // LL |     |y| x + y
+                    //    |     ^^^^^^^^^
+                    //    |     |
+                    //    |     the found closure
+                    //    |     expected `()`, found closure
+                    //    |
+                    //    = note: expected unit type `()`
+                    //                 found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]`
+                    if !self.ignore_span.overlaps(span) {
+                        self.types.entry(kind).or_default().insert(span);
+                    }
+                }
+                t.super_visit_with(self)
+            }
+        }
+
         debug!("note_type_err(diag={:?})", diag);
         let (expected_found, exp_found, is_simple_error) = match values {
             None => (None, None, false),
@@ -1307,6 +1403,13 @@ pub fn note_type_err(
                     ValuePairs::Types(exp_found) => {
                         let is_simple_err =
                             exp_found.expected.is_simple_text() && exp_found.found.is_simple_text();
+                        OpaqueTypesVisitor::visit_expected_found(
+                            self.tcx,
+                            exp_found.expected,
+                            exp_found.found,
+                            span,
+                        )
+                        .report(diag);
 
                         (is_simple_err, Some(exp_found))
                     }
@@ -1324,8 +1427,6 @@ pub fn note_type_err(
             }
         };
 
-        let span = cause.span(self.tcx);
-
         // Ignore msg for object safe coercion
         // since E0038 message will be printed
         match terr {
@@ -1337,7 +1438,6 @@ pub fn note_type_err(
                 }
             }
         };
-
         if let Some((expected, found)) = expected_found {
             let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
             let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());
@@ -1489,8 +1589,8 @@ pub fn report_and_explain_type_error(
         let failure_code = trace.cause.as_failure_code(terr);
         let mut diag = match failure_code {
             FailureCode::Error0038(did) => {
-                let violations = self.tcx.object_safety_violations(did);
-                self.tcx.report_object_safety_error(span, did, violations)
+                let violations = object_safety_violations(self.tcx, did);
+                report_object_safety_error(self.tcx, span, did, violations)
             }
             FailureCode::Error0317(failure_str) => {
                 struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
@@ -1719,7 +1819,8 @@ fn binding_suggestion<'tcx, S: fmt::Display>(
                     "consider adding an explicit lifetime bound for `{}`",
                     bound_kind
                 ));
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     &format!("{} must be valid for ", labeled_user_string),
@@ -1747,7 +1848,8 @@ fn report_sub_sup_conflict(
     ) {
         let mut err = self.report_inference_failure(var_origin);
 
-        self.tcx.note_and_explain_region(
+        note_and_explain_region(
+            self.tcx,
             region_scope_tree,
             &mut err,
             "first, the lifetime cannot outlive ",
@@ -1771,7 +1873,8 @@ fn report_sub_sup_conflict(
                     (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values))
                 {
                     if sub_expected == sup_expected && sub_found == sup_found {
-                        self.tcx.note_and_explain_region(
+                        note_and_explain_region(
+                            self.tcx,
                             region_scope_tree,
                             &mut err,
                             "...but the lifetime must also be valid for ",
@@ -1794,7 +1897,8 @@ fn report_sub_sup_conflict(
 
         self.note_region_origin(&mut err, &sup_origin);
 
-        self.tcx.note_and_explain_region(
+        note_and_explain_region(
+            self.tcx,
             region_scope_tree,
             &mut err,
             "but, the lifetime must be valid for ",
@@ -1930,3 +2034,34 @@ fn as_requirement_str(&self) -> &'static str {
         }
     }
 }
+
+/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
+/// extra information about each type, but we only care about the category.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+crate enum TyCategory {
+    Closure,
+    Opaque,
+    Generator,
+    Foreign,
+}
+
+impl TyCategory {
+    fn descr(&self) -> &'static str {
+        match self {
+            Self::Closure => "closure",
+            Self::Opaque => "opaque type",
+            Self::Generator => "generator",
+            Self::Foreign => "foreign type",
+        }
+    }
+
+    pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
+        match ty.kind {
+            ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
+            ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
+            ty::Generator(def_id, ..) => Some((Self::Generator, def_id)),
+            ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
+            _ => None,
+        }
+    }
+}
index 091bfba7ca677ff0e9fbc805362243dde512402a..70f7987faf4ccf83d202b3092143cdec2a1ca443 100644 (file)
@@ -1,12 +1,12 @@
-use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use crate::hir::map::Map;
 use crate::infer::type_variable::TypeVariableOriginKind;
 use crate::infer::InferCtxt;
 use crate::ty::print::Print;
 use crate::ty::{self, DefIdTree, Infer, Ty, TyVar};
-use errors::{Applicability, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FunctionRetTy, HirId, Local, Pat};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::kw;
@@ -66,7 +66,9 @@ fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.hir_map)
     }
 
@@ -149,16 +151,13 @@ pub enum TypeAnnotationNeeded {
     E0284,
 }
 
-impl Into<errors::DiagnosticId> for TypeAnnotationNeeded {
-    fn into(self) -> errors::DiagnosticId {
-        syntax::diagnostic_used!(E0282);
-        syntax::diagnostic_used!(E0283);
-        syntax::diagnostic_used!(E0284);
-        errors::DiagnosticId::Error(match self {
-            Self::E0282 => "E0282".to_string(),
-            Self::E0283 => "E0283".to_string(),
-            Self::E0284 => "E0284".to_string(),
-        })
+impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
+    fn into(self) -> rustc_errors::DiagnosticId {
+        match self {
+            Self::E0282 => rustc_errors::error_code!(E0282),
+            Self::E0283 => rustc_errors::error_code!(E0283),
+            Self::E0284 => rustc_errors::error_code!(E0284),
+        }
     }
 }
 
index cfb6d5bd244b9161b1d9702d01094a5635dc95ba..d6e50209f72ddf73471091869bd6d72ea42a31d6 100644 (file)
@@ -6,6 +6,7 @@
 use crate::util::common::ErrorReported;
 
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
index 6edf8f1e78755f9274a52c77a9c489eda2a0a0ca..8e2592b5318855a9ac70ad62c69a1ac12828cc30 100644 (file)
@@ -1,8 +1,9 @@
-use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use crate::hir::map::Map;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::middle::resolve_lifetime as rl;
 use crate::ty::{self, Region, TyCtxt};
 use rustc_hir as hir;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::Node;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -90,7 +91,9 @@ struct FindNestedTypeVisitor<'tcx> {
 }
 
 impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
@@ -207,7 +210,9 @@ struct TyPathVisitor<'tcx> {
 }
 
 impl Visitor<'tcx> for TyPathVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Map<'tcx>> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
index 5da65a3019395f297455536c1b14335498a9d4be..8749d6cd34bed27cff82613a032fc75c8e18b448 100644 (file)
@@ -3,7 +3,7 @@
 use crate::infer::InferCtxt;
 use crate::ty::{self, TyCtxt};
 use crate::util::common::ErrorReported;
-use errors::DiagnosticBuilder;
+use rustc_errors::DiagnosticBuilder;
 use rustc_span::source_map::Span;
 
 mod different_lifetimes;
index 0d56fc57230e3958bd2b64f3bc42b671c867430f..2344d408a43a5d39e752f4a72c09b97aeabf985c 100644 (file)
@@ -2,7 +2,7 @@
 //! where one region is named and the other is anonymous.
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::ty;
-use errors::{Applicability, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir::{FunctionRetTy, TyKind};
 
 use rustc_error_codes::*;
index f276dab5000bc20a0c6ad75d35d1f35f702b2ae4..7b31fe7cd7e4d208af4f8124867c07e4dc1feeae 100644 (file)
@@ -7,7 +7,7 @@
 use crate::ty::print::{FmtPrinter, Print, RegionHighlightMode};
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, TyCtxt};
-use errors::DiagnosticBuilder;
+use rustc_errors::DiagnosticBuilder;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 
index 69ebbe1fd367977b5ce6c05bda047c0109ea3b95..c6fc4cd3c15f7721301e49c892756df0e19f037a 100644 (file)
@@ -1,10 +1,11 @@
 //! Error Reporting for static impl Traits.
 
+use crate::infer::error_reporting::msg_span_from_free_region;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::ty::{BoundRegion, FreeRegion, RegionKind};
 use crate::util::common::ErrorReported;
-use errors::Applicability;
+use rustc_errors::Applicability;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the return type is a static impl Trait.
@@ -32,7 +33,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                     );
                     err.span_label(sup_origin.span(), "...but this borrow...");
 
-                    let (lifetime, lt_sp_opt) = self.tcx().msg_span_from_free_region(sup_r);
+                    let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r);
                     if let Some(lifetime_sp) = lt_sp_opt {
                         err.span_note(lifetime_sp, &format!("...can't outlive {}", lifetime));
                     }
index 979bcca619c2ff6a3573fdc75fb60cb4198e3143..6303104e39dd317e5d28aa1acf9aba320346b85d 100644 (file)
@@ -1,8 +1,9 @@
+use crate::infer::error_reporting::note_and_explain_region;
 use crate::infer::{self, InferCtxt, SubregionOrigin};
 use crate::middle::region;
 use crate::ty::error::TypeError;
 use crate::ty::{self, Region};
-use errors::DiagnosticBuilder;
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 
 use rustc_error_codes::*;
 
@@ -167,8 +168,9 @@ pub(super) fn report_concrete_failure(
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
                 let mut err = self.report_and_explain_type_error(trace, &terr);
-                self.tcx.note_and_explain_region(region_scope_tree, &mut err, "", sup, "...");
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(self.tcx, region_scope_tree, &mut err, "", sup, "...");
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...does not necessarily outlive ",
@@ -185,14 +187,16 @@ pub(super) fn report_concrete_failure(
                     "lifetime of reference outlives lifetime of \
                                                 borrowed content..."
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...the reference is valid for ",
                     sub,
                     "...",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...but the borrowed content is only valid for ",
@@ -211,14 +215,16 @@ pub(super) fn report_concrete_failure(
                                                 of captured variable `{}`...",
                     var_name
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...the borrowed pointer is valid for ",
                     sub,
                     "...",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     &format!("...but `{}` is only valid for ", var_name),
@@ -230,14 +236,16 @@ pub(super) fn report_concrete_failure(
             infer::InfStackClosure(span) => {
                 let mut err =
                     struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame");
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...the closure must be valid for ",
                     sub,
                     "...",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "...but the closure's stack frame is only valid \
@@ -254,7 +262,8 @@ pub(super) fn report_concrete_failure(
                     E0315,
                     "cannot invoke closure outside of its lifetime"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the closure is only valid for ",
@@ -270,7 +279,8 @@ pub(super) fn report_concrete_failure(
                     E0473,
                     "dereference of reference outside its lifetime"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the reference is only valid for ",
@@ -288,14 +298,16 @@ pub(super) fn report_concrete_failure(
                                                 enclosing closure",
                     self.tcx.hir().name(id)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "captured variable is valid for ",
                     sup,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "closure is valid for ",
@@ -311,7 +323,8 @@ pub(super) fn report_concrete_failure(
                     E0475,
                     "index of slice outside its lifetime"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the slice is only valid for ",
@@ -328,14 +341,16 @@ pub(super) fn report_concrete_failure(
                     "lifetime of the source pointer does not outlive \
                                                 lifetime bound of the object type"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "object type is valid for ",
                     sub,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "source pointer is only valid for ",
@@ -354,14 +369,16 @@ pub(super) fn report_concrete_failure(
                     self.ty_to_string(ty)
                 );
                 match *sub {
-                    ty::ReStatic => self.tcx.note_and_explain_region(
+                    ty::ReStatic => note_and_explain_region(
+                        self.tcx,
                         region_scope_tree,
                         &mut err,
                         "type must satisfy ",
                         sub,
                         "",
                     ),
-                    _ => self.tcx.note_and_explain_region(
+                    _ => note_and_explain_region(
+                        self.tcx,
                         region_scope_tree,
                         &mut err,
                         "type must outlive ",
@@ -374,14 +391,16 @@ pub(super) fn report_concrete_failure(
             infer::RelateRegionParamBound(span) => {
                 let mut err =
                     struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "lifetime parameter instantiated with ",
                     sup,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "but lifetime parameter must outlive ",
@@ -399,7 +418,8 @@ pub(super) fn report_concrete_failure(
                                                 parameter) is not valid at this point",
                     self.ty_to_string(ty)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "type must outlive ",
@@ -416,7 +436,8 @@ pub(super) fn report_concrete_failure(
                     "lifetime of method receiver does not outlive the \
                                                 method call"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the receiver is only valid for ",
@@ -433,7 +454,8 @@ pub(super) fn report_concrete_failure(
                     "lifetime of function argument does not outlive \
                                                 the function call"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the function argument is only valid for ",
@@ -450,7 +472,8 @@ pub(super) fn report_concrete_failure(
                     "lifetime of return value does not outlive the \
                                                 function call"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the return value is only valid for ",
@@ -467,7 +490,8 @@ pub(super) fn report_concrete_failure(
                     "lifetime of operand does not outlive the \
                                                 operation"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the operand is only valid for ",
@@ -483,7 +507,8 @@ pub(super) fn report_concrete_failure(
                     E0484,
                     "reference is not valid at the time of borrow"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the borrow is only valid for ",
@@ -500,7 +525,8 @@ pub(super) fn report_concrete_failure(
                     "automatically reference is not valid at the time \
                                                 of borrow"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the automatic borrow is only valid for ",
@@ -518,7 +544,8 @@ pub(super) fn report_concrete_failure(
                                                 not valid during the expression: `{}`",
                     self.ty_to_string(t)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "type is only valid for ",
@@ -536,14 +563,16 @@ pub(super) fn report_concrete_failure(
                                                 called while references are dead"
                 );
                 // FIXME (22171): terms "super/subregion" are suboptimal
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "superregion: ",
                     sup,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "subregion: ",
@@ -560,7 +589,8 @@ pub(super) fn report_concrete_failure(
                     "lifetime of variable does not enclose its \
                                                 declaration"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the variable is only valid for ",
@@ -576,7 +606,8 @@ pub(super) fn report_concrete_failure(
                     E0489,
                     "type/lifetime parameter not in scope here"
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the parameter is only valid for ",
@@ -593,14 +624,16 @@ pub(super) fn report_concrete_failure(
                     "a value of type `{}` is borrowed for too long",
                     self.ty_to_string(ty)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the type is valid for ",
                     sub,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "but the borrow lasts for ",
@@ -618,14 +651,16 @@ pub(super) fn report_concrete_failure(
                                                 than the data it references",
                     self.ty_to_string(ty)
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "the pointer is valid for ",
                     sub,
                     "",
                 );
-                self.tcx.note_and_explain_region(
+                note_and_explain_region(
+                    self.tcx,
                     region_scope_tree,
                     &mut err,
                     "but the referenced data is only valid for ",
index e78382c0a3234286f4ab29dc289702b2971e81c9..0bc49a290150554055f9c38bd47d6084f4014f72 100644 (file)
@@ -204,9 +204,7 @@ fn enforce_member_constraints(
         // want to stop at the first constraint that makes a change.
         let mut any_changed = false;
         for member_constraint in &self.data.member_constraints {
-            if self.enforce_member_constraint(graph, member_constraint, var_values) {
-                any_changed = true;
-            }
+            any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values);
         }
         any_changed
     }
@@ -337,9 +335,7 @@ fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
             for index in live_indices.iter() {
                 let constraint = constraints[index];
                 let (edge_changed, retain) = process_constraint(constraint);
-                if edge_changed {
-                    changed = true;
-                }
+                changed |= edge_changed;
                 if !retain {
                     let changed = killed_indices.insert(index);
                     debug_assert!(changed);
index 4eb8d79a067ef78ece7409f52fd35d70289330ef..f67669e367f00c9eb5f2224dff04c3968f19beb4 100644 (file)
 use crate::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
 use crate::ty::{ConstVid, FloatVid, IntVid, TyVid};
 
-use errors::DiagnosticBuilder;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unify as ut;
+use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::Symbol;
index e9b1ebbd3f643a8a778652808d80423ea177d9d8..a1afb1a86be44b563fe1382167d8ca1284267bf4 100644 (file)
@@ -1,14 +1,15 @@
-use crate::infer::outlives::free_region_map::FreeRegionRelations;
+use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region};
 use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
 use crate::middle::region;
 use crate::traits::{self, PredicateObligation};
 use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::free_region_map::FreeRegionRelations;
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
 use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
-use errors::DiagnosticBuilder;
 use rustc::session::config::nightly_options;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_hir::Node;
@@ -349,7 +350,8 @@ pub fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
             debug!("constrain_opaque_type: bounds={:#?}", bounds);
             let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
 
-            let required_region_bounds = tcx.required_region_bounds(opaque_type, bounds.predicates);
+            let required_region_bounds =
+                required_region_bounds(tcx, opaque_type, bounds.predicates);
             debug_assert!(!required_region_bounds.is_empty());
 
             for required_region in required_region_bounds {
@@ -522,11 +524,7 @@ fn member_constraint_feature_gate(
         err.span_label(span, label);
 
         if nightly_options::is_nightly_build() {
-            help!(
-                err,
-                "add #![feature(member_constraints)] to the crate attributes \
-                   to enable"
-            );
+            err.help("add #![feature(member_constraints)] to the crate attributes to enable");
         }
 
         err.emit();
@@ -624,7 +622,8 @@ pub fn unexpected_hidden_region_diagnostic(
         //
         // (*) if not, the `tainted_by_errors` flag would be set to
         // true in any case, so we wouldn't be here at all.
-        tcx.note_and_explain_free_region(
+        note_and_explain_free_region(
+            tcx,
             &mut err,
             &format!("hidden type `{}` captures ", hidden_ty),
             hidden_region,
@@ -649,7 +648,8 @@ pub fn unexpected_hidden_region_diagnostic(
             // If the `region_scope_tree` is available, this is being
             // invoked from the "region inferencer error". We can at
             // least report a really cryptic error for now.
-            tcx.note_and_explain_region(
+            note_and_explain_region(
+                tcx,
                 region_scope_tree,
                 &mut err,
                 &format!("hidden type `{}` captures ", hidden_ty),
@@ -1130,7 +1130,7 @@ fn fold_opaque_ty(
 
         debug!("instantiate_opaque_types: bounds={:?}", bounds);
 
-        let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone());
+        let required_region_bounds = required_region_bounds(tcx, ty, bounds.predicates.clone());
         debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
 
         // Make sure that we are in fact defining the *entire* type
@@ -1225,3 +1225,67 @@ pub fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: DefId, opaque_hir_id: hir
     );
     res
 }
+
+/// Given a set of predicates that apply to an object type, returns
+/// the region bounds that the (erased) `Self` type must
+/// outlive. Precisely *because* the `Self` type is erased, the
+/// parameter `erased_self_ty` must be supplied to indicate what type
+/// has been used to represent `Self` in the predicates
+/// themselves. This should really be a unique type; `FreshTy(0)` is a
+/// popular choice.
+///
+/// N.B., in some cases, particularly around higher-ranked bounds,
+/// this function returns a kind of conservative approximation.
+/// That is, all regions returned by this function are definitely
+/// required, but there may be other region bounds that are not
+/// returned, as well as requirements like `for<'a> T: 'a`.
+///
+/// Requires that trait definitions have been processed so that we can
+/// elaborate predicates and walk supertraits.
+//
+// FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's
+// what this code should accept.
+crate fn required_region_bounds(
+    tcx: TyCtxt<'tcx>,
+    erased_self_ty: Ty<'tcx>,
+    predicates: Vec<ty::Predicate<'tcx>>,
+) -> Vec<ty::Region<'tcx>> {
+    debug!(
+        "required_region_bounds(erased_self_ty={:?}, predicates={:?})",
+        erased_self_ty, predicates
+    );
+
+    assert!(!erased_self_ty.has_escaping_bound_vars());
+
+    traits::elaborate_predicates(tcx, predicates)
+        .filter_map(|predicate| {
+            match predicate {
+                ty::Predicate::Projection(..)
+                | ty::Predicate::Trait(..)
+                | ty::Predicate::Subtype(..)
+                | ty::Predicate::WellFormed(..)
+                | ty::Predicate::ObjectSafe(..)
+                | ty::Predicate::ClosureKind(..)
+                | ty::Predicate::RegionOutlives(..)
+                | ty::Predicate::ConstEvaluatable(..) => None,
+                ty::Predicate::TypeOutlives(predicate) => {
+                    // Search for a bound of the form `erased_self_ty
+                    // : 'a`, but be wary of something like `for<'a>
+                    // erased_self_ty : 'a` (we interpret a
+                    // higher-ranked bound like that as 'static,
+                    // though at present the code in `fulfill.rs`
+                    // considers such bounds to be unsatisfiable, so
+                    // it's kind of a moot point since you could never
+                    // construct such an object, but this seems
+                    // correct even if that code changes).
+                    let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
+                    if t == &erased_self_ty && !r.has_escaping_bound_vars() {
+                        Some(*r)
+                    } else {
+                        None
+                    }
+                }
+            }
+        })
+        .collect()
+}
index 130cffe5022872b3d3675bbb95b23c427da1d3db..ee2e629c2fcd269bf053bf8d0bd48c47b91a4ddc 100644 (file)
@@ -1,6 +1,6 @@
-use crate::infer::outlives::free_region_map::FreeRegionMap;
 use crate::infer::{GenericKind, InferCtxt};
 use crate::traits::query::outlives_bounds::{self, OutlivesBound};
+use crate::ty::free_region_map::FreeRegionMap;
 use crate::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
diff --git a/src/librustc/infer/outlives/free_region_map.rs b/src/librustc/infer/outlives/free_region_map.rs
deleted file mode 100644 (file)
index 42f5066..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-use crate::ty::{self, Lift, Region, TyCtxt};
-use rustc_data_structures::transitive_relation::TransitiveRelation;
-
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)]
-pub struct FreeRegionMap<'tcx> {
-    // Stores the relation `a < b`, where `a` and `b` are regions.
-    //
-    // Invariant: only free regions like `'x` or `'static` are stored
-    // in this relation, not scopes.
-    relation: TransitiveRelation<Region<'tcx>>,
-}
-
-impl<'tcx> FreeRegionMap<'tcx> {
-    pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> {
-        self.relation.elements()
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.relation.is_empty()
-    }
-
-    // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
-    // (with the exception that `'static: 'x` is not notable)
-    pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
-        debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
-        if is_free_or_static(sub) && is_free(sup) {
-            self.relation.add(sub, sup)
-        }
-    }
-
-    /// Computes the least-upper-bound of two free regions. In some
-    /// cases, this is more conservative than necessary, in order to
-    /// avoid making arbitrary choices. See
-    /// `TransitiveRelation::postdom_upper_bound` for more details.
-    pub fn lub_free_regions(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        r_a: Region<'tcx>,
-        r_b: Region<'tcx>,
-    ) -> Region<'tcx> {
-        debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
-        assert!(is_free(r_a));
-        assert!(is_free(r_b));
-        let result = if r_a == r_b {
-            r_a
-        } else {
-            match self.relation.postdom_upper_bound(&r_a, &r_b) {
-                None => tcx.mk_region(ty::ReStatic),
-                Some(r) => *r,
-            }
-        };
-        debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
-        result
-    }
-}
-
-/// The NLL region handling code represents free region relations in a
-/// slightly different way; this trait allows functions to be abstract
-/// over which version is in use.
-pub trait FreeRegionRelations<'tcx> {
-    /// Tests whether `r_a <= r_b`. Both must be free regions or
-    /// `'static`.
-    fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
-}
-
-impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
-    fn sub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
-        assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
-        if let ty::ReStatic = r_b {
-            true // `'a <= 'static` is just always true, and not stored in the relation explicitly
-        } else {
-            r_a == r_b || self.relation.contains(&r_a, &r_b)
-        }
-    }
-}
-
-fn is_free(r: Region<'_>) -> bool {
-    match *r {
-        ty::ReEarlyBound(_) | ty::ReFree(_) => true,
-        _ => false,
-    }
-}
-
-fn is_free_or_static(r: Region<'_>) -> bool {
-    match *r {
-        ty::ReStatic => true,
-        _ => is_free(r),
-    }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
-    type Lifted = FreeRegionMap<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
-        self.relation.maybe_map(|&fr| tcx.lift(&fr)).map(|relation| FreeRegionMap { relation })
-    }
-}
index e421d6fb6922f921d8a903981fea72e4f96c1a29..6fc72470c9fb7816a822e689ee5f57557fec7451 100644 (file)
@@ -1,6 +1,5 @@
 //! Various code related to computing outlives relations.
 
 pub mod env;
-pub mod free_region_map;
 pub mod obligations;
 pub mod verify;
index 0380d0e35e78d196df30642f3be4297a14bce976..8ee8482e79dbc3f1b216cc79bdb161277e7e2831 100644 (file)
@@ -3,7 +3,7 @@
 use crate::traits;
 use crate::ty::subst::{InternalSubsts, Subst};
 use crate::ty::{self, Ty, TyCtxt};
-use crate::util::captures::Captures;
+use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
index 37761c17f52433b7fcc5c7b2c90e1d047f5db871..2164a0b44bdcb9381df3d8395cfea166a2c94943 100644 (file)
@@ -31,7 +31,6 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_fn)]
 #![feature(const_transmute)]
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
@@ -50,6 +49,7 @@
 #![feature(thread_local)]
 #![feature(trace_macros)]
 #![feature(trusted_len)]
+#![feature(vec_remove_item)]
 #![feature(stmt_expr_attributes)]
 #![feature(integer_atomics)]
 #![feature(test)]
@@ -72,8 +72,6 @@
 #[macro_use]
 extern crate log;
 #[macro_use]
-extern crate syntax;
-#[macro_use]
 extern crate smallvec;
 
 #[cfg(test)]
 
 pub mod util {
     pub mod bug;
-    pub mod captures;
     pub mod common;
 }
 
diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs
new file mode 100644 (file)
index 0000000..2ed6cd5
--- /dev/null
@@ -0,0 +1,369 @@
+use std::cmp;
+
+use crate::ich::StableHashingContext;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_hir::HirId;
+pub use rustc_session::lint::{builtin, Level, Lint, LintId, LintPass};
+use rustc_session::{DiagnosticMessageId, Session};
+use rustc_span::hygiene::MacroKind;
+use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
+use rustc_span::{Span, Symbol};
+
+/// How a lint level was set.
+#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
+pub enum LintSource {
+    /// Lint is at the default level as declared
+    /// in rustc or a plugin.
+    Default,
+
+    /// Lint level was set by an attribute.
+    Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),
+
+    /// Lint level was set by a command-line flag.
+    CommandLine(Symbol),
+}
+
+pub type LevelSource = (Level, LintSource);
+
+pub struct LintLevelSets {
+    pub list: Vec<LintSet>,
+    pub lint_cap: Level,
+}
+
+pub enum LintSet {
+    CommandLine {
+        // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
+        // flag.
+        specs: FxHashMap<LintId, LevelSource>,
+    },
+
+    Node {
+        specs: FxHashMap<LintId, LevelSource>,
+        parent: u32,
+    },
+}
+
+impl LintLevelSets {
+    pub fn new() -> Self {
+        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
+    }
+
+    pub fn get_lint_level(
+        &self,
+        lint: &'static Lint,
+        idx: u32,
+        aux: Option<&FxHashMap<LintId, LevelSource>>,
+        sess: &Session,
+    ) -> LevelSource {
+        let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
+
+        // If `level` is none then we actually assume the default level for this
+        // lint.
+        let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));
+
+        // If we're about to issue a warning, check at the last minute for any
+        // directives against the warnings "lint". If, for example, there's an
+        // `allow(warnings)` in scope then we want to respect that instead.
+        if level == Level::Warn {
+            let (warnings_level, warnings_src) =
+                self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
+            if let Some(configured_warning_level) = warnings_level {
+                if configured_warning_level != Level::Warn {
+                    level = configured_warning_level;
+                    src = warnings_src;
+                }
+            }
+        }
+
+        // Ensure that we never exceed the `--cap-lints` argument.
+        level = cmp::min(level, self.lint_cap);
+
+        if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
+            // Ensure that we never exceed driver level.
+            level = cmp::min(*driver_level, level);
+        }
+
+        return (level, src);
+    }
+
+    pub fn get_lint_id_level(
+        &self,
+        id: LintId,
+        mut idx: u32,
+        aux: Option<&FxHashMap<LintId, LevelSource>>,
+    ) -> (Option<Level>, LintSource) {
+        if let Some(specs) = aux {
+            if let Some(&(level, src)) = specs.get(&id) {
+                return (Some(level), src);
+            }
+        }
+        loop {
+            match self.list[idx as usize] {
+                LintSet::CommandLine { ref specs } => {
+                    if let Some(&(level, src)) = specs.get(&id) {
+                        return (Some(level), src);
+                    }
+                    return (None, LintSource::Default);
+                }
+                LintSet::Node { ref specs, parent } => {
+                    if let Some(&(level, src)) = specs.get(&id) {
+                        return (Some(level), src);
+                    }
+                    idx = parent;
+                }
+            }
+        }
+    }
+}
+
+pub struct LintLevelMap {
+    pub sets: LintLevelSets,
+    pub id_to_set: FxHashMap<HirId, u32>,
+}
+
+impl LintLevelMap {
+    /// If the `id` was previously registered with `register_id` when building
+    /// this `LintLevelMap` this returns the corresponding lint level and source
+    /// of the lint level for the lint provided.
+    ///
+    /// If the `id` was not previously registered, returns `None`. If `None` is
+    /// returned then the parent of `id` should be acquired and this function
+    /// should be called again.
+    pub fn level_and_source(
+        &self,
+        lint: &'static Lint,
+        id: HirId,
+        session: &Session,
+    ) -> Option<LevelSource> {
+        self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        let LintLevelMap { ref sets, ref id_to_set } = *self;
+
+        id_to_set.hash_stable(hcx, hasher);
+
+        let LintLevelSets { ref list, lint_cap } = *sets;
+
+        lint_cap.hash_stable(hcx, hasher);
+
+        hcx.while_hashing_spans(true, |hcx| {
+            list.len().hash_stable(hcx, hasher);
+
+            // We are working under the assumption here that the list of
+            // lint-sets is built in a deterministic order.
+            for lint_set in list {
+                ::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);
+
+                match *lint_set {
+                    LintSet::CommandLine { ref specs } => {
+                        specs.hash_stable(hcx, hasher);
+                    }
+                    LintSet::Node { ref specs, parent } => {
+                        specs.hash_stable(hcx, hasher);
+                        parent.hash_stable(hcx, hasher);
+                    }
+                }
+            }
+        })
+    }
+}
+
+pub fn struct_lint_level<'a>(
+    sess: &'a Session,
+    lint: &'static Lint,
+    level: Level,
+    src: LintSource,
+    span: Option<MultiSpan>,
+    msg: &str,
+) -> DiagnosticBuilder<'a> {
+    let mut err = match (level, span) {
+        (Level::Allow, _) => return sess.diagnostic().struct_dummy(),
+        (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
+        (Level::Warn, None) => sess.struct_warn(msg),
+        (Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
+        (Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg),
+    };
+
+    // Check for future incompatibility lints and issue a stronger warning.
+    let lint_id = LintId::of(lint);
+    let future_incompatible = lint.future_incompatible;
+
+    // If this code originates in a foreign macro, aka something that this crate
+    // did not itself author, then it's likely that there's nothing this crate
+    // can do about it. We probably want to skip the lint entirely.
+    if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
+        // Any suggestions made here are likely to be incorrect, so anything we
+        // emit shouldn't be automatically fixed by rustfix.
+        err.allow_suggestions(false);
+
+        // If this is a future incompatible lint it'll become a hard error, so
+        // we have to emit *something*. Also allow lints to whitelist themselves
+        // on a case-by-case basis for emission in a foreign macro.
+        if future_incompatible.is_none() && !lint.report_in_external_macro {
+            err.cancel();
+            // Don't continue further, since we don't want to have
+            // `diag_span_note_once` called for a diagnostic that isn't emitted.
+            return err;
+        }
+    }
+
+    let name = lint.name_lower();
+    match src {
+        LintSource::Default => {
+            sess.diag_note_once(
+                &mut err,
+                DiagnosticMessageId::from(lint),
+                &format!("`#[{}({})]` on by default", level.as_str(), name),
+            );
+        }
+        LintSource::CommandLine(lint_flag_val) => {
+            let flag = match level {
+                Level::Warn => "-W",
+                Level::Deny => "-D",
+                Level::Forbid => "-F",
+                Level::Allow => panic!(),
+            };
+            let hyphen_case_lint_name = name.replace("_", "-");
+            if lint_flag_val.as_str() == name {
+                sess.diag_note_once(
+                    &mut err,
+                    DiagnosticMessageId::from(lint),
+                    &format!(
+                        "requested on the command line with `{} {}`",
+                        flag, hyphen_case_lint_name
+                    ),
+                );
+            } else {
+                let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
+                sess.diag_note_once(
+                    &mut err,
+                    DiagnosticMessageId::from(lint),
+                    &format!(
+                        "`{} {}` implied by `{} {}`",
+                        flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
+                    ),
+                );
+            }
+        }
+        LintSource::Node(lint_attr_name, src, reason) => {
+            if let Some(rationale) = reason {
+                err.note(&rationale.as_str());
+            }
+            sess.diag_span_note_once(
+                &mut err,
+                DiagnosticMessageId::from(lint),
+                src,
+                "lint level defined here",
+            );
+            if lint_attr_name.as_str() != name {
+                let level_str = level.as_str();
+                sess.diag_note_once(
+                    &mut err,
+                    DiagnosticMessageId::from(lint),
+                    &format!(
+                        "`#[{}({})]` implied by `#[{}({})]`",
+                        level_str, name, level_str, lint_attr_name
+                    ),
+                );
+            }
+        }
+    }
+
+    err.code(DiagnosticId::Lint(name));
+
+    if let Some(future_incompatible) = future_incompatible {
+        const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
+             it will become a hard error";
+
+        let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
+            "once this method is added to the standard library, \
+             the ambiguity may cause an error or change in behavior!"
+                .to_owned()
+        } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
+            "this borrowing pattern was not meant to be accepted, \
+             and may become a hard error in the future"
+                .to_owned()
+        } else if let Some(edition) = future_incompatible.edition {
+            format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
+        } else {
+            format!("{} in a future release!", STANDARD_MESSAGE)
+        };
+        let citation = format!("for more information, see {}", future_incompatible.reference);
+        err.warn(&explanation);
+        err.note(&citation);
+    }
+
+    return err;
+}
+
+/// Returns whether `span` originates in a foreign crate's external macro.
+///
+/// This is used to test whether a lint should not even begin to figure out whether it should
+/// be reported on the current node.
+pub fn in_external_macro(sess: &Session, span: Span) -> bool {
+    let expn_data = span.ctxt().outer_expn_data();
+    match expn_data.kind {
+        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
+        ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
+        ExpnKind::Macro(MacroKind::Bang, _) => {
+            if expn_data.def_site.is_dummy() {
+                // Dummy span for the `def_site` means it's an external macro.
+                return true;
+            }
+            match sess.source_map().span_to_snippet(expn_data.def_site) {
+                Ok(code) => !code.starts_with("macro_rules"),
+                // No snippet means external macro or compiler-builtin expansion.
+                Err(_) => true,
+            }
+        }
+        ExpnKind::Macro(..) => true, // definitely a plugin
+    }
+}
+
+pub fn add_elided_lifetime_in_path_suggestion(
+    sess: &Session,
+    db: &mut DiagnosticBuilder<'_>,
+    n: usize,
+    path_span: Span,
+    incl_angl_brckt: bool,
+    insertion_span: Span,
+    anon_lts: String,
+) {
+    let (replace_span, suggestion) = if incl_angl_brckt {
+        (insertion_span, anon_lts)
+    } else {
+        // When possible, prefer a suggestion that replaces the whole
+        // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
+        // at a point (which makes for an ugly/confusing label)
+        if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
+            // But our spans can get out of whack due to macros; if the place we think
+            // we want to insert `'_` isn't even within the path expression's span, we
+            // should bail out of making any suggestion rather than panicking on a
+            // subtract-with-overflow or string-slice-out-out-bounds (!)
+            // FIXME: can we do better?
+            if insertion_span.lo().0 < path_span.lo().0 {
+                return;
+            }
+            let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
+            if insertion_index > snippet.len() {
+                return;
+            }
+            let (before, after) = snippet.split_at(insertion_index);
+            (path_span, format!("{}{}{}", before, anon_lts, after))
+        } else {
+            (insertion_span, anon_lts)
+        }
+    };
+    db.span_suggestion(
+        replace_span,
+        &format!("indicate the anonymous lifetime{}", pluralize!(n)),
+        suggestion,
+        Applicability::MachineApplicable,
+    );
+}
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
deleted file mode 100644 (file)
index 847c610..0000000
+++ /dev/null
@@ -1,650 +0,0 @@
-//! Some lints that are built in to the compiler.
-//!
-//! These are the built-in lints that are emitted direct in the main
-//! compiler code, rather than using their own custom pass. Those
-//! lints are all available in `rustc_lint::builtin`.
-
-use crate::lint::{FutureIncompatibleInfo, LateLintPass, LintArray, LintPass};
-use crate::middle::stability;
-use crate::session::Session;
-use errors::{pluralize, Applicability, DiagnosticBuilder};
-use rustc_session::declare_lint;
-use rustc_span::edition::Edition;
-use rustc_span::source_map::Span;
-use rustc_span::symbol::Symbol;
-use syntax::ast;
-use syntax::early_buffered_lints::{ILL_FORMED_ATTRIBUTE_INPUT, META_VARIABLE_MISUSE};
-
-declare_lint! {
-    pub EXCEEDING_BITSHIFTS,
-    Deny,
-    "shift exceeds the type's number of bits"
-}
-
-declare_lint! {
-    pub CONST_ERR,
-    Deny,
-    "constant evaluation detected erroneous expression",
-    report_in_external_macro
-}
-
-declare_lint! {
-    pub UNUSED_IMPORTS,
-    Warn,
-    "imports that are never used"
-}
-
-declare_lint! {
-    pub UNUSED_EXTERN_CRATES,
-    Allow,
-    "extern crates that are never used"
-}
-
-declare_lint! {
-    pub UNUSED_QUALIFICATIONS,
-    Allow,
-    "detects unnecessarily qualified names"
-}
-
-declare_lint! {
-    pub UNKNOWN_LINTS,
-    Warn,
-    "unrecognized lint attribute"
-}
-
-declare_lint! {
-    pub UNUSED_VARIABLES,
-    Warn,
-    "detect variables which are not used in any way"
-}
-
-declare_lint! {
-    pub UNUSED_ASSIGNMENTS,
-    Warn,
-    "detect assignments that will never be read"
-}
-
-declare_lint! {
-    pub DEAD_CODE,
-    Warn,
-    "detect unused, unexported items"
-}
-
-declare_lint! {
-    pub UNUSED_ATTRIBUTES,
-    Warn,
-    "detects attributes that were not used by the compiler"
-}
-
-declare_lint! {
-    pub UNREACHABLE_CODE,
-    Warn,
-    "detects unreachable code paths",
-    report_in_external_macro
-}
-
-declare_lint! {
-    pub UNREACHABLE_PATTERNS,
-    Warn,
-    "detects unreachable patterns"
-}
-
-declare_lint! {
-    pub OVERLAPPING_PATTERNS,
-    Warn,
-    "detects overlapping patterns"
-}
-
-declare_lint! {
-    pub UNUSED_MACROS,
-    Warn,
-    "detects macros that were not used"
-}
-
-declare_lint! {
-    pub WARNINGS,
-    Warn,
-    "mass-change the level for lints which produce warnings"
-}
-
-declare_lint! {
-    pub UNUSED_FEATURES,
-    Warn,
-    "unused features found in crate-level `#[feature]` directives"
-}
-
-declare_lint! {
-    pub STABLE_FEATURES,
-    Warn,
-    "stable features found in `#[feature]` directive"
-}
-
-declare_lint! {
-    pub UNKNOWN_CRATE_TYPES,
-    Deny,
-    "unknown crate type found in `#[crate_type]` directive"
-}
-
-declare_lint! {
-    pub TRIVIAL_CASTS,
-    Allow,
-    "detects trivial casts which could be removed"
-}
-
-declare_lint! {
-    pub TRIVIAL_NUMERIC_CASTS,
-    Allow,
-    "detects trivial casts of numeric types which could be removed"
-}
-
-declare_lint! {
-    pub PRIVATE_IN_PUBLIC,
-    Warn,
-    "detect private items in public interfaces not caught by the old implementation",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub EXPORTED_PRIVATE_DEPENDENCIES,
-    Warn,
-    "public interface leaks type from a private dependency"
-}
-
-declare_lint! {
-    pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
-    Deny,
-    "detect public re-exports of private extern crates",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub INVALID_TYPE_PARAM_DEFAULT,
-    Deny,
-    "type parameter default erroneously allowed in invalid location",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub RENAMED_AND_REMOVED_LINTS,
-    Warn,
-    "lints that have been renamed or removed"
-}
-
-declare_lint! {
-    pub SAFE_PACKED_BORROWS,
-    Warn,
-    "safe borrows of fields of packed structs were was erroneously allowed",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub PATTERNS_IN_FNS_WITHOUT_BODY,
-    Deny,
-    "patterns in functions without body were erroneously allowed",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub MISSING_FRAGMENT_SPECIFIER,
-    Deny,
-    "detects missing fragment specifiers in unused `macro_rules!` patterns",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub LATE_BOUND_LIFETIME_ARGUMENTS,
-    Warn,
-    "detects generic lifetime arguments in path segments with late bound lifetime parameters",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub ORDER_DEPENDENT_TRAIT_OBJECTS,
-    Deny,
-    "trait-object types were treated as different depending on marker-trait order",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub DEPRECATED,
-    Warn,
-    "detects use of deprecated items",
-    report_in_external_macro
-}
-
-declare_lint! {
-    pub UNUSED_UNSAFE,
-    Warn,
-    "unnecessary use of an `unsafe` block"
-}
-
-declare_lint! {
-    pub UNUSED_MUT,
-    Warn,
-    "detect mut variables which don't need to be mutable"
-}
-
-declare_lint! {
-    pub UNCONDITIONAL_RECURSION,
-    Warn,
-    "functions that cannot return without calling themselves"
-}
-
-declare_lint! {
-    pub SINGLE_USE_LIFETIMES,
-    Allow,
-    "detects lifetime parameters that are only used once"
-}
-
-declare_lint! {
-    pub UNUSED_LIFETIMES,
-    Allow,
-    "detects lifetime parameters that are never used"
-}
-
-declare_lint! {
-    pub TYVAR_BEHIND_RAW_POINTER,
-    Warn,
-    "raw pointer to an inference variable",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
-        edition: Some(Edition::Edition2018),
-    };
-}
-
-declare_lint! {
-    pub ELIDED_LIFETIMES_IN_PATHS,
-    Allow,
-    "hidden lifetime parameters in types are deprecated"
-}
-
-declare_lint! {
-    pub BARE_TRAIT_OBJECTS,
-    Warn,
-    "suggest using `dyn Trait` for trait objects"
-}
-
-declare_lint! {
-    pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
-    Allow,
-    "fully qualified paths that start with a module name \
-     instead of `crate`, `self`, or an extern crate name",
-     @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>",
-        edition: Some(Edition::Edition2018),
-     };
-}
-
-declare_lint! {
-    pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-    Warn,
-    "floating-point literals cannot be used in patterns",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub UNSTABLE_NAME_COLLISIONS,
-    Warn,
-    "detects name collision with an existing but unstable method",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>",
-        edition: None,
-        // Note: this item represents future incompatibility of all unstable functions in the
-        //       standard library, and thus should never be removed or changed to an error.
-    };
-}
-
-declare_lint! {
-    pub IRREFUTABLE_LET_PATTERNS,
-    Warn,
-    "detects irrefutable patterns in if-let and while-let statements"
-}
-
-declare_lint! {
-    pub UNUSED_LABELS,
-    Warn,
-    "detects labels that are never used"
-}
-
-declare_lint! {
-    pub INTRA_DOC_LINK_RESOLUTION_FAILURE,
-    Warn,
-    "failures in resolving intra-doc link targets"
-}
-
-declare_lint! {
-    pub MISSING_DOC_CODE_EXAMPLES,
-    Allow,
-    "detects publicly-exported items without code samples in their documentation"
-}
-
-declare_lint! {
-    pub PRIVATE_DOC_TESTS,
-    Allow,
-    "detects code samples in docs of private items not documented by rustdoc"
-}
-
-declare_lint! {
-    pub WHERE_CLAUSES_OBJECT_SAFETY,
-    Warn,
-    "checks the object safety of where clauses",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-    Warn,
-    "detects proc macro derives using inaccessible names from parent modules",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub MACRO_USE_EXTERN_CRATE,
-    Allow,
-    "the `#[macro_use]` attribute is now deprecated in favor of using macros \
-     via the module system"
-}
-
-declare_lint! {
-    pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
-    Deny,
-    "macro-expanded `macro_export` macros from the current crate \
-     cannot be referred to by absolute paths",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub EXPLICIT_OUTLIVES_REQUIREMENTS,
-    Allow,
-    "outlives requirements can be inferred"
-}
-
-declare_lint! {
-    pub INDIRECT_STRUCTURAL_MATCH,
-    // defaulting to allow until rust-lang/rust#62614 is fixed.
-    Allow,
-    "pattern with const indirectly referencing non-`#[structural_match]` type",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub DEPRECATED_IN_FUTURE,
-    Allow,
-    "detects use of items that will be deprecated in a future version",
-    report_in_external_macro
-}
-
-declare_lint! {
-    pub AMBIGUOUS_ASSOCIATED_ITEMS,
-    Deny,
-    "ambiguous associated items",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub MUTABLE_BORROW_RESERVATION_CONFLICT,
-    Warn,
-    "reservation of a two-phased borrow conflicts with other shared borrows",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub SOFT_UNSTABLE,
-    Deny,
-    "a feature gate that doesn't break dependent crates",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>",
-        edition: None,
-    };
-}
-
-declare_lint_pass! {
-    /// Does nothing as a lint pass, but registers some `Lint`s
-    /// that are used by other parts of the compiler.
-    HardwiredLints => [
-        ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-        EXCEEDING_BITSHIFTS,
-        UNUSED_IMPORTS,
-        UNUSED_EXTERN_CRATES,
-        UNUSED_QUALIFICATIONS,
-        UNKNOWN_LINTS,
-        UNUSED_VARIABLES,
-        UNUSED_ASSIGNMENTS,
-        DEAD_CODE,
-        UNREACHABLE_CODE,
-        UNREACHABLE_PATTERNS,
-        OVERLAPPING_PATTERNS,
-        UNUSED_MACROS,
-        WARNINGS,
-        UNUSED_FEATURES,
-        STABLE_FEATURES,
-        UNKNOWN_CRATE_TYPES,
-        TRIVIAL_CASTS,
-        TRIVIAL_NUMERIC_CASTS,
-        PRIVATE_IN_PUBLIC,
-        EXPORTED_PRIVATE_DEPENDENCIES,
-        PUB_USE_OF_PRIVATE_EXTERN_CRATE,
-        INVALID_TYPE_PARAM_DEFAULT,
-        CONST_ERR,
-        RENAMED_AND_REMOVED_LINTS,
-        SAFE_PACKED_BORROWS,
-        PATTERNS_IN_FNS_WITHOUT_BODY,
-        MISSING_FRAGMENT_SPECIFIER,
-        LATE_BOUND_LIFETIME_ARGUMENTS,
-        ORDER_DEPENDENT_TRAIT_OBJECTS,
-        DEPRECATED,
-        UNUSED_UNSAFE,
-        UNUSED_MUT,
-        UNCONDITIONAL_RECURSION,
-        SINGLE_USE_LIFETIMES,
-        UNUSED_LIFETIMES,
-        UNUSED_LABELS,
-        TYVAR_BEHIND_RAW_POINTER,
-        ELIDED_LIFETIMES_IN_PATHS,
-        BARE_TRAIT_OBJECTS,
-        ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
-        UNSTABLE_NAME_COLLISIONS,
-        IRREFUTABLE_LET_PATTERNS,
-        INTRA_DOC_LINK_RESOLUTION_FAILURE,
-        MISSING_DOC_CODE_EXAMPLES,
-        PRIVATE_DOC_TESTS,
-        WHERE_CLAUSES_OBJECT_SAFETY,
-        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-        MACRO_USE_EXTERN_CRATE,
-        MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
-        ILL_FORMED_ATTRIBUTE_INPUT,
-        META_VARIABLE_MISUSE,
-        DEPRECATED_IN_FUTURE,
-        AMBIGUOUS_ASSOCIATED_ITEMS,
-        MUTABLE_BORROW_RESERVATION_CONFLICT,
-        INDIRECT_STRUCTURAL_MATCH,
-        SOFT_UNSTABLE,
-    ]
-}
-
-// this could be a closure, but then implementing derive traits
-// becomes hacky (and it gets allocated)
-#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
-pub enum BuiltinLintDiagnostics {
-    Normal,
-    BareTraitObject(Span, /* is_global */ bool),
-    AbsPathWithModule(Span),
-    ProcMacroDeriveResolutionFallback(Span),
-    MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
-    ElidedLifetimesInPaths(usize, Span, bool, Span, String),
-    UnknownCrateTypes(Span, String, String),
-    UnusedImports(String, Vec<(Span, String)>),
-    RedundantImport(Vec<(Span, bool)>, ast::Ident),
-    DeprecatedMacro(Option<Symbol>, Span),
-}
-
-pub fn add_elided_lifetime_in_path_suggestion(
-    sess: &Session,
-    db: &mut DiagnosticBuilder<'_>,
-    n: usize,
-    path_span: Span,
-    incl_angl_brckt: bool,
-    insertion_span: Span,
-    anon_lts: String,
-) {
-    let (replace_span, suggestion) = if incl_angl_brckt {
-        (insertion_span, anon_lts)
-    } else {
-        // When possible, prefer a suggestion that replaces the whole
-        // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
-        // at a point (which makes for an ugly/confusing label)
-        if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
-            // But our spans can get out of whack due to macros; if the place we think
-            // we want to insert `'_` isn't even within the path expression's span, we
-            // should bail out of making any suggestion rather than panicking on a
-            // subtract-with-overflow or string-slice-out-out-bounds (!)
-            // FIXME: can we do better?
-            if insertion_span.lo().0 < path_span.lo().0 {
-                return;
-            }
-            let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
-            if insertion_index > snippet.len() {
-                return;
-            }
-            let (before, after) = snippet.split_at(insertion_index);
-            (path_span, format!("{}{}{}", before, anon_lts, after))
-        } else {
-            (insertion_span, anon_lts)
-        }
-    };
-    db.span_suggestion(
-        replace_span,
-        &format!("indicate the anonymous lifetime{}", pluralize!(n)),
-        suggestion,
-        Applicability::MachineApplicable,
-    );
-}
-
-impl BuiltinLintDiagnostics {
-    pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder<'_>) {
-        match self {
-            BuiltinLintDiagnostics::Normal => (),
-            BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
-                let (sugg, app) = match sess.source_map().span_to_snippet(span) {
-                    Ok(ref s) if is_global => {
-                        (format!("dyn ({})", s), Applicability::MachineApplicable)
-                    }
-                    Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
-                    Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders),
-                };
-                db.span_suggestion(span, "use `dyn`", sugg, app);
-            }
-            BuiltinLintDiagnostics::AbsPathWithModule(span) => {
-                let (sugg, app) = match sess.source_map().span_to_snippet(span) {
-                    Ok(ref s) => {
-                        // FIXME(Manishearth) ideally the emitting code
-                        // can tell us whether or not this is global
-                        let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" };
-
-                        (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable)
-                    }
-                    Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
-                };
-                db.span_suggestion(span, "use `crate`", sugg, app);
-            }
-            BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => {
-                db.span_label(
-                    span,
-                    "names from parent modules are not \
-                                     accessible without an explicit import",
-                );
-            }
-            BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
-                db.span_note(span_def, "the macro is defined here");
-            }
-            BuiltinLintDiagnostics::ElidedLifetimesInPaths(
-                n,
-                path_span,
-                incl_angl_brckt,
-                insertion_span,
-                anon_lts,
-            ) => {
-                add_elided_lifetime_in_path_suggestion(
-                    sess,
-                    db,
-                    n,
-                    path_span,
-                    incl_angl_brckt,
-                    insertion_span,
-                    anon_lts,
-                );
-            }
-            BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
-                db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
-            }
-            BuiltinLintDiagnostics::UnusedImports(message, replaces) => {
-                if !replaces.is_empty() {
-                    db.tool_only_multipart_suggestion(
-                        &message,
-                        replaces,
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            BuiltinLintDiagnostics::RedundantImport(spans, ident) => {
-                for (span, is_imported) in spans {
-                    let introduced = if is_imported { "imported" } else { "defined" };
-                    db.span_label(
-                        span,
-                        format!("the item `{}` is already {} here", ident, introduced),
-                    );
-                }
-            }
-            BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => {
-                stability::deprecation_suggestion(db, suggestion, span)
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {}
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
deleted file mode 100644 (file)
index 0ac6824..0000000
+++ /dev/null
@@ -1,772 +0,0 @@
-//! Implementation of lint checking.
-//!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
-
-use self::TargetLint::*;
-
-use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData};
-use crate::lint::builtin::BuiltinLintDiagnostics;
-use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
-use crate::lint::{EarlyLintPassObject, LateLintPassObject};
-use crate::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
-use crate::middle::privacy::AccessLevels;
-use crate::session::Session;
-use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
-use crate::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
-use errors::DiagnosticBuilder;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync;
-use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_span::{symbol::Symbol, MultiSpan, Span};
-use std::slice;
-use syntax::ast;
-use syntax::util::lev_distance::find_best_match_for_name;
-
-use rustc_error_codes::*;
-
-/// Information about the registered lints.
-///
-/// This is basically the subset of `Context` that we can
-/// build early in the compile pipeline.
-pub struct LintStore {
-    /// Registered lints.
-    lints: Vec<&'static Lint>,
-
-    /// Constructor functions for each variety of lint pass.
-    ///
-    /// These should only be called once, but since we want to avoid locks or
-    /// interior mutability, we don't enforce this (and lints should, in theory,
-    /// be compatible with being constructed more than once, though not
-    /// necessarily in a sane manner. This is safe though.)
-    pub pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
-    pub early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
-    pub late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
-    /// This is unique in that we construct them per-module, so not once.
-    pub late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
-
-    /// Lints indexed by name.
-    by_name: FxHashMap<String, TargetLint>,
-
-    /// Map of registered lint groups to what lints they expand to.
-    lint_groups: FxHashMap<&'static str, LintGroup>,
-}
-
-/// Lints that are buffered up early on in the `Session` before the
-/// `LintLevels` is calculated
-#[derive(PartialEq, Debug)]
-pub struct BufferedEarlyLint {
-    pub lint_id: LintId,
-    pub ast_id: ast::NodeId,
-    pub span: MultiSpan,
-    pub msg: String,
-    pub diagnostic: BuiltinLintDiagnostics,
-}
-
-/// The target of the `by_name` map, which accounts for renaming/deprecation.
-enum TargetLint {
-    /// A direct lint target
-    Id(LintId),
-
-    /// Temporary renaming, used for easing migration pain; see #16545
-    Renamed(String, LintId),
-
-    /// Lint with this name existed previously, but has been removed/deprecated.
-    /// The string argument is the reason for removal.
-    Removed(String),
-}
-
-pub enum FindLintError {
-    NotFound,
-    Removed,
-}
-
-struct LintAlias {
-    name: &'static str,
-    /// Whether deprecation warnings should be suppressed for this alias.
-    silent: bool,
-}
-
-struct LintGroup {
-    lint_ids: Vec<LintId>,
-    from_plugin: bool,
-    depr: Option<LintAlias>,
-}
-
-pub enum CheckLintNameResult<'a> {
-    Ok(&'a [LintId]),
-    /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
-    NoLint(Option<Symbol>),
-    /// The lint is either renamed or removed. This is the warning
-    /// message, and an optional new name (`None` if removed).
-    Warning(String, Option<String>),
-    /// The lint is from a tool. If the Option is None, then either
-    /// the lint does not exist in the tool or the code was not
-    /// compiled with the tool and therefore the lint was never
-    /// added to the `LintStore`. Otherwise the `LintId` will be
-    /// returned as if it where a rustc lint.
-    Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>),
-}
-
-impl LintStore {
-    pub fn new() -> LintStore {
-        LintStore {
-            lints: vec![],
-            pre_expansion_passes: vec![],
-            early_passes: vec![],
-            late_passes: vec![],
-            late_module_passes: vec![],
-            by_name: Default::default(),
-            lint_groups: Default::default(),
-        }
-    }
-
-    pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
-        &self.lints
-    }
-
-    pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
-        self.lint_groups
-            .iter()
-            .filter(|(_, LintGroup { depr, .. })| {
-                // Don't display deprecated lint groups.
-                depr.is_none()
-            })
-            .map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
-                (*k, lint_ids.clone(), *from_plugin)
-            })
-            .collect()
-    }
-
-    pub fn register_early_pass(
-        &mut self,
-        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
-    ) {
-        self.early_passes.push(Box::new(pass));
-    }
-
-    pub fn register_pre_expansion_pass(
-        &mut self,
-        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
-    ) {
-        self.pre_expansion_passes.push(Box::new(pass));
-    }
-
-    pub fn register_late_pass(
-        &mut self,
-        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
-    ) {
-        self.late_passes.push(Box::new(pass));
-    }
-
-    pub fn register_late_mod_pass(
-        &mut self,
-        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
-    ) {
-        self.late_module_passes.push(Box::new(pass));
-    }
-
-    // Helper method for register_early/late_pass
-    pub fn register_lints(&mut self, lints: &[&'static Lint]) {
-        for lint in lints {
-            self.lints.push(lint);
-
-            let id = LintId::of(lint);
-            if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
-                bug!("duplicate specification of lint {}", lint.name_lower())
-            }
-
-            if let Some(FutureIncompatibleInfo { edition, .. }) = lint.future_incompatible {
-                if let Some(edition) = edition {
-                    self.lint_groups
-                        .entry(edition.lint_name())
-                        .or_insert(LintGroup {
-                            lint_ids: vec![],
-                            from_plugin: lint.is_plugin,
-                            depr: None,
-                        })
-                        .lint_ids
-                        .push(id);
-                }
-
-                self.lint_groups
-                    .entry("future_incompatible")
-                    .or_insert(LintGroup {
-                        lint_ids: vec![],
-                        from_plugin: lint.is_plugin,
-                        depr: None,
-                    })
-                    .lint_ids
-                    .push(id);
-            }
-        }
-    }
-
-    pub fn register_group_alias(&mut self, lint_name: &'static str, alias: &'static str) {
-        self.lint_groups.insert(
-            alias,
-            LintGroup {
-                lint_ids: vec![],
-                from_plugin: false,
-                depr: Some(LintAlias { name: lint_name, silent: true }),
-            },
-        );
-    }
-
-    pub fn register_group(
-        &mut self,
-        from_plugin: bool,
-        name: &'static str,
-        deprecated_name: Option<&'static str>,
-        to: Vec<LintId>,
-    ) {
-        let new = self
-            .lint_groups
-            .insert(name, LintGroup { lint_ids: to, from_plugin, depr: None })
-            .is_none();
-        if let Some(deprecated) = deprecated_name {
-            self.lint_groups.insert(
-                deprecated,
-                LintGroup {
-                    lint_ids: vec![],
-                    from_plugin,
-                    depr: Some(LintAlias { name, silent: false }),
-                },
-            );
-        }
-
-        if !new {
-            bug!("duplicate specification of lint group {}", name);
-        }
-    }
-
-    pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
-        let target = match self.by_name.get(new_name) {
-            Some(&Id(lint_id)) => lint_id.clone(),
-            _ => bug!("invalid lint renaming of {} to {}", old_name, new_name),
-        };
-        self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
-    }
-
-    pub fn register_removed(&mut self, name: &str, reason: &str) {
-        self.by_name.insert(name.into(), Removed(reason.into()));
-    }
-
-    pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
-        match self.by_name.get(lint_name) {
-            Some(&Id(lint_id)) => Ok(vec![lint_id]),
-            Some(&Renamed(_, lint_id)) => Ok(vec![lint_id]),
-            Some(&Removed(_)) => Err(FindLintError::Removed),
-            None => loop {
-                return match self.lint_groups.get(lint_name) {
-                    Some(LintGroup { lint_ids, depr, .. }) => {
-                        if let Some(LintAlias { name, .. }) = depr {
-                            lint_name = name;
-                            continue;
-                        }
-                        Ok(lint_ids.clone())
-                    }
-                    None => Err(FindLintError::Removed),
-                };
-            },
-        }
-    }
-
-    /// Checks the validity of lint names derived from the command line
-    pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
-        let db = match self.check_lint_name(lint_name, None) {
-            CheckLintNameResult::Ok(_) => None,
-            CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
-            CheckLintNameResult::NoLint(suggestion) => {
-                let mut err = struct_err!(sess, E0602, "unknown lint: `{}`", lint_name);
-
-                if let Some(suggestion) = suggestion {
-                    err.help(&format!("did you mean: `{}`", suggestion));
-                }
-
-                Some(err)
-            }
-            CheckLintNameResult::Tool(result) => match result {
-                Err((Some(_), new_name)) => Some(sess.struct_warn(&format!(
-                    "lint name `{}` is deprecated \
-                     and does not have an effect anymore. \
-                     Use: {}",
-                    lint_name, new_name
-                ))),
-                _ => None,
-            },
-        };
-
-        if let Some(mut db) = db {
-            let msg = format!(
-                "requested on the command line with `{} {}`",
-                match level {
-                    Level::Allow => "-A",
-                    Level::Warn => "-W",
-                    Level::Deny => "-D",
-                    Level::Forbid => "-F",
-                },
-                lint_name
-            );
-            db.note(&msg);
-            db.emit();
-        }
-    }
-
-    /// Checks the name of a lint for its existence, and whether it was
-    /// renamed or removed. Generates a DiagnosticBuilder containing a
-    /// warning for renamed and removed lints. This is over both lint
-    /// names from attributes and those passed on the command line. Since
-    /// it emits non-fatal warnings and there are *two* lint passes that
-    /// inspect attributes, this is only run from the late pass to avoid
-    /// printing duplicate warnings.
-    pub fn check_lint_name(
-        &self,
-        lint_name: &str,
-        tool_name: Option<Symbol>,
-    ) -> CheckLintNameResult<'_> {
-        let complete_name = if let Some(tool_name) = tool_name {
-            format!("{}::{}", tool_name, lint_name)
-        } else {
-            lint_name.to_string()
-        };
-        // If the lint was scoped with `tool::` check if the tool lint exists
-        if let Some(_) = tool_name {
-            match self.by_name.get(&complete_name) {
-                None => match self.lint_groups.get(&*complete_name) {
-                    None => return CheckLintNameResult::Tool(Err((None, String::new()))),
-                    Some(LintGroup { lint_ids, .. }) => {
-                        return CheckLintNameResult::Tool(Ok(&lint_ids));
-                    }
-                },
-                Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
-                // If the lint was registered as removed or renamed by the lint tool, we don't need
-                // to treat tool_lints and rustc lints different and can use the code below.
-                _ => {}
-            }
-        }
-        match self.by_name.get(&complete_name) {
-            Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
-                format!("lint `{}` has been renamed to `{}`", complete_name, new_name),
-                Some(new_name.to_owned()),
-            ),
-            Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
-                format!("lint `{}` has been removed: `{}`", complete_name, reason),
-                None,
-            ),
-            None => match self.lint_groups.get(&*complete_name) {
-                // If neither the lint, nor the lint group exists check if there is a `clippy::`
-                // variant of this lint
-                None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
-                Some(LintGroup { lint_ids, depr, .. }) => {
-                    // Check if the lint group name is deprecated
-                    if let Some(LintAlias { name, silent }) = depr {
-                        let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
-                        return if *silent {
-                            CheckLintNameResult::Ok(&lint_ids)
-                        } else {
-                            CheckLintNameResult::Tool(Err((Some(&lint_ids), name.to_string())))
-                        };
-                    }
-                    CheckLintNameResult::Ok(&lint_ids)
-                }
-            },
-            Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
-        }
-    }
-
-    fn check_tool_name_for_backwards_compat(
-        &self,
-        lint_name: &str,
-        tool_name: &str,
-    ) -> CheckLintNameResult<'_> {
-        let complete_name = format!("{}::{}", tool_name, lint_name);
-        match self.by_name.get(&complete_name) {
-            None => match self.lint_groups.get(&*complete_name) {
-                // Now we are sure, that this lint exists nowhere
-                None => {
-                    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);
-
-                    CheckLintNameResult::NoLint(suggestion)
-                }
-                Some(LintGroup { lint_ids, depr, .. }) => {
-                    // Reaching this would be weird, but let's cover this case anyway
-                    if let Some(LintAlias { name, silent }) = depr {
-                        let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
-                        return if *silent {
-                            CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
-                        } else {
-                            CheckLintNameResult::Tool(Err((Some(&lint_ids), name.to_string())))
-                        };
-                    }
-                    CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
-                }
-            },
-            Some(&Id(ref id)) => {
-                CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
-            }
-            _ => CheckLintNameResult::NoLint(None),
-        }
-    }
-}
-
-/// Context for lint checking after type checking.
-pub struct LateContext<'a, 'tcx> {
-    /// Type context we're checking in.
-    pub tcx: TyCtxt<'tcx>,
-
-    /// Side-tables for the body we are in.
-    // FIXME: Make this lazy to avoid running the TypeckTables query?
-    pub tables: &'a ty::TypeckTables<'tcx>,
-
-    /// Parameter environment for the item we are in.
-    pub param_env: ty::ParamEnv<'tcx>,
-
-    /// Items accessible from the crate being checked.
-    pub access_levels: &'a AccessLevels,
-
-    /// The store of registered lints and the lint levels.
-    pub lint_store: &'tcx LintStore,
-
-    pub last_node_with_lint_attrs: hir::HirId,
-
-    /// Generic type parameters in scope for the item we are in.
-    pub generics: Option<&'tcx hir::Generics<'tcx>>,
-
-    /// We are only looking at one module
-    pub only_module: bool,
-}
-
-/// Context for lint checking of the AST, after expansion, before lowering to
-/// HIR.
-pub struct EarlyContext<'a> {
-    /// Type context we're checking in.
-    pub sess: &'a Session,
-
-    /// The crate being checked.
-    pub krate: &'a ast::Crate,
-
-    pub builder: LintLevelsBuilder<'a>,
-
-    /// The store of registered lints and the lint levels.
-    pub lint_store: &'a LintStore,
-
-    pub buffered: LintBuffer,
-}
-
-pub trait LintPassObject: Sized {}
-
-impl LintPassObject for EarlyLintPassObject {}
-
-impl LintPassObject for LateLintPassObject {}
-
-pub trait LintContext: Sized {
-    type PassObject: LintPassObject;
-
-    fn sess(&self) -> &Session;
-    fn lints(&self) -> &LintStore;
-
-    fn lookup_and_emit<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: Option<S>, msg: &str) {
-        self.lookup(lint, span, msg).emit();
-    }
-
-    fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(
-        &self,
-        lint: &'static Lint,
-        span: Option<S>,
-        msg: &str,
-        diagnostic: BuiltinLintDiagnostics,
-    ) {
-        let mut db = self.lookup(lint, span, msg);
-        diagnostic.run(self.sess(), &mut db);
-        db.emit();
-    }
-
-    fn lookup<S: Into<MultiSpan>>(
-        &self,
-        lint: &'static Lint,
-        span: Option<S>,
-        msg: &str,
-    ) -> DiagnosticBuilder<'_>;
-
-    /// Emit a lint at the appropriate level, for a particular span.
-    fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
-        self.lookup_and_emit(lint, Some(span), msg);
-    }
-
-    fn struct_span_lint<S: Into<MultiSpan>>(
-        &self,
-        lint: &'static Lint,
-        span: S,
-        msg: &str,
-    ) -> DiagnosticBuilder<'_> {
-        self.lookup(lint, Some(span), msg)
-    }
-
-    /// Emit a lint and note at the appropriate level, for a particular span.
-    fn span_lint_note(
-        &self,
-        lint: &'static Lint,
-        span: Span,
-        msg: &str,
-        note_span: Span,
-        note: &str,
-    ) {
-        let mut err = self.lookup(lint, Some(span), msg);
-        if note_span == span {
-            err.note(note);
-        } else {
-            err.span_note(note_span, note);
-        }
-        err.emit();
-    }
-
-    /// Emit a lint and help at the appropriate level, for a particular span.
-    fn span_lint_help(&self, lint: &'static Lint, span: Span, msg: &str, help: &str) {
-        let mut err = self.lookup(lint, Some(span), msg);
-        self.span_lint(lint, span, msg);
-        err.span_help(span, help);
-        err.emit();
-    }
-
-    /// Emit a lint at the appropriate level, with no associated span.
-    fn lint(&self, lint: &'static Lint, msg: &str) {
-        self.lookup_and_emit(lint, None as Option<Span>, msg);
-    }
-}
-
-impl<'a> EarlyContext<'a> {
-    pub fn new(
-        sess: &'a Session,
-        lint_store: &'a LintStore,
-        krate: &'a ast::Crate,
-        buffered: LintBuffer,
-        warn_about_weird_lints: bool,
-    ) -> EarlyContext<'a> {
-        EarlyContext {
-            sess,
-            krate,
-            lint_store,
-            builder: LintLevelSets::builder(sess, warn_about_weird_lints, lint_store),
-            buffered,
-        }
-    }
-}
-
-impl LintContext for LateContext<'_, '_> {
-    type PassObject = LateLintPassObject;
-
-    /// Gets the overall compiler `Session` object.
-    fn sess(&self) -> &Session {
-        &self.tcx.sess
-    }
-
-    fn lints(&self) -> &LintStore {
-        &*self.lint_store
-    }
-
-    fn lookup<S: Into<MultiSpan>>(
-        &self,
-        lint: &'static Lint,
-        span: Option<S>,
-        msg: &str,
-    ) -> DiagnosticBuilder<'_> {
-        let hir_id = self.last_node_with_lint_attrs;
-
-        match span {
-            Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg),
-            None => self.tcx.struct_lint_node(lint, hir_id, msg),
-        }
-    }
-}
-
-impl LintContext for EarlyContext<'_> {
-    type PassObject = EarlyLintPassObject;
-
-    /// Gets the overall compiler `Session` object.
-    fn sess(&self) -> &Session {
-        &self.sess
-    }
-
-    fn lints(&self) -> &LintStore {
-        &*self.lint_store
-    }
-
-    fn lookup<S: Into<MultiSpan>>(
-        &self,
-        lint: &'static Lint,
-        span: Option<S>,
-        msg: &str,
-    ) -> DiagnosticBuilder<'_> {
-        self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
-    }
-}
-
-impl<'a, 'tcx> LateContext<'a, 'tcx> {
-    pub fn current_lint_root(&self) -> hir::HirId {
-        self.last_node_with_lint_attrs
-    }
-
-    /// Check if a `DefId`'s path matches the given absolute type path usage.
-    ///
-    /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
-    /// inherent `impl` blocks are matched with the name of the type.
-    ///
-    /// # Examples
-    ///
-    /// ```rust,ignore (no context or def id available)
-    /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) {
-    ///     // The given `def_id` is that of an `Option` type
-    /// }
-    /// ```
-    pub fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool {
-        let names = self.get_def_path(def_id);
-
-        names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b)
-    }
-
-    /// Gets the absolute path of `def_id` as a vector of `Symbol`.
-    ///
-    /// # Examples
-    ///
-    /// ```rust,ignore (no context or def id available)
-    /// let def_path = cx.get_def_path(def_id);
-    /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] {
-    ///     // The given `def_id` is that of an `Option` type
-    /// }
-    /// ```
-    pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
-        pub struct AbsolutePathPrinter<'tcx> {
-            pub tcx: TyCtxt<'tcx>,
-        }
-
-        impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
-            type Error = !;
-
-            type Path = Vec<Symbol>;
-            type Region = ();
-            type Type = ();
-            type DynExistential = ();
-            type Const = ();
-
-            fn tcx(&self) -> TyCtxt<'tcx> {
-                self.tcx
-            }
-
-            fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
-                Ok(())
-            }
-
-            fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
-                Ok(())
-            }
-
-            fn print_dyn_existential(
-                self,
-                _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
-            ) -> Result<Self::DynExistential, Self::Error> {
-                Ok(())
-            }
-
-            fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
-                Ok(())
-            }
-
-            fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-                Ok(vec![self.tcx.original_crate_name(cnum)])
-            }
-
-            fn path_qualified(
-                self,
-                self_ty: Ty<'tcx>,
-                trait_ref: Option<ty::TraitRef<'tcx>>,
-            ) -> Result<Self::Path, Self::Error> {
-                if trait_ref.is_none() {
-                    if let ty::Adt(def, substs) = self_ty.kind {
-                        return self.print_def_path(def.did, substs);
-                    }
-                }
-
-                // This shouldn't ever be needed, but just in case:
-                Ok(vec![match trait_ref {
-                    Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)),
-                    None => Symbol::intern(&format!("<{}>", self_ty)),
-                }])
-            }
-
-            fn path_append_impl(
-                self,
-                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
-                _disambiguated_data: &DisambiguatedDefPathData,
-                self_ty: Ty<'tcx>,
-                trait_ref: Option<ty::TraitRef<'tcx>>,
-            ) -> Result<Self::Path, Self::Error> {
-                let mut path = print_prefix(self)?;
-
-                // This shouldn't ever be needed, but just in case:
-                path.push(match trait_ref {
-                    Some(trait_ref) => Symbol::intern(&format!(
-                        "<impl {} for {}>",
-                        trait_ref.print_only_trait_path(),
-                        self_ty
-                    )),
-                    None => Symbol::intern(&format!("<impl {}>", self_ty)),
-                });
-
-                Ok(path)
-            }
-
-            fn path_append(
-                self,
-                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
-                disambiguated_data: &DisambiguatedDefPathData,
-            ) -> Result<Self::Path, Self::Error> {
-                let mut path = print_prefix(self)?;
-
-                // Skip `::{{constructor}}` on tuple/unit structs.
-                match disambiguated_data.data {
-                    DefPathData::Ctor => return Ok(path),
-                    _ => {}
-                }
-
-                path.push(disambiguated_data.data.as_symbol());
-                Ok(path)
-            }
-
-            fn path_generic_args(
-                self,
-                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
-                _args: &[GenericArg<'tcx>],
-            ) -> Result<Self::Path, Self::Error> {
-                print_prefix(self)
-            }
-        }
-
-        AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap()
-    }
-}
-
-impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
-
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
-        self.tcx.layout_of(self.param_env.and(ty))
-    }
-}
diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs
deleted file mode 100644 (file)
index 69f212a..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
-//! Clippy.
-
-use crate::lint::{
-    EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
-};
-use errors::Applicability;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
-use rustc_session::declare_tool_lint;
-use rustc_span::symbol::{sym, Symbol};
-use syntax::ast::{Ident, Item, ItemKind};
-
-declare_tool_lint! {
-    pub rustc::DEFAULT_HASH_TYPES,
-    Allow,
-    "forbid HashMap and HashSet and suggest the FxHash* variants"
-}
-
-pub struct DefaultHashTypes {
-    map: FxHashMap<Symbol, Symbol>,
-}
-
-impl DefaultHashTypes {
-    // we are allowed to use `HashMap` and `HashSet` as identifiers for implementing the lint itself
-    #[allow(rustc::default_hash_types)]
-    pub fn new() -> Self {
-        let mut map = FxHashMap::default();
-        map.insert(sym::HashMap, sym::FxHashMap);
-        map.insert(sym::HashSet, sym::FxHashSet);
-        Self { map }
-    }
-}
-
-impl_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]);
-
-impl EarlyLintPass for DefaultHashTypes {
-    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
-        if let Some(replace) = self.map.get(&ident.name) {
-            let msg = format!("Prefer {} over {}, it has better performance", replace, ident);
-            let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
-            db.span_suggestion(
-                ident.span,
-                "use",
-                replace.to_string(),
-                Applicability::MaybeIncorrect, // FxHashMap, ... needs another import
-            );
-            db.note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
-                .emit();
-        }
-    }
-}
-
-declare_tool_lint! {
-    pub rustc::USAGE_OF_TY_TYKIND,
-    Allow,
-    "usage of `ty::TyKind` outside of the `ty::sty` module"
-}
-
-declare_tool_lint! {
-    pub rustc::TY_PASS_BY_REFERENCE,
-    Allow,
-    "passing `Ty` or `TyCtxt` by reference"
-}
-
-declare_tool_lint! {
-    pub rustc::USAGE_OF_QUALIFIED_TY,
-    Allow,
-    "using `ty::{Ty,TyCtxt}` instead of importing it"
-}
-
-declare_lint_pass!(TyTyKind => [
-    USAGE_OF_TY_TYKIND,
-    TY_PASS_BY_REFERENCE,
-    USAGE_OF_QUALIFIED_TY,
-]);
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
-    fn check_path(&mut self, cx: &LateContext<'_, '_>, path: &'tcx Path<'tcx>, _: HirId) {
-        let segments = path.segments.iter().rev().skip(1).rev();
-
-        if let Some(last) = segments.last() {
-            let span = path.span.with_hi(last.ident.span.hi());
-            if lint_ty_kind_usage(cx, last) {
-                cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, "usage of `ty::TyKind::<kind>`")
-                    .span_suggestion(
-                        span,
-                        "try using ty::<kind> directly",
-                        "ty".to_string(),
-                        Applicability::MaybeIncorrect, // ty maybe needs an import
-                    )
-                    .emit();
-            }
-        }
-    }
-
-    fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty<'tcx>) {
-        match &ty.kind {
-            TyKind::Path(qpath) => {
-                if let QPath::Resolved(_, path) = qpath {
-                    if let Some(last) = path.segments.iter().last() {
-                        if lint_ty_kind_usage(cx, last) {
-                            cx.struct_span_lint(
-                                USAGE_OF_TY_TYKIND,
-                                path.span,
-                                "usage of `ty::TyKind`",
-                            )
-                            .help("try using `Ty` instead")
-                            .emit();
-                        } else {
-                            if ty.span.from_expansion() {
-                                return;
-                            }
-                            if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
-                                if path.segments.len() > 1 {
-                                    cx.struct_span_lint(
-                                        USAGE_OF_QUALIFIED_TY,
-                                        path.span,
-                                        &format!("usage of qualified `ty::{}`", t),
-                                    )
-                                    .span_suggestion(
-                                        path.span,
-                                        "try using it unqualified",
-                                        t,
-                                        // The import probably needs to be changed
-                                        Applicability::MaybeIncorrect,
-                                    )
-                                    .emit();
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => {
-                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner_def_id()) {
-                    if cx.tcx.impl_trait_ref(impl_did).is_some() {
-                        return;
-                    }
-                }
-                if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
-                    cx.struct_span_lint(
-                        TY_PASS_BY_REFERENCE,
-                        ty.span,
-                        &format!("passing `{}` by reference", t),
-                    )
-                    .span_suggestion(
-                        ty.span,
-                        "try passing by value",
-                        t,
-                        // Changing type of function argument
-                        Applicability::MaybeIncorrect,
-                    )
-                    .emit();
-                }
-            }
-            _ => {}
-        }
-    }
-}
-
-fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment<'_>) -> bool {
-    if let Some(res) = segment.res {
-        if let Some(did) = res.opt_def_id() {
-            return cx.tcx.is_diagnostic_item(sym::TyKind, did);
-        }
-    }
-
-    false
-}
-
-fn is_ty_or_ty_ctxt(cx: &LateContext<'_, '_>, ty: &Ty<'_>) -> Option<String> {
-    match &ty.kind {
-        TyKind::Path(qpath) => {
-            if let QPath::Resolved(_, path) = qpath {
-                let did = path.res.opt_def_id()?;
-                if cx.tcx.is_diagnostic_item(sym::Ty, did) {
-                    return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
-                } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
-                    return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
-                }
-            }
-        }
-        _ => {}
-    }
-
-    None
-}
-
-fn gen_args(segment: &PathSegment<'_>) -> String {
-    if let Some(args) = &segment.args {
-        let lifetimes = args
-            .args
-            .iter()
-            .filter_map(|arg| {
-                if let GenericArg::Lifetime(lt) = arg {
-                    Some(lt.name.ident().to_string())
-                } else {
-                    None
-                }
-            })
-            .collect::<Vec<_>>();
-
-        if !lifetimes.is_empty() {
-            return format!("<{}>", lifetimes.join(", "));
-        }
-    }
-
-    String::new()
-}
-
-declare_tool_lint! {
-    pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO,
-    Allow,
-    "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
-}
-
-declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
-
-impl EarlyLintPass for LintPassImpl {
-    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.kind {
-            if let Some(last) = lint_pass.path.segments.last() {
-                if last.ident.name == sym::LintPass {
-                    let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
-                    let call_site = expn_data.call_site;
-                    if expn_data.kind.descr() != sym::impl_lint_pass
-                        && call_site.ctxt().outer_expn_data().kind.descr() != sym::declare_lint_pass
-                    {
-                        cx.struct_span_lint(
-                            LINT_PASS_IMPL_WITHOUT_MACRO,
-                            lint_pass.path.span,
-                            "implementing `LintPass` by hand",
-                        )
-                        .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
-                        .emit();
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
deleted file mode 100644 (file)
index 78d01ff..0000000
+++ /dev/null
@@ -1,549 +0,0 @@
-use std::cmp;
-
-use crate::ich::StableHashingContext;
-use crate::lint::builtin;
-use crate::lint::context::{CheckLintNameResult, LintStore};
-use crate::lint::{self, Level, Lint, LintId, LintSource};
-use crate::session::Session;
-use errors::{Applicability, DiagnosticBuilder};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::HirId;
-use rustc_span::source_map::MultiSpan;
-use rustc_span::symbol::{sym, Symbol};
-use syntax::ast;
-use syntax::attr;
-use syntax::feature_gate;
-use syntax::print::pprust;
-
-use rustc_error_codes::*;
-
-pub struct LintLevelSets {
-    list: Vec<LintSet>,
-    lint_cap: Level,
-}
-
-enum LintSet {
-    CommandLine {
-        // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
-        // flag.
-        specs: FxHashMap<LintId, (Level, LintSource)>,
-    },
-
-    Node {
-        specs: FxHashMap<LintId, (Level, LintSource)>,
-        parent: u32,
-    },
-}
-
-impl LintLevelSets {
-    pub fn new(sess: &Session, lint_store: &LintStore) -> LintLevelSets {
-        let mut me = LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid };
-        me.process_command_line(sess, lint_store);
-        return me;
-    }
-
-    pub fn builder<'a>(
-        sess: &'a Session,
-        warn_about_weird_lints: bool,
-        store: &LintStore,
-    ) -> LintLevelsBuilder<'a> {
-        LintLevelsBuilder::new(sess, warn_about_weird_lints, LintLevelSets::new(sess, store))
-    }
-
-    fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
-        let mut specs = FxHashMap::default();
-        self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
-
-        for &(ref lint_name, level) in &sess.opts.lint_opts {
-            store.check_lint_name_cmdline(sess, &lint_name, level);
-
-            // If the cap is less than this specified level, e.g., if we've got
-            // `--cap-lints allow` but we've also got `-D foo` then we ignore
-            // this specification as the lint cap will set it to allow anyway.
-            let level = cmp::min(level, self.lint_cap);
-
-            let lint_flag_val = Symbol::intern(lint_name);
-            let ids = match store.find_lints(&lint_name) {
-                Ok(ids) => ids,
-                Err(_) => continue, // errors handled in check_lint_name_cmdline above
-            };
-            for id in ids {
-                let src = LintSource::CommandLine(lint_flag_val);
-                specs.insert(id, (level, src));
-            }
-        }
-
-        self.list.push(LintSet::CommandLine { specs: specs });
-    }
-
-    fn get_lint_level(
-        &self,
-        lint: &'static Lint,
-        idx: u32,
-        aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
-        sess: &Session,
-    ) -> (Level, LintSource) {
-        let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
-
-        // If `level` is none then we actually assume the default level for this
-        // lint.
-        let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));
-
-        // If we're about to issue a warning, check at the last minute for any
-        // directives against the warnings "lint". If, for example, there's an
-        // `allow(warnings)` in scope then we want to respect that instead.
-        if level == Level::Warn {
-            let (warnings_level, warnings_src) =
-                self.get_lint_id_level(LintId::of(lint::builtin::WARNINGS), idx, aux);
-            if let Some(configured_warning_level) = warnings_level {
-                if configured_warning_level != Level::Warn {
-                    level = configured_warning_level;
-                    src = warnings_src;
-                }
-            }
-        }
-
-        // Ensure that we never exceed the `--cap-lints` argument.
-        level = cmp::min(level, self.lint_cap);
-
-        if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
-            // Ensure that we never exceed driver level.
-            level = cmp::min(*driver_level, level);
-        }
-
-        return (level, src);
-    }
-
-    fn get_lint_id_level(
-        &self,
-        id: LintId,
-        mut idx: u32,
-        aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
-    ) -> (Option<Level>, LintSource) {
-        if let Some(specs) = aux {
-            if let Some(&(level, src)) = specs.get(&id) {
-                return (Some(level), src);
-            }
-        }
-        loop {
-            match self.list[idx as usize] {
-                LintSet::CommandLine { ref specs } => {
-                    if let Some(&(level, src)) = specs.get(&id) {
-                        return (Some(level), src);
-                    }
-                    return (None, LintSource::Default);
-                }
-                LintSet::Node { ref specs, parent } => {
-                    if let Some(&(level, src)) = specs.get(&id) {
-                        return (Some(level), src);
-                    }
-                    idx = parent;
-                }
-            }
-        }
-    }
-}
-
-pub struct LintLevelsBuilder<'a> {
-    sess: &'a Session,
-    sets: LintLevelSets,
-    id_to_set: FxHashMap<HirId, u32>,
-    cur: u32,
-    warn_about_weird_lints: bool,
-}
-
-pub struct BuilderPush {
-    prev: u32,
-    pub changed: bool,
-}
-
-impl<'a> LintLevelsBuilder<'a> {
-    pub fn new(
-        sess: &'a Session,
-        warn_about_weird_lints: bool,
-        sets: LintLevelSets,
-    ) -> LintLevelsBuilder<'a> {
-        assert_eq!(sets.list.len(), 1);
-        LintLevelsBuilder {
-            sess,
-            sets,
-            cur: 0,
-            id_to_set: Default::default(),
-            warn_about_weird_lints,
-        }
-    }
-
-    /// Pushes a list of AST lint attributes onto this context.
-    ///
-    /// This function will return a `BuilderPush` object which should be passed
-    /// to `pop` when this scope for the attributes provided is exited.
-    ///
-    /// This function will perform a number of tasks:
-    ///
-    /// * It'll validate all lint-related attributes in `attrs`
-    /// * It'll mark all lint-related attributes as used
-    /// * Lint levels will be updated based on the attributes provided
-    /// * Lint attributes are validated, e.g., a #[forbid] can't be switched to
-    ///   #[allow]
-    ///
-    /// Don't forget to call `pop`!
-    pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
-        let mut specs = FxHashMap::default();
-        let sess = self.sess;
-        let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
-        for attr in attrs {
-            let level = match Level::from_symbol(attr.name_or_empty()) {
-                None => continue,
-                Some(lvl) => lvl,
-            };
-
-            let meta = unwrap_or!(attr.meta(), continue);
-            attr::mark_used(attr);
-
-            let mut metas = unwrap_or!(meta.meta_item_list(), continue);
-
-            if metas.is_empty() {
-                // FIXME (#55112): issue unused-attributes lint for `#[level()]`
-                continue;
-            }
-
-            // Before processing the lint names, look for a reason (RFC 2383)
-            // at the end.
-            let mut reason = None;
-            let tail_li = &metas[metas.len() - 1];
-            if let Some(item) = tail_li.meta_item() {
-                match item.kind {
-                    ast::MetaItemKind::Word => {} // actual lint names handled later
-                    ast::MetaItemKind::NameValue(ref name_value) => {
-                        if item.path == sym::reason {
-                            // found reason, reslice meta list to exclude it
-                            metas = &metas[0..metas.len() - 1];
-                            // FIXME (#55112): issue unused-attributes lint if we thereby
-                            // don't have any lint names (`#[level(reason = "foo")]`)
-                            if let ast::LitKind::Str(rationale, _) = name_value.kind {
-                                if !self.sess.features_untracked().lint_reasons {
-                                    feature_gate::feature_err(
-                                        &self.sess.parse_sess,
-                                        sym::lint_reasons,
-                                        item.span,
-                                        "lint reasons are experimental",
-                                    )
-                                    .emit();
-                                }
-                                reason = Some(rationale);
-                            } else {
-                                bad_attr(name_value.span)
-                                    .span_label(name_value.span, "reason must be a string literal")
-                                    .emit();
-                            }
-                        } else {
-                            bad_attr(item.span)
-                                .span_label(item.span, "bad attribute argument")
-                                .emit();
-                        }
-                    }
-                    ast::MetaItemKind::List(_) => {
-                        bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
-                    }
-                }
-            }
-
-            for li in metas {
-                let meta_item = match li.meta_item() {
-                    Some(meta_item) if meta_item.is_word() => meta_item,
-                    _ => {
-                        let sp = li.span();
-                        let mut err = bad_attr(sp);
-                        let mut add_label = true;
-                        if let Some(item) = li.meta_item() {
-                            if let ast::MetaItemKind::NameValue(_) = item.kind {
-                                if item.path == sym::reason {
-                                    err.span_label(sp, "reason in lint attribute must come last");
-                                    add_label = false;
-                                }
-                            }
-                        }
-                        if add_label {
-                            err.span_label(sp, "bad attribute argument");
-                        }
-                        err.emit();
-                        continue;
-                    }
-                };
-                let tool_name = if meta_item.path.segments.len() > 1 {
-                    let tool_ident = meta_item.path.segments[0].ident;
-                    if !attr::is_known_lint_tool(tool_ident) {
-                        span_err!(
-                            sess,
-                            tool_ident.span,
-                            E0710,
-                            "an unknown tool name found in scoped lint: `{}`",
-                            pprust::path_to_string(&meta_item.path),
-                        );
-                        continue;
-                    }
-
-                    Some(tool_ident.name)
-                } else {
-                    None
-                };
-                let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
-                match store.check_lint_name(&name.as_str(), tool_name) {
-                    CheckLintNameResult::Ok(ids) => {
-                        let src = LintSource::Node(name, li.span(), reason);
-                        for id in ids {
-                            specs.insert(*id, (level, src));
-                        }
-                    }
-
-                    CheckLintNameResult::Tool(result) => {
-                        match result {
-                            Ok(ids) => {
-                                let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
-                                let src = LintSource::Node(
-                                    Symbol::intern(complete_name),
-                                    li.span(),
-                                    reason,
-                                );
-                                for id in ids {
-                                    specs.insert(*id, (level, src));
-                                }
-                            }
-                            Err((Some(ids), new_lint_name)) => {
-                                let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                                let (lvl, src) =
-                                    self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
-                                let msg = format!(
-                                    "lint name `{}` is deprecated \
-                                     and may not have an effect in the future. \
-                                     Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
-                                    name
-                                );
-                                lint::struct_lint_level(
-                                    self.sess,
-                                    lint,
-                                    lvl,
-                                    src,
-                                    Some(li.span().into()),
-                                    &msg,
-                                )
-                                .span_suggestion(
-                                    li.span(),
-                                    "change it to",
-                                    new_lint_name.to_string(),
-                                    Applicability::MachineApplicable,
-                                )
-                                .emit();
-
-                                let src = LintSource::Node(
-                                    Symbol::intern(&new_lint_name),
-                                    li.span(),
-                                    reason,
-                                );
-                                for id in ids {
-                                    specs.insert(*id, (level, src));
-                                }
-                            }
-                            Err((None, _)) => {
-                                // If Tool(Err(None, _)) is returned, then either the lint does not
-                                // exist in the tool or the code was not compiled with the tool and
-                                // therefore the lint was never added to the `LintStore`. To detect
-                                // this is the responsibility of the lint tool.
-                            }
-                        }
-                    }
-
-                    _ if !self.warn_about_weird_lints => {}
-
-                    CheckLintNameResult::Warning(msg, renamed) => {
-                        let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                        let (level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
-                        let mut err = lint::struct_lint_level(
-                            self.sess,
-                            lint,
-                            level,
-                            src,
-                            Some(li.span().into()),
-                            &msg,
-                        );
-                        if let Some(new_name) = renamed {
-                            err.span_suggestion(
-                                li.span(),
-                                "use the new name",
-                                new_name,
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        err.emit();
-                    }
-                    CheckLintNameResult::NoLint(suggestion) => {
-                        let lint = builtin::UNKNOWN_LINTS;
-                        let (level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
-                        let msg = format!("unknown lint: `{}`", name);
-                        let mut db = lint::struct_lint_level(
-                            self.sess,
-                            lint,
-                            level,
-                            src,
-                            Some(li.span().into()),
-                            &msg,
-                        );
-
-                        if let Some(suggestion) = suggestion {
-                            db.span_suggestion(
-                                li.span(),
-                                "did you mean",
-                                suggestion.to_string(),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-
-                        db.emit();
-                    }
-                }
-            }
-        }
-
-        for (id, &(level, ref src)) in specs.iter() {
-            if level == Level::Forbid {
-                continue;
-            }
-            let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) {
-                (Some(Level::Forbid), src) => src,
-                _ => continue,
-            };
-            let forbidden_lint_name = match forbid_src {
-                LintSource::Default => id.to_string(),
-                LintSource::Node(name, _, _) => name.to_string(),
-                LintSource::CommandLine(name) => name.to_string(),
-            };
-            let (lint_attr_name, lint_attr_span) = match *src {
-                LintSource::Node(name, span, _) => (name, span),
-                _ => continue,
-            };
-            let mut diag_builder = struct_span_err!(
-                self.sess,
-                lint_attr_span,
-                E0453,
-                "{}({}) overruled by outer forbid({})",
-                level.as_str(),
-                lint_attr_name,
-                forbidden_lint_name
-            );
-            diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
-            match forbid_src {
-                LintSource::Default => {}
-                LintSource::Node(_, forbid_source_span, reason) => {
-                    diag_builder.span_label(forbid_source_span, "`forbid` level set here");
-                    if let Some(rationale) = reason {
-                        diag_builder.note(&rationale.as_str());
-                    }
-                }
-                LintSource::CommandLine(_) => {
-                    diag_builder.note("`forbid` lint level was set on command line");
-                }
-            }
-            diag_builder.emit();
-            // don't set a separate error for every lint in the group
-            break;
-        }
-
-        let prev = self.cur;
-        if specs.len() > 0 {
-            self.cur = self.sets.list.len() as u32;
-            self.sets.list.push(LintSet::Node { specs: specs, parent: prev });
-        }
-
-        BuilderPush { prev: prev, changed: prev != self.cur }
-    }
-
-    /// Called after `push` when the scope of a set of attributes are exited.
-    pub fn pop(&mut self, push: BuilderPush) {
-        self.cur = push.prev;
-    }
-
-    /// Used to emit a lint-related diagnostic based on the current state of
-    /// this lint context.
-    pub fn struct_lint(
-        &self,
-        lint: &'static Lint,
-        span: Option<MultiSpan>,
-        msg: &str,
-    ) -> DiagnosticBuilder<'a> {
-        let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
-        lint::struct_lint_level(self.sess, lint, level, src, span, msg)
-    }
-
-    /// Registers the ID provided with the current set of lints stored in
-    /// this context.
-    pub fn register_id(&mut self, id: HirId) {
-        self.id_to_set.insert(id, self.cur);
-    }
-
-    pub fn build(self) -> LintLevelSets {
-        self.sets
-    }
-
-    pub fn build_map(self) -> LintLevelMap {
-        LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
-    }
-}
-
-pub struct LintLevelMap {
-    sets: LintLevelSets,
-    id_to_set: FxHashMap<HirId, u32>,
-}
-
-impl LintLevelMap {
-    /// If the `id` was previously registered with `register_id` when building
-    /// this `LintLevelMap` this returns the corresponding lint level and source
-    /// of the lint level for the lint provided.
-    ///
-    /// If the `id` was not previously registered, returns `None`. If `None` is
-    /// returned then the parent of `id` should be acquired and this function
-    /// should be called again.
-    pub fn level_and_source(
-        &self,
-        lint: &'static Lint,
-        id: HirId,
-        session: &Session,
-    ) -> Option<(Level, LintSource)> {
-        self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
-    }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let LintLevelMap { ref sets, ref id_to_set } = *self;
-
-        id_to_set.hash_stable(hcx, hasher);
-
-        let LintLevelSets { ref list, lint_cap } = *sets;
-
-        lint_cap.hash_stable(hcx, hasher);
-
-        hcx.while_hashing_spans(true, |hcx| {
-            list.len().hash_stable(hcx, hasher);
-
-            // We are working under the assumption here that the list of
-            // lint-sets is built in a deterministic order.
-            for lint_set in list {
-                ::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);
-
-                match *lint_set {
-                    LintSet::CommandLine { ref specs } => {
-                        specs.hash_stable(hcx, hasher);
-                    }
-                    LintSet::Node { ref specs, parent } => {
-                        specs.hash_stable(hcx, hasher);
-                        parent.hash_stable(hcx, hasher);
-                    }
-                }
-            }
-        })
-    }
-}
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
deleted file mode 100644 (file)
index 2147ff1..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-//! Lints, aka compiler warnings.
-//!
-//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
-//! want to enforce, but might reasonably want to permit as well, on a
-//! module-by-module basis. They contrast with static constraints enforced by
-//! other phases of the compiler, which are generally required to hold in order
-//! to compile the program at all.
-//!
-//! Most lints can be written as `LintPass` instances. These run after
-//! all other analyses. The `LintPass`es built into rustc are defined
-//! within `builtin.rs`, which has further comments on how to add such a lint.
-//! rustc can also load user-defined lint plugins via the plugin mechanism.
-//!
-//! Some of rustc's lints are defined elsewhere in the compiler and work by
-//! calling `add_lint()` on the overall `Session` object. This works when
-//! it happens before the main lint pass, which emits the lints stored by
-//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
-//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
-//! in `context.rs`.
-
-pub use self::Level::*;
-pub use self::LintSource::*;
-
-use rustc_data_structures::sync;
-
-use crate::lint::builtin::BuiltinLintDiagnostics;
-use crate::ty::TyCtxt;
-use errors::{DiagnosticBuilder, DiagnosticId};
-use rustc_hir as hir;
-use rustc_session::node_id::NodeMap;
-use rustc_session::{DiagnosticMessageId, Session};
-use rustc_span::hygiene::MacroKind;
-use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
-use rustc_span::symbol::Symbol;
-use rustc_span::Span;
-use syntax::ast;
-
-pub use crate::lint::context::{
-    BufferedEarlyLint, CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore,
-};
-
-pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId};
-
-/// Declares a static `LintArray` and return it as an expression.
-#[macro_export]
-macro_rules! lint_array {
-    ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) };
-    ($( $lint:expr ),*) => {{
-        vec![$($lint),*]
-    }}
-}
-
-pub type LintArray = Vec<&'static Lint>;
-
-pub trait LintPass {
-    fn name(&self) -> &'static str;
-}
-
-/// Implements `LintPass for $name` with the given list of `Lint` statics.
-#[macro_export]
-macro_rules! impl_lint_pass {
-    ($name:ident => [$($lint:expr),* $(,)?]) => {
-        impl LintPass for $name {
-            fn name(&self) -> &'static str { stringify!($name) }
-        }
-        impl $name {
-            pub fn get_lints() -> LintArray { $crate::lint_array!($($lint),*) }
-        }
-    };
-}
-
-/// Declares a type named `$name` which implements `LintPass`.
-/// To the right of `=>` a comma separated list of `Lint` statics is given.
-#[macro_export]
-macro_rules! declare_lint_pass {
-    ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => {
-        $(#[$m])* #[derive(Copy, Clone)] pub struct $name;
-        $crate::impl_lint_pass!($name => [$($lint),*]);
-    };
-}
-
-#[macro_export]
-macro_rules! late_lint_methods {
-    ($macro:path, $args:tt, [$hir:tt]) => (
-        $macro!($args, [$hir], [
-            fn check_param(a: &$hir hir::Param<$hir>);
-            fn check_body(a: &$hir hir::Body<$hir>);
-            fn check_body_post(a: &$hir hir::Body<$hir>);
-            fn check_name(a: Span, b: ast::Name);
-            fn check_crate(a: &$hir hir::Crate<$hir>);
-            fn check_crate_post(a: &$hir hir::Crate<$hir>);
-            fn check_mod(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId);
-            fn check_mod_post(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId);
-            fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>);
-            fn check_foreign_item_post(a: &$hir hir::ForeignItem<$hir>);
-            fn check_item(a: &$hir hir::Item<$hir>);
-            fn check_item_post(a: &$hir hir::Item<$hir>);
-            fn check_local(a: &$hir hir::Local<$hir>);
-            fn check_block(a: &$hir hir::Block<$hir>);
-            fn check_block_post(a: &$hir hir::Block<$hir>);
-            fn check_stmt(a: &$hir hir::Stmt<$hir>);
-            fn check_arm(a: &$hir hir::Arm<$hir>);
-            fn check_pat(a: &$hir hir::Pat<$hir>);
-            fn check_expr(a: &$hir hir::Expr<$hir>);
-            fn check_expr_post(a: &$hir hir::Expr<$hir>);
-            fn check_ty(a: &$hir hir::Ty<$hir>);
-            fn check_generic_param(a: &$hir hir::GenericParam<$hir>);
-            fn check_generics(a: &$hir hir::Generics<$hir>);
-            fn check_where_predicate(a: &$hir hir::WherePredicate<$hir>);
-            fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef<$hir>, b: hir::TraitBoundModifier);
-            fn check_fn(
-                a: $crate::hir::intravisit::FnKind<$hir>,
-                b: &$hir hir::FnDecl<$hir>,
-                c: &$hir hir::Body<$hir>,
-                d: Span,
-                e: hir::HirId);
-            fn check_fn_post(
-                a: $crate::hir::intravisit::FnKind<$hir>,
-                b: &$hir hir::FnDecl<$hir>,
-                c: &$hir hir::Body<$hir>,
-                d: Span,
-                e: hir::HirId
-            );
-            fn check_trait_item(a: &$hir hir::TraitItem<$hir>);
-            fn check_trait_item_post(a: &$hir hir::TraitItem<$hir>);
-            fn check_impl_item(a: &$hir hir::ImplItem<$hir>);
-            fn check_impl_item_post(a: &$hir hir::ImplItem<$hir>);
-            fn check_struct_def(a: &$hir hir::VariantData<$hir>);
-            fn check_struct_def_post(a: &$hir hir::VariantData<$hir>);
-            fn check_struct_field(a: &$hir hir::StructField<$hir>);
-            fn check_variant(a: &$hir hir::Variant<$hir>);
-            fn check_variant_post(a: &$hir hir::Variant<$hir>);
-            fn check_lifetime(a: &$hir hir::Lifetime);
-            fn check_path(a: &$hir hir::Path<$hir>, b: hir::HirId);
-            fn check_attribute(a: &$hir ast::Attribute);
-
-            /// Called when entering a syntax node that can have lint attributes such
-            /// as `#[allow(...)]`. Called with *all* the attributes of that node.
-            fn enter_lint_attrs(a: &$hir [ast::Attribute]);
-
-            /// Counterpart to `enter_lint_attrs`.
-            fn exit_lint_attrs(a: &$hir [ast::Attribute]);
-        ]);
-    )
-}
-
-/// Trait for types providing lint checks.
-///
-/// Each `check` method checks a single syntax node, and should not
-/// invoke methods recursively (unlike `Visitor`). By default they
-/// do nothing.
-//
-// FIXME: eliminate the duplication with `Visitor`. But this also
-// contains a few lint-specific methods with no equivalent in `Visitor`.
-
-macro_rules! expand_lint_pass_methods {
-    ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
-    )
-}
-
-macro_rules! declare_late_lint_pass {
-    ([], [$hir:tt], [$($methods:tt)*]) => (
-        pub trait LateLintPass<'a, $hir>: LintPass {
-            expand_lint_pass_methods!(&LateContext<'a, $hir>, [$($methods)*]);
-        }
-    )
-}
-
-late_lint_methods!(declare_late_lint_pass, [], ['tcx]);
-
-#[macro_export]
-macro_rules! expand_combined_late_lint_pass_method {
-    ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
-        $($self.$passes.$name $params;)*
-    })
-}
-
-#[macro_export]
-macro_rules! expand_combined_late_lint_pass_methods {
-    ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(fn $name(&mut self, context: &LateContext<'a, 'tcx>, $($param: $arg),*) {
-            expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*));
-        })*
-    )
-}
-
-#[macro_export]
-macro_rules! declare_combined_late_lint_pass {
-    ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => (
-        #[allow(non_snake_case)]
-        $v struct $name {
-            $($passes: $passes,)*
-        }
-
-        impl $name {
-            $v fn new() -> Self {
-                Self {
-                    $($passes: $constructor,)*
-                }
-            }
-
-            $v fn get_lints() -> LintArray {
-                let mut lints = Vec::new();
-                $(lints.extend_from_slice(&$passes::get_lints());)*
-                lints
-            }
-        }
-
-        impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $name {
-            expand_combined_late_lint_pass_methods!([$($passes),*], $methods);
-        }
-
-        impl LintPass for $name {
-            fn name(&self) -> &'static str {
-                panic!()
-            }
-        }
-    )
-}
-
-#[macro_export]
-macro_rules! early_lint_methods {
-    ($macro:path, $args:tt) => (
-        $macro!($args, [
-            fn check_param(a: &ast::Param);
-            fn check_ident(a: ast::Ident);
-            fn check_crate(a: &ast::Crate);
-            fn check_crate_post(a: &ast::Crate);
-            fn check_mod(a: &ast::Mod, b: Span, c: ast::NodeId);
-            fn check_mod_post(a: &ast::Mod, b: Span, c: ast::NodeId);
-            fn check_foreign_item(a: &ast::ForeignItem);
-            fn check_foreign_item_post(a: &ast::ForeignItem);
-            fn check_item(a: &ast::Item);
-            fn check_item_post(a: &ast::Item);
-            fn check_local(a: &ast::Local);
-            fn check_block(a: &ast::Block);
-            fn check_block_post(a: &ast::Block);
-            fn check_stmt(a: &ast::Stmt);
-            fn check_arm(a: &ast::Arm);
-            fn check_pat(a: &ast::Pat);
-            fn check_pat_post(a: &ast::Pat);
-            fn check_expr(a: &ast::Expr);
-            fn check_expr_post(a: &ast::Expr);
-            fn check_ty(a: &ast::Ty);
-            fn check_generic_param(a: &ast::GenericParam);
-            fn check_generics(a: &ast::Generics);
-            fn check_where_predicate(a: &ast::WherePredicate);
-            fn check_poly_trait_ref(a: &ast::PolyTraitRef,
-                                    b: &ast::TraitBoundModifier);
-            fn check_fn(a: syntax::visit::FnKind<'_>, b: &ast::FnDecl, c: Span, d_: ast::NodeId);
-            fn check_fn_post(
-                a: syntax::visit::FnKind<'_>,
-                b: &ast::FnDecl,
-                c: Span,
-                d: ast::NodeId
-            );
-            fn check_trait_item(a: &ast::AssocItem);
-            fn check_trait_item_post(a: &ast::AssocItem);
-            fn check_impl_item(a: &ast::AssocItem);
-            fn check_impl_item_post(a: &ast::AssocItem);
-            fn check_struct_def(a: &ast::VariantData);
-            fn check_struct_def_post(a: &ast::VariantData);
-            fn check_struct_field(a: &ast::StructField);
-            fn check_variant(a: &ast::Variant);
-            fn check_variant_post(a: &ast::Variant);
-            fn check_lifetime(a: &ast::Lifetime);
-            fn check_path(a: &ast::Path, b: ast::NodeId);
-            fn check_attribute(a: &ast::Attribute);
-            fn check_mac_def(a: &ast::MacroDef, b: ast::NodeId);
-            fn check_mac(a: &ast::Mac);
-
-            /// Called when entering a syntax node that can have lint attributes such
-            /// as `#[allow(...)]`. Called with *all* the attributes of that node.
-            fn enter_lint_attrs(a: &[ast::Attribute]);
-
-            /// Counterpart to `enter_lint_attrs`.
-            fn exit_lint_attrs(a: &[ast::Attribute]);
-        ]);
-    )
-}
-
-macro_rules! expand_early_lint_pass_methods {
-    ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
-    )
-}
-
-macro_rules! declare_early_lint_pass {
-    ([], [$($methods:tt)*]) => (
-        pub trait EarlyLintPass: LintPass {
-            expand_early_lint_pass_methods!(&EarlyContext<'_>, [$($methods)*]);
-        }
-    )
-}
-
-early_lint_methods!(declare_early_lint_pass, []);
-
-#[macro_export]
-macro_rules! expand_combined_early_lint_pass_method {
-    ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
-        $($self.$passes.$name $params;)*
-    })
-}
-
-#[macro_export]
-macro_rules! expand_combined_early_lint_pass_methods {
-    ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
-        $(fn $name(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) {
-            expand_combined_early_lint_pass_method!($passes, self, $name, (context, $($param),*));
-        })*
-    )
-}
-
-#[macro_export]
-macro_rules! declare_combined_early_lint_pass {
-    ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], $methods:tt) => (
-        #[allow(non_snake_case)]
-        $v struct $name {
-            $($passes: $passes,)*
-        }
-
-        impl $name {
-            $v fn new() -> Self {
-                Self {
-                    $($passes: $constructor,)*
-                }
-            }
-
-            $v fn get_lints() -> LintArray {
-                let mut lints = Vec::new();
-                $(lints.extend_from_slice(&$passes::get_lints());)*
-                lints
-            }
-        }
-
-        impl EarlyLintPass for $name {
-            expand_combined_early_lint_pass_methods!([$($passes),*], $methods);
-        }
-
-        impl LintPass for $name {
-            fn name(&self) -> &'static str {
-                panic!()
-            }
-        }
-    )
-}
-
-/// A lint pass boxed up as a trait object.
-pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>;
-pub type LateLintPassObject =
-    Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>;
-
-/// How a lint level was set.
-#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
-pub enum LintSource {
-    /// Lint is at the default level as declared
-    /// in rustc or a plugin.
-    Default,
-
-    /// Lint level was set by an attribute.
-    Node(ast::Name, Span, Option<Symbol> /* RFC 2383 reason */),
-
-    /// Lint level was set by a command-line flag.
-    CommandLine(Symbol),
-}
-
-pub type LevelSource = (Level, LintSource);
-
-pub mod builtin;
-mod context;
-pub mod internal;
-mod levels;
-
-pub use self::levels::{LintLevelMap, LintLevelSets, LintLevelsBuilder};
-
-#[derive(Default)]
-pub struct LintBuffer {
-    pub map: NodeMap<Vec<BufferedEarlyLint>>,
-}
-
-impl LintBuffer {
-    pub fn add_lint(
-        &mut self,
-        lint: &'static Lint,
-        id: ast::NodeId,
-        sp: MultiSpan,
-        msg: &str,
-        diagnostic: BuiltinLintDiagnostics,
-    ) {
-        let early_lint = BufferedEarlyLint {
-            lint_id: LintId::of(lint),
-            ast_id: id,
-            span: sp,
-            msg: msg.to_string(),
-            diagnostic,
-        };
-        let arr = self.map.entry(id).or_default();
-        if !arr.contains(&early_lint) {
-            arr.push(early_lint);
-        }
-    }
-
-    pub fn take(&mut self, id: ast::NodeId) -> Vec<BufferedEarlyLint> {
-        self.map.remove(&id).unwrap_or_default()
-    }
-
-    pub fn buffer_lint<S: Into<MultiSpan>>(
-        &mut self,
-        lint: &'static Lint,
-        id: ast::NodeId,
-        sp: S,
-        msg: &str,
-    ) {
-        self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
-    }
-
-    pub fn buffer_lint_with_diagnostic<S: Into<MultiSpan>>(
-        &mut self,
-        lint: &'static Lint,
-        id: ast::NodeId,
-        sp: S,
-        msg: &str,
-        diagnostic: BuiltinLintDiagnostics,
-    ) {
-        self.add_lint(lint, id, sp.into(), msg, diagnostic)
-    }
-}
-
-pub fn struct_lint_level<'a>(
-    sess: &'a Session,
-    lint: &'static Lint,
-    level: Level,
-    src: LintSource,
-    span: Option<MultiSpan>,
-    msg: &str,
-) -> DiagnosticBuilder<'a> {
-    let mut err = match (level, span) {
-        (Level::Allow, _) => return sess.diagnostic().struct_dummy(),
-        (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
-        (Level::Warn, None) => sess.struct_warn(msg),
-        (Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
-        (Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg),
-    };
-
-    // Check for future incompatibility lints and issue a stronger warning.
-    let lint_id = LintId::of(lint);
-    let future_incompatible = lint.future_incompatible;
-
-    // If this code originates in a foreign macro, aka something that this crate
-    // did not itself author, then it's likely that there's nothing this crate
-    // can do about it. We probably want to skip the lint entirely.
-    if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
-        // Any suggestions made here are likely to be incorrect, so anything we
-        // emit shouldn't be automatically fixed by rustfix.
-        err.allow_suggestions(false);
-
-        // If this is a future incompatible lint it'll become a hard error, so
-        // we have to emit *something*. Also allow lints to whitelist themselves
-        // on a case-by-case basis for emission in a foreign macro.
-        if future_incompatible.is_none() && !lint.report_in_external_macro {
-            err.cancel();
-            // Don't continue further, since we don't want to have
-            // `diag_span_note_once` called for a diagnostic that isn't emitted.
-            return err;
-        }
-    }
-
-    let name = lint.name_lower();
-    match src {
-        LintSource::Default => {
-            sess.diag_note_once(
-                &mut err,
-                DiagnosticMessageId::from(lint),
-                &format!("`#[{}({})]` on by default", level.as_str(), name),
-            );
-        }
-        LintSource::CommandLine(lint_flag_val) => {
-            let flag = match level {
-                Level::Warn => "-W",
-                Level::Deny => "-D",
-                Level::Forbid => "-F",
-                Level::Allow => panic!(),
-            };
-            let hyphen_case_lint_name = name.replace("_", "-");
-            if lint_flag_val.as_str() == name {
-                sess.diag_note_once(
-                    &mut err,
-                    DiagnosticMessageId::from(lint),
-                    &format!(
-                        "requested on the command line with `{} {}`",
-                        flag, hyphen_case_lint_name
-                    ),
-                );
-            } else {
-                let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
-                sess.diag_note_once(
-                    &mut err,
-                    DiagnosticMessageId::from(lint),
-                    &format!(
-                        "`{} {}` implied by `{} {}`",
-                        flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
-                    ),
-                );
-            }
-        }
-        LintSource::Node(lint_attr_name, src, reason) => {
-            if let Some(rationale) = reason {
-                err.note(&rationale.as_str());
-            }
-            sess.diag_span_note_once(
-                &mut err,
-                DiagnosticMessageId::from(lint),
-                src,
-                "lint level defined here",
-            );
-            if lint_attr_name.as_str() != name {
-                let level_str = level.as_str();
-                sess.diag_note_once(
-                    &mut err,
-                    DiagnosticMessageId::from(lint),
-                    &format!(
-                        "`#[{}({})]` implied by `#[{}({})]`",
-                        level_str, name, level_str, lint_attr_name
-                    ),
-                );
-            }
-        }
-    }
-
-    err.code(DiagnosticId::Lint(name));
-
-    if let Some(future_incompatible) = future_incompatible {
-        const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
-             it will become a hard error";
-
-        let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
-            "once this method is added to the standard library, \
-             the ambiguity may cause an error or change in behavior!"
-                .to_owned()
-        } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
-            "this borrowing pattern was not meant to be accepted, \
-             and may become a hard error in the future"
-                .to_owned()
-        } else if let Some(edition) = future_incompatible.edition {
-            format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
-        } else {
-            format!("{} in a future release!", STANDARD_MESSAGE)
-        };
-        let citation = format!("for more information, see {}", future_incompatible.reference);
-        err.warn(&explanation);
-        err.note(&citation);
-    }
-
-    return err;
-}
-
-pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
-    let attrs = tcx.hir().attrs(id);
-    attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some())
-}
-
-/// Returns whether `span` originates in a foreign crate's external macro.
-///
-/// This is used to test whether a lint should not even begin to figure out whether it should
-/// be reported on the current node.
-pub fn in_external_macro(sess: &Session, span: Span) -> bool {
-    let expn_data = span.ctxt().outer_expn_data();
-    match expn_data.kind {
-        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
-        ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
-        ExpnKind::Macro(MacroKind::Bang, _) => {
-            if expn_data.def_site.is_dummy() {
-                // Dummy span for the `def_site` means it's an external macro.
-                return true;
-            }
-            match sess.source_map().span_to_snippet(expn_data.def_site) {
-                Ok(code) => !code.starts_with("macro_rules"),
-                // No snippet means external macro or compiler-builtin expansion.
-                Err(_) => true,
-            }
-        }
-        ExpnKind::Macro(..) => true, // definitely a plugin
-    }
-}
-
-/// Returns `true` if `span` originates in a derive-macro's expansion.
-pub fn in_derive_expansion(span: Span) -> bool {
-    if let ExpnKind::Macro(MacroKind::Derive, _) = span.ctxt().outer_expn_data().kind {
-        return true;
-    }
-    false
-}
index ee43c35c1d05b9f70e56a5e706dbf8e39b37ab9d..5b1e7673629b192fefb1c6cf5a01b331f253474b 100644 (file)
@@ -5,8 +5,8 @@
 use crate::hir::map as hir_map;
 use crate::hir::map::definitions::{DefKey, DefPathTable};
 use crate::session::search_paths::PathKind;
-use crate::session::{CrateDisambiguator, Session};
-use crate::ty::{self, TyCtxt};
+use crate::session::CrateDisambiguator;
+use crate::ty::TyCtxt;
 
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{self, MetadataRef};
@@ -208,7 +208,6 @@ pub trait CrateStore {
     fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
     fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
-    fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
 
     // This is basically a 1-based range of ints, which is a little
     // silly - I may fix that.
index 253e00f9e4db55faa0c80f899746021c8ca69bfb..355f949b8700860fdf005758da74bf50f03c7fb8 100644 (file)
@@ -3,8 +3,8 @@
 //! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type,
 //! and use that to decide when one free region outlives another, and so forth.
 
-use crate::infer::outlives::free_region_map::{FreeRegionMap, FreeRegionRelations};
 use crate::middle::region;
+use crate::ty::free_region_map::{FreeRegionMap, FreeRegionRelations};
 use crate::ty::{self, Region, TyCtxt};
 use rustc_hir::def_id::DefId;
 
index 220560a67e08842afb3d47e46362533a3e8b1dce..42fc3e030e7bb4f88cb071a633745faf1126074b 100644 (file)
@@ -15,6 +15,7 @@
 use crate::ty::{self, TyCtxt};
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
@@ -184,7 +185,8 @@ fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
                         span,
                         E0152,
                         "duplicate lang item found: `{}`.",
-                        name),
+                        name
+                    ),
                     None => {
                         match self.tcx.extern_crate(item_def_id) {
                             Some(ExternCrate {dependency_of, ..}) => {
@@ -204,7 +206,7 @@ fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
                     },
                 };
                 if let Some(span) = self.tcx.hir().span_if_local(original_def_id) {
-                    span_note!(&mut err, span, "first defined here.");
+                    err.span_note(span, "first defined here.");
                 } else {
                     match self.tcx.extern_crate(original_def_id) {
                         Some(ExternCrate {dependency_of, ..}) => {
index a29b1b48c24f937c787f841ba93b25cacb1bcfe0..1176ffc79d26d0749080c114d1d2161170b5278e 100644 (file)
@@ -3,23 +3,21 @@
 
 pub use self::StabilityLevel::*;
 
-use crate::lint::builtin::BuiltinLintDiagnostics;
-use crate::lint::{self, in_derive_expansion, Lint};
 use crate::session::{DiagnosticMessageId, Session};
 use crate::ty::{self, TyCtxt};
-use errors::DiagnosticBuilder;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_feature::GateIssue;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_hir::{self, HirId};
+use rustc_session::lint::{self, BuiltinLintDiagnostics, Lint, LintBuffer};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{MultiSpan, Span};
 use syntax::ast::CRATE_NODE_ID;
 use syntax::attr::{self, ConstStability, Deprecation, RustcDeprecation, Stability};
-use syntax::errors::Applicability;
-use syntax::feature_gate::feature_err_issue;
+use syntax::sess::feature_err_issue;
 
 use std::num::NonZeroU32;
 
@@ -196,13 +194,13 @@ pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String
 }
 
 pub fn early_report_deprecation(
-    lint_buffer: &'a mut lint::LintBuffer,
+    lint_buffer: &'a mut LintBuffer,
     message: &str,
     suggestion: Option<Symbol>,
     lint: &'static Lint,
     span: Span,
 ) {
-    if in_derive_expansion(span) {
+    if span.in_derive_expansion() {
         return;
     }
 
@@ -219,7 +217,7 @@ fn late_report_deprecation(
     def_id: DefId,
     hir_id: HirId,
 ) {
-    if in_derive_expansion(span) {
+    if span.in_derive_expansion() {
         return;
     }
 
@@ -245,35 +243,35 @@ pub enum EvalResult {
     Unmarked,
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    // See issue #38412.
-    fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool {
-        // Check if `def_id` is a trait method.
-        match self.def_kind(def_id) {
-            Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => {
-                if let ty::TraitContainer(trait_def_id) = self.associated_item(def_id).container {
-                    // Trait methods do not declare visibility (even
-                    // for visibility info in cstore). Use containing
-                    // trait instead, so methods of `pub` traits are
-                    // themselves considered `pub`.
-                    def_id = trait_def_id;
-                }
+// See issue #38412.
+fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, mut def_id: DefId) -> bool {
+    // Check if `def_id` is a trait method.
+    match tcx.def_kind(def_id) {
+        Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => {
+            if let ty::TraitContainer(trait_def_id) = tcx.associated_item(def_id).container {
+                // Trait methods do not declare visibility (even
+                // for visibility info in cstore). Use containing
+                // trait instead, so methods of `pub` traits are
+                // themselves considered `pub`.
+                def_id = trait_def_id;
             }
-            _ => {}
         }
+        _ => {}
+    }
 
-        let visibility = self.visibility(def_id);
+    let visibility = tcx.visibility(def_id);
 
-        match visibility {
-            // Must check stability for `pub` items.
-            ty::Visibility::Public => false,
+    match visibility {
+        // Must check stability for `pub` items.
+        ty::Visibility::Public => false,
 
-            // These are not visible outside crate; therefore
-            // stability markers are irrelevant, if even present.
-            ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true,
-        }
+        // These are not visible outside crate; therefore
+        // stability markers are irrelevant, if even present.
+        ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true,
     }
+}
 
+impl<'tcx> TyCtxt<'tcx> {
     /// Evaluates the stability of an item.
     ///
     /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
@@ -338,7 +336,7 @@ pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> Eva
         }
 
         // Issue #38412: private items lack stability markers.
-        if self.skip_stability_check_due_to_privacy(def_id) {
+        if skip_stability_check_due_to_privacy(self, def_id) {
             return EvalResult::Allow;
         }
 
@@ -402,9 +400,7 @@ pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
             }
         }
     }
-}
 
-impl<'tcx> TyCtxt<'tcx> {
     pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
         self.lookup_deprecation_entry(id).map(|depr| depr.attr)
     }
index 8e6ac165fab17287dae7e413997cd8099c297d21..fdffd1251ce8f747f73ed6bc785b187741b29964 100644 (file)
@@ -3,12 +3,13 @@
 use crate::middle::lang_items;
 use crate::session::config;
 
-use crate::hir::intravisit;
-use crate::hir::intravisit::{NestedVisitorMap, Visitor};
+use crate::hir::map::Map;
 use crate::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::PanicStrategy;
@@ -124,15 +125,20 @@ fn register(&mut self, name: Symbol, span: Span) {
                 self.items.missing.push(lang_items::$item);
             }
         } else)* {
-            span_err!(self.tcx.sess, span, E0264,
-                      "unknown external lang item: `{}`",
-                      name);
+            struct_span_err!(
+                self.tcx.sess, span, E0264,
+                "unknown external lang item: `{}`",
+                name
+            )
+            .emit();
         }
     }
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+    type Map = Map<'v>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Map<'v>> {
         NestedVisitorMap::None
     }
 
index f54b9231d1acf1b816ccfef8794d526dc889220e..8643bd63d8cba29e9ab99dbf4e14fcba938c2ed1 100644 (file)
@@ -7,8 +7,8 @@
 use crate::ty::{self, layout, Ty};
 
 use backtrace::Backtrace;
-use errors::DiagnosticBuilder;
 use hir::GeneratorKind;
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_macros::HashStable;
 use rustc_span::symbol::Symbol;
@@ -154,7 +154,7 @@ fn struct_generic(
                 .next()
                 .unwrap_or(lint_root);
             tcx.struct_span_lint_hir(
-                crate::rustc::lint::builtin::CONST_ERR,
+                rustc_session::lint::builtin::CONST_ERR,
                 hir_id,
                 tcx.span,
                 message,
index 161c9a3fcc1f7ea558a973bfe424911684d5d2cf..ed57f81e782167638a72f317bc7b101a4c759d6c 100644 (file)
@@ -36,11 +36,16 @@ pub fn const_eval_resolve(
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
+        promoted: Option<mir::Promoted>,
         span: Option<Span>,
     ) -> ConstEvalResult<'tcx> {
         let instance = ty::Instance::resolve(self, param_env, def_id, substs);
         if let Some(instance) = instance {
-            self.const_eval_instance(param_env, instance, span)
+            if let Some(promoted) = promoted {
+                self.const_eval_promoted(param_env, instance, promoted)
+            } else {
+                self.const_eval_instance(param_env, instance, span)
+            }
         } else {
             Err(ErrorHandled::TooGeneric)
         }
@@ -63,11 +68,11 @@ pub fn const_eval_instance(
     /// Evaluate a promoted constant.
     pub fn const_eval_promoted(
         self,
+        param_env: ty::ParamEnv<'tcx>,
         instance: ty::Instance<'tcx>,
         promoted: mir::Promoted,
     ) -> ConstEvalResult<'tcx> {
         let cid = GlobalId { instance, promoted: Some(promoted) };
-        let param_env = ty::ParamEnv::reveal_all();
         self.const_eval_validated(param_env.and(cid))
     }
 }
index ff64302b1e506a13bc8d69c47f0600239941223a..ccd2a968ded4cb3e61fbcea42ca56479ca2c08cd 100644 (file)
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 //! MIR datatypes and passes. See the [rustc guide] for more info.
 //!
 //! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/index.html
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::graph::{self, GraphSuccessors};
-use rustc_data_structures::sync::Lrc;
 use rustc_index::bit_set::BitMatrix;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
-use smallvec::SmallVec;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Display, Formatter, Write};
 use std::ops::Index;
 pub use syntax::ast::Mutability;
 use syntax::ast::Name;
 
-pub use crate::mir::cache::{BodyAndCache, ReadOnlyBodyAndCache};
-pub use crate::mir::interpret::AssertMessage;
+pub use self::cache::{BodyAndCache, ReadOnlyBodyAndCache};
+pub use self::interpret::AssertMessage;
+pub use self::query::*;
 pub use crate::read_only;
 
 mod cache;
 pub mod interpret;
 pub mod mono;
+mod query;
 pub mod tcx;
 pub mod traversal;
 pub mod visit;
@@ -166,6 +164,16 @@ pub struct Body<'tcx> {
 
     /// A span representing this MIR, for error reporting.
     pub span: Span,
+
+    /// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
+    /// we'd statically know that no thing with interior mutability will ever be available to the
+    /// user without some serious unsafe code.  Now this means that our promoted is actually
+    /// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the
+    /// index may be a runtime value. Such a promoted value is illegal because it has reachable
+    /// interior mutability. This flag just makes this situation very obvious where the previous
+    /// implementation without the flag hid this situation silently.
+    /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
+    pub ignore_interior_mut_in_const_validation: bool,
 }
 
 impl<'tcx> Body<'tcx> {
@@ -202,6 +210,7 @@ pub fn new(
             spread_arg: None,
             var_debug_info,
             span,
+            ignore_interior_mut_in_const_validation: false,
             control_flow_destroyed,
         }
     }
@@ -1642,9 +1651,9 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)]
 pub struct Place<'tcx> {
-    pub base: PlaceBase<'tcx>,
+    pub local: Local,
 
     /// projection out of a place (access a field, deref a pointer, etc)
     pub projection: &'tcx List<PlaceElem<'tcx>>,
@@ -1652,58 +1661,6 @@ pub struct Place<'tcx> {
 
 impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)]
-pub enum PlaceBase<'tcx> {
-    /// local variable
-    Local(Local),
-
-    /// static or static mut variable
-    Static(Box<Static<'tcx>>),
-}
-
-/// We store the normalized type to avoid requiring normalization when reading MIR
-#[derive(
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord,
-    Hash,
-    RustcEncodable,
-    RustcDecodable,
-    HashStable
-)]
-pub struct Static<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub kind: StaticKind<'tcx>,
-    /// The `DefId` of the item this static was declared in. For promoted values, usually, this is
-    /// the same as the `DefId` of the `mir::Body` containing the `Place` this promoted appears in.
-    /// However, after inlining, that might no longer be the case as inlined `Place`s are copied
-    /// into the calling frame.
-    pub def_id: DefId,
-}
-
-#[derive(
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord,
-    Hash,
-    HashStable,
-    RustcEncodable,
-    RustcDecodable
-)]
-pub enum StaticKind<'tcx> {
-    /// Promoted references consist of an id (`Promoted`) and the substs necessary to monomorphize
-    /// it. Usually, these substs are just the identity substs for the item. However, the inliner
-    /// will adjust these substs when it inlines a function based on the substs at the callsite.
-    Promoted(Promoted, SubstsRef<'tcx>),
-    Static,
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(RustcEncodable, RustcDecodable, HashStable)]
 pub enum ProjectionElem<V, T> {
@@ -1791,14 +1748,14 @@ pub struct Field {
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct PlaceRef<'a, 'tcx> {
-    pub base: &'a PlaceBase<'tcx>,
+    pub local: &'a Local,
     pub projection: &'a [PlaceElem<'tcx>],
 }
 
 impl<'tcx> Place<'tcx> {
     // FIXME change this to a const fn by also making List::empty a const fn.
     pub fn return_place() -> Place<'tcx> {
-        Place { base: PlaceBase::Local(RETURN_PLACE), projection: List::empty() }
+        Place { local: RETURN_PLACE, projection: List::empty() }
     }
 
     /// Returns `true` if this `Place` contains a `Deref` projection.
@@ -1815,10 +1772,8 @@ pub fn is_indirect(&self) -> bool {
     // FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
     pub fn local_or_deref_local(&self) -> Option<Local> {
         match self.as_ref() {
-            PlaceRef { base: &PlaceBase::Local(local), projection: &[] }
-            | PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => {
-                Some(local)
-            }
+            PlaceRef { local, projection: &[] }
+            | PlaceRef { local, projection: &[ProjectionElem::Deref] } => Some(*local),
             _ => None,
         }
     }
@@ -1830,19 +1785,13 @@ pub fn as_local(&self) -> Option<Local> {
     }
 
     pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
-        PlaceRef { base: &self.base, projection: &self.projection }
+        PlaceRef { local: &self.local, projection: &self.projection }
     }
 }
 
 impl From<Local> for Place<'_> {
     fn from(local: Local) -> Self {
-        Place { base: local.into(), projection: List::empty() }
-    }
-}
-
-impl From<Local> for PlaceBase<'_> {
-    fn from(local: Local) -> Self {
-        PlaceBase::Local(local)
+        Place { local, projection: List::empty() }
     }
 }
 
@@ -1853,10 +1802,8 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
     // FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
     pub fn local_or_deref_local(&self) -> Option<Local> {
         match self {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] }
-            | PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] } => {
-                Some(*local)
-            }
+            PlaceRef { local, projection: [] }
+            | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(**local),
             _ => None,
         }
     }
@@ -1865,7 +1812,7 @@ pub fn local_or_deref_local(&self) -> Option<Local> {
     /// projections, return `Some(_X)`.
     pub fn as_local(&self) -> Option<Local> {
         match self {
-            PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l),
+            PlaceRef { local, projection: [] } => Some(**local),
             _ => None,
         }
     }
@@ -1887,7 +1834,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
             }
         }
 
-        write!(fmt, "{:?}", self.base)?;
+        write!(fmt, "{:?}", self.local)?;
 
         for elem in self.projection.iter() {
             match elem {
@@ -1931,22 +1878,6 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
     }
 }
 
-impl Debug for PlaceBase<'_> {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        match *self {
-            PlaceBase::Local(id) => write!(fmt, "{:?}", id),
-            PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static, def_id }) => {
-                write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty)
-            }
-            PlaceBase::Static(box self::Static {
-                ty,
-                kind: StaticKind::Promoted(promoted, _),
-                def_id: _,
-            }) => write!(fmt, "({:?}: {:?})", promoted, ty),
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Scopes
 
@@ -2648,221 +2579,6 @@ pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) ->
     }
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
-pub enum UnsafetyViolationKind {
-    General,
-    /// Permitted both in `const fn`s and regular `fn`s.
-    GeneralAndConstFn,
-    BorrowPacked(hir::HirId),
-}
-
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
-pub struct UnsafetyViolation {
-    pub source_info: SourceInfo,
-    pub description: Symbol,
-    pub details: Symbol,
-    pub kind: UnsafetyViolationKind,
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub struct UnsafetyCheckResult {
-    /// Violations that are propagated *upwards* from this function.
-    pub violations: Lrc<[UnsafetyViolation]>,
-    /// `unsafe` blocks in this function, along with whether they are used. This is
-    /// used for the "unused_unsafe" lint.
-    pub unsafe_blocks: Lrc<[(hir::HirId, bool)]>,
-}
-
-rustc_index::newtype_index! {
-    pub struct GeneratorSavedLocal {
-        derive [HashStable]
-        DEBUG_FORMAT = "_{}",
-    }
-}
-
-/// The layout of generator state.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
-pub struct GeneratorLayout<'tcx> {
-    /// The type of every local stored inside the generator.
-    pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>,
-
-    /// Which of the above fields are in each variant. Note that one field may
-    /// be stored in multiple variants.
-    pub variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>>,
-
-    /// Which saved locals are storage-live at the same time. Locals that do not
-    /// have conflicts with each other are allowed to overlap in the computed
-    /// layout.
-    pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
-}
-
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
-pub struct BorrowCheckResult<'tcx> {
-    pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
-    pub used_mut_upvars: SmallVec<[Field; 8]>,
-}
-
-/// The result of the `mir_const_qualif` query.
-///
-/// Each field corresponds to an implementer of the `Qualif` trait in
-/// `librustc_mir/transform/check_consts/qualifs.rs`. See that file for more information on each
-/// `Qualif`.
-#[derive(Clone, Copy, Debug, Default, RustcEncodable, RustcDecodable, HashStable)]
-pub struct ConstQualifs {
-    pub has_mut_interior: bool,
-    pub needs_drop: bool,
-}
-
-/// After we borrow check a closure, we are left with various
-/// requirements that we have inferred between the free regions that
-/// appear in the closure's signature or on its field types. These
-/// requirements are then verified and proved by the closure's
-/// creating function. This struct encodes those requirements.
-///
-/// The requirements are listed as being between various
-/// `RegionVid`. The 0th region refers to `'static`; subsequent region
-/// vids refer to the free regions that appear in the closure (or
-/// generator's) type, in order of appearance. (This numbering is
-/// actually defined by the `UniversalRegions` struct in the NLL
-/// region checker. See for example
-/// `UniversalRegions::closure_mapping`.) Note that we treat the free
-/// regions in the closure's type "as if" they were erased, so their
-/// precise identity is not important, only their position.
-///
-/// Example: If type check produces a closure with the closure substs:
-///
-/// ```text
-/// ClosureSubsts = [
-///     i8,                                  // the "closure kind"
-///     for<'x> fn(&'a &'x u32) -> &'x u32,  // the "closure signature"
-///     &'a String,                          // some upvar
-/// ]
-/// ```
-///
-/// here, there is one unique free region (`'a`) but it appears
-/// twice. We would "renumber" each occurrence to a unique vid, as follows:
-///
-/// ```text
-/// ClosureSubsts = [
-///     i8,                                  // the "closure kind"
-///     for<'x> fn(&'1 &'x u32) -> &'x u32,  // the "closure signature"
-///     &'2 String,                          // some upvar
-/// ]
-/// ```
-///
-/// Now the code might impose a requirement like `'1: '2`. When an
-/// instance of the closure is created, the corresponding free regions
-/// can be extracted from its type and constrained to have the given
-/// outlives relationship.
-///
-/// In some cases, we have to record outlives requirements between
-/// types and regions as well. In that case, if those types include
-/// any regions, those regions are recorded as `ReClosureBound`
-/// instances assigned one of these same indices. Those regions will
-/// be substituted away by the creator. We use `ReClosureBound` in
-/// that case because the regions must be allocated in the global
-/// `TyCtxt`, and hence we cannot use `ReVar` (which is what we use
-/// internally within the rest of the NLL code).
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
-pub struct ClosureRegionRequirements<'tcx> {
-    /// The number of external regions defined on the closure. In our
-    /// example above, it would be 3 -- one for `'static`, then `'1`
-    /// and `'2`. This is just used for a sanity check later on, to
-    /// make sure that the number of regions we see at the callsite
-    /// matches.
-    pub num_external_vids: usize,
-
-    /// Requirements between the various free regions defined in
-    /// indices.
-    pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
-}
-
-/// Indicates an outlives-constraint between a type or between two
-/// free regions declared on the closure.
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
-pub struct ClosureOutlivesRequirement<'tcx> {
-    // This region or type ...
-    pub subject: ClosureOutlivesSubject<'tcx>,
-
-    // ... must outlive this one.
-    pub outlived_free_region: ty::RegionVid,
-
-    // If not, report an error here ...
-    pub blame_span: Span,
-
-    // ... due to this reason.
-    pub category: ConstraintCategory,
-}
-
-/// Outlives-constraints can be categorized to determine whether and why they
-/// are interesting (for error reporting). Order of variants indicates sort
-/// order of the category, thereby influencing diagnostic output.
-///
-/// See also [rustc_mir::borrow_check::nll::constraints].
-#[derive(
-    Copy,
-    Clone,
-    Debug,
-    Eq,
-    PartialEq,
-    PartialOrd,
-    Ord,
-    Hash,
-    RustcEncodable,
-    RustcDecodable,
-    HashStable
-)]
-pub enum ConstraintCategory {
-    Return,
-    Yield,
-    UseAsConst,
-    UseAsStatic,
-    TypeAnnotation,
-    Cast,
-
-    /// A constraint that came from checking the body of a closure.
-    ///
-    /// We try to get the category that the closure used when reporting this.
-    ClosureBounds,
-    CallArgument,
-    CopyBound,
-    SizedBound,
-    Assignment,
-    OpaqueType,
-
-    /// A "boring" constraint (caused by the given location) is one that
-    /// the user probably doesn't want to see described in diagnostics,
-    /// because it is kind of an artifact of the type system setup.
-    /// Example: `x = Foo { field: y }` technically creates
-    /// intermediate regions representing the "type of `Foo { field: y
-    /// }`", and data flows from `y` into those variables, but they
-    /// are not very interesting. The assignment into `x` on the other
-    /// hand might be.
-    Boring,
-    // Boring and applicable everywhere.
-    BoringNoLocation,
-
-    /// A constraint that doesn't correspond to anything the user sees.
-    Internal,
-}
-
-/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
-/// that must outlive some region.
-#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
-pub enum ClosureOutlivesSubject<'tcx> {
-    /// Subject is a type, typically a type parameter, but could also
-    /// be a projection. Indicates a requirement like `T: 'a` being
-    /// passed to the caller, where the type here is `T`.
-    ///
-    /// The type here is guaranteed not to contain any free regions at
-    /// present.
-    Ty(Ty<'tcx>),
-
-    /// Subject is a free region from the closure. Indicates a requirement
-    /// like `'a: 'b` being passed to the caller; the region here is `'a`.
-    Region(ty::RegionVid),
-}
-
 /*
  * `TypeFoldable` implementations for MIR types
 */
@@ -3007,27 +2723,11 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
 
 impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Place { base: self.base.fold_with(folder), projection: self.projection.fold_with(folder) }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.base.visit_with(visitor) || self.projection.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match self {
-            PlaceBase::Local(local) => PlaceBase::Local(local.fold_with(folder)),
-            PlaceBase::Static(static_) => PlaceBase::Static(static_.fold_with(folder)),
-        }
+        Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match self {
-            PlaceBase::Local(local) => local.visit_with(visitor),
-            PlaceBase::Static(static_) => (**static_).visit_with(visitor),
-        }
+        self.local.visit_with(visitor) || self.projection.visit_with(visitor)
     }
 }
 
@@ -3042,42 +2742,6 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Static {
-            ty: self.ty.fold_with(folder),
-            kind: self.kind.fold_with(folder),
-            def_id: self.def_id,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        let Static { ty, kind, def_id: _ } = self;
-
-        ty.visit_with(visitor) || kind.visit_with(visitor)
-    }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for StaticKind<'tcx> {
-    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match self {
-            StaticKind::Promoted(promoted, substs) => {
-                StaticKind::Promoted(promoted.fold_with(folder), substs.fold_with(folder))
-            }
-            StaticKind::Static => StaticKind::Static,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        match self {
-            StaticKind::Promoted(promoted, substs) => {
-                promoted.visit_with(visitor) || substs.visit_with(visitor)
-            }
-            StaticKind::Static => false,
-        }
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         use crate::mir::Rvalue::*;
diff --git a/src/librustc/mir/query.rs b/src/librustc/mir/query.rs
new file mode 100644 (file)
index 0000000..34f58ab
--- /dev/null
@@ -0,0 +1,223 @@
+//! Values computed by queries that use MIR.
+
+use crate::ty::{self, Ty};
+use rustc_data_structures::sync::Lrc;
+use rustc_hir as hir;
+use rustc_index::bit_set::BitMatrix;
+use rustc_index::vec::IndexVec;
+use rustc_span::{Span, Symbol};
+use rustc_target::abi::VariantIdx;
+use smallvec::SmallVec;
+
+use super::{Field, SourceInfo};
+
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+pub enum UnsafetyViolationKind {
+    General,
+    /// Permitted both in `const fn`s and regular `fn`s.
+    GeneralAndConstFn,
+    BorrowPacked(hir::HirId),
+}
+
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
+pub struct UnsafetyViolation {
+    pub source_info: SourceInfo,
+    pub description: Symbol,
+    pub details: Symbol,
+    pub kind: UnsafetyViolationKind,
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
+pub struct UnsafetyCheckResult {
+    /// Violations that are propagated *upwards* from this function.
+    pub violations: Lrc<[UnsafetyViolation]>,
+    /// `unsafe` blocks in this function, along with whether they are used. This is
+    /// used for the "unused_unsafe" lint.
+    pub unsafe_blocks: Lrc<[(hir::HirId, bool)]>,
+}
+
+rustc_index::newtype_index! {
+    pub struct GeneratorSavedLocal {
+        derive [HashStable]
+        DEBUG_FORMAT = "_{}",
+    }
+}
+
+/// The layout of generator state.
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+pub struct GeneratorLayout<'tcx> {
+    /// The type of every local stored inside the generator.
+    pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>,
+
+    /// Which of the above fields are in each variant. Note that one field may
+    /// be stored in multiple variants.
+    pub variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>>,
+
+    /// Which saved locals are storage-live at the same time. Locals that do not
+    /// have conflicts with each other are allowed to overlap in the computed
+    /// layout.
+    pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
+}
+
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+pub struct BorrowCheckResult<'tcx> {
+    pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
+    pub used_mut_upvars: SmallVec<[Field; 8]>,
+}
+
+/// The result of the `mir_const_qualif` query.
+///
+/// Each field corresponds to an implementer of the `Qualif` trait in
+/// `librustc_mir/transform/check_consts/qualifs.rs`. See that file for more information on each
+/// `Qualif`.
+#[derive(Clone, Copy, Debug, Default, RustcEncodable, RustcDecodable, HashStable)]
+pub struct ConstQualifs {
+    pub has_mut_interior: bool,
+    pub needs_drop: bool,
+}
+
+/// After we borrow check a closure, we are left with various
+/// requirements that we have inferred between the free regions that
+/// appear in the closure's signature or on its field types. These
+/// requirements are then verified and proved by the closure's
+/// creating function. This struct encodes those requirements.
+///
+/// The requirements are listed as being between various
+/// `RegionVid`. The 0th region refers to `'static`; subsequent region
+/// vids refer to the free regions that appear in the closure (or
+/// generator's) type, in order of appearance. (This numbering is
+/// actually defined by the `UniversalRegions` struct in the NLL
+/// region checker. See for example
+/// `UniversalRegions::closure_mapping`.) Note that we treat the free
+/// regions in the closure's type "as if" they were erased, so their
+/// precise identity is not important, only their position.
+///
+/// Example: If type check produces a closure with the closure substs:
+///
+/// ```text
+/// ClosureSubsts = [
+///     i8,                                  // the "closure kind"
+///     for<'x> fn(&'a &'x u32) -> &'x u32,  // the "closure signature"
+///     &'a String,                          // some upvar
+/// ]
+/// ```
+///
+/// here, there is one unique free region (`'a`) but it appears
+/// twice. We would "renumber" each occurrence to a unique vid, as follows:
+///
+/// ```text
+/// ClosureSubsts = [
+///     i8,                                  // the "closure kind"
+///     for<'x> fn(&'1 &'x u32) -> &'x u32,  // the "closure signature"
+///     &'2 String,                          // some upvar
+/// ]
+/// ```
+///
+/// Now the code might impose a requirement like `'1: '2`. When an
+/// instance of the closure is created, the corresponding free regions
+/// can be extracted from its type and constrained to have the given
+/// outlives relationship.
+///
+/// In some cases, we have to record outlives requirements between
+/// types and regions as well. In that case, if those types include
+/// any regions, those regions are recorded as `ReClosureBound`
+/// instances assigned one of these same indices. Those regions will
+/// be substituted away by the creator. We use `ReClosureBound` in
+/// that case because the regions must be allocated in the global
+/// `TyCtxt`, and hence we cannot use `ReVar` (which is what we use
+/// internally within the rest of the NLL code).
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+pub struct ClosureRegionRequirements<'tcx> {
+    /// The number of external regions defined on the closure. In our
+    /// example above, it would be 3 -- one for `'static`, then `'1`
+    /// and `'2`. This is just used for a sanity check later on, to
+    /// make sure that the number of regions we see at the callsite
+    /// matches.
+    pub num_external_vids: usize,
+
+    /// Requirements between the various free regions defined in
+    /// indices.
+    pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
+}
+
+/// Indicates an outlives-constraint between a type or between two
+/// free regions declared on the closure.
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+pub struct ClosureOutlivesRequirement<'tcx> {
+    // This region or type ...
+    pub subject: ClosureOutlivesSubject<'tcx>,
+
+    // ... must outlive this one.
+    pub outlived_free_region: ty::RegionVid,
+
+    // If not, report an error here ...
+    pub blame_span: Span,
+
+    // ... due to this reason.
+    pub category: ConstraintCategory,
+}
+
+/// Outlives-constraints can be categorized to determine whether and why they
+/// are interesting (for error reporting). Order of variants indicates sort
+/// order of the category, thereby influencing diagnostic output.
+///
+/// See also [rustc_mir::borrow_check::nll::constraints].
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
+#[derive(RustcEncodable, RustcDecodable, HashStable)]
+pub enum ConstraintCategory {
+    Return,
+    Yield,
+    UseAsConst,
+    UseAsStatic,
+    TypeAnnotation,
+    Cast,
+
+    /// A constraint that came from checking the body of a closure.
+    ///
+    /// We try to get the category that the closure used when reporting this.
+    ClosureBounds,
+    CallArgument,
+    CopyBound,
+    SizedBound,
+    Assignment,
+    OpaqueType,
+
+    /// A "boring" constraint (caused by the given location) is one that
+    /// the user probably doesn't want to see described in diagnostics,
+    /// because it is kind of an artifact of the type system setup.
+    /// Example: `x = Foo { field: y }` technically creates
+    /// intermediate regions representing the "type of `Foo { field: y
+    /// }`", and data flows from `y` into those variables, but they
+    /// are not very interesting. The assignment into `x` on the other
+    /// hand might be.
+    Boring,
+    // Boring and applicable everywhere.
+    BoringNoLocation,
+
+    /// A constraint that doesn't correspond to anything the user sees.
+    Internal,
+}
+
+/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
+/// that must outlive some region.
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
+pub enum ClosureOutlivesSubject<'tcx> {
+    /// Subject is a type, typically a type parameter, but could also
+    /// be a projection. Indicates a requirement like `T: 'a` being
+    /// passed to the caller, where the type here is `T`.
+    ///
+    /// The type here is guaranteed not to contain any free regions at
+    /// present.
+    Ty(Ty<'tcx>),
+
+    /// Subject is a free region from the closure. Indicates a requirement
+    /// like `'a: 'b` being passed to the caller; the region here is `'a`.
+    Region(ty::RegionVid),
+}
+
+/// The constituent parts of an ADT or array.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct DestructuredConst<'tcx> {
+    pub variant: VariantIdx,
+    pub fields: &'tcx [&'tcx ty::Const<'tcx>],
+}
index 77f3ff47ff2475946a7a4a1a324fc06a0ea5b70f..e2aac562cc4ccf9ef81482b263e37f30ce8688e3 100644 (file)
@@ -114,7 +114,7 @@ pub fn projection_ty_core<V, T>(
 
 impl<'tcx> Place<'tcx> {
     pub fn ty_from<D>(
-        base: &PlaceBase<'tcx>,
+        local: &Local,
         projection: &[PlaceElem<'tcx>],
         local_decls: &D,
         tcx: TyCtxt<'tcx>,
@@ -124,26 +124,16 @@ pub fn ty_from<D>(
     {
         projection
             .iter()
-            .fold(base.ty(local_decls), |place_ty, elem| place_ty.projection_ty(tcx, elem))
+            .fold(PlaceTy::from_ty(local_decls.local_decls()[*local].ty), |place_ty, elem| {
+                place_ty.projection_ty(tcx, elem)
+            })
     }
 
     pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
     where
         D: HasLocalDecls<'tcx>,
     {
-        Place::ty_from(&self.base, &self.projection, local_decls, tcx)
-    }
-}
-
-impl<'tcx> PlaceBase<'tcx> {
-    pub fn ty<D>(&self, local_decls: &D) -> PlaceTy<'tcx>
-    where
-        D: HasLocalDecls<'tcx>,
-    {
-        match self {
-            PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty),
-            PlaceBase::Static(data) => PlaceTy::from_ty(data.ty),
-        }
+        Place::ty_from(&self.local, &self.projection, local_decls, tcx)
     }
 }
 
index 9173c328006411cda989ebe0f3d2d0bd22da4b4a..4c5db1b07d225d783e49c97b765698bb5bf96f1f 100644 (file)
@@ -164,10 +164,10 @@ fn visit_place(&mut self,
             }
 
             fn visit_place_base(&mut self,
-                                base: & $($mutability)? PlaceBase<'tcx>,
+                                local: & $($mutability)? Local,
                                 context: PlaceContext,
                                 location: Location) {
-                self.super_place_base(base, context, location);
+                self.super_place_base(local, context, location);
             }
 
             visit_place_fns!($($mutability)?);
@@ -705,17 +705,10 @@ fn super_retag(&mut self,
             }
 
             fn super_place_base(&mut self,
-                                place_base: & $($mutability)? PlaceBase<'tcx>,
+                                local: & $($mutability)? Local,
                                 context: PlaceContext,
                                 location: Location) {
-                match place_base {
-                    PlaceBase::Local(local) => {
-                        self.visit_local(local, context, location);
-                    }
-                    PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => {
-                        self.visit_ty(& $($mutability)? *ty, TyContext::Location(location));
-                    }
-                }
+                self.visit_local(local, context, location);
             }
 
             fn super_local_decl(&mut self,
@@ -848,7 +841,7 @@ fn super_place(
             context: PlaceContext,
             location: Location,
         ) {
-            self.visit_place_base(&mut place.base, context, location);
+            self.visit_place_base(&mut place.local, context, location);
 
             if let Some(new_projection) = self.process_projection(&place.projection) {
                 place.projection = self.tcx().intern_place_elems(&new_projection);
@@ -889,23 +882,23 @@ fn process_projection_elem(
     () => (
         fn visit_projection(
             &mut self,
-            base: &PlaceBase<'tcx>,
+            local: &Local,
             projection: &[PlaceElem<'tcx>],
             context: PlaceContext,
             location: Location,
         ) {
-            self.super_projection(base, projection, context, location);
+            self.super_projection(local, projection, context, location);
         }
 
         fn visit_projection_elem(
             &mut self,
-            base: &PlaceBase<'tcx>,
+            local: &Local,
             proj_base: &[PlaceElem<'tcx>],
             elem: &PlaceElem<'tcx>,
             context: PlaceContext,
             location: Location,
         ) {
-            self.super_projection_elem(base, proj_base, elem, context, location);
+            self.super_projection_elem(local, proj_base, elem, context, location);
         }
 
         fn super_place(
@@ -924,9 +917,9 @@ fn super_place(
                 };
             }
 
-            self.visit_place_base(&place.base, context, location);
+            self.visit_place_base(&place.local, context, location);
 
-            self.visit_projection(&place.base,
+            self.visit_projection(&place.local,
                                   &place.projection,
                                   context,
                                   location);
@@ -934,7 +927,7 @@ fn super_place(
 
         fn super_projection(
             &mut self,
-            base: &PlaceBase<'tcx>,
+            local: &Local,
             projection: &[PlaceElem<'tcx>],
             context: PlaceContext,
             location: Location,
@@ -942,13 +935,13 @@ fn super_projection(
             let mut cursor = projection;
             while let [proj_base @ .., elem] = cursor {
                 cursor = proj_base;
-                self.visit_projection_elem(base, cursor, elem, context, location);
+                self.visit_projection_elem(local, cursor, elem, context, location);
             }
         }
 
         fn super_projection_elem(
             &mut self,
-            _base: &PlaceBase<'tcx>,
+            _local: &Local,
             _proj_base: &[PlaceElem<'tcx>],
             elem: &PlaceElem<'tcx>,
             _context: PlaceContext,
index 4a2ec9b9687f39590be5ca7f104a3dc85b7efe0b..50ef115da2c4219e4e76d8c8bc20441cce3d44b5 100644 (file)
@@ -82,7 +82,7 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
             desc { "looking up the native libraries of a linked crate" }
         }
 
-        query lint_levels(_: CrateNum) -> &'tcx lint::LintLevelMap {
+        query lint_levels(_: CrateNum) -> &'tcx LintLevelMap {
             eval_always
             desc { "computing the lint levels for items in this crate" }
         }
@@ -505,6 +505,15 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
             desc { "extract field of const" }
         }
 
+        /// Destructure a constant ADT or array into its variant indent and its
+        /// field values.
+        query destructure_const(
+            key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
+        ) -> mir::DestructuredConst<'tcx> {
+            no_force
+            desc { "destructure constant" }
+        }
+
         query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> &'tcx ty::Const<'tcx> {
             no_force
             desc { "get a &core::panic::Location referring to a span" }
@@ -686,10 +695,6 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
             fatal_cycle
             desc { "checking if the crate has_panic_handler" }
         }
-        query is_sanitizer_runtime(_: CrateNum) -> bool {
-            fatal_cycle
-            desc { "query a crate is `#![sanitizer_runtime]`" }
-        }
         query is_profiler_runtime(_: CrateNum) -> bool {
             fatal_cycle
             desc { "query a crate is `#![profiler_runtime]`" }
index 8bd3f3141d53d6b963e0579cb3dff0cd4f212ffc..8a264a79fb6c27cc8d82861e9cd323c640315c88 100644 (file)
@@ -8,7 +8,6 @@
     FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable,
 };
 use crate::ty::fold::TypeFoldable;
-use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::{self, TyCtxt};
 
 /// Attempts to resolve an obligation to a vtable. The result is
@@ -76,31 +75,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
     })
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    /// Monomorphizes a type from the AST by first applying the
-    /// in-scope substitutions and then normalizing any associated
-    /// types.
-    pub fn subst_and_normalize_erasing_regions<T>(
-        self,
-        param_substs: SubstsRef<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        value: &T,
-    ) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        debug!(
-            "subst_and_normalize_erasing_regions(\
-             param_substs={:?}, \
-             value={:?}, \
-             param_env={:?})",
-            param_substs, value, param_env,
-        );
-        let substituted = value.subst(self, param_substs);
-        self.normalize_erasing_regions(param_env, substituted)
-    }
-}
-
 // # Global Cache
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
index db7cda3b95bb2fb2c52b81b789be9a21131f1c32..29ea47809a077a8240a1b9113539f35a8f978881 100644 (file)
@@ -38,7 +38,7 @@ pub struct OverlapResult<'tcx> {
     pub involves_placeholder: bool,
 }
 
-pub fn add_placeholder_note(err: &mut errors::DiagnosticBuilder<'_>) {
+pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) {
     err.note(&format!(
         "this behavior recently changed as a result of a bug fix; \
          see rust-lang/rust#56105 for details"
index b5030f3efe9caf8a95f94e093d4862908a611333..0c9a73d78a5ebe184290243e052fa6acb2f87b95 100644 (file)
@@ -6,11 +6,12 @@
     TraitNotObjectSafe,
 };
 
-use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode;
+use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{self, InferCtxt};
 use crate::mir::interpret::ErrorHandled;
 use crate::session::DiagnosticMessageId;
+use crate::traits::object_safety_violations;
 use crate::ty::error::ExpectedFound;
 use crate::ty::fast_reject;
 use crate::ty::fold::TypeFolder;
@@ -19,8 +20,9 @@
 use crate::ty::SubtypePredicate;
 use crate::ty::TypeckTables;
 use crate::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
-use errors::{pluralize, Applicability, DiagnosticBuilder, Style};
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::Node;
@@ -444,7 +446,7 @@ fn on_unimplemented_note(
                 flags.push((sym::from_method, Some(method.to_string())));
             }
         }
-        if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
+        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
             flags.push((sym::parent_trait, Some(t)));
         }
 
@@ -663,13 +665,21 @@ pub fn report_extra_impl_obligation(
     }
 
     /// Gets the parent trait chain start
-    fn get_parent_trait_ref(&self, code: &ObligationCauseCode<'tcx>) -> Option<String> {
+    fn get_parent_trait_ref(
+        &self,
+        code: &ObligationCauseCode<'tcx>,
+    ) -> Option<(String, Option<Span>)> {
         match code {
             &ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
                 let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
                 match self.get_parent_trait_ref(&data.parent_code) {
                     Some(t) => Some(t),
-                    None => Some(parent_trait_ref.skip_binder().self_ty().to_string()),
+                    None => {
+                        let ty = parent_trait_ref.skip_binder().self_ty();
+                        let span =
+                            TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
+                        Some((ty.to_string(), span))
+                    }
                 }
             }
             _ => None,
@@ -717,9 +727,15 @@ pub fn report_selection_error(
                             return;
                         }
                         let trait_ref = trait_predicate.to_poly_trait_ref();
-                        let (post_message, pre_message) = self
+                        let (post_message, pre_message, type_def) = self
                             .get_parent_trait_ref(&obligation.cause.code)
-                            .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
+                            .map(|(t, s)| {
+                                (
+                                    format!(" in `{}`", t),
+                                    format!("within `{}`, ", t),
+                                    s.map(|s| (format!("within this `{}`", t), s)),
+                                )
+                            })
                             .unwrap_or_default();
 
                         let OnUnimplementedNote { message, label, note, enclosing_scope } =
@@ -793,6 +809,9 @@ pub fn report_selection_error(
                         } else {
                             err.span_label(span, explanation);
                         }
+                        if let Some((msg, span)) = type_def {
+                            err.span_label(span, &msg);
+                        }
                         if let Some(ref s) = note {
                             // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
                             err.note(s.as_str());
@@ -915,8 +934,8 @@ pub fn report_selection_error(
                     }
 
                     ty::Predicate::ObjectSafe(trait_def_id) => {
-                        let violations = self.tcx.object_safety_violations(trait_def_id);
-                        self.tcx.report_object_safety_error(span, trait_def_id, violations)
+                        let violations = object_safety_violations(self.tcx, trait_def_id);
+                        report_object_safety_error(self.tcx, span, trait_def_id, violations)
                     }
 
                     ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
@@ -1079,8 +1098,8 @@ pub fn report_selection_error(
             }
 
             TraitNotObjectSafe(did) => {
-                let violations = self.tcx.object_safety_violations(did);
-                self.tcx.report_object_safety_error(span, did, violations)
+                let violations = object_safety_violations(self.tcx, did);
+                report_object_safety_error(self.tcx, span, did, violations)
             }
 
             // already reported in the query
@@ -1945,64 +1964,62 @@ fn build_fn_sig_string<'tcx>(tcx: TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>)
     }
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn recursive_type_with_infinite_size_error(
-        self,
-        type_def_id: DefId,
-    ) -> DiagnosticBuilder<'tcx> {
-        assert!(type_def_id.is_local());
-        let span = self.hir().span_if_local(type_def_id).unwrap();
-        let span = self.sess.source_map().def_span(span);
-        let mut err = struct_span_err!(
-            self.sess,
-            span,
-            E0072,
-            "recursive type `{}` has infinite size",
-            self.def_path_str(type_def_id)
-        );
-        err.span_label(span, "recursive type has infinite size");
-        err.help(&format!(
-            "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
+pub fn recursive_type_with_infinite_size_error(
+    tcx: TyCtxt<'tcx>,
+    type_def_id: DefId,
+) -> DiagnosticBuilder<'tcx> {
+    assert!(type_def_id.is_local());
+    let span = tcx.hir().span_if_local(type_def_id).unwrap();
+    let span = tcx.sess.source_map().def_span(span);
+    let mut err = struct_span_err!(
+        tcx.sess,
+        span,
+        E0072,
+        "recursive type `{}` has infinite size",
+        tcx.def_path_str(type_def_id)
+    );
+    err.span_label(span, "recursive type has infinite size");
+    err.help(&format!(
+        "insert indirection (e.g., a `Box`, `Rc`, or `&`) \
                            at some point to make `{}` representable",
-            self.def_path_str(type_def_id)
-        ));
-        err
-    }
-
-    pub fn report_object_safety_error(
-        self,
-        span: Span,
-        trait_def_id: DefId,
-        violations: Vec<ObjectSafetyViolation>,
-    ) -> DiagnosticBuilder<'tcx> {
-        let trait_str = self.def_path_str(trait_def_id);
-        let span = self.sess.source_map().def_span(span);
-        let mut err = struct_span_err!(
-            self.sess,
-            span,
-            E0038,
-            "the trait `{}` cannot be made into an object",
-            trait_str
-        );
-        err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
-
-        let mut reported_violations = FxHashSet::default();
-        for violation in violations {
-            if reported_violations.insert(violation.clone()) {
-                match violation.span() {
-                    Some(span) => err.span_label(span, violation.error_msg()),
-                    None => err.note(&violation.error_msg()),
-                };
-            }
-        }
+        tcx.def_path_str(type_def_id)
+    ));
+    err
+}
 
-        if self.sess.trait_methods_not_found.borrow().contains(&span) {
-            // Avoid emitting error caused by non-existing method (#58734)
-            err.cancel();
+pub fn report_object_safety_error(
+    tcx: TyCtxt<'tcx>,
+    span: Span,
+    trait_def_id: DefId,
+    violations: Vec<ObjectSafetyViolation>,
+) -> DiagnosticBuilder<'tcx> {
+    let trait_str = tcx.def_path_str(trait_def_id);
+    let span = tcx.sess.source_map().def_span(span);
+    let mut err = struct_span_err!(
+        tcx.sess,
+        span,
+        E0038,
+        "the trait `{}` cannot be made into an object",
+        trait_str
+    );
+    err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
+
+    let mut reported_violations = FxHashSet::default();
+    for violation in violations {
+        if reported_violations.insert(violation.clone()) {
+            match violation.span() {
+                Some(span) => err.span_label(span, violation.error_msg()),
+                None => err.note(&violation.error_msg()),
+            };
         }
+    }
 
-        err
+    if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
+        // Avoid emitting error caused by non-existing method (#58734)
+        err.cancel();
     }
+
+    err
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -2075,7 +2092,12 @@ fn maybe_report_ambiguity(
                 }
                 let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283);
                 err.note(&format!("cannot resolve `{}`", predicate));
-                if let (Ok(ref snippet), ObligationCauseCode::BindingObligation(ref def_id, _)) =
+                if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
+                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
+                } else if let (
+                    Ok(ref snippet),
+                    ObligationCauseCode::BindingObligation(ref def_id, _),
+                ) =
                     (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code)
                 {
                     let generics = self.tcx.generics_of(*def_id);
@@ -2173,6 +2195,30 @@ fn maybe_report_ambiguity(
         err.emit();
     }
 
+    fn suggest_fully_qualified_path(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        def_id: DefId,
+        span: Span,
+        trait_ref: DefId,
+    ) {
+        if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) {
+            if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
+                err.note(&format!(
+                    "{}s cannot be accessed directly on a `trait`, they can only be \
+                        accessed through a specific `impl`",
+                    assoc_item.kind.suggestion_descr(),
+                ));
+                err.span_suggestion(
+                    span,
+                    "use the fully qualified path to an implementation",
+                    format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident),
+                    Applicability::HasPlaceholders,
+                );
+            }
+        }
+    }
+
     /// Returns `true` if the trait predicate may apply for *some* assignment
     /// to the type parameters.
     fn predicate_can_apply(
index 614375287ba6effd4d89777ede2395984cefb6ed..46ece6fc4059364039f0d72d885d6411476a39b3 100644 (file)
@@ -9,6 +9,7 @@
 use super::engine::{TraitEngine, TraitEngineExt};
 use super::project;
 use super::select::SelectionContext;
+use super::wf;
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
 use super::CodeSelectionError;
@@ -461,7 +462,7 @@ fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
             }
 
             ty::Predicate::WellFormed(ty) => {
-                match ty::wf::obligations(
+                match wf::obligations(
                     self.selcx.infcx(),
                     obligation.param_env,
                     obligation.cause.body_id,
@@ -514,6 +515,7 @@ fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
                             obligation.param_env,
                             def_id,
                             substs,
+                            None,
                             Some(obligation.cause.span),
                         ) {
                             Ok(_) => ProcessResult::Changed(vec![]),
diff --git a/src/librustc/traits/misc.rs b/src/librustc/traits/misc.rs
new file mode 100644 (file)
index 0000000..08c3a77
--- /dev/null
@@ -0,0 +1,202 @@
+//! Miscellaneous type-system utilities that are too small to deserve their own modules.
+
+use crate::middle::lang_items;
+use crate::traits::{self, ObligationCause};
+use crate::ty::util::NeedsDrop;
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+
+use rustc_hir as hir;
+use rustc_span::DUMMY_SP;
+
+#[derive(Clone)]
+pub enum CopyImplementationError<'tcx> {
+    InfrigingFields(Vec<&'tcx ty::FieldDef>),
+    NotAnAdt,
+    HasDestructor,
+}
+
+pub fn can_type_implement_copy(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    self_type: Ty<'tcx>,
+) -> Result<(), CopyImplementationError<'tcx>> {
+    // FIXME: (@jroesch) float this code up
+    tcx.infer_ctxt().enter(|infcx| {
+        let (adt, substs) = match self_type.kind {
+            // These types used to have a builtin impl.
+            // Now libcore provides that impl.
+            ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::Char
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
+
+            ty::Adt(adt, substs) => (adt, substs),
+
+            _ => return Err(CopyImplementationError::NotAnAdt),
+        };
+
+        let mut infringing = Vec::new();
+        for variant in &adt.variants {
+            for field in &variant.fields {
+                let ty = field.ty(tcx, substs);
+                if ty.references_error() {
+                    continue;
+                }
+                let span = tcx.def_span(field.did);
+                let cause = ObligationCause { span, ..ObligationCause::dummy() };
+                let ctx = traits::FulfillmentContext::new();
+                match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) {
+                    Ok(ty) => {
+                        if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
+                            infringing.push(field);
+                        }
+                    }
+                    Err(errors) => {
+                        infcx.report_fulfillment_errors(&errors, None, false);
+                    }
+                };
+            }
+        }
+        if !infringing.is_empty() {
+            return Err(CopyImplementationError::InfrigingFields(infringing));
+        }
+        if adt.has_dtor(tcx) {
+            return Err(CopyImplementationError::HasDestructor);
+        }
+
+        Ok(())
+    })
+}
+
+fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
+}
+
+fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
+}
+
+fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+    is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
+}
+
+fn is_item_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    item: lang_items::LangItem,
+) -> bool {
+    let (param_env, ty) = query.into_parts();
+    let trait_def_id = tcx.require_lang_item(item, None);
+    tcx.infer_ctxt().enter(|infcx| {
+        traits::type_known_to_meet_bound_modulo_regions(
+            &infcx,
+            param_env,
+            ty,
+            trait_def_id,
+            DUMMY_SP,
+        )
+    })
+}
+
+fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
+    let (param_env, ty) = query.into_parts();
+
+    let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
+
+    assert!(!ty.needs_infer());
+
+    NeedsDrop(match ty.kind {
+        // Fast-path for primitive types
+        ty::Infer(ty::FreshIntTy(_))
+        | ty::Infer(ty::FreshFloatTy(_))
+        | ty::Bool
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Never
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Char
+        | ty::GeneratorWitness(..)
+        | ty::RawPtr(_)
+        | ty::Ref(..)
+        | ty::Str => false,
+
+        // Foreign types can never have destructors
+        ty::Foreign(..) => false,
+
+        // `ManuallyDrop` doesn't have a destructor regardless of field types.
+        ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
+
+        // Issue #22536: We first query `is_copy_modulo_regions`.  It sees a
+        // normalized version of the type, and therefore will definitely
+        // know whether the type implements Copy (and thus needs no
+        // cleanup/drop/zeroing) ...
+        _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
+
+        // ... (issue #22536 continued) but as an optimization, still use
+        // prior logic of asking for the structural "may drop".
+
+        // FIXME(#22815): Note that this is a conservative heuristic;
+        // it may report that the type "may drop" when actual type does
+        // not actually have a destructor associated with it. But since
+        // the type absolutely did not have the `Copy` bound attached
+        // (see above), it is sound to treat it as having a destructor.
+
+        // User destructors are the only way to have concrete drop types.
+        ty::Adt(def, _) if def.has_dtor(tcx) => true,
+
+        // Can refer to a type which may drop.
+        // FIXME(eddyb) check this against a ParamEnv.
+        ty::Dynamic(..)
+        | ty::Projection(..)
+        | ty::Param(_)
+        | ty::Bound(..)
+        | ty::Placeholder(..)
+        | ty::Opaque(..)
+        | ty::Infer(_)
+        | ty::Error => true,
+
+        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
+        // Zero-length arrays never contain anything to drop.
+        ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
+
+        // Structural recursion.
+        ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
+
+        ty::Closure(def_id, ref substs) => {
+            substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
+        }
+
+        // Pessimistically assume that all generators will require destructors
+        // as we don't know if a destructor is a noop or not until after the MIR
+        // state transformation pass
+        ty::Generator(..) => true,
+
+        ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
+
+        // unions don't have destructors because of the child types,
+        // only if they manually implement `Drop` (handled above).
+        ty::Adt(def, _) if def.is_union() => false,
+
+        ty::Adt(def, substs) => def
+            .variants
+            .iter()
+            .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
+    })
+}
+
+pub fn provide(providers: &mut ty::query::Providers<'_>) {
+    *providers = ty::query::Providers {
+        is_copy_raw,
+        is_sized_raw,
+        is_freeze_raw,
+        needs_drop_raw,
+        ..*providers
+    };
+}
index 3ba673d1a7d499c59d21cbdc25e7c7aed3dbdfc4..2d3160dc3e51a430b03bcbcad748f04f4294679a 100644 (file)
@@ -10,6 +10,7 @@
 mod engine;
 pub mod error_reporting;
 mod fulfill;
+pub mod misc;
 mod object_safety;
 mod on_unimplemented;
 mod project;
@@ -17,7 +18,9 @@
 mod select;
 mod specialize;
 mod structural_impls;
+mod structural_match;
 mod util;
+pub mod wf;
 
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::{InferCtxt, SuppressRegionErrors};
@@ -47,6 +50,9 @@
 pub use self::coherence::{OrphanCheckErr, OverlapResult};
 pub use self::engine::{TraitEngine, TraitEngineExt};
 pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
+pub use self::object_safety::astconv_object_safety_violations;
+pub use self::object_safety::is_vtable_safe_method;
+pub use self::object_safety::object_safety_violations;
 pub use self::object_safety::MethodViolationCode;
 pub use self::object_safety::ObjectSafetyViolation;
 pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
 pub use self::specialize::specialization_graph::FutureCompatOverlapError;
 pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
+pub use self::structural_match::search_for_structural_match_violation;
+pub use self::structural_match::type_marked_structural;
+pub use self::structural_match::NonStructuralMatchTy;
 pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
 pub use self::util::{expand_trait_aliases, TraitAliasExpander};
+pub use self::util::{
+    get_vtable_index_of_object_method, impl_is_default, impl_item_is_final,
+    predicate_for_trait_def, upcast_choices,
+};
 pub use self::util::{
     supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
 };
@@ -1062,7 +1075,7 @@ fn vtable_methods<'tcx>(
             let def_id = trait_method.def_id;
 
             // Some methods cannot be called on an object; skip those.
-            if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
+            if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
                 debug!("vtable_methods: not vtable safe");
                 return None;
             }
@@ -1231,6 +1244,7 @@ fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
 }
 
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
+    misc::provide(providers);
     *providers = ty::query::Providers {
         is_object_safe: object_safety::is_object_safe_provider,
         specialization_graph_of: specialize::specialization_graph_provider,
index 836e67cff8b2caba51f10d4c65c4f6496408c2ad..ce57fb8110496036f86b0109aa636336a5f04f61 100644 (file)
 
 use super::elaborate_predicates;
 
-use crate::lint;
 use crate::traits::{self, Obligation, ObligationCause};
 use crate::ty::subst::{InternalSubsts, Subst};
 use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
+use syntax::ast;
+
 use std::borrow::Cow;
 use std::iter::{self};
-use syntax::ast::{self};
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum ObjectSafetyViolation {
@@ -108,614 +109,620 @@ pub enum MethodViolationCode {
     UndispatchableReceiver,
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    /// Returns the object safety violations that affect
-    /// astconv -- currently, `Self` in supertraits. This is needed
-    /// because `object_safety_violations` can't be used during
-    /// type collection.
-    pub fn astconv_object_safety_violations(
-        self,
-        trait_def_id: DefId,
-    ) -> Vec<ObjectSafetyViolation> {
-        debug_assert!(self.generics_of(trait_def_id).has_self);
-        let violations = traits::supertrait_def_ids(self, trait_def_id)
-            .filter(|&def_id| self.predicates_reference_self(def_id, true))
-            .map(|_| ObjectSafetyViolation::SupertraitSelf)
-            .collect();
-
-        debug!(
-            "astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
-            trait_def_id, violations
-        );
+/// Returns the object safety violations that affect
+/// astconv -- currently, `Self` in supertraits. This is needed
+/// because `object_safety_violations` can't be used during
+/// type collection.
+pub fn astconv_object_safety_violations(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+    debug_assert!(tcx.generics_of(trait_def_id).has_self);
+    let violations = traits::supertrait_def_ids(tcx, trait_def_id)
+        .filter(|&def_id| predicates_reference_self(tcx, def_id, true))
+        .map(|_| ObjectSafetyViolation::SupertraitSelf)
+        .collect();
+
+    debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations);
+
+    violations
+}
 
-        violations
-    }
+pub fn object_safety_violations(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+    debug_assert!(tcx.generics_of(trait_def_id).has_self);
+    debug!("object_safety_violations: {:?}", trait_def_id);
 
-    pub fn object_safety_violations(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
-        debug_assert!(self.generics_of(trait_def_id).has_self);
-        debug!("object_safety_violations: {:?}", trait_def_id);
+    traits::supertrait_def_ids(tcx, trait_def_id)
+        .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id))
+        .collect()
+}
 
-        traits::supertrait_def_ids(self, trait_def_id)
-            .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
-            .collect()
+/// We say a method is *vtable safe* if it can be invoked on a trait
+/// object. Note that object-safe traits can have some
+/// non-vtable-safe methods, so long as they require `Self: Sized` or
+/// otherwise ensure that they cannot be used when `Self = Trait`.
+pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
+    debug_assert!(tcx.generics_of(trait_def_id).has_self);
+    debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
+    // Any method that has a `Self: Sized` bound cannot be called.
+    if generics_require_sized_self(tcx, method.def_id) {
+        return false;
     }
 
-    /// We say a method is *vtable safe* if it can be invoked on a trait
-    /// object. Note that object-safe traits can have some
-    /// non-vtable-safe methods, so long as they require `Self: Sized` or
-    /// otherwise ensure that they cannot be used when `Self = Trait`.
-    pub fn is_vtable_safe_method(self, trait_def_id: DefId, method: &ty::AssocItem) -> bool {
-        debug_assert!(self.generics_of(trait_def_id).has_self);
-        debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
-        // Any method that has a `Self: Sized` bound cannot be called.
-        if self.generics_require_sized_self(method.def_id) {
-            return false;
-        }
-
-        match self.virtual_call_violation_for_method(trait_def_id, method) {
-            None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
-            Some(_) => false,
-        }
+    match virtual_call_violation_for_method(tcx, trait_def_id, method) {
+        None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
+        Some(_) => false,
     }
+}
 
-    fn object_safety_violations_for_trait(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
-        // Check methods for violations.
-        let mut violations: Vec<_> = self
-            .associated_items(trait_def_id)
-            .filter(|item| item.kind == ty::AssocKind::Method)
-            .filter_map(|item| {
-                self.object_safety_violation_for_method(trait_def_id, &item).map(|code| {
-                    ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span)
-                })
-            })
-            .filter(|violation| {
-                if let ObjectSafetyViolation::Method(
-                    _,
-                    MethodViolationCode::WhereClauseReferencesSelf,
-                    span,
-                ) = violation
-                {
-                    // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
-                    // It's also hard to get a use site span, so we use the method definition span.
-                    self.lint_node_note(
-                        lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
-                        hir::CRATE_HIR_ID,
-                        *span,
-                        &format!(
-                            "the trait `{}` cannot be made into an object",
-                            self.def_path_str(trait_def_id)
-                        ),
-                        &violation.error_msg(),
-                    );
-                    false
-                } else {
-                    true
-                }
-            })
-            .collect();
-
-        // Check the trait itself.
-        if self.trait_has_sized_self(trait_def_id) {
-            violations.push(ObjectSafetyViolation::SizedSelf);
-        }
-        if self.predicates_reference_self(trait_def_id, false) {
-            violations.push(ObjectSafetyViolation::SupertraitSelf);
-        }
-
-        violations.extend(
-            self.associated_items(trait_def_id)
-                .filter(|item| item.kind == ty::AssocKind::Const)
-                .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
-        );
-
-        debug!(
-            "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
-            trait_def_id, violations
-        );
+fn object_safety_violations_for_trait(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+    // Check methods for violations.
+    let mut violations: Vec<_> = tcx
+        .associated_items(trait_def_id)
+        .filter(|item| item.kind == ty::AssocKind::Method)
+        .filter_map(|item| {
+            object_safety_violation_for_method(tcx, trait_def_id, &item)
+                .map(|code| ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span))
+        })
+        .filter(|violation| {
+            if let ObjectSafetyViolation::Method(
+                _,
+                MethodViolationCode::WhereClauseReferencesSelf,
+                span,
+            ) = violation
+            {
+                // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
+                // It's also hard to get a use site span, so we use the method definition span.
+                tcx.struct_span_lint_hir(
+                    WHERE_CLAUSES_OBJECT_SAFETY,
+                    hir::CRATE_HIR_ID,
+                    *span,
+                    &format!(
+                        "the trait `{}` cannot be made into an object",
+                        tcx.def_path_str(trait_def_id)
+                    ),
+                )
+                .note(&violation.error_msg())
+                .emit();
+                false
+            } else {
+                true
+            }
+        })
+        .collect();
 
-        violations
+    // Check the trait itself.
+    if trait_has_sized_self(tcx, trait_def_id) {
+        violations.push(ObjectSafetyViolation::SizedSelf);
     }
-
-    fn predicates_reference_self(self, trait_def_id: DefId, supertraits_only: bool) -> bool {
-        let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id));
-        let predicates = if supertraits_only {
-            self.super_predicates_of(trait_def_id)
-        } else {
-            self.predicates_of(trait_def_id)
-        };
-        let self_ty = self.types.self_param;
-        let has_self_ty = |t: Ty<'tcx>| t.walk().any(|t| t == self_ty);
-        predicates
-            .predicates
-            .iter()
-            .map(|(predicate, _)| predicate.subst_supertrait(self, &trait_ref))
-            .any(|predicate| {
-                match predicate {
-                    ty::Predicate::Trait(ref data) => {
-                        // In the case of a trait predicate, we can skip the "self" type.
-                        data.skip_binder().input_types().skip(1).any(has_self_ty)
-                    }
-                    ty::Predicate::Projection(ref data) => {
-                        // And similarly for projections. This should be redundant with
-                        // the previous check because any projection should have a
-                        // matching `Trait` predicate with the same inputs, but we do
-                        // the check to be safe.
-                        //
-                        // Note that we *do* allow projection *outputs* to contain
-                        // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
-                        // we just require the user to specify *both* outputs
-                        // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
-                        //
-                        // This is ALT2 in issue #56288, see that for discussion of the
-                        // possible alternatives.
-                        data.skip_binder()
-                            .projection_ty
-                            .trait_ref(self)
-                            .input_types()
-                            .skip(1)
-                            .any(has_self_ty)
-                    }
-                    ty::Predicate::WellFormed(..)
-                    | ty::Predicate::ObjectSafe(..)
-                    | ty::Predicate::TypeOutlives(..)
-                    | ty::Predicate::RegionOutlives(..)
-                    | ty::Predicate::ClosureKind(..)
-                    | ty::Predicate::Subtype(..)
-                    | ty::Predicate::ConstEvaluatable(..) => false,
-                }
-            })
+    if predicates_reference_self(tcx, trait_def_id, false) {
+        violations.push(ObjectSafetyViolation::SupertraitSelf);
     }
 
-    fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
-        self.generics_require_sized_self(trait_def_id)
-    }
+    violations.extend(
+        tcx.associated_items(trait_def_id)
+            .filter(|item| item.kind == ty::AssocKind::Const)
+            .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
+    );
 
-    fn generics_require_sized_self(self, def_id: DefId) -> bool {
-        let sized_def_id = match self.lang_items().sized_trait() {
-            Some(def_id) => def_id,
-            None => {
-                return false; /* No Sized trait, can't require it! */
-            }
-        };
+    debug!(
+        "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
+        trait_def_id, violations
+    );
 
-        // Search for a predicate like `Self : Sized` amongst the trait bounds.
-        let predicates = self.predicates_of(def_id);
-        let predicates = predicates.instantiate_identity(self).predicates;
-        elaborate_predicates(self, predicates).any(|predicate| match predicate {
-            ty::Predicate::Trait(ref trait_pred) => {
-                trait_pred.def_id() == sized_def_id
-                    && trait_pred.skip_binder().self_ty().is_param(0)
+    violations
+}
+
+fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool {
+    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
+    let predicates = if supertraits_only {
+        tcx.super_predicates_of(trait_def_id)
+    } else {
+        tcx.predicates_of(trait_def_id)
+    };
+    let self_ty = tcx.types.self_param;
+    let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty);
+    predicates
+        .predicates
+        .iter()
+        .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref))
+        .any(|predicate| {
+            match predicate {
+                ty::Predicate::Trait(ref data) => {
+                    // In the case of a trait predicate, we can skip the "self" type.
+                    data.skip_binder().input_types().skip(1).any(has_self_ty)
+                }
+                ty::Predicate::Projection(ref data) => {
+                    // And similarly for projections. This should be redundant with
+                    // the previous check because any projection should have a
+                    // matching `Trait` predicate with the same inputs, but we do
+                    // the check to be safe.
+                    //
+                    // Note that we *do* allow projection *outputs* to contain
+                    // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
+                    // we just require the user to specify *both* outputs
+                    // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
+                    //
+                    // This is ALT2 in issue #56288, see that for discussion of the
+                    // possible alternatives.
+                    data.skip_binder()
+                        .projection_ty
+                        .trait_ref(tcx)
+                        .input_types()
+                        .skip(1)
+                        .any(has_self_ty)
+                }
+                ty::Predicate::WellFormed(..)
+                | ty::Predicate::ObjectSafe(..)
+                | ty::Predicate::TypeOutlives(..)
+                | ty::Predicate::RegionOutlives(..)
+                | ty::Predicate::ClosureKind(..)
+                | ty::Predicate::Subtype(..)
+                | ty::Predicate::ConstEvaluatable(..) => false,
             }
-            ty::Predicate::Projection(..)
-            | ty::Predicate::Subtype(..)
-            | ty::Predicate::RegionOutlives(..)
-            | ty::Predicate::WellFormed(..)
-            | ty::Predicate::ObjectSafe(..)
-            | ty::Predicate::ClosureKind(..)
-            | ty::Predicate::TypeOutlives(..)
-            | ty::Predicate::ConstEvaluatable(..) => false,
         })
-    }
+}
+
+fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
+    generics_require_sized_self(tcx, trait_def_id)
+}
 
-    /// Returns `Some(_)` if this method makes the containing trait not object safe.
-    fn object_safety_violation_for_method(
-        self,
-        trait_def_id: DefId,
-        method: &ty::AssocItem,
-    ) -> Option<MethodViolationCode> {
-        debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
-        // Any method that has a `Self : Sized` requisite is otherwise
-        // exempt from the regulations.
-        if self.generics_require_sized_self(method.def_id) {
-            return None;
+fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    let sized_def_id = match tcx.lang_items().sized_trait() {
+        Some(def_id) => def_id,
+        None => {
+            return false; /* No Sized trait, can't require it! */
+        }
+    };
+
+    // Search for a predicate like `Self : Sized` amongst the trait bounds.
+    let predicates = tcx.predicates_of(def_id);
+    let predicates = predicates.instantiate_identity(tcx).predicates;
+    elaborate_predicates(tcx, predicates).any(|predicate| match predicate {
+        ty::Predicate::Trait(ref trait_pred) => {
+            trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0)
         }
+        ty::Predicate::Projection(..)
+        | ty::Predicate::Subtype(..)
+        | ty::Predicate::RegionOutlives(..)
+        | ty::Predicate::WellFormed(..)
+        | ty::Predicate::ObjectSafe(..)
+        | ty::Predicate::ClosureKind(..)
+        | ty::Predicate::TypeOutlives(..)
+        | ty::Predicate::ConstEvaluatable(..) => false,
+    })
+}
 
-        self.virtual_call_violation_for_method(trait_def_id, method)
+/// Returns `Some(_)` if this method makes the containing trait not object safe.
+fn object_safety_violation_for_method(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+    method: &ty::AssocItem,
+) -> Option<MethodViolationCode> {
+    debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
+    // Any method that has a `Self : Sized` requisite is otherwise
+    // exempt from the regulations.
+    if generics_require_sized_self(tcx, method.def_id) {
+        return None;
     }
 
-    /// Returns `Some(_)` if this method cannot be called on a trait
-    /// object; this does not necessarily imply that the enclosing trait
-    /// is not object safe, because the method might have a where clause
-    /// `Self:Sized`.
-    fn virtual_call_violation_for_method(
-        self,
-        trait_def_id: DefId,
-        method: &ty::AssocItem,
-    ) -> Option<MethodViolationCode> {
-        // The method's first parameter must be named `self`
-        if !method.method_has_self_argument {
-            return Some(MethodViolationCode::StaticMethod);
-        }
+    virtual_call_violation_for_method(tcx, trait_def_id, method)
+}
 
-        let sig = self.fn_sig(method.def_id);
+/// Returns `Some(_)` if this method cannot be called on a trait
+/// object; this does not necessarily imply that the enclosing trait
+/// is not object safe, because the method might have a where clause
+/// `Self:Sized`.
+fn virtual_call_violation_for_method<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    method: &ty::AssocItem,
+) -> Option<MethodViolationCode> {
+    // The method's first parameter must be named `self`
+    if !method.method_has_self_argument {
+        return Some(MethodViolationCode::StaticMethod);
+    }
 
-        for input_ty in &sig.skip_binder().inputs()[1..] {
-            if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
-                return Some(MethodViolationCode::ReferencesSelf);
-            }
-        }
-        if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
+    let sig = tcx.fn_sig(method.def_id);
+
+    for input_ty in &sig.skip_binder().inputs()[1..] {
+        if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
             return Some(MethodViolationCode::ReferencesSelf);
         }
+    }
+    if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) {
+        return Some(MethodViolationCode::ReferencesSelf);
+    }
 
-        // We can't monomorphize things like `fn foo<A>(...)`.
-        let own_counts = self.generics_of(method.def_id).own_counts();
-        if own_counts.types + own_counts.consts != 0 {
-            return Some(MethodViolationCode::Generic);
-        }
+    // We can't monomorphize things like `fn foo<A>(...)`.
+    let own_counts = tcx.generics_of(method.def_id).own_counts();
+    if own_counts.types + own_counts.consts != 0 {
+        return Some(MethodViolationCode::Generic);
+    }
 
-        if self
-            .predicates_of(method.def_id)
-            .predicates
-            .iter()
-            // A trait object can't claim to live more than the concrete type,
-            // so outlives predicates will always hold.
-            .cloned()
-            .filter(|(p, _)| p.to_opt_type_outlives().is_none())
-            .collect::<Vec<_>>()
-            // Do a shallow visit so that `contains_illegal_self_type_reference`
-            // may apply it's custom visiting.
-            .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t))
-        {
-            return Some(MethodViolationCode::WhereClauseReferencesSelf);
-        }
+    if tcx
+        .predicates_of(method.def_id)
+        .predicates
+        .iter()
+        // A trait object can't claim to live more than the concrete type,
+        // so outlives predicates will always hold.
+        .cloned()
+        .filter(|(p, _)| p.to_opt_type_outlives().is_none())
+        .collect::<Vec<_>>()
+        // Do a shallow visit so that `contains_illegal_self_type_reference`
+        // may apply it's custom visiting.
+        .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t))
+    {
+        return Some(MethodViolationCode::WhereClauseReferencesSelf);
+    }
 
-        let receiver_ty =
-            self.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0]));
+    let receiver_ty =
+        tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0]));
 
-        // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
-        // However, this is already considered object-safe. We allow it as a special case here.
-        // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
-        // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
-        if receiver_ty != self.types.self_param {
-            if !self.receiver_is_dispatchable(method, receiver_ty) {
-                return Some(MethodViolationCode::UndispatchableReceiver);
-            } else {
-                // Do sanity check to make sure the receiver actually has the layout of a pointer.
+    // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
+    // However, this is already considered object-safe. We allow it as a special case here.
+    // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
+    // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
+    if receiver_ty != tcx.types.self_param {
+        if !receiver_is_dispatchable(tcx, method, receiver_ty) {
+            return Some(MethodViolationCode::UndispatchableReceiver);
+        } else {
+            // Do sanity check to make sure the receiver actually has the layout of a pointer.
 
-                use crate::ty::layout::Abi;
+            use crate::ty::layout::Abi;
 
-                let param_env = self.param_env(method.def_id);
+            let param_env = tcx.param_env(method.def_id);
 
-                let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
-                    match self.layout_of(param_env.and(ty)) {
-                        Ok(layout) => &layout.abi,
-                        Err(err) => {
-                            bug!("error: {}\n while computing layout for type {:?}", err, ty)
-                        }
-                    }
-                };
-
-                // e.g., `Rc<()>`
-                let unit_receiver_ty =
-                    self.receiver_for_self_ty(receiver_ty, self.mk_unit(), method.def_id);
-
-                match abi_of_ty(unit_receiver_ty) {
-                    &Abi::Scalar(..) => (),
-                    abi => {
-                        self.sess.delay_span_bug(
-                            self.def_span(method.def_id),
-                            &format!(
-                                "receiver when `Self = ()` should have a Scalar ABI; found {:?}",
-                                abi
-                            ),
-                        );
-                    }
+            let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
+                match tcx.layout_of(param_env.and(ty)) {
+                    Ok(layout) => &layout.abi,
+                    Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty),
                 }
+            };
 
-                let trait_object_ty =
-                    self.object_ty_for_trait(trait_def_id, self.mk_region(ty::ReStatic));
+            // e.g., `Rc<()>`
+            let unit_receiver_ty =
+                receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id);
 
-                // e.g., `Rc<dyn Trait>`
-                let trait_object_receiver =
-                    self.receiver_for_self_ty(receiver_ty, trait_object_ty, method.def_id);
+            match abi_of_ty(unit_receiver_ty) {
+                &Abi::Scalar(..) => (),
+                abi => {
+                    tcx.sess.delay_span_bug(
+                        tcx.def_span(method.def_id),
+                        &format!(
+                            "receiver when `Self = ()` should have a Scalar ABI; found {:?}",
+                            abi
+                        ),
+                    );
+                }
+            }
 
-                match abi_of_ty(trait_object_receiver) {
-                    &Abi::ScalarPair(..) => (),
-                    abi => {
-                        self.sess.delay_span_bug(
-                            self.def_span(method.def_id),
-                            &format!(
-                                "receiver when `Self = {}` should have a ScalarPair ABI; \
+            let trait_object_ty =
+                object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic));
+
+            // e.g., `Rc<dyn Trait>`
+            let trait_object_receiver =
+                receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id);
+
+            match abi_of_ty(trait_object_receiver) {
+                &Abi::ScalarPair(..) => (),
+                abi => {
+                    tcx.sess.delay_span_bug(
+                        tcx.def_span(method.def_id),
+                        &format!(
+                            "receiver when `Self = {}` should have a ScalarPair ABI; \
                                  found {:?}",
-                                trait_object_ty, abi
-                            ),
-                        );
-                    }
+                            trait_object_ty, abi
+                        ),
+                    );
                 }
             }
         }
-
-        None
     }
 
-    /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
-    /// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
-    fn receiver_for_self_ty(
-        self,
-        receiver_ty: Ty<'tcx>,
-        self_ty: Ty<'tcx>,
-        method_def_id: DefId,
-    ) -> Ty<'tcx> {
-        debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
-        let substs = InternalSubsts::for_item(self, method_def_id, |param, _| {
-            if param.index == 0 { self_ty.into() } else { self.mk_param_from_def(param) }
-        });
-
-        let result = receiver_ty.subst(self, substs);
-        debug!(
-            "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
-            receiver_ty, self_ty, method_def_id, result
-        );
-        result
-    }
+    None
+}
 
-    /// Creates the object type for the current trait. For example,
-    /// if the current trait is `Deref`, then this will be
-    /// `dyn Deref<Target = Self::Target> + 'static`.
-    fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> Ty<'tcx> {
-        debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
-
-        let trait_ref = ty::TraitRef::identity(self, trait_def_id);
-
-        let trait_predicate = ty::ExistentialPredicate::Trait(
-            ty::ExistentialTraitRef::erase_self_ty(self, trait_ref),
-        );
-
-        let mut associated_types = traits::supertraits(self, ty::Binder::dummy(trait_ref))
-            .flat_map(|super_trait_ref| {
-                self.associated_items(super_trait_ref.def_id())
-                    .map(move |item| (super_trait_ref, item))
-            })
-            .filter(|(_, item)| item.kind == ty::AssocKind::Type)
-            .collect::<Vec<_>>();
-
-        // existential predicates need to be in a specific order
-        associated_types.sort_by_cached_key(|(_, item)| self.def_path_hash(item.def_id));
-
-        let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
-            // We *can* get bound lifetimes here in cases like
-            // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
-            //
-            // binder moved to (*)...
-            let super_trait_ref = super_trait_ref.skip_binder();
-            ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                ty: self.mk_projection(item.def_id, super_trait_ref.substs),
-                item_def_id: item.def_id,
-                substs: super_trait_ref.substs,
-            })
-        });
-
-        let existential_predicates = self
-            .mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
-
-        let object_ty = self.mk_dynamic(
-            // (*) ... binder re-introduced here
-            ty::Binder::bind(existential_predicates),
-            lifetime,
-        );
-
-        debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
-
-        object_ty
-    }
+/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
+/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
+fn receiver_for_self_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    receiver_ty: Ty<'tcx>,
+    self_ty: Ty<'tcx>,
+    method_def_id: DefId,
+) -> Ty<'tcx> {
+    debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
+    let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| {
+        if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
+    });
+
+    let result = receiver_ty.subst(tcx, substs);
+    debug!(
+        "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
+        receiver_ty, self_ty, method_def_id, result
+    );
+    result
+}
 
-    /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
-    /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
-    /// in the following way:
-    /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
-    /// - require the following bound:
-    ///
-    ///   ```
-    ///   Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
-    ///   ```
-    ///
-    ///   where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
-    ///   (substitution notation).
-    ///
-    /// Some examples of receiver types and their required obligation:
-    /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
-    /// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
-    /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
-    ///
-    /// The only case where the receiver is not dispatchable, but is still a valid receiver
-    /// type (just not object-safe), is when there is more than one level of pointer indirection.
-    /// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
-    /// is no way, or at least no inexpensive way, to coerce the receiver from the version where
-    /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
-    /// contained by the trait object, because the object that needs to be coerced is behind
-    /// a pointer.
-    ///
-    /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
-    /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
-    /// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
-    /// Instead, we fudge a little by introducing a new type parameter `U` such that
-    /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
-    /// Written as a chalk-style query:
-    ///
-    ///     forall (U: Trait + ?Sized) {
-    ///         if (Self: Unsize<U>) {
-    ///             Receiver: DispatchFromDyn<Receiver[Self => U]>
-    ///         }
-    ///     }
-    ///
-    /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
-    /// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
-    /// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
-    //
-    // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
-    // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
-    // `self: Wrapper<Self>`.
-    #[allow(dead_code)]
-    fn receiver_is_dispatchable(self, method: &ty::AssocItem, receiver_ty: Ty<'tcx>) -> bool {
-        debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
-
-        let traits =
-            (self.lang_items().unsize_trait(), self.lang_items().dispatch_from_dyn_trait());
-        let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
-            (u, cu)
-        } else {
-            debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
-            return false;
-        };
+/// Creates the object type for the current trait. For example,
+/// if the current trait is `Deref`, then this will be
+/// `dyn Deref<Target = Self::Target> + 'static`.
+fn object_ty_for_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    lifetime: ty::Region<'tcx>,
+) -> Ty<'tcx> {
+    debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
 
-        // the type `U` in the query
-        // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
-        // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
-        // replace this with `dyn Trait`
-        let unsized_self_ty: Ty<'tcx> =
-            self.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome"));
-
-        // `Receiver[Self => U]`
-        let unsized_receiver_ty =
-            self.receiver_for_self_ty(receiver_ty, unsized_self_ty, method.def_id);
-
-        // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
-        // `U: ?Sized` is already implied here
-        let param_env = {
-            let mut param_env = self.param_env(method.def_id);
-
-            // Self: Unsize<U>
-            let unsize_predicate = ty::TraitRef {
-                def_id: unsize_did,
-                substs: self.mk_substs_trait(self.types.self_param, &[unsized_self_ty.into()]),
-            }
-            .to_predicate();
-
-            // U: Trait<Arg1, ..., ArgN>
-            let trait_predicate = {
-                let substs =
-                    InternalSubsts::for_item(self, method.container.assert_trait(), |param, _| {
-                        if param.index == 0 {
-                            unsized_self_ty.into()
-                        } else {
-                            self.mk_param_from_def(param)
-                        }
-                    });
-
-                ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
-            };
+    let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
 
-            let caller_bounds: Vec<Predicate<'tcx>> = param_env
-                .caller_bounds
-                .iter()
-                .cloned()
-                .chain(iter::once(unsize_predicate))
-                .chain(iter::once(trait_predicate))
-                .collect();
+    let trait_predicate =
+        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
 
-            param_env.caller_bounds = self.intern_predicates(&caller_bounds);
+    let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref))
+        .flat_map(|super_trait_ref| {
+            tcx.associated_items(super_trait_ref.def_id()).map(move |item| (super_trait_ref, item))
+        })
+        .filter(|(_, item)| item.kind == ty::AssocKind::Type)
+        .collect::<Vec<_>>();
 
-            param_env
-        };
+    // existential predicates need to be in a specific order
+    associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
 
-        // Receiver: DispatchFromDyn<Receiver[Self => U]>
-        let obligation = {
-            let predicate = ty::TraitRef {
-                def_id: dispatch_from_dyn_did,
-                substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
-            }
-            .to_predicate();
+    let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
+        // We *can* get bound lifetimes here in cases like
+        // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
+        //
+        // binder moved to (*)...
+        let super_trait_ref = super_trait_ref.skip_binder();
+        ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
+            ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
+            item_def_id: item.def_id,
+            substs: super_trait_ref.substs,
+        })
+    });
 
-            Obligation::new(ObligationCause::dummy(), param_env, predicate)
-        };
+    let existential_predicates =
+        tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
 
-        self.infer_ctxt().enter(|ref infcx| {
-            // the receiver is dispatchable iff the obligation holds
-            infcx.predicate_must_hold_modulo_regions(&obligation)
-        })
-    }
+    let object_ty = tcx.mk_dynamic(
+        // (*) ... binder re-introduced here
+        ty::Binder::bind(existential_predicates),
+        lifetime,
+    );
 
-    fn contains_illegal_self_type_reference(self, trait_def_id: DefId, ty: Ty<'tcx>) -> bool {
-        // This is somewhat subtle. In general, we want to forbid
-        // references to `Self` in the argument and return types,
-        // since the value of `Self` is erased. However, there is one
-        // exception: it is ok to reference `Self` in order to access
-        // an associated type of the current trait, since we retain
-        // the value of those associated types in the object type
-        // itself.
-        //
-        // ```rust
-        // trait SuperTrait {
-        //     type X;
-        // }
-        //
-        // trait Trait : SuperTrait {
-        //     type Y;
-        //     fn foo(&self, x: Self) // bad
-        //     fn foo(&self) -> Self // bad
-        //     fn foo(&self) -> Option<Self> // bad
-        //     fn foo(&self) -> Self::Y // OK, desugars to next example
-        //     fn foo(&self) -> <Self as Trait>::Y // OK
-        //     fn foo(&self) -> Self::X // OK, desugars to next example
-        //     fn foo(&self) -> <Self as SuperTrait>::X // OK
-        // }
-        // ```
-        //
-        // However, it is not as simple as allowing `Self` in a projected
-        // type, because there are illegal ways to use `Self` as well:
-        //
-        // ```rust
-        // trait Trait : SuperTrait {
-        //     ...
-        //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
-        // }
-        // ```
-        //
-        // Here we will not have the type of `X` recorded in the
-        // object type, and we cannot resolve `Self as SomeOtherTrait`
-        // without knowing what `Self` is.
-
-        let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
-        let mut error = false;
-        let self_ty = self.types.self_param;
-        ty.maybe_walk(|ty| {
-            match ty.kind {
-                ty::Param(_) => {
-                    if ty == self_ty {
-                        error = true;
+    debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
+
+    object_ty
+}
+
+/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
+/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
+/// in the following way:
+/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
+/// - require the following bound:
+///
+///   ```
+///   Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
+///   ```
+///
+///   where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
+///   (substitution notation).
+///
+/// Some examples of receiver types and their required obligation:
+/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
+/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
+/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
+///
+/// The only case where the receiver is not dispatchable, but is still a valid receiver
+/// type (just not object-safe), is when there is more than one level of pointer indirection.
+/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
+/// is no way, or at least no inexpensive way, to coerce the receiver from the version where
+/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
+/// contained by the trait object, because the object that needs to be coerced is behind
+/// a pointer.
+///
+/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
+/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
+/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
+/// Instead, we fudge a little by introducing a new type parameter `U` such that
+/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
+/// Written as a chalk-style query:
+///
+///     forall (U: Trait + ?Sized) {
+///         if (Self: Unsize<U>) {
+///             Receiver: DispatchFromDyn<Receiver[Self => U]>
+///         }
+///     }
+///
+/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
+/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
+/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
+//
+// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
+// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
+// `self: Wrapper<Self>`.
+#[allow(dead_code)]
+fn receiver_is_dispatchable<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    method: &ty::AssocItem,
+    receiver_ty: Ty<'tcx>,
+) -> bool {
+    debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
+
+    let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
+    let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
+        (u, cu)
+    } else {
+        debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
+        return false;
+    };
+
+    // the type `U` in the query
+    // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
+    // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
+    // replace this with `dyn Trait`
+    let unsized_self_ty: Ty<'tcx> =
+        tcx.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome"));
+
+    // `Receiver[Self => U]`
+    let unsized_receiver_ty =
+        receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
+
+    // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
+    // `U: ?Sized` is already implied here
+    let param_env = {
+        let mut param_env = tcx.param_env(method.def_id);
+
+        // Self: Unsize<U>
+        let unsize_predicate = ty::TraitRef {
+            def_id: unsize_did,
+            substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
+        }
+        .to_predicate();
+
+        // U: Trait<Arg1, ..., ArgN>
+        let trait_predicate = {
+            let substs =
+                InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| {
+                    if param.index == 0 {
+                        unsized_self_ty.into()
+                    } else {
+                        tcx.mk_param_from_def(param)
                     }
+                });
+
+            ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
+        };
+
+        let caller_bounds: Vec<Predicate<'tcx>> = param_env
+            .caller_bounds
+            .iter()
+            .cloned()
+            .chain(iter::once(unsize_predicate))
+            .chain(iter::once(trait_predicate))
+            .collect();
+
+        param_env.caller_bounds = tcx.intern_predicates(&caller_bounds);
+
+        param_env
+    };
+
+    // Receiver: DispatchFromDyn<Receiver[Self => U]>
+    let obligation = {
+        let predicate = ty::TraitRef {
+            def_id: dispatch_from_dyn_did,
+            substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
+        }
+        .to_predicate();
+
+        Obligation::new(ObligationCause::dummy(), param_env, predicate)
+    };
 
-                    false // no contained types to walk
+    tcx.infer_ctxt().enter(|ref infcx| {
+        // the receiver is dispatchable iff the obligation holds
+        infcx.predicate_must_hold_modulo_regions(&obligation)
+    })
+}
+
+fn contains_illegal_self_type_reference<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def_id: DefId,
+    ty: Ty<'tcx>,
+) -> bool {
+    // This is somewhat subtle. In general, we want to forbid
+    // references to `Self` in the argument and return types,
+    // since the value of `Self` is erased. However, there is one
+    // exception: it is ok to reference `Self` in order to access
+    // an associated type of the current trait, since we retain
+    // the value of those associated types in the object type
+    // itself.
+    //
+    // ```rust
+    // trait SuperTrait {
+    //     type X;
+    // }
+    //
+    // trait Trait : SuperTrait {
+    //     type Y;
+    //     fn foo(&self, x: Self) // bad
+    //     fn foo(&self) -> Self // bad
+    //     fn foo(&self) -> Option<Self> // bad
+    //     fn foo(&self) -> Self::Y // OK, desugars to next example
+    //     fn foo(&self) -> <Self as Trait>::Y // OK
+    //     fn foo(&self) -> Self::X // OK, desugars to next example
+    //     fn foo(&self) -> <Self as SuperTrait>::X // OK
+    // }
+    // ```
+    //
+    // However, it is not as simple as allowing `Self` in a projected
+    // type, because there are illegal ways to use `Self` as well:
+    //
+    // ```rust
+    // trait Trait : SuperTrait {
+    //     ...
+    //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
+    // }
+    // ```
+    //
+    // Here we will not have the type of `X` recorded in the
+    // object type, and we cannot resolve `Self as SomeOtherTrait`
+    // without knowing what `Self` is.
+
+    let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
+    let mut error = false;
+    let self_ty = tcx.types.self_param;
+    ty.maybe_walk(|ty| {
+        match ty.kind {
+            ty::Param(_) => {
+                if ty == self_ty {
+                    error = true;
                 }
 
-                ty::Projection(ref data) => {
-                    // This is a projected type `<Foo as SomeTrait>::X`.
+                false // no contained types to walk
+            }
 
-                    // Compute supertraits of current trait lazily.
-                    if supertraits.is_none() {
-                        let trait_ref =
-                            ty::Binder::bind(ty::TraitRef::identity(self, trait_def_id));
-                        supertraits = Some(traits::supertraits(self, trait_ref).collect());
-                    }
+            ty::Projection(ref data) => {
+                // This is a projected type `<Foo as SomeTrait>::X`.
 
-                    // Determine whether the trait reference `Foo as
-                    // SomeTrait` is in fact a supertrait of the
-                    // current trait. In that case, this type is
-                    // legal, because the type `X` will be specified
-                    // in the object type.  Note that we can just use
-                    // direct equality here because all of these types
-                    // are part of the formal parameter listing, and
-                    // hence there should be no inference variables.
-                    let projection_trait_ref = ty::Binder::bind(data.trait_ref(self));
-                    let is_supertrait_of_current_trait =
-                        supertraits.as_ref().unwrap().contains(&projection_trait_ref);
-
-                    if is_supertrait_of_current_trait {
-                        false // do not walk contained types, do not report error, do collect $200
-                    } else {
-                        true // DO walk contained types, POSSIBLY reporting an error
-                    }
+                // Compute supertraits of current trait lazily.
+                if supertraits.is_none() {
+                    let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id));
+                    supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
                 }
 
-                _ => true, // walk contained types, if any
+                // Determine whether the trait reference `Foo as
+                // SomeTrait` is in fact a supertrait of the
+                // current trait. In that case, this type is
+                // legal, because the type `X` will be specified
+                // in the object type.  Note that we can just use
+                // direct equality here because all of these types
+                // are part of the formal parameter listing, and
+                // hence there should be no inference variables.
+                let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx));
+                let is_supertrait_of_current_trait =
+                    supertraits.as_ref().unwrap().contains(&projection_trait_ref);
+
+                if is_supertrait_of_current_trait {
+                    false // do not walk contained types, do not report error, do collect $200
+                } else {
+                    true // DO walk contained types, POSSIBLY reporting an error
+                }
             }
-        });
 
-        error
-    }
+            _ => true, // walk contained types, if any
+        }
+    });
+
+    error
 }
 
 pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
-    tcx.object_safety_violations(trait_def_id).is_empty()
+    object_safety_violations(tcx, trait_def_id).is_empty()
 }
index 92984b48ae938479f823424d5371465624f5de67..1afe153bb1361937a7f72c4be81b61df8812bee5 100644 (file)
@@ -2,7 +2,9 @@
 
 use crate::ty::{self, GenericParamDefKind, TyCtxt};
 use crate::util::common::ErrorReported;
+
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::struct_span_err;
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
@@ -292,26 +294,28 @@ fn verify(
                         match generics.params.iter().find(|param| param.name == s) {
                             Some(_) => (),
                             None => {
-                                span_err!(
+                                struct_span_err!(
                                     tcx.sess,
                                     span,
                                     E0230,
                                     "there is no parameter `{}` on trait `{}`",
                                     s,
                                     name
-                                );
+                                )
+                                .emit();
                                 result = Err(ErrorReported);
                             }
                         }
                     }
                     // `{:1}` and `{}` are not to be used
                     Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => {
-                        span_err!(
+                        struct_span_err!(
                             tcx.sess,
                             span,
                             E0231,
                             "only named substitution parameters are allowed"
-                        );
+                        )
+                        .emit();
                         result = Err(ErrorReported);
                     }
                 },
index 22bfba37443fd2f111ab3f6890dfb65a84dcaa8b..5bc211ade40ad1d6fd5d5175b8031cf572f26cee 100644 (file)
@@ -17,7 +17,6 @@
 use crate::ty::fold::{TypeFoldable, TypeFolder};
 use crate::ty::subst::{InternalSubsts, Subst};
 use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
-use crate::util::common::FN_OUTPUT_NAME;
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
@@ -1057,7 +1056,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     node_item.item.defaultness.has_value()
                 } else {
                     node_item.item.defaultness.is_default()
-                        || selcx.tcx().impl_is_default(node_item.node.def_id())
+                        || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id())
                 };
 
                 // Only reveal a specializable default if we're past type-checking
@@ -1263,26 +1262,30 @@ fn confirm_generator_candidate<'cx, 'tcx>(
 
     let gen_def_id = tcx.lang_items().gen_trait().unwrap();
 
-    let predicate = tcx
-        .generator_trait_ref_and_outputs(gen_def_id, obligation.predicate.self_ty(), gen_sig)
-        .map_bound(|(trait_ref, yield_ty, return_ty)| {
-            let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
-            let ty = if name == sym::Return {
-                return_ty
-            } else if name == sym::Yield {
-                yield_ty
-            } else {
-                bug!()
-            };
+    let predicate = super::util::generator_trait_ref_and_outputs(
+        tcx,
+        gen_def_id,
+        obligation.predicate.self_ty(),
+        gen_sig,
+    )
+    .map_bound(|(trait_ref, yield_ty, return_ty)| {
+        let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
+        let ty = if name == sym::Return {
+            return_ty
+        } else if name == sym::Yield {
+            yield_ty
+        } else {
+            bug!()
+        };
 
-            ty::ProjectionPredicate {
-                projection_ty: ty::ProjectionTy {
-                    substs: trait_ref.substs,
-                    item_def_id: obligation.predicate.item_def_id,
-                },
-                ty: ty,
-            }
-        });
+        ty::ProjectionPredicate {
+            projection_ty: ty::ProjectionTy {
+                substs: trait_ref.substs,
+                item_def_id: obligation.predicate.item_def_id,
+            },
+            ty: ty,
+        }
+    });
 
     confirm_param_env_candidate(selcx, obligation, predicate)
         .with_addl_obligations(vtable.nested)
@@ -1349,21 +1352,21 @@ fn confirm_callable_candidate<'cx, 'tcx>(
     // the `Output` associated type is declared on `FnOnce`
     let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap();
 
-    let predicate = tcx
-        .closure_trait_ref_and_return_type(
-            fn_once_def_id,
-            obligation.predicate.self_ty(),
-            fn_sig,
-            flag,
-        )
-        .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
-            projection_ty: ty::ProjectionTy::from_ref_and_name(
-                tcx,
-                trait_ref,
-                Ident::with_dummy_span(FN_OUTPUT_NAME),
-            ),
-            ty: ret_type,
-        });
+    let predicate = super::util::closure_trait_ref_and_return_type(
+        tcx,
+        fn_once_def_id,
+        obligation.predicate.self_ty(),
+        fn_sig,
+        flag,
+    )
+    .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
+        projection_ty: ty::ProjectionTy::from_ref_and_name(
+            tcx,
+            trait_ref,
+            Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME),
+        ),
+        ty: ret_type,
+    });
 
     confirm_param_env_candidate(selcx, obligation, predicate)
 }
@@ -1464,7 +1467,7 @@ fn assoc_ty_def(
     // cycle error if the specialization graph is currently being built.
     let impl_node = specialization_graph::Node::Impl(impl_def_id);
     for item in impl_node.items(tcx) {
-        if item.kind == ty::AssocKind::Type
+        if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy)
             && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
         {
             return specialization_graph::NodeItem {
index 87f7f674dab100c0178d542b9a1dce12daef68d5..34866b684de01a9369ed73182edf3c7093732a3f 100644 (file)
@@ -76,15 +76,15 @@ pub struct DropckOutlivesResult<'tcx> {
 impl<'tcx> DropckOutlivesResult<'tcx> {
     pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
         if let Some(overflow_ty) = self.overflows.iter().next() {
-            let mut err = struct_span_err!(
+            rustc_errors::struct_span_err!(
                 tcx.sess,
                 span,
                 E0320,
                 "overflow while adding drop-check rules for {}",
                 ty,
-            );
-            err.note(&format!("overflowed on {}", overflow_ty));
-            err.emit();
+            )
+            .note(&format!("overflowed on {}", overflow_ty))
+            .emit();
         }
     }
 
index fb9f46011b99b3075e0f4a96d1339f96851b1d67..440268aab8fb399629903853ea01b7d7ffaaff63 100644 (file)
@@ -13,7 +13,6 @@
 pub mod evaluate_obligation;
 pub mod method_autoderef;
 pub mod normalize;
-pub mod normalize_erasing_regions;
 pub mod outlives_bounds;
 pub mod type_op;
 
diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs
deleted file mode 100644 (file)
index 2fa52e8..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-//! Methods for normalizing when you don't care about regions (and
-//! aren't doing type inference). If either of those things don't
-//! apply to you, use `infcx.normalize(...)`.
-//!
-//! The methods in this file use a `TypeFolder` to recursively process
-//! contents, invoking the underlying
-//! `normalize_ty_after_erasing_regions` query for each type found
-//! within. (This underlying query is what is cached.)
-
-use crate::ty::fold::{TypeFoldable, TypeFolder};
-use crate::ty::{self, Ty, TyCtxt};
-
-impl<'tcx> TyCtxt<'tcx> {
-    /// Erase the regions in `value` and then fully normalize all the
-    /// types found within. The result will also have regions erased.
-    ///
-    /// This is appropriate to use only after type-check: it assumes
-    /// that normalization will succeed, for example.
-    pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        debug!(
-            "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
-            ::std::any::type_name::<T>(),
-            value,
-            param_env,
-        );
-
-        // Erase first before we do the real query -- this keeps the
-        // cache from being too polluted.
-        let value = self.erase_regions(&value);
-        if !value.has_projections() {
-            value
-        } else {
-            value.fold_with(&mut NormalizeAfterErasingRegionsFolder {
-                tcx: self,
-                param_env: param_env,
-            })
-        }
-    }
-
-    /// If you have a `Binder<T>`, you can do this to strip out the
-    /// late-bound regions and then normalize the result, yielding up
-    /// a `T` (with regions erased). This is appropriate when the
-    /// binder is being instantiated at the call site.
-    ///
-    /// N.B., currently, higher-ranked type bounds inhibit
-    /// normalization. Therefore, each time we erase them in
-    /// codegen, we need to normalize the contents.
-    pub fn normalize_erasing_late_bound_regions<T>(
-        self,
-        param_env: ty::ParamEnv<'tcx>,
-        value: &ty::Binder<T>,
-    ) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        assert!(!value.needs_subst());
-        let value = self.erase_late_bound_regions(value);
-        self.normalize_erasing_regions(param_env, value)
-    }
-}
-
-struct NormalizeAfterErasingRegionsFolder<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
-
-impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty))
-    }
-}
index 94d5723778a9a0791727f2345998b45ebeb553ff..e96697cc7e09d4360581ea9fb4f24b2b5b9a719e 100644 (file)
@@ -11,6 +11,8 @@
 use super::project;
 use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
 use super::util;
+use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
+use super::wf;
 use super::DerivedObligationCause;
 use super::Selection;
 use super::SelectionResult;
@@ -100,7 +102,7 @@ pub enum IntercrateAmbiguityCause {
 impl IntercrateAmbiguityCause {
     /// Emits notes when the overlap is caused by complex intercrate ambiguities.
     /// See #23980 for details.
-    pub fn add_intercrate_ambiguity_hint(&self, err: &mut errors::DiagnosticBuilder<'_>) {
+    pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) {
         err.note(&self.intercrate_ambiguity_hint());
     }
 
@@ -737,7 +739,7 @@ fn evaluate_predicate_recursively<'o>(
                 }
             }
 
-            ty::Predicate::WellFormed(ty) => match ty::wf::obligations(
+            ty::Predicate::WellFormed(ty) => match wf::obligations(
                 self.infcx,
                 obligation.param_env,
                 obligation.cause.body_id,
@@ -800,8 +802,13 @@ fn evaluate_predicate_recursively<'o>(
 
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
                 if !(obligation.param_env, substs).has_local_value() {
-                    match self.tcx().const_eval_resolve(obligation.param_env, def_id, substs, None)
-                    {
+                    match self.tcx().const_eval_resolve(
+                        obligation.param_env,
+                        def_id,
+                        substs,
+                        None,
+                        None,
+                    ) {
                         Ok(_) => Ok(EvaluatedToOk),
                         Err(_) => Ok(EvaluatedToErr),
                     }
@@ -1153,7 +1160,7 @@ fn insert_evaluation_cache(
     /// to have a *lower* recursion_depth than the obligation used to create it.
     /// Projection sub-obligations may be returned from the projection cache,
     /// which results in obligations with an 'old' `recursion_depth`.
-    /// Additionally, methods like `ty::wf::obligations` and
+    /// Additionally, methods like `wf::obligations` and
     /// `InferCtxt.subtype_predicate` produce subobligations without
     /// taking in a 'parent' depth, causing the generated subobligations
     /// to have a `recursion_depth` of `0`.
@@ -2651,7 +2658,8 @@ fn collect_predicates_for_types(
                             recursion_depth,
                             &skol_ty,
                         );
-                    let skol_obligation = self.tcx().predicate_for_trait_def(
+                    let skol_obligation = predicate_for_trait_def(
+                        self.tcx(),
                         param_env,
                         cause.clone(),
                         trait_def_id,
@@ -2988,7 +2996,7 @@ fn confirm_object_candidate(
             // we pass over, we sum up the set of number of vtable
             // entries, so that we can compute the offset for the selected
             // trait.
-            vtable_base = nonmatching.map(|t| tcx.count_own_vtable_entries(t)).sum();
+            vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
         }
 
         VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
@@ -3003,15 +3011,14 @@ fn confirm_fn_pointer_candidate(
         // Okay to skip binder; it is reintroduced below.
         let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
         let sig = self_ty.fn_sig(self.tcx());
-        let trait_ref = self
-            .tcx()
-            .closure_trait_ref_and_return_type(
-                obligation.predicate.def_id(),
-                self_ty,
-                sig,
-                util::TupleArgumentsFlag::Yes,
-            )
-            .map_bound(|(trait_ref, _)| trait_ref);
+        let trait_ref = closure_trait_ref_and_return_type(
+            self.tcx(),
+            obligation.predicate.def_id(),
+            self_ty,
+            sig,
+            util::TupleArgumentsFlag::Yes,
+        )
+        .map_bound(|(trait_ref, _)| trait_ref);
 
         let Normalized { value: trait_ref, obligations } = project::normalize_with_depth(
             self,
@@ -3381,7 +3388,8 @@ fn confirm_builtin_unsize_candidate(
                 nested.extend(obligations);
 
                 // Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
-                nested.push(tcx.predicate_for_trait_def(
+                nested.push(predicate_for_trait_def(
+                    tcx,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.predicate.def_id(),
@@ -3416,7 +3424,8 @@ fn confirm_builtin_unsize_candidate(
                 nested.extend(obligations);
 
                 // Construct the nested `T: Unsize<U>` predicate.
-                nested.push(tcx.predicate_for_trait_def(
+                nested.push(predicate_for_trait_def(
+                    tcx,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.predicate.def_id(),
@@ -3627,14 +3636,14 @@ fn closure_trait_ref_unnormalized(
         // in fact unparameterized (or at least does not reference any
         // regions bound in the obligation). Still probably some
         // refactoring could make this nicer.
-        self.tcx()
-            .closure_trait_ref_and_return_type(
-                obligation.predicate.def_id(),
-                obligation.predicate.skip_binder().self_ty(), // (1)
-                closure_type,
-                util::TupleArgumentsFlag::No,
-            )
-            .map_bound(|(trait_ref, _)| trait_ref)
+        closure_trait_ref_and_return_type(
+            self.tcx(),
+            obligation.predicate.def_id(),
+            obligation.predicate.skip_binder().self_ty(), // (1)
+            closure_type,
+            util::TupleArgumentsFlag::No,
+        )
+        .map_bound(|(trait_ref, _)| trait_ref)
     }
 
     fn generator_trait_ref_unnormalized(
@@ -3651,13 +3660,13 @@ fn generator_trait_ref_unnormalized(
         // regions bound in the obligation). Still probably some
         // refactoring could make this nicer.
 
-        self.tcx()
-            .generator_trait_ref_and_outputs(
-                obligation.predicate.def_id(),
-                obligation.predicate.skip_binder().self_ty(), // (1)
-                gen_sig,
-            )
-            .map_bound(|(trait_ref, ..)| trait_ref)
+        super::util::generator_trait_ref_and_outputs(
+            self.tcx(),
+            obligation.predicate.def_id(),
+            obligation.predicate.skip_binder().self_ty(), // (1)
+            gen_sig,
+        )
+        .map_bound(|(trait_ref, ..)| trait_ref)
     }
 
     /// Returns the obligations that are implied by instantiating an
index 520cd3e38520a1a9f541080d36c8995fcc26fd25..f5199dbdabb2f42534d164b92ef1b4820e33e084 100644 (file)
 pub mod specialization_graph;
 
 use crate::infer::{InferCtxt, InferOk};
-use crate::lint;
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
 use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use crate::ty::{self, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::struct_span_err;
 use rustc_hir::def_id::DefId;
+use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
 use rustc_span::DUMMY_SP;
 
 use super::util::impl_trait_ref_and_oblig;
@@ -341,7 +342,7 @@ pub(super) fn specialization_graph_provider(
                                 unreachable!("converted to hard error above")
                             }
                             FutureCompatOverlapErrorKind::Issue33140 => {
-                                lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS
+                                ORDER_DEPENDENT_TRAIT_OBJECTS
                             }
                         };
                         tcx.struct_span_lint_hir(
diff --git a/src/librustc/traits/structural_match.rs b/src/librustc/traits/structural_match.rs
new file mode 100644 (file)
index 0000000..b2c3c23
--- /dev/null
@@ -0,0 +1,217 @@
+use crate::ty::fold::{TypeFoldable, TypeVisitor};
+use crate::ty::{self, AdtDef, Ty, TyCtxt};
+
+use rustc::infer::InferCtxt;
+use rustc::traits::ObligationCause;
+use rustc::traits::{self, ConstPatternStructural, TraitEngine};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_span::Span;
+
+#[derive(Debug)]
+pub enum NonStructuralMatchTy<'tcx> {
+    Adt(&'tcx AdtDef),
+    Param,
+}
+
+/// This method traverses the structure of `ty`, trying to find an
+/// instance of an ADT (i.e. struct or enum) that was declared without
+/// the `#[structural_match]` attribute, or a generic type parameter
+/// (which cannot be determined to be `structural_match`).
+///
+/// The "structure of a type" includes all components that would be
+/// considered when doing a pattern match on a constant of that
+/// type.
+///
+///  * This means this method descends into fields of structs/enums,
+///    and also descends into the inner type `T` of `&T` and `&mut T`
+///
+///  * The traversal doesn't dereference unsafe pointers (`*const T`,
+///    `*mut T`), and it does not visit the type arguments of an
+///    instantiated generic like `PhantomData<T>`.
+///
+/// The reason we do this search is Rust currently require all ADTs
+/// reachable from a constant's type to be annotated with
+/// `#[structural_match]`, an attribute which essentially says that
+/// the implementation of `PartialEq::eq` behaves *equivalently* to a
+/// comparison against the unfolded structure.
+///
+/// For more background on why Rust has this requirement, and issues
+/// that arose when the requirement was not enforced completely, see
+/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
+pub fn search_for_structural_match_violation<'tcx>(
+    id: hir::HirId,
+    span: Span,
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<NonStructuralMatchTy<'tcx>> {
+    // FIXME: we should instead pass in an `infcx` from the outside.
+    tcx.infer_ctxt().enter(|infcx| {
+        let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
+        ty.visit_with(&mut search);
+        search.found
+    })
+}
+
+/// This method returns true if and only if `adt_ty` itself has been marked as
+/// eligible for structural-match: namely, if it implements both
+/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
+/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
+///
+/// Note that this does *not* recursively check if the substructure of `adt_ty`
+/// implements the traits.
+pub fn type_marked_structural(
+    id: hir::HirId,
+    span: Span,
+    infcx: &InferCtxt<'_, 'tcx>,
+    adt_ty: Ty<'tcx>,
+) -> bool {
+    let mut fulfillment_cx = traits::FulfillmentContext::new();
+    let cause = ObligationCause::new(span, id, ConstPatternStructural);
+    // require `#[derive(PartialEq)]`
+    let structural_peq_def_id = infcx.tcx.lang_items().structural_peq_trait().unwrap();
+    fulfillment_cx.register_bound(
+        infcx,
+        ty::ParamEnv::empty(),
+        adt_ty,
+        structural_peq_def_id,
+        cause,
+    );
+    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
+    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
+    let cause = ObligationCause::new(span, id, ConstPatternStructural);
+    let structural_teq_def_id = infcx.tcx.lang_items().structural_teq_trait().unwrap();
+    fulfillment_cx.register_bound(
+        infcx,
+        ty::ParamEnv::empty(),
+        adt_ty,
+        structural_teq_def_id,
+        cause,
+    );
+
+    // We deliberately skip *reporting* fulfillment errors (via
+    // `report_fulfillment_errors`), for two reasons:
+    //
+    // 1. The error messages would mention `std::marker::StructuralPartialEq`
+    //    (a trait which is solely meant as an implementation detail
+    //    for now), and
+    //
+    // 2. We are sometimes doing future-incompatibility lints for
+    //    now, so we do not want unconditional errors here.
+    fulfillment_cx.select_all_or_error(infcx).is_ok()
+}
+
+/// This implements the traversal over the structure of a given type to try to
+/// find instances of ADTs (specifically structs or enums) that do not implement
+/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
+struct Search<'a, 'tcx> {
+    id: hir::HirId,
+    span: Span,
+
+    infcx: InferCtxt<'a, 'tcx>,
+
+    /// Records first ADT that does not implement a structural-match trait.
+    found: Option<NonStructuralMatchTy<'tcx>>,
+
+    /// Tracks ADTs previously encountered during search, so that
+    /// we will not recur on them again.
+    seen: FxHashSet<hir::def_id::DefId>,
+}
+
+impl Search<'a, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
+        type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
+    }
+}
+
+impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+        debug!("Search visiting ty: {:?}", ty);
+
+        let (adt_def, substs) = match ty.kind {
+            ty::Adt(adt_def, substs) => (adt_def, substs),
+            ty::Param(_) => {
+                self.found = Some(NonStructuralMatchTy::Param);
+                return true; // Stop visiting.
+            }
+            ty::RawPtr(..) => {
+                // structural-match ignores substructure of
+                // `*const _`/`*mut _`, so skip `super_visit_with`.
+                //
+                // For example, if you have:
+                // ```
+                // struct NonStructural;
+                // #[derive(PartialEq, Eq)]
+                // struct T(*const NonStructural);
+                // const C: T = T(std::ptr::null());
+                // ```
+                //
+                // Even though `NonStructural` does not implement `PartialEq`,
+                // structural equality on `T` does not recur into the raw
+                // pointer. Therefore, one can still use `C` in a pattern.
+
+                // (But still tell caller to continue search.)
+                return false;
+            }
+            ty::FnDef(..) | ty::FnPtr(..) => {
+                // types of formals and return in `fn(_) -> _` are also irrelevant;
+                // so we do not recur into them via `super_visit_with`
+                //
+                // (But still tell caller to continue search.)
+                return false;
+            }
+            ty::Array(_, n)
+                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
+            {
+                // rust-lang/rust#62336: ignore type of contents
+                // for empty array.
+                return false;
+            }
+            _ => {
+                ty.super_visit_with(self);
+                return false;
+            }
+        };
+
+        if !self.seen.insert(adt_def.did) {
+            debug!("Search already seen adt_def: {:?}", adt_def);
+            // let caller continue its search
+            return false;
+        }
+
+        if !self.type_marked_structural(ty) {
+            debug!("Search found ty: {:?}", ty);
+            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
+            return true; // Halt visiting!
+        }
+
+        // structural-match does not care about the
+        // instantiation of the generics in an ADT (it
+        // instead looks directly at its fields outside
+        // this match), so we skip super_visit_with.
+        //
+        // (Must not recur on substs for `PhantomData<T>` cf
+        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
+        // want to skip substs when only uses of generic are
+        // behind unsafe pointers `*const T`/`*mut T`.)
+
+        // even though we skip super_visit_with, we must recur on
+        // fields of ADT.
+        let tcx = self.tcx();
+        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
+            if field_ty.visit_with(self) {
+                // found an ADT without structural-match; halt visiting!
+                assert!(self.found.is_some());
+                return true;
+            }
+        }
+
+        // Even though we do not want to recur on substs, we do
+        // want our caller to continue its own search.
+        false
+    }
+}
index 14cfe7cda4e282d86ecd517afa44986adf24d784..65fd809657bd08fec282c73130cc6d86e9a017b0 100644 (file)
@@ -1,4 +1,4 @@
-use errors::DiagnosticBuilder;
+use rustc_errors::DiagnosticBuilder;
 use rustc_span::Span;
 use smallvec::SmallVec;
 
@@ -548,123 +548,121 @@ pub fn predicate_for_trait_ref<'tcx>(
     Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() }
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    pub fn predicate_for_trait_def(
-        self,
-        param_env: ty::ParamEnv<'tcx>,
-        cause: ObligationCause<'tcx>,
-        trait_def_id: DefId,
-        recursion_depth: usize,
-        self_ty: Ty<'tcx>,
-        params: &[GenericArg<'tcx>],
-    ) -> PredicateObligation<'tcx> {
-        let trait_ref =
-            ty::TraitRef { def_id: trait_def_id, substs: self.mk_substs_trait(self_ty, params) };
-        predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
-    }
-
-    /// Casts a trait reference into a reference to one of its super
-    /// traits; returns `None` if `target_trait_def_id` is not a
-    /// supertrait.
-    pub fn upcast_choices(
-        self,
-        source_trait_ref: ty::PolyTraitRef<'tcx>,
-        target_trait_def_id: DefId,
-    ) -> Vec<ty::PolyTraitRef<'tcx>> {
-        if source_trait_ref.def_id() == target_trait_def_id {
-            return vec![source_trait_ref]; // Shortcut the most common case.
-        }
+pub fn predicate_for_trait_def(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    cause: ObligationCause<'tcx>,
+    trait_def_id: DefId,
+    recursion_depth: usize,
+    self_ty: Ty<'tcx>,
+    params: &[GenericArg<'tcx>],
+) -> PredicateObligation<'tcx> {
+    let trait_ref =
+        ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
+    predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
+}
 
-        supertraits(self, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
+/// Casts a trait reference into a reference to one of its super
+/// traits; returns `None` if `target_trait_def_id` is not a
+/// supertrait.
+pub fn upcast_choices(
+    tcx: TyCtxt<'tcx>,
+    source_trait_ref: ty::PolyTraitRef<'tcx>,
+    target_trait_def_id: DefId,
+) -> Vec<ty::PolyTraitRef<'tcx>> {
+    if source_trait_ref.def_id() == target_trait_def_id {
+        return vec![source_trait_ref]; // Shortcut the most common case.
     }
 
-    /// Given a trait `trait_ref`, returns the number of vtable entries
-    /// that come from `trait_ref`, excluding its supertraits. Used in
-    /// computing the vtable base for an upcast trait of a trait object.
-    pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
-        let mut entries = 0;
-        // Count number of methods and add them to the total offset.
-        // Skip over associated types and constants.
-        for trait_item in self.associated_items(trait_ref.def_id()) {
-            if trait_item.kind == ty::AssocKind::Method {
-                entries += 1;
-            }
+    supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
+}
+
+/// Given a trait `trait_ref`, returns the number of vtable entries
+/// that come from `trait_ref`, excluding its supertraits. Used in
+/// computing the vtable base for an upcast trait of a trait object.
+pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
+    let mut entries = 0;
+    // Count number of methods and add them to the total offset.
+    // Skip over associated types and constants.
+    for trait_item in tcx.associated_items(trait_ref.def_id()) {
+        if trait_item.kind == ty::AssocKind::Method {
+            entries += 1;
         }
-        entries
     }
+    entries
+}
 
-    /// Given an upcast trait object described by `object`, returns the
-    /// index of the method `method_def_id` (which should be part of
-    /// `object.upcast_trait_ref`) within the vtable for `object`.
-    pub fn get_vtable_index_of_object_method<N>(
-        self,
-        object: &super::VtableObjectData<'tcx, N>,
-        method_def_id: DefId,
-    ) -> usize {
-        // Count number of methods preceding the one we are selecting and
-        // add them to the total offset.
-        // Skip over associated types and constants.
-        let mut entries = object.vtable_base;
-        for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) {
-            if trait_item.def_id == method_def_id {
-                // The item with the ID we were given really ought to be a method.
-                assert_eq!(trait_item.kind, ty::AssocKind::Method);
-                return entries;
-            }
-            if trait_item.kind == ty::AssocKind::Method {
-                entries += 1;
-            }
+/// Given an upcast trait object described by `object`, returns the
+/// index of the method `method_def_id` (which should be part of
+/// `object.upcast_trait_ref`) within the vtable for `object`.
+pub fn get_vtable_index_of_object_method<N>(
+    tcx: TyCtxt<'tcx>,
+    object: &super::VtableObjectData<'tcx, N>,
+    method_def_id: DefId,
+) -> usize {
+    // Count number of methods preceding the one we are selecting and
+    // add them to the total offset.
+    // Skip over associated types and constants.
+    let mut entries = object.vtable_base;
+    for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()) {
+        if trait_item.def_id == method_def_id {
+            // The item with the ID we were given really ought to be a method.
+            assert_eq!(trait_item.kind, ty::AssocKind::Method);
+            return entries;
+        }
+        if trait_item.kind == ty::AssocKind::Method {
+            entries += 1;
         }
-
-        bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
     }
 
-    pub fn closure_trait_ref_and_return_type(
-        self,
-        fn_trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        sig: ty::PolyFnSig<'tcx>,
-        tuple_arguments: TupleArgumentsFlag,
-    ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
-        let arguments_tuple = match tuple_arguments {
-            TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
-            TupleArgumentsFlag::Yes => self.intern_tup(sig.skip_binder().inputs()),
-        };
-        let trait_ref = ty::TraitRef {
-            def_id: fn_trait_def_id,
-            substs: self.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
-        };
-        ty::Binder::bind((trait_ref, sig.skip_binder().output()))
-    }
+    bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
+}
 
-    pub fn generator_trait_ref_and_outputs(
-        self,
-        fn_trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        sig: ty::PolyGenSig<'tcx>,
-    ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
-        let trait_ref =
-            ty::TraitRef { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[]) };
-        ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
-    }
+pub fn closure_trait_ref_and_return_type(
+    tcx: TyCtxt<'tcx>,
+    fn_trait_def_id: DefId,
+    self_ty: Ty<'tcx>,
+    sig: ty::PolyFnSig<'tcx>,
+    tuple_arguments: TupleArgumentsFlag,
+) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
+    let arguments_tuple = match tuple_arguments {
+        TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
+        TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
+    };
+    let trait_ref = ty::TraitRef {
+        def_id: fn_trait_def_id,
+        substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
+    };
+    ty::Binder::bind((trait_ref, sig.skip_binder().output()))
+}
 
-    pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
-        match self.hir().as_local_hir_id(node_item_def_id) {
-            Some(hir_id) => {
-                let item = self.hir().expect_item(hir_id);
-                if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
-                    defaultness.is_default()
-                } else {
-                    false
-                }
+pub fn generator_trait_ref_and_outputs(
+    tcx: TyCtxt<'tcx>,
+    fn_trait_def_id: DefId,
+    self_ty: Ty<'tcx>,
+    sig: ty::PolyGenSig<'tcx>,
+) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
+    let trait_ref =
+        ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[]) };
+    ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
+}
+
+pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool {
+    match tcx.hir().as_local_hir_id(node_item_def_id) {
+        Some(hir_id) => {
+            let item = tcx.hir().expect_item(hir_id);
+            if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
+                defaultness.is_default()
+            } else {
+                false
             }
-            None => self.impl_defaultness(node_item_def_id).is_default(),
         }
+        None => tcx.impl_defaultness(node_item_def_id).is_default(),
     }
+}
 
-    pub fn impl_item_is_final(self, assoc_item: &ty::AssocItem) -> bool {
-        assoc_item.defaultness.is_final() && !self.impl_is_default(assoc_item.container.id())
-    }
+pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
+    assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id())
 }
 
 pub enum TupleArgumentsFlag {
diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs
new file mode 100644 (file)
index 0000000..2301395
--- /dev/null
@@ -0,0 +1,749 @@
+use crate::infer::opaque_types::required_region_bounds;
+use crate::infer::InferCtxt;
+use crate::middle::lang_items;
+use crate::traits::{self, AssocTypeBoundData};
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::Span;
+use std::iter::once;
+
+/// Returns the set of obligations needed to make `ty` well-formed.
+/// If `ty` contains unresolved inference variables, this may include
+/// further WF obligations. However, if `ty` IS an unresolved
+/// inference variable, returns `None`, because we are not able to
+/// make any progress at all. This is to prevent "livelock" where we
+/// say "$0 is WF if $0 is WF".
+pub fn obligations<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: hir::HirId,
+    ty: Ty<'tcx>,
+    span: Span,
+) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
+    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
+    if wf.compute(ty) {
+        debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
+        let result = wf.normalize();
+        debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
+        Some(result)
+    } else {
+        None // no progress made, return None
+    }
+}
+
+/// Returns the obligations that make this trait reference
+/// well-formed.  For example, if there is a trait `Set` defined like
+/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
+/// if `Bar: Eq`.
+pub fn trait_obligations<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: hir::HirId,
+    trait_ref: &ty::TraitRef<'tcx>,
+    span: Span,
+    item: Option<&'tcx hir::Item<'tcx>>,
+) -> Vec<traits::PredicateObligation<'tcx>> {
+    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
+    wf.compute_trait_ref(trait_ref, Elaborate::All);
+    wf.normalize()
+}
+
+pub fn predicate_obligations<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: hir::HirId,
+    predicate: &ty::Predicate<'tcx>,
+    span: Span,
+) -> Vec<traits::PredicateObligation<'tcx>> {
+    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
+
+    // (*) ok to skip binders, because wf code is prepared for it
+    match *predicate {
+        ty::Predicate::Trait(ref t) => {
+            wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*)
+        }
+        ty::Predicate::RegionOutlives(..) => {}
+        ty::Predicate::TypeOutlives(ref t) => {
+            wf.compute(t.skip_binder().0);
+        }
+        ty::Predicate::Projection(ref t) => {
+            let t = t.skip_binder(); // (*)
+            wf.compute_projection(t.projection_ty);
+            wf.compute(t.ty);
+        }
+        ty::Predicate::WellFormed(t) => {
+            wf.compute(t);
+        }
+        ty::Predicate::ObjectSafe(_) => {}
+        ty::Predicate::ClosureKind(..) => {}
+        ty::Predicate::Subtype(ref data) => {
+            wf.compute(data.skip_binder().a); // (*)
+            wf.compute(data.skip_binder().b); // (*)
+        }
+        ty::Predicate::ConstEvaluatable(def_id, substs) => {
+            let obligations = wf.nominal_obligations(def_id, substs);
+            wf.out.extend(obligations);
+
+            for ty in substs.types() {
+                wf.compute(ty);
+            }
+        }
+    }
+
+    wf.normalize()
+}
+
+struct WfPredicates<'a, 'tcx> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: hir::HirId,
+    span: Span,
+    out: Vec<traits::PredicateObligation<'tcx>>,
+    item: Option<&'tcx hir::Item<'tcx>>,
+}
+
+/// Controls whether we "elaborate" supertraits and so forth on the WF
+/// predicates. This is a kind of hack to address #43784. The
+/// underlying problem in that issue was a trait structure like:
+///
+/// ```
+/// trait Foo: Copy { }
+/// trait Bar: Foo { }
+/// impl<T: Bar> Foo for T { }
+/// impl<T> Bar for T { }
+/// ```
+///
+/// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but
+/// we decide that this is true because `T: Bar` is in the
+/// where-clauses (and we can elaborate that to include `T:
+/// Copy`). This wouldn't be a problem, except that when we check the
+/// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo`
+/// impl. And so nowhere did we check that `T: Copy` holds!
+///
+/// To resolve this, we elaborate the WF requirements that must be
+/// proven when checking impls. This means that (e.g.) the `impl Bar
+/// for T` will be forced to prove not only that `T: Foo` but also `T:
+/// Copy` (which it won't be able to do, because there is no `Copy`
+/// impl for `T`).
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+enum Elaborate {
+    All,
+    None,
+}
+
+impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
+    fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
+        traits::ObligationCause::new(self.span, self.body_id, code)
+    }
+
+    fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
+        let cause = self.cause(traits::MiscObligation);
+        let infcx = &mut self.infcx;
+        let param_env = self.param_env;
+        self.out
+            .iter()
+            .inspect(|pred| assert!(!pred.has_escaping_bound_vars()))
+            .flat_map(|pred| {
+                let mut selcx = traits::SelectionContext::new(infcx);
+                let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred);
+                once(pred.value).chain(pred.obligations)
+            })
+            .collect()
+    }
+
+    /// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
+    fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
+        let tcx = self.infcx.tcx;
+        let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
+
+        let cause = self.cause(traits::MiscObligation);
+        let param_env = self.param_env;
+
+        let item = &self.item;
+        let extend_cause_with_original_assoc_item_obligation =
+            |cause: &mut traits::ObligationCause<'_>,
+             pred: &ty::Predicate<'_>,
+             trait_assoc_items: ty::AssocItemsIterator<'_>| {
+                let trait_item = tcx
+                    .hir()
+                    .as_local_hir_id(trait_ref.def_id)
+                    .and_then(|trait_id| tcx.hir().find(trait_id));
+                let (trait_name, trait_generics) = match trait_item {
+                    Some(hir::Node::Item(hir::Item {
+                        ident,
+                        kind: hir::ItemKind::Trait(.., generics, _, _),
+                        ..
+                    }))
+                    | Some(hir::Node::Item(hir::Item {
+                        ident,
+                        kind: hir::ItemKind::TraitAlias(generics, _),
+                        ..
+                    })) => (Some(ident), Some(generics)),
+                    _ => (None, None),
+                };
+
+                let item_span = item.map(|i| tcx.sess.source_map().def_span(i.span));
+                match pred {
+                    ty::Predicate::Projection(proj) => {
+                        // The obligation comes not from the current `impl` nor the `trait` being
+                        // implemented, but rather from a "second order" obligation, like in
+                        // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
+                        //
+                        //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
+                        //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
+                        //      |
+                        //   LL |     type Ok;
+                        //      |          -- associated type defined here
+                        //   ...
+                        //   LL | impl Bar for Foo {
+                        //      | ---------------- in this `impl` item
+                        //   LL |     type Ok = ();
+                        //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
+                        //      |
+                        //      = note: expected type `u32`
+                        //                 found type `()`
+                        //
+                        // FIXME: we would want to point a span to all places that contributed to this
+                        // obligation. In the case above, it should be closer to:
+                        //
+                        //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
+                        //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
+                        //      |
+                        //   LL |     type Ok;
+                        //      |          -- associated type defined here
+                        //   LL |     type Sibling: Bar2<Ok=Self::Ok>;
+                        //      |     -------------------------------- obligation set here
+                        //   ...
+                        //   LL | impl Bar for Foo {
+                        //      | ---------------- in this `impl` item
+                        //   LL |     type Ok = ();
+                        //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
+                        //   ...
+                        //   LL | impl Bar2 for Foo2 {
+                        //      | ---------------- in this `impl` item
+                        //   LL |     type Ok = u32;
+                        //      |     -------------- obligation set here
+                        //      |
+                        //      = note: expected type `u32`
+                        //                 found type `()`
+                        if let Some(hir::ItemKind::Impl(.., impl_items)) = item.map(|i| &i.kind) {
+                            let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
+                            if let Some(impl_item) = impl_items
+                                .iter()
+                                .filter(|item| item.ident == trait_assoc_item.ident)
+                                .next()
+                            {
+                                cause.span = impl_item.span;
+                                cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
+                                    impl_span: item_span,
+                                    original: trait_assoc_item.ident.span,
+                                    bounds: vec![],
+                                }));
+                            }
+                        }
+                    }
+                    ty::Predicate::Trait(proj) => {
+                        // An associated item obligation born out of the `trait` failed to be met.
+                        // Point at the `impl` that failed the obligation, the associated item that
+                        // needed to meet the obligation, and the definition of that associated item,
+                        // which should hold the obligation in most cases. An example can be seen in
+                        // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
+                        //
+                        //   error[E0277]: the trait bound `bool: Bar` is not satisfied
+                        //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
+                        //      |
+                        //   LL |     type Assoc: Bar;
+                        //      |          ----- associated type defined here
+                        //   ...
+                        //   LL | impl Foo for () {
+                        //      | --------------- in this `impl` item
+                        //   LL |     type Assoc = bool;
+                        //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+                        //
+                        // If the obligation comes from the where clause in the `trait`, we point at it:
+                        //
+                        //   error[E0277]: the trait bound `bool: Bar` is not satisfied
+                        //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
+                        //      |
+                        //      | trait Foo where <Self as Foo>>::Assoc: Bar {
+                        //      |                 -------------------------- restricted in this bound
+                        //   LL |     type Assoc;
+                        //      |          ----- associated type defined here
+                        //   ...
+                        //   LL | impl Foo for () {
+                        //      | --------------- in this `impl` item
+                        //   LL |     type Assoc = bool;
+                        //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+                        if let (
+                            ty::Projection(ty::ProjectionTy { item_def_id, .. }),
+                            Some(hir::ItemKind::Impl(.., impl_items)),
+                        ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
+                        {
+                            if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
+                                .filter(|i| i.def_id == *item_def_id)
+                                .next()
+                                .and_then(|trait_assoc_item| {
+                                    impl_items
+                                        .iter()
+                                        .filter(|i| i.ident == trait_assoc_item.ident)
+                                        .next()
+                                        .map(|impl_item| (impl_item, trait_assoc_item))
+                                })
+                            {
+                                let bounds = trait_generics
+                                    .map(|generics| {
+                                        get_generic_bound_spans(
+                                            &generics,
+                                            trait_name,
+                                            trait_assoc_item.ident,
+                                        )
+                                    })
+                                    .unwrap_or_else(Vec::new);
+                                cause.span = impl_item.span;
+                                cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
+                                    impl_span: item_span,
+                                    original: trait_assoc_item.ident.span,
+                                    bounds,
+                                }));
+                            }
+                        }
+                    }
+                    _ => {}
+                }
+            };
+
+        if let Elaborate::All = elaborate {
+            let trait_assoc_items = tcx.associated_items(trait_ref.def_id);
+
+            let predicates =
+                obligations.iter().map(|obligation| obligation.predicate.clone()).collect();
+            let implied_obligations = traits::elaborate_predicates(tcx, predicates);
+            let implied_obligations = implied_obligations.map(|pred| {
+                let mut cause = cause.clone();
+                extend_cause_with_original_assoc_item_obligation(
+                    &mut cause,
+                    &pred,
+                    trait_assoc_items.clone(),
+                );
+                traits::Obligation::new(cause, param_env, pred)
+            });
+            self.out.extend(implied_obligations);
+        }
+
+        self.out.extend(obligations);
+
+        self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map(
+            |ty| traits::Obligation::new(cause.clone(), param_env, ty::Predicate::WellFormed(ty)),
+        ));
+    }
+
+    /// Pushes the obligations required for `trait_ref::Item` to be WF
+    /// into `self.out`.
+    fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
+        // A projection is well-formed if (a) the trait ref itself is
+        // WF and (b) the trait-ref holds.  (It may also be
+        // normalizable and be WF that way.)
+        let trait_ref = data.trait_ref(self.infcx.tcx);
+        self.compute_trait_ref(&trait_ref, Elaborate::None);
+
+        if !data.has_escaping_bound_vars() {
+            let predicate = trait_ref.to_predicate();
+            let cause = self.cause(traits::ProjectionWf(data));
+            self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
+        }
+    }
+
+    /// Pushes the obligations required for an array length to be WF
+    /// into `self.out`.
+    fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
+        if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
+            assert!(promoted.is_none());
+
+            let obligations = self.nominal_obligations(def_id, substs);
+            self.out.extend(obligations);
+
+            let predicate = ty::Predicate::ConstEvaluatable(def_id, substs);
+            let cause = self.cause(traits::MiscObligation);
+            self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
+        }
+    }
+
+    fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
+        if !subty.has_escaping_bound_vars() {
+            let cause = self.cause(cause);
+            let trait_ref = ty::TraitRef {
+                def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
+                substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
+            };
+            self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
+        }
+    }
+
+    /// Pushes new obligations into `out`. Returns `true` if it was able
+    /// to generate all the predicates needed to validate that `ty0`
+    /// is WF. Returns false if `ty0` is an unresolved type variable,
+    /// in which case we are not able to simplify at all.
+    fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
+        let mut subtys = ty0.walk();
+        let param_env = self.param_env;
+        while let Some(ty) = subtys.next() {
+            match ty.kind {
+                ty::Bool
+                | ty::Char
+                | ty::Int(..)
+                | ty::Uint(..)
+                | ty::Float(..)
+                | ty::Error
+                | ty::Str
+                | ty::GeneratorWitness(..)
+                | ty::Never
+                | ty::Param(_)
+                | ty::Bound(..)
+                | ty::Placeholder(..)
+                | ty::Foreign(..) => {
+                    // WfScalar, WfParameter, etc
+                }
+
+                ty::Slice(subty) => {
+                    self.require_sized(subty, traits::SliceOrArrayElem);
+                }
+
+                ty::Array(subty, len) => {
+                    self.require_sized(subty, traits::SliceOrArrayElem);
+                    self.compute_array_len(*len);
+                }
+
+                ty::Tuple(ref tys) => {
+                    if let Some((_last, rest)) = tys.split_last() {
+                        for elem in rest {
+                            self.require_sized(elem.expect_ty(), traits::TupleElem);
+                        }
+                    }
+                }
+
+                ty::RawPtr(_) => {
+                    // simple cases that are WF if their type args are WF
+                }
+
+                ty::Projection(data) => {
+                    subtys.skip_current_subtree(); // subtree handled by compute_projection
+                    self.compute_projection(data);
+                }
+
+                ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
+                ty::Adt(def, substs) => {
+                    // WfNominalType
+                    let obligations = self.nominal_obligations(def.did, substs);
+                    self.out.extend(obligations);
+                }
+
+                ty::FnDef(did, substs) => {
+                    let obligations = self.nominal_obligations(did, substs);
+                    self.out.extend(obligations);
+                }
+
+                ty::Ref(r, rty, _) => {
+                    // WfReference
+                    if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
+                        let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
+                        self.out.push(traits::Obligation::new(
+                            cause,
+                            param_env,
+                            ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
+                                rty, r,
+                            ))),
+                        ));
+                    }
+                }
+
+                ty::Generator(..) => {
+                    // Walk ALL the types in the generator: this will
+                    // include the upvar types as well as the yield
+                    // type. Note that this is mildly distinct from
+                    // the closure case, where we have to be careful
+                    // about the signature of the closure. We don't
+                    // have the problem of implied bounds here since
+                    // generators don't take arguments.
+                }
+
+                ty::Closure(def_id, substs) => {
+                    // Only check the upvar types for WF, not the rest
+                    // of the types within. This is needed because we
+                    // capture the signature and it may not be WF
+                    // without the implied bounds. Consider a closure
+                    // like `|x: &'a T|` -- it may be that `T: 'a` is
+                    // not known to hold in the creator's context (and
+                    // indeed the closure may not be invoked by its
+                    // creator, but rather turned to someone who *can*
+                    // verify that).
+                    //
+                    // The special treatment of closures here really
+                    // ought not to be necessary either; the problem
+                    // is related to #25860 -- there is no way for us
+                    // to express a fn type complete with the implied
+                    // bounds that it is assuming. I think in reality
+                    // the WF rules around fn are a bit messed up, and
+                    // that is the rot problem: `fn(&'a T)` should
+                    // probably always be WF, because it should be
+                    // shorthand for something like `where(T: 'a) {
+                    // fn(&'a T) }`, as discussed in #25860.
+                    //
+                    // Note that we are also skipping the generic
+                    // types. This is consistent with the `outlives`
+                    // code, but anyway doesn't matter: within the fn
+                    // body where they are created, the generics will
+                    // always be WF, and outside of that fn body we
+                    // are not directly inspecting closure types
+                    // anyway, except via auto trait matching (which
+                    // only inspects the upvar types).
+                    subtys.skip_current_subtree(); // subtree handled by compute_projection
+                    for upvar_ty in substs.as_closure().upvar_tys(def_id, self.infcx.tcx) {
+                        self.compute(upvar_ty);
+                    }
+                }
+
+                ty::FnPtr(_) => {
+                    // let the loop iterate into the argument/return
+                    // types appearing in the fn signature
+                }
+
+                ty::Opaque(did, substs) => {
+                    // all of the requirements on type parameters
+                    // should've been checked by the instantiation
+                    // of whatever returned this exact `impl Trait`.
+
+                    // for named opaque `impl Trait` types we still need to check them
+                    if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() {
+                        let obligations = self.nominal_obligations(did, substs);
+                        self.out.extend(obligations);
+                    }
+                }
+
+                ty::Dynamic(data, r) => {
+                    // WfObject
+                    //
+                    // Here, we defer WF checking due to higher-ranked
+                    // regions. This is perhaps not ideal.
+                    self.from_object_ty(ty, data, r);
+
+                    // FIXME(#27579) RFC also considers adding trait
+                    // obligations that don't refer to Self and
+                    // checking those
+
+                    let defer_to_coercion = self.infcx.tcx.features().object_safe_for_dispatch;
+
+                    if !defer_to_coercion {
+                        let cause = self.cause(traits::MiscObligation);
+                        let component_traits = data.auto_traits().chain(data.principal_def_id());
+                        self.out.extend(component_traits.map(|did| {
+                            traits::Obligation::new(
+                                cause.clone(),
+                                param_env,
+                                ty::Predicate::ObjectSafe(did),
+                            )
+                        }));
+                    }
+                }
+
+                // Inference variables are the complicated case, since we don't
+                // know what type they are. We do two things:
+                //
+                // 1. Check if they have been resolved, and if so proceed with
+                //    THAT type.
+                // 2. If not, check whether this is the type that we
+                //    started with (ty0). In that case, we've made no
+                //    progress at all, so return false. Otherwise,
+                //    we've at least simplified things (i.e., we went
+                //    from `Vec<$0>: WF` to `$0: WF`, so we can
+                //    register a pending obligation and keep
+                //    moving. (Goal is that an "inductive hypothesis"
+                //    is satisfied to ensure termination.)
+                ty::Infer(_) => {
+                    let ty = self.infcx.shallow_resolve(ty);
+                    if let ty::Infer(_) = ty.kind {
+                        // not yet resolved...
+                        if ty == ty0 {
+                            // ...this is the type we started from! no progress.
+                            return false;
+                        }
+
+                        let cause = self.cause(traits::MiscObligation);
+                        self.out.push(
+                            // ...not the type we started from, so we made progress.
+                            traits::Obligation::new(
+                                cause,
+                                self.param_env,
+                                ty::Predicate::WellFormed(ty),
+                            ),
+                        );
+                    } else {
+                        // Yes, resolved, proceed with the
+                        // result. Should never return false because
+                        // `ty` is not a Infer.
+                        assert!(self.compute(ty));
+                    }
+                }
+            }
+        }
+
+        // if we made it through that loop above, we made progress!
+        return true;
+    }
+
+    fn nominal_obligations(
+        &mut self,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> Vec<traits::PredicateObligation<'tcx>> {
+        let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs);
+        let cause = self.cause(traits::ItemObligation(def_id));
+        predicates
+            .predicates
+            .into_iter()
+            .map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred))
+            .filter(|pred| !pred.has_escaping_bound_vars())
+            .collect()
+    }
+
+    fn from_object_ty(
+        &mut self,
+        ty: Ty<'tcx>,
+        data: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
+        region: ty::Region<'tcx>,
+    ) {
+        // Imagine a type like this:
+        //
+        //     trait Foo { }
+        //     trait Bar<'c> : 'c { }
+        //
+        //     &'b (Foo+'c+Bar<'d>)
+        //         ^
+        //
+        // In this case, the following relationships must hold:
+        //
+        //     'b <= 'c
+        //     'd <= 'c
+        //
+        // The first conditions is due to the normal region pointer
+        // rules, which say that a reference cannot outlive its
+        // referent.
+        //
+        // The final condition may be a bit surprising. In particular,
+        // you may expect that it would have been `'c <= 'd`, since
+        // usually lifetimes of outer things are conservative
+        // approximations for inner things. However, it works somewhat
+        // differently with trait objects: here the idea is that if the
+        // user specifies a region bound (`'c`, in this case) it is the
+        // "master bound" that *implies* that bounds from other traits are
+        // all met. (Remember that *all bounds* in a type like
+        // `Foo+Bar+Zed` must be met, not just one, hence if we write
+        // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
+        // 'y.)
+        //
+        // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
+        // am looking forward to the future here.
+        if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
+            let implicit_bounds = object_region_bounds(self.infcx.tcx, data);
+
+            let explicit_bound = region;
+
+            self.out.reserve(implicit_bounds.len());
+            for implicit_bound in implicit_bounds {
+                let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
+                let outlives =
+                    ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
+                self.out.push(traits::Obligation::new(
+                    cause,
+                    self.param_env,
+                    outlives.to_predicate(),
+                ));
+            }
+        }
+    }
+}
+
+/// Given an object type like `SomeTrait + Send`, computes the lifetime
+/// bounds that must hold on the elided self type. These are derived
+/// from the declarations of `SomeTrait`, `Send`, and friends -- if
+/// they declare `trait SomeTrait : 'static`, for example, then
+/// `'static` would appear in the list. The hard work is done by
+/// `infer::required_region_bounds`, see that for more information.
+pub fn object_region_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
+) -> Vec<ty::Region<'tcx>> {
+    // Since we don't actually *know* the self type for an object,
+    // this "open(err)" serves as a kind of dummy standin -- basically
+    // a placeholder type.
+    let open_ty = tcx.mk_ty_infer(ty::FreshTy(0));
+
+    let predicates = existential_predicates
+        .iter()
+        .filter_map(|predicate| {
+            if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() {
+                None
+            } else {
+                Some(predicate.with_self_ty(tcx, open_ty))
+            }
+        })
+        .collect();
+
+    required_region_bounds(tcx, open_ty, predicates)
+}
+
+/// Find the span of a generic bound affecting an associated type.
+fn get_generic_bound_spans(
+    generics: &hir::Generics<'_>,
+    trait_name: Option<&Ident>,
+    assoc_item_name: Ident,
+) -> Vec<Span> {
+    let mut bounds = vec![];
+    for clause in generics.where_clause.predicates.iter() {
+        if let hir::WherePredicate::BoundPredicate(pred) = clause {
+            match &pred.bounded_ty.kind {
+                hir::TyKind::Path(hir::QPath::Resolved(Some(ty), path)) => {
+                    let mut s = path.segments.iter();
+                    if let (a, Some(b), None) = (s.next(), s.next(), s.next()) {
+                        if a.map(|s| &s.ident) == trait_name
+                            && b.ident == assoc_item_name
+                            && is_self_path(&ty.kind)
+                        {
+                            // `<Self as Foo>::Bar`
+                            bounds.push(pred.span);
+                        }
+                    }
+                }
+                hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => {
+                    if segment.ident == assoc_item_name {
+                        if is_self_path(&ty.kind) {
+                            // `Self::Bar`
+                            bounds.push(pred.span);
+                        }
+                    }
+                }
+                _ => {}
+            }
+        }
+    }
+    bounds
+}
+
+fn is_self_path(kind: &hir::TyKind<'_>) -> bool {
+    match kind {
+        hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
+            let mut s = path.segments.iter();
+            if let (Some(segment), None) = (s.next(), s.next()) {
+                if segment.ident.name == kw::SelfUpper {
+                    // `type(Self)`
+                    return true;
+                }
+            }
+        }
+        _ => {}
+    }
+    false
+}
index 9b2714082f1e1735e0d7b58c2759103f99f5cfa0..df1602b2ac46d83dd9265983a1eca524d252e490 100644 (file)
@@ -226,11 +226,11 @@ pub fn decode_place<D>(decoder: &mut D) -> Result<mir::Place<'tcx>, D::Error>
 where
     D: TyDecoder<'tcx>,
 {
-    let base: mir::PlaceBase<'tcx> = Decodable::decode(decoder)?;
+    let local: mir::Local = Decodable::decode(decoder)?;
     let len = decoder.read_usize()?;
     let projection: &'tcx List<mir::PlaceElem<'tcx>> =
         decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
-    Ok(mir::Place { base, projection })
+    Ok(mir::Place { local, projection })
 }
 
 #[inline]
diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
deleted file mode 100644 (file)
index cc5131c..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-use crate::hir::map::blocks::FnLikeNode;
-use crate::ty::query::Providers;
-use crate::ty::TyCtxt;
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_span::symbol::Symbol;
-use rustc_target::spec::abi::Abi;
-use syntax::attr;
-
-impl<'tcx> TyCtxt<'tcx> {
-    /// Whether the `def_id` counts as const fn in your current crate, considering all active
-    /// feature gates
-    pub fn is_const_fn(self, def_id: DefId) -> bool {
-        self.is_const_fn_raw(def_id)
-            && match self.is_unstable_const_fn(def_id) {
-                Some(feature_name) => {
-                    // has a `rustc_const_unstable` attribute, check whether the user enabled the
-                    // corresponding feature gate.
-                    self.features()
-                        .declared_lib_features
-                        .iter()
-                        .any(|&(sym, _)| sym == feature_name)
-                }
-                // functions without const stability are either stable user written
-                // const fn or the user is using feature gates and we thus don't
-                // care what they do
-                None => true,
-            }
-    }
-
-    /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
-    pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
-        if self.is_const_fn_raw(def_id) {
-            let const_stab = self.lookup_const_stability(def_id)?;
-            if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
-        } else {
-            None
-        }
-    }
-
-    /// Returns `true` if this function must conform to `min_const_fn`
-    pub fn is_min_const_fn(self, def_id: DefId) -> bool {
-        // Bail out if the signature doesn't contain `const`
-        if !self.is_const_fn_raw(def_id) {
-            return false;
-        }
-
-        if self.features().staged_api {
-            // In order for a libstd function to be considered min_const_fn
-            // it needs to be stable and have no `rustc_const_unstable` attribute.
-            match self.lookup_const_stability(def_id) {
-                // `rustc_const_unstable` functions don't need to conform.
-                Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
-                None => {
-                    if let Some(stab) = self.lookup_stability(def_id) {
-                        if stab.level.is_stable() {
-                            self.sess.span_err(
-                                self.def_span(def_id),
-                                "stable const functions must have either `rustc_const_stable` or \
-                            `rustc_const_unstable` attribute",
-                            );
-                            // While we errored above, because we don't know if we need to conform, we
-                            // err on the "safe" side and require min_const_fn.
-                            true
-                        } else {
-                            // Unstable functions need not conform to min_const_fn.
-                            false
-                        }
-                    } else {
-                        // Internal functions are forced to conform to min_const_fn.
-                        // Annotate the internal function with a const stability attribute if
-                        // you need to use unstable features.
-                        // Note: this is an arbitrary choice that does not affect stability or const
-                        // safety or anything, it just changes whether we need to annotate some
-                        // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
-                        true
-                    }
-                }
-                // Everything else needs to conform, because it would be callable from
-                // other `min_const_fn` functions.
-                _ => true,
-            }
-        } else {
-            // users enabling the `const_fn` feature gate can do what they want
-            !self.features().const_fn
-        }
-    }
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    /// Const evaluability whitelist is here to check evaluability at the
-    /// top level beforehand.
-    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
-        match tcx.fn_sig(def_id).abi() {
-            Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
-                Some(tcx.lookup_const_stability(def_id).is_some())
-            }
-            _ => None,
-        }
-    }
-
-    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
-    /// said intrinsic is on the whitelist for being const callable.
-    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        let hir_id = tcx
-            .hir()
-            .as_local_hir_id(def_id)
-            .expect("Non-local call to local provider is_const_fn");
-
-        let node = tcx.hir().get(hir_id);
-
-        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
-            whitelisted
-        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
-            fn_like.constness() == hir::Constness::Const
-        } else if let hir::Node::Ctor(_) = node {
-            true
-        } else {
-            false
-        }
-    }
-
-    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        tcx.is_const_fn(def_id)
-            && match tcx.lookup_const_stability(def_id) {
-                Some(stab) => {
-                    if cfg!(debug_assertions) && stab.promotable {
-                        let sig = tcx.fn_sig(def_id);
-                        assert_eq!(
-                            sig.unsafety(),
-                            hir::Unsafety::Normal,
-                            "don't mark const unsafe fns as promotable",
-                            // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
-                        );
-                    }
-                    stab.promotable
-                }
-                None => false,
-            }
-    }
-
-    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        tcx.is_const_fn(def_id)
-            && tcx
-                .lookup_const_stability(def_id)
-                .map(|stab| stab.allow_const_fn_ptr)
-                .unwrap_or(false)
-    }
-
-    *providers = Providers {
-        is_const_fn_raw,
-        is_promotable_const_fn,
-        const_fn_is_allowed_fn_ptr,
-        ..*providers
-    };
-}
index a2e5edb67fc675a657b9dcbe8e8af4b54655a332..6b98fddb22ef913b72ca56820d7fbada126c3f6f 100644 (file)
@@ -8,8 +8,7 @@
 use crate::hir::map::DefPathHash;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
-use crate::infer::outlives::free_region_map::FreeRegionMap;
-use crate::lint::{self, Lint};
+use crate::lint::{struct_lint_level, LintSource};
 use crate::middle;
 use crate::middle::cstore::CrateStoreDyn;
 use crate::middle::cstore::EncodedMetadata;
 use crate::mir::{
     interpret, BodyAndCache, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
 };
-use crate::session::config::CrateType;
-use crate::session::config::{BorrowckMode, OutputFilenames};
-use crate::session::Session;
 use crate::traits;
 use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
+use crate::ty::free_region_map::FreeRegionMap;
 use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
 use crate::ty::query;
 use crate::ty::steal::Steal;
 use crate::ty::{InferConst, ParamConst};
 use crate::ty::{List, TyKind, TyS};
 use crate::util::common::ErrorReported;
+use rustc_data_structures::sync;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE};
 use rustc_hir::{HirId, Node, TraitCandidate};
 use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet};
+use rustc_session::config::CrateType;
+use rustc_session::config::{BorrowckMode, OutputFilenames};
+use rustc_session::Session;
 
 use arena::SyncDroplessArena;
-use errors::DiagnosticBuilder;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::ShardedHashMap;
     hash_stable_hashmap, HashStable, StableHasher, StableVec,
 };
 use rustc_data_structures::sync::{Lock, Lrc, WorkerLocal};
+use rustc_errors::DiagnosticBuilder;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
+use rustc_session::lint::{Level, Lint};
 use rustc_session::node_id::NodeMap;
 use rustc_span::source_map::MultiSpan;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -946,7 +948,11 @@ pub struct GlobalCtxt<'tcx> {
 
     pub sess: &'tcx Session,
 
-    pub lint_store: Lrc<lint::LintStore>,
+    /// This only ever stores a `LintStore` but we don't want a dependency on that type here.
+    ///
+    /// FIXME(Centril): consider `dyn LintStoreMarker` once
+    /// we can upcast to `Any` for some additional type safety.
+    pub lint_store: Lrc<dyn Any + sync::Sync + sync::Send>,
 
     pub dep_graph: DepGraph,
 
@@ -1115,7 +1121,7 @@ pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
     /// reference to the context, to allow formatting values that need it.
     pub fn create_global_ctxt(
         s: &'tcx Session,
-        lint_store: Lrc<lint::LintStore>,
+        lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
         local_providers: ty::query::Providers<'tcx>,
         extern_providers: ty::query::Providers<'tcx>,
         arenas: &'tcx AllArenas,
@@ -1613,10 +1619,10 @@ pub mod tls {
 
     use crate::dep_graph::TaskDeps;
     use crate::ty::query;
-    use errors::Diagnostic;
     use rustc_data_structures::sync::{self, Lock, Lrc};
     use rustc_data_structures::thin_vec::ThinVec;
     use rustc_data_structures::OnDrop;
+    use rustc_errors::Diagnostic;
     use std::mem;
 
     #[cfg(not(parallel_compiler))]
@@ -2434,7 +2440,7 @@ pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'
         let mut projection = place.projection.to_vec();
         projection.push(elem);
 
-        Place { base: place.base, projection: self.intern_place_elems(&projection) }
+        Place { local: place.local, projection: self.intern_place_elems(&projection) }
     }
 
     pub fn intern_existential_predicates(
@@ -2551,57 +2557,29 @@ pub fn mk_goals<I: InternAs<[Goal<'tcx>], Goals<'tcx>>>(self, iter: I) -> I::Out
         iter.intern_with(|xs| self.intern_goals(xs))
     }
 
-    pub fn lint_hir<S: Into<MultiSpan>>(
+    pub fn lint_hir(
         self,
         lint: &'static Lint,
         hir_id: HirId,
-        span: S,
+        span: impl Into<MultiSpan>,
         msg: &str,
     ) {
         self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
     }
 
-    pub fn lint_hir_note<S: Into<MultiSpan>>(
-        self,
-        lint: &'static Lint,
-        hir_id: HirId,
-        span: S,
-        msg: &str,
-        note: &str,
-    ) {
-        let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg);
-        err.note(note);
-        err.emit()
-    }
-
-    pub fn lint_node_note<S: Into<MultiSpan>>(
-        self,
-        lint: &'static Lint,
-        id: hir::HirId,
-        span: S,
-        msg: &str,
-        note: &str,
-    ) {
-        let mut err = self.struct_span_lint_hir(lint, id, span.into(), msg);
-        err.note(note);
-        err.emit()
-    }
-
     /// Walks upwards from `id` to find a node which might change lint levels with attributes.
     /// It stops at `bound` and just returns it if reached.
-    pub fn maybe_lint_level_root_bounded(
-        self,
-        mut id: hir::HirId,
-        bound: hir::HirId,
-    ) -> hir::HirId {
+    pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
+        let hir = self.hir();
         loop {
             if id == bound {
                 return bound;
             }
-            if lint::maybe_lint_level_root(self, id) {
+
+            if hir.attrs(id).iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) {
                 return id;
             }
-            let next = self.hir().get_parent_node(id);
+            let next = hir.get_parent_node(id);
             if next == id {
                 bug!("lint traversal reached the root of the crate");
             }
@@ -2613,7 +2591,7 @@ pub fn lint_level_at_node(
         self,
         lint: &'static Lint,
         mut id: hir::HirId,
-    ) -> (lint::Level, lint::LintSource) {
+    ) -> (Level, LintSource) {
         let sets = self.lint_levels(LOCAL_CRATE);
         loop {
             if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
@@ -2627,15 +2605,15 @@ pub fn lint_level_at_node(
         }
     }
 
-    pub fn struct_span_lint_hir<S: Into<MultiSpan>>(
+    pub fn struct_span_lint_hir(
         self,
         lint: &'static Lint,
         hir_id: HirId,
-        span: S,
+        span: impl Into<MultiSpan>,
         msg: &str,
     ) -> DiagnosticBuilder<'tcx> {
         let (level, src) = self.lint_level_at_node(lint, hir_id);
-        lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
+        struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
     }
 
     pub fn struct_lint_node(
@@ -2645,7 +2623,7 @@ pub fn struct_lint_node(
         msg: &str,
     ) -> DiagnosticBuilder<'tcx> {
         let (level, src) = self.lint_level_at_node(lint, id);
-        lint::struct_lint_level(self.sess, lint, level, src, None, msg)
+        struct_lint_level(self.sess, lint, level, src, None, msg)
     }
 
     pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
index 25fc484cd530150b9b94ef1139a3680affdc6275..f7612874e05b6b9b9ee5a455707eb27447cbf155 100644 (file)
@@ -1,12 +1,10 @@
 use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt};
+use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-
-use errors::{Applicability, DiagnosticBuilder};
 use rustc_span::Span;
 use rustc_target::spec::abi;
 use syntax::ast;
-use syntax::errors::pluralize;
 
 use std::borrow::Cow;
 use std::fmt;
index b9aa12b46658946dc1fc76edeea5f8a66087ac29..4a4280ba7dc4dd3fabe48f0479d55bf27cc3fb36 100644 (file)
@@ -219,7 +219,7 @@ fn add_region(&mut self, r: ty::Region<'_>) {
     fn add_const(&mut self, c: &ty::Const<'_>) {
         self.add_ty(c.ty);
         match c.val {
-            ty::ConstKind::Unevaluated(_, substs) => {
+            ty::ConstKind::Unevaluated(_, substs, _) => {
                 self.add_substs(substs);
                 self.add_flags(TypeFlags::HAS_PROJECTION);
             }
diff --git a/src/librustc/ty/free_region_map.rs b/src/librustc/ty/free_region_map.rs
new file mode 100644 (file)
index 0000000..42f5066
--- /dev/null
@@ -0,0 +1,96 @@
+use crate::ty::{self, Lift, Region, TyCtxt};
+use rustc_data_structures::transitive_relation::TransitiveRelation;
+
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)]
+pub struct FreeRegionMap<'tcx> {
+    // Stores the relation `a < b`, where `a` and `b` are regions.
+    //
+    // Invariant: only free regions like `'x` or `'static` are stored
+    // in this relation, not scopes.
+    relation: TransitiveRelation<Region<'tcx>>,
+}
+
+impl<'tcx> FreeRegionMap<'tcx> {
+    pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> {
+        self.relation.elements()
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.relation.is_empty()
+    }
+
+    // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
+    // (with the exception that `'static: 'x` is not notable)
+    pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
+        debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
+        if is_free_or_static(sub) && is_free(sup) {
+            self.relation.add(sub, sup)
+        }
+    }
+
+    /// Computes the least-upper-bound of two free regions. In some
+    /// cases, this is more conservative than necessary, in order to
+    /// avoid making arbitrary choices. See
+    /// `TransitiveRelation::postdom_upper_bound` for more details.
+    pub fn lub_free_regions(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        r_a: Region<'tcx>,
+        r_b: Region<'tcx>,
+    ) -> Region<'tcx> {
+        debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
+        assert!(is_free(r_a));
+        assert!(is_free(r_b));
+        let result = if r_a == r_b {
+            r_a
+        } else {
+            match self.relation.postdom_upper_bound(&r_a, &r_b) {
+                None => tcx.mk_region(ty::ReStatic),
+                Some(r) => *r,
+            }
+        };
+        debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
+        result
+    }
+}
+
+/// The NLL region handling code represents free region relations in a
+/// slightly different way; this trait allows functions to be abstract
+/// over which version is in use.
+pub trait FreeRegionRelations<'tcx> {
+    /// Tests whether `r_a <= r_b`. Both must be free regions or
+    /// `'static`.
+    fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
+}
+
+impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
+    fn sub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
+        assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
+        if let ty::ReStatic = r_b {
+            true // `'a <= 'static` is just always true, and not stored in the relation explicitly
+        } else {
+            r_a == r_b || self.relation.contains(&r_a, &r_b)
+        }
+    }
+}
+
+fn is_free(r: Region<'_>) -> bool {
+    match *r {
+        ty::ReEarlyBound(_) | ty::ReFree(_) => true,
+        _ => false,
+    }
+}
+
+fn is_free_or_static(r: Region<'_>) -> bool {
+    match *r {
+        ty::ReStatic => true,
+        _ => is_free(r),
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
+    type Lifted = FreeRegionMap<'tcx>;
+    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
+        self.relation.maybe_map(|&fr| tcx.lift(&fr)).map(|relation| FreeRegionMap { relation })
+    }
+}
index 73ca0075994a517dc647bb1b37369b6448e57b41..144e3bc9c8bc6d16cb5e6962948ce2d01a29a3a2 100644 (file)
@@ -96,15 +96,11 @@ pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
         // ```
         // forest.is_empty()
         // ```
-        self.ty_inhabitedness_forest(ty).contains(self, module)
+        ty.uninhabited_from(self).contains(self, module)
     }
 
     pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool {
-        !self.ty_inhabitedness_forest(ty).is_empty()
-    }
-
-    fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
-        ty.uninhabited_from(self)
+        !ty.uninhabited_from(self).is_empty()
     }
 }
 
index 0db49183d101454977dc54b6d45a413b5a648490..9be50d19a5030e45b0e56a959ab9cff5ac1945c6 100644 (file)
@@ -411,7 +411,7 @@ fn resolve_associated_item<'tcx>(
             substs: rcvr_substs,
         }),
         traits::VtableObject(ref data) => {
-            let index = tcx.get_vtable_index_of_object_method(data, def_id);
+            let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
             Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
         }
         traits::VtableBuiltin(..) => {
index 4b7304e7c1e8d025b004eccb80d6be50ab7fa571..acaa4eec9410d5e7a00bd6eebcef0eab07d38fbd 100644 (file)
@@ -2507,17 +2507,21 @@ fn new_internal(
         let extra_args = if sig.abi == RustCall {
             assert!(!sig.c_variadic && extra_args.is_empty());
 
-            match sig.inputs().last().unwrap().kind {
-                ty::Tuple(tupled_arguments) => {
+            if let Some(input) = sig.inputs().last() {
+                if let ty::Tuple(tupled_arguments) = input.kind {
                     inputs = &sig.inputs()[0..sig.inputs().len() - 1];
                     tupled_arguments.iter().map(|k| k.expect_ty()).collect()
-                }
-                _ => {
+                } else {
                     bug!(
                         "argument to function with \"rust-call\" ABI \
-                         is not a tuple"
+                            is not a tuple"
                     );
                 }
+            } else {
+                bug!(
+                    "argument to function with \"rust-call\" ABI \
+                        is not a tuple"
+                );
             }
         } else {
             assert!(sig.c_variadic || extra_args.is_empty());
index 1698a0685b7aadc7f82937c2408e774ba3191a19..d1e37a4ea1151f09e8a1dc01e9d2c71ae784fc03 100644 (file)
@@ -26,8 +26,8 @@
 use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use crate::ty::util::{Discr, IntTypeExt};
 use crate::ty::walk::TypeWalker;
-use crate::util::captures::Captures;
 use arena::SyncDroplessArena;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
 pub use self::instance::{Instance, InstanceDef};
 
-pub use self::structural_match::search_for_structural_match_violation;
-pub use self::structural_match::type_marked_structural;
-pub use self::structural_match::NonStructuralMatchTy;
-
 pub use self::trait_def::TraitDef;
 
 pub use self::query::queries;
 #[macro_use]
 pub mod codec;
 pub mod _match;
-mod constness;
 mod erase_regions;
 pub mod error;
 pub mod fast_reject;
 pub mod flags;
 pub mod fold;
+pub mod free_region_map;
 pub mod inhabitedness;
 pub mod layout;
+pub mod normalize_erasing_regions;
 pub mod outlives;
 pub mod print;
 pub mod query;
 pub mod trait_def;
 pub mod util;
 pub mod walk;
-pub mod wf;
 
 mod context;
 mod diagnostics;
 mod instance;
 mod structural_impls;
-mod structural_match;
 mod sty;
 
 // Data types
@@ -813,13 +808,6 @@ pub struct UpvarBorrow<'tcx> {
 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
 pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
 
-#[derive(Copy, Clone, TypeFoldable)]
-pub struct ClosureUpvar<'tcx> {
-    pub res: Res,
-    pub span: Span,
-    pub ty: Ty<'tcx>,
-}
-
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub enum IntVarValue {
     IntType(ast::IntTy),
@@ -3322,8 +3310,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     context::provide(providers);
     erase_regions::provide(providers);
     layout::provide(providers);
-    util::provide(providers);
-    constness::provide(providers);
     *providers = ty::query::Providers {
         asyncness,
         associated_item,
diff --git a/src/librustc/ty/normalize_erasing_regions.rs b/src/librustc/ty/normalize_erasing_regions.rs
new file mode 100644 (file)
index 0000000..dc64482
--- /dev/null
@@ -0,0 +1,102 @@
+//! Methods for normalizing when you don't care about regions (and
+//! aren't doing type inference). If either of those things don't
+//! apply to you, use `infcx.normalize(...)`.
+//!
+//! The methods in this file use a `TypeFolder` to recursively process
+//! contents, invoking the underlying
+//! `normalize_ty_after_erasing_regions` query for each type found
+//! within. (This underlying query is what is cached.)
+
+use crate::ty::fold::{TypeFoldable, TypeFolder};
+use crate::ty::subst::{Subst, SubstsRef};
+use crate::ty::{self, Ty, TyCtxt};
+
+impl<'tcx> TyCtxt<'tcx> {
+    /// Erase the regions in `value` and then fully normalize all the
+    /// types found within. The result will also have regions erased.
+    ///
+    /// This is appropriate to use only after type-check: it assumes
+    /// that normalization will succeed, for example.
+    pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        debug!(
+            "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
+            ::std::any::type_name::<T>(),
+            value,
+            param_env,
+        );
+
+        // Erase first before we do the real query -- this keeps the
+        // cache from being too polluted.
+        let value = self.erase_regions(&value);
+        if !value.has_projections() {
+            value
+        } else {
+            value.fold_with(&mut NormalizeAfterErasingRegionsFolder {
+                tcx: self,
+                param_env: param_env,
+            })
+        }
+    }
+
+    /// If you have a `Binder<T>`, you can do this to strip out the
+    /// late-bound regions and then normalize the result, yielding up
+    /// a `T` (with regions erased). This is appropriate when the
+    /// binder is being instantiated at the call site.
+    ///
+    /// N.B., currently, higher-ranked type bounds inhibit
+    /// normalization. Therefore, each time we erase them in
+    /// codegen, we need to normalize the contents.
+    pub fn normalize_erasing_late_bound_regions<T>(
+        self,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &ty::Binder<T>,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        assert!(!value.needs_subst());
+        let value = self.erase_late_bound_regions(value);
+        self.normalize_erasing_regions(param_env, value)
+    }
+
+    /// Monomorphizes a type from the AST by first applying the
+    /// in-scope substitutions and then normalizing any associated
+    /// types.
+    pub fn subst_and_normalize_erasing_regions<T>(
+        self,
+        param_substs: SubstsRef<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &T,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        debug!(
+            "subst_and_normalize_erasing_regions(\
+             param_substs={:?}, \
+             value={:?}, \
+             param_env={:?})",
+            param_substs, value, param_env,
+        );
+        let substituted = value.subst(self, param_substs);
+        self.normalize_erasing_regions(param_env, substituted)
+    }
+}
+
+struct NormalizeAfterErasingRegionsFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty))
+    }
+}
index 383ccbd337a7d25ffc66ccb46c0affe33645f172..b397a2c80d59b93f08b10e81e5b590448208f714 100644 (file)
@@ -48,32 +48,29 @@ pub enum Component<'tcx> {
 impl<'tcx> TyCtxt<'tcx> {
     /// Push onto `out` all the things that must outlive `'a` for the condition
     /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
-    pub fn push_outlives_components(
-        &self,
-        ty0: Ty<'tcx>,
-        out: &mut SmallVec<[Component<'tcx>; 4]>,
-    ) {
-        self.compute_components(ty0, out);
+    pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
+        compute_components(self, ty0, out);
         debug!("components({:?}) = {:?}", ty0, out);
     }
+}
 
-    fn compute_components(&self, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
-        // Descend through the types, looking for the various "base"
-        // components and collecting them into `out`. This is not written
-        // with `collect()` because of the need to sometimes skip subtrees
-        // in the `subtys` iterator (e.g., when encountering a
-        // projection).
-        match ty.kind {
+fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
+    // Descend through the types, looking for the various "base"
+    // components and collecting them into `out`. This is not written
+    // with `collect()` because of the need to sometimes skip subtrees
+    // in the `subtys` iterator (e.g., when encountering a
+    // projection).
+    match ty.kind {
             ty::Closure(def_id, ref substs) => {
-                for upvar_ty in substs.as_closure().upvar_tys(def_id, *self) {
-                    self.compute_components(upvar_ty, out);
+                for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) {
+                    compute_components(tcx, upvar_ty, out);
                 }
             }
 
             ty::Generator(def_id, ref substs, _) => {
                 // Same as the closure case
-                for upvar_ty in substs.as_generator().upvar_tys(def_id, *self) {
-                    self.compute_components(upvar_ty, out);
+                for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) {
+                    compute_components(tcx, upvar_ty, out);
                 }
 
                 // We ignore regions in the generator interior as we don't
@@ -110,7 +107,7 @@ pub fn push_outlives_components(
                     // fallback case: hard code
                     // OutlivesProjectionComponents.  Continue walking
                     // through and constrain Pi.
-                    let subcomponents = self.capture_components(ty);
+                    let subcomponents = capture_components(tcx, ty);
                     out.push(Component::EscapingProjection(subcomponents));
                 }
             }
@@ -159,20 +156,19 @@ pub fn push_outlives_components(
 
                 push_region_constraints(ty, out);
                 for subty in ty.walk_shallow() {
-                    self.compute_components(subty, out);
+                    compute_components(tcx, subty, out);
                 }
             }
         }
-    }
+}
 
-    fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
-        let mut temp = smallvec![];
-        push_region_constraints(ty, &mut temp);
-        for subty in ty.walk_shallow() {
-            self.compute_components(subty, &mut temp);
-        }
-        temp.into_iter().collect()
+fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
+    let mut temp = smallvec![];
+    push_region_constraints(ty, &mut temp);
+    for subty in ty.walk_shallow() {
+        compute_components(tcx, subty, &mut temp);
     }
+    temp.into_iter().collect()
 }
 
 fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
index b3fb455feb5dadf805675ee68c56d765299cf65f..8b1b2bb586597662a39a5c5cd05e278469d2e3ed 100644 (file)
@@ -841,23 +841,31 @@ fn pretty_print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const
 
         match (ct.val, &ct.ty.kind) {
             (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
-            (ty::ConstKind::Unevaluated(did, substs), _) => match self.tcx().def_kind(did) {
-                Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => {
-                    p!(print_value_path(did, substs))
-                }
-                _ => {
-                    if did.is_local() {
-                        let span = self.tcx().def_span(did);
-                        if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
-                            p!(write("{}", snip))
-                        } else {
-                            p!(write("_: "), print(ct.ty))
+            (ty::ConstKind::Unevaluated(did, substs, promoted), _) => {
+                if let Some(promoted) = promoted {
+                    p!(print_value_path(did, substs));
+                    p!(write("::{:?}", promoted));
+                } else {
+                    match self.tcx().def_kind(did) {
+                        Some(DefKind::Static)
+                        | Some(DefKind::Const)
+                        | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
+                        _ => {
+                            if did.is_local() {
+                                let span = self.tcx().def_span(did);
+                                if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
+                                {
+                                    p!(write("{}", snip))
+                                } else {
+                                    p!(write("_: "), print(ct.ty))
+                                }
+                            } else {
+                                p!(write("_: "), print(ct.ty))
+                            }
                         }
-                    } else {
-                        p!(write("_: "), print(ct.ty))
                     }
                 }
-            },
+            }
             (ty::ConstKind::Infer(..), _) => p!(write("_: "), print(ct.ty)),
             (ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
             (ty::ConstKind::Value(value), _) => return self.pretty_print_const_value(value, ct.ty),
@@ -1036,26 +1044,26 @@ pub fn new(tcx: TyCtxt<'tcx>, fmt: F, ns: Namespace) -> Self {
     }
 }
 
-impl TyCtxt<'t> {
-    // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
-    // (but also some things just print a `DefId` generally so maybe we need this?)
-    fn guess_def_namespace(self, def_id: DefId) -> Namespace {
-        match self.def_key(def_id).disambiguated_data.data {
-            DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => {
-                Namespace::TypeNS
-            }
+// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
+// (but also some things just print a `DefId` generally so maybe we need this?)
+fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
+    match tcx.def_key(def_id).disambiguated_data.data {
+        DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => {
+            Namespace::TypeNS
+        }
 
-            DefPathData::ValueNs(..)
-            | DefPathData::AnonConst
-            | DefPathData::ClosureExpr
-            | DefPathData::Ctor => Namespace::ValueNS,
+        DefPathData::ValueNs(..)
+        | DefPathData::AnonConst
+        | DefPathData::ClosureExpr
+        | DefPathData::Ctor => Namespace::ValueNS,
 
-            DefPathData::MacroNs(..) => Namespace::MacroNS,
+        DefPathData::MacroNs(..) => Namespace::MacroNS,
 
-            _ => Namespace::TypeNS,
-        }
+        _ => Namespace::TypeNS,
     }
+}
 
+impl TyCtxt<'t> {
     /// Returns a string identifying this `DefId`. This string is
     /// suitable for user output.
     pub fn def_path_str(self, def_id: DefId) -> String {
@@ -1063,7 +1071,7 @@ pub fn def_path_str(self, def_id: DefId) -> String {
     }
 
     pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String {
-        let ns = self.guess_def_namespace(def_id);
+        let ns = guess_def_namespace(self, def_id);
         debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns);
         let mut s = String::new();
         let _ = FmtPrinter::new(self, &mut s, ns).print_def_path(def_id, substs);
index c77cf8c41be9a84652f57923cb7506319179b1df..dbb6a1080e6d46f6a305ea5ab0a8dd186d718226 100644 (file)
@@ -2,8 +2,7 @@
 use crate::dep_graph::{DepKind, DepNode};
 use crate::ty::query::plumbing::CycleError;
 use crate::ty::query::queries;
-use crate::ty::query::QueryCache;
-use crate::ty::query::{Query, QueryName};
+use crate::ty::query::{Query, QueryCache};
 use crate::ty::TyCtxt;
 use rustc_data_structures::profiling::ProfileCategory;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -20,7 +19,7 @@
 // FIXME(eddyb) false positive, the lifetime parameter is used for `Key`/`Value`.
 #[allow(unused_lifetimes)]
 pub trait QueryConfig<'tcx> {
-    const NAME: QueryName;
+    const NAME: &'static str;
     const CATEGORY: ProfileCategory;
 
     type Key: Eq + Hash + Clone + Debug;
index 8a713e3b6a096eab6d25a88f3a4baafab793886b..d64f27d9cc26ca75ffba41d0fb2d5e0789ac3193 100644 (file)
@@ -142,7 +142,7 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
     }
 }
 
-impl<'tcx> Key for ty::Const<'tcx> {
+impl<'tcx> Key for &'tcx ty::Const<'tcx> {
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
index b163d23e2394bc53588b5e19e8f989406ffe1af6..1d41871bb33a924979c0bfdde0e1f0a8a87efb2e 100644 (file)
@@ -1,7 +1,7 @@
 use crate::dep_graph::{self, DepNode};
 use crate::hir::exports::Export;
 use crate::infer::canonical::{self, Canonical};
-use crate::lint;
+use crate::lint::LintLevelMap;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind};
 use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary};
@@ -81,6 +81,9 @@
 mod on_disk_cache;
 pub use self::on_disk_cache::OnDiskCache;
 
+mod profiling_support;
+pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder};
+
 // Each of these queries corresponds to a function pointer field in the
 // `Providers` struct for requesting a value of that type, and a method
 // on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
index d01927b91b9544be80b30ae88204b8b3fb4d9069..a81fe33831c96bc6d012c1a3a1105f145cb34f04 100644 (file)
@@ -7,10 +7,10 @@
 use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
 use crate::ty::context::TyCtxt;
 use crate::ty::{self, Ty};
-use errors::Diagnostic;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, Once};
 use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::Diagnostic;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
@@ -198,7 +198,7 @@ pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(
             // Encode query results.
             let mut query_result_index = EncodedQueryResultIndex::new();
 
-            tcx.sess.time("encode query results", || {
+            tcx.sess.time("encode_query_results", || {
                 let enc = &mut encoder;
                 let qri = &mut query_result_index;
 
@@ -1053,8 +1053,8 @@ fn encode_query_results<'a, 'tcx, Q, E>(
     Q: super::config::QueryDescription<'tcx, Value: Encodable>,
     E: 'a + TyEncoder,
 {
-    let desc = &format!("encode_query_results for {}", ::std::any::type_name::<Q>());
-    let _timer = tcx.sess.prof.generic_pass(desc);
+    let desc = &format!("encode_query_results_for_{}", ::std::any::type_name::<Q>());
+    let _timer = tcx.sess.prof.extra_verbose_generic_activity(desc);
 
     let shards = Q::query_cache(tcx).lock_shards();
     assert!(shards.iter().all(|shard| shard.active.is_empty()));
index e56955b0e44417ad31f59b5fd4bbf6426c9548f6..84efbe21f10aa25bce31a01e0599f574e9e4e92f 100644 (file)
@@ -9,17 +9,15 @@
 use crate::ty::tls;
 use crate::ty::{self, TyCtxt};
 
-use errors::Diagnostic;
-use errors::DiagnosticBuilder;
-use errors::FatalError;
-use errors::Handler;
-use errors::Level;
 #[cfg(not(parallel_compiler))]
 use rustc_data_structures::cold_path;
 use rustc_data_structures::fx::{FxHashMap, FxHasher};
+#[cfg(parallel_compiler)]
+use rustc_data_structures::profiling::TimingGuard;
 use rustc_data_structures::sharded::Sharded;
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, FatalError, Handler, Level};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::Span;
 use std::collections::hash_map::Entry;
@@ -86,6 +84,19 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
     /// for some compile-time benchmarks.
     #[inline(always)]
     pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<'a, 'tcx, Q> {
+        // Handling the `query_blocked_prof_timer` is a bit weird because of the
+        // control flow in this function: Blocking is implemented by
+        // awaiting a running job and, once that is done, entering the loop below
+        // again from the top. In that second iteration we will hit the
+        // cache which provides us with the information we need for
+        // finishing the "query-blocked" event.
+        //
+        // We thus allocate `query_blocked_prof_timer` outside the loop,
+        // initialize it during the first iteration and finish it during the
+        // second iteration.
+        #[cfg(parallel_compiler)]
+        let mut query_blocked_prof_timer: Option<TimingGuard<'_>> = None;
+
         let cache = Q::query_cache(tcx);
         loop {
             // We compute the key's hash once and then use it for both the
@@ -99,7 +110,17 @@ pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<
             if let Some((_, value)) =
                 lock.results.raw_entry().from_key_hashed_nocheck(key_hash, key)
             {
-                tcx.prof.query_cache_hit(Q::NAME);
+                if unlikely!(tcx.prof.enabled()) {
+                    tcx.prof.query_cache_hit(value.index.into());
+
+                    #[cfg(parallel_compiler)]
+                    {
+                        if let Some(prof_timer) = query_blocked_prof_timer.take() {
+                            prof_timer.finish_with_query_invocation_id(value.index.into());
+                        }
+                    }
+                }
+
                 let result = (value.value.clone(), value.index);
                 #[cfg(debug_assertions)]
                 {
@@ -108,9 +129,6 @@ pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<
                 return TryGetJob::JobCompleted(result);
             }
 
-            #[cfg(parallel_compiler)]
-            let query_blocked_prof_timer;
-
             let job = match lock.active.entry((*key).clone()) {
                 Entry::Occupied(entry) => {
                     match *entry.get() {
@@ -120,7 +138,7 @@ pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<
                             // self-profiler.
                             #[cfg(parallel_compiler)]
                             {
-                                query_blocked_prof_timer = tcx.prof.query_blocked(Q::NAME);
+                                query_blocked_prof_timer = Some(tcx.prof.query_blocked());
                             }
 
                             job.clone()
@@ -157,11 +175,6 @@ pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<
             {
                 let result = job.r#await(tcx, span);
 
-                // This `drop()` is not strictly necessary as the binding
-                // would go out of scope anyway. But it's good to have an
-                // explicit marker of how far the measurement goes.
-                drop(query_blocked_prof_timer);
-
                 if let Err(cycle) = result {
                     return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle));
                 }
@@ -351,7 +364,7 @@ pub fn try_print_query_stack(handler: &Handler) {
 
     #[inline(never)]
     pub(super) fn get_query<Q: QueryDescription<'tcx>>(self, span: Span, key: Q::Key) -> Q::Value {
-        debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME.as_str(), key, span);
+        debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
 
         let job = match JobOwner::try_get(self, span, &key) {
             TryGetJob::NotYetStarted(job) => job,
@@ -370,7 +383,7 @@ pub(super) fn get_query<Q: QueryDescription<'tcx>>(self, span: Span, key: Q::Key
         }
 
         if Q::ANON {
-            let prof_timer = self.prof.query_provider(Q::NAME);
+            let prof_timer = self.prof.query_provider();
 
             let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
                 self.start_query(job.job.clone(), diagnostics, |tcx| {
@@ -378,7 +391,7 @@ pub(super) fn get_query<Q: QueryDescription<'tcx>>(self, span: Span, key: Q::Key
                 })
             });
 
-            drop(prof_timer);
+            prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
             self.dep_graph.read_index(dep_node_index);
 
@@ -440,8 +453,9 @@ fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'tcx>>(
         let result = if Q::cache_on_disk(self, key.clone(), None)
             && self.sess.opts.debugging_opts.incremental_queries
         {
-            let _prof_timer = self.prof.incr_cache_loading(Q::NAME);
+            let prof_timer = self.prof.incr_cache_loading();
             let result = Q::try_load_from_disk(self, prev_dep_node_index);
+            prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
             // We always expect to find a cached result for things that
             // can be forced from `DepNode`.
@@ -461,11 +475,13 @@ fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'tcx>>(
         } else {
             // We could not load a result from the on-disk cache, so
             // recompute.
-            let _prof_timer = self.prof.query_provider(Q::NAME);
+            let prof_timer = self.prof.query_provider();
 
             // The dep-graph for this computation is already in-place.
             let result = self.dep_graph.with_ignore(|| Q::compute(self, key));
 
+            prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+
             result
         };
 
@@ -527,7 +543,7 @@ fn force_query_with_job<Q: QueryDescription<'tcx>>(
             dep_node
         );
 
-        let prof_timer = self.prof.query_provider(Q::NAME);
+        let prof_timer = self.prof.query_provider();
 
         let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
             self.start_query(job.job.clone(), diagnostics, |tcx| {
@@ -545,7 +561,7 @@ fn force_query_with_job<Q: QueryDescription<'tcx>>(
             })
         });
 
-        drop(prof_timer);
+        prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
         if unlikely!(!diagnostics.is_empty()) {
             if dep_node.kind != crate::dep_graph::DepKind::Null {
@@ -576,17 +592,19 @@ pub(super) fn ensure_query<Q: QueryDescription<'tcx>>(self, key: Q::Key) -> () {
 
         let dep_node = Q::to_dep_node(self, &key);
 
-        if self.dep_graph.try_mark_green_and_read(self, &dep_node).is_none() {
-            // A None return from `try_mark_green_and_read` means that this is either
-            // a new dep node or that the dep node has already been marked red.
-            // Either way, we can't call `dep_graph.read()` as we don't have the
-            // DepNodeIndex. We must invoke the query itself. The performance cost
-            // this introduces should be negligible as we'll immediately hit the
-            // in-memory cache, or another query down the line will.
-
-            let _ = self.get_query::<Q>(DUMMY_SP, key);
-        } else {
-            self.prof.query_cache_hit(Q::NAME);
+        match self.dep_graph.try_mark_green_and_read(self, &dep_node) {
+            None => {
+                // A None return from `try_mark_green_and_read` means that this is either
+                // a new dep node or that the dep node has already been marked red.
+                // Either way, we can't call `dep_graph.read()` as we don't have the
+                // DepNodeIndex. We must invoke the query itself. The performance cost
+                // this introduces should be negligible as we'll immediately hit the
+                // in-memory cache, or another query down the line will.
+                let _ = self.get_query::<Q>(DUMMY_SP, key);
+            }
+            Some((_, dep_node_index)) => {
+                self.prof.query_cache_hit(dep_node_index.into());
+            }
         }
     }
 
@@ -817,36 +835,6 @@ fn stats<'tcx, Q: QueryConfig<'tcx>>(
             }
         }
 
-        #[allow(nonstandard_style)]
-        #[derive(Clone, Copy)]
-        pub enum QueryName {
-            $($name),*
-        }
-
-        impl rustc_data_structures::profiling::QueryName for QueryName {
-            fn discriminant(self) -> std::mem::Discriminant<QueryName> {
-                std::mem::discriminant(&self)
-            }
-
-            fn as_str(self) -> &'static str {
-                QueryName::as_str(&self)
-            }
-        }
-
-        impl QueryName {
-            pub fn register_with_profiler(
-                profiler: &rustc_data_structures::profiling::SelfProfiler,
-            ) {
-                $(profiler.register_query_name(QueryName::$name);)*
-            }
-
-            pub fn as_str(&self) -> &'static str {
-                match self {
-                    $(QueryName::$name => stringify!($name),)*
-                }
-            }
-        }
-
         #[allow(nonstandard_style)]
         #[derive(Clone, Debug)]
         pub enum Query<$tcx> {
@@ -887,12 +875,6 @@ pub fn default_span(&self, tcx: TyCtxt<$tcx>, span: Span) -> Span {
                     $(Query::$name(key) => key.default_span(tcx),)*
                 }
             }
-
-            pub fn query_name(&self) -> QueryName {
-                match self {
-                    $(Query::$name(_) => QueryName::$name,)*
-                }
-            }
         }
 
         impl<'a, $tcx> HashStable<StableHashingContext<'a>> for Query<$tcx> {
@@ -927,7 +909,7 @@ pub fn $name<F: FnOnce() -> R, R>(f: F) -> R {
             type Key = $K;
             type Value = $V;
 
-            const NAME: QueryName = QueryName::$name;
+            const NAME: &'static str = stringify!($name);
             const CATEGORY: ProfileCategory = $category;
         }
 
@@ -1039,6 +1021,35 @@ pub fn at(self, span: Span) -> TyCtxtAt<$tcx> {
             pub fn $name(self, key: $K) -> $V {
                 self.at(DUMMY_SP).$name(key)
             })*
+
+            /// All self-profiling events generated by the query engine use
+            /// virtual `StringId`s for their `event_id`. This method makes all
+            /// those virtual `StringId`s point to actual strings.
+            ///
+            /// If we are recording only summary data, the ids will point to
+            /// just the query names. If we are recording query keys too, we
+            /// allocate the corresponding strings here.
+            pub fn alloc_self_profile_query_strings(self) {
+                use crate::ty::query::profiling_support::{
+                    alloc_self_profile_query_strings_for_query_cache,
+                    QueryKeyStringCache,
+                };
+
+                if !self.prof.enabled() {
+                    return;
+                }
+
+                let mut string_cache = QueryKeyStringCache::new();
+
+                $({
+                    alloc_self_profile_query_strings_for_query_cache(
+                        self,
+                        stringify!($name),
+                        &self.queries.$name,
+                        &mut string_cache,
+                    );
+                })*
+            }
         }
 
         impl TyCtxtAt<$tcx> {
diff --git a/src/librustc/ty/query/profiling_support.rs b/src/librustc/ty/query/profiling_support.rs
new file mode 100644 (file)
index 0000000..79b32ba
--- /dev/null
@@ -0,0 +1,235 @@
+use crate::hir::map::definitions::DefPathData;
+use crate::ty::context::TyCtxt;
+use crate::ty::query::config::QueryConfig;
+use crate::ty::query::plumbing::QueryCache;
+use measureme::{StringComponent, StringId};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::profiling::SelfProfiler;
+use rustc_data_structures::sharded::Sharded;
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use std::fmt::Debug;
+use std::io::Write;
+
+pub struct QueryKeyStringCache {
+    def_id_cache: FxHashMap<DefId, StringId>,
+}
+
+impl QueryKeyStringCache {
+    pub fn new() -> QueryKeyStringCache {
+        QueryKeyStringCache { def_id_cache: Default::default() }
+    }
+}
+
+pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
+    profiler: &'p SelfProfiler,
+    tcx: TyCtxt<'tcx>,
+    string_cache: &'c mut QueryKeyStringCache,
+}
+
+impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
+    pub fn new(
+        profiler: &'p SelfProfiler,
+        tcx: TyCtxt<'tcx>,
+        string_cache: &'c mut QueryKeyStringCache,
+    ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> {
+        QueryKeyStringBuilder { profiler, tcx, string_cache }
+    }
+
+    // The current implementation is rather crude. In the future it might be a
+    // good idea to base this on `ty::print` in order to get nicer and more
+    // efficient query keys.
+    fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
+        if let Some(&string_id) = self.string_cache.def_id_cache.get(&def_id) {
+            return string_id;
+        }
+
+        let def_key = self.tcx.def_key(def_id);
+
+        let (parent_string_id, start_index) = match def_key.parent {
+            Some(parent_index) => {
+                let parent_def_id = DefId { index: parent_index, krate: def_id.krate };
+
+                (self.def_id_to_string_id(parent_def_id), 0)
+            }
+            None => (StringId::INVALID, 2),
+        };
+
+        let dis_buffer = &mut [0u8; 16];
+        let name;
+        let dis;
+        let end_index;
+
+        match def_key.disambiguated_data.data {
+            DefPathData::CrateRoot => {
+                name = self.tcx.original_crate_name(def_id.krate).as_str();
+                dis = "";
+                end_index = 3;
+            }
+            other => {
+                name = other.as_symbol().as_str();
+                if def_key.disambiguated_data.disambiguator == 0 {
+                    dis = "";
+                    end_index = 3;
+                } else {
+                    write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator)
+                        .unwrap();
+                    let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap();
+                    dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap();
+                    end_index = 4;
+                }
+            }
+        }
+
+        let components = [
+            StringComponent::Ref(parent_string_id),
+            StringComponent::Value("::"),
+            StringComponent::Value(&name[..]),
+            StringComponent::Value(dis),
+        ];
+
+        let string_id = self.profiler.alloc_string(&components[start_index..end_index]);
+
+        self.string_cache.def_id_cache.insert(def_id, string_id);
+
+        string_id
+    }
+}
+
+pub trait IntoSelfProfilingString {
+    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
+}
+
+// The default implementation of `IntoSelfProfilingString` just uses `Debug`
+// which is slow and causes lots of duplication of string data.
+// The specialized impls below take care of making the `DefId` case more
+// efficient.
+impl<T: Debug> IntoSelfProfilingString for T {
+    default fn to_self_profile_string(
+        &self,
+        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+    ) -> StringId {
+        let s = format!("{:?}", self);
+        builder.profiler.alloc_string(&s[..])
+    }
+}
+
+impl IntoSelfProfilingString for DefId {
+    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
+        builder.def_id_to_string_id(*self)
+    }
+}
+
+impl IntoSelfProfilingString for CrateNum {
+    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
+        builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
+    }
+}
+
+impl IntoSelfProfilingString for DefIndex {
+    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
+        builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
+    }
+}
+
+impl<T0, T1> IntoSelfProfilingString for (T0, T1)
+where
+    T0: IntoSelfProfilingString + Debug,
+    T1: IntoSelfProfilingString + Debug,
+{
+    default fn to_self_profile_string(
+        &self,
+        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+    ) -> StringId {
+        let val0 = self.0.to_self_profile_string(builder);
+        let val1 = self.1.to_self_profile_string(builder);
+
+        let components = &[
+            StringComponent::Value("("),
+            StringComponent::Ref(val0),
+            StringComponent::Value(","),
+            StringComponent::Ref(val1),
+            StringComponent::Value(")"),
+        ];
+
+        builder.profiler.alloc_string(components)
+    }
+}
+
+/// Allocate the self-profiling query strings for a single query cache. This
+/// method is called from `alloc_self_profile_query_strings` which knows all
+/// the queries via macro magic.
+pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, Q>(
+    tcx: TyCtxt<'tcx>,
+    query_name: &'static str,
+    query_cache: &Sharded<QueryCache<'tcx, Q>>,
+    string_cache: &mut QueryKeyStringCache,
+) where
+    Q: QueryConfig<'tcx>,
+{
+    tcx.prof.with_profiler(|profiler| {
+        let event_id_builder = profiler.event_id_builder();
+
+        // Walk the entire query cache and allocate the appropriate
+        // string representations. Each cache entry is uniquely
+        // identified by its dep_node_index.
+        if profiler.query_key_recording_enabled() {
+            let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache);
+
+            let query_name = profiler.get_or_alloc_cached_string(query_name);
+
+            // Since building the string representation of query keys might
+            // need to invoke queries itself, we cannot keep the query caches
+            // locked while doing so. Instead we copy out the
+            // `(query_key, dep_node_index)` pairs and release the lock again.
+            let query_keys_and_indices = {
+                let shards = query_cache.lock_shards();
+                let len = shards.iter().map(|shard| shard.results.len()).sum();
+
+                let mut query_keys_and_indices = Vec::with_capacity(len);
+
+                for shard in &shards {
+                    query_keys_and_indices.extend(
+                        shard.results.iter().map(|(q_key, q_val)| (q_key.clone(), q_val.index)),
+                    );
+                }
+
+                query_keys_and_indices
+            };
+
+            // Now actually allocate the strings. If allocating the strings
+            // generates new entries in the query cache, we'll miss them but
+            // we don't actually care.
+            for (query_key, dep_node_index) in query_keys_and_indices {
+                // Translate the DepNodeIndex into a QueryInvocationId
+                let query_invocation_id = dep_node_index.into();
+
+                // Create the string version of the query-key
+                let query_key = query_key.to_self_profile_string(&mut query_string_builder);
+                let event_id = event_id_builder.from_label_and_arg(query_name, query_key);
+
+                // Doing this in bulk might be a good idea:
+                profiler.map_query_invocation_id_to_string(
+                    query_invocation_id,
+                    event_id.to_string_id(),
+                );
+            }
+        } else {
+            // In this branch we don't allocate query keys
+            let query_name = profiler.get_or_alloc_cached_string(query_name);
+            let event_id = event_id_builder.from_label(query_name).to_string_id();
+
+            let shards = query_cache.lock_shards();
+
+            for shard in shards.iter() {
+                let query_invocation_ids = shard
+                    .results
+                    .values()
+                    .map(|v| v.index)
+                    .map(|dep_node_index| dep_node_index.into());
+
+                profiler
+                    .bulk_map_query_invocation_id_to_single_string(query_invocation_ids, event_id);
+            }
+        }
+    });
+}
index 9472281b56fecf144ca8b4672db86eb4d398cf2b..3b9df72266f09a688f0ff5c2061f529c1a8accfc 100644 (file)
@@ -568,12 +568,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),
-            ty::ConstKind::Unevaluated(b_def_id, b_substs),
-        ) if a_def_id == b_def_id => {
+            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 => {
             let substs =
                 relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs))
+            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
         }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
     };
index d87296c03dd2fb96c8d749395e95ab734b12581e..62e895af7f355262852cc5f50f2ccd9dc623231b 100644 (file)
@@ -45,12 +45,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-impl fmt::Debug for ty::ClosureUpvar<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "ClosureUpvar({:?},{:?})", self.res, self.ty)
-    }
-}
-
 impl fmt::Debug for ty::UpvarId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let name = ty::tls::with(|tcx| tcx.hir().name(self.var_path.hir_id));
@@ -1043,8 +1037,8 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
             ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
             ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
-            ty::ConstKind::Unevaluated(did, substs) => {
-                ty::ConstKind::Unevaluated(did, substs.fold_with(folder))
+            ty::ConstKind::Unevaluated(did, substs, promoted) => {
+                ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
             }
             ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => {
                 *self
@@ -1056,7 +1050,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
             ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
             ty::ConstKind::Param(p) => p.visit_with(visitor),
-            ty::ConstKind::Unevaluated(_, substs) => substs.visit_with(visitor),
+            ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
             ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
                 false
             }
diff --git a/src/librustc/ty/structural_match.rs b/src/librustc/ty/structural_match.rs
deleted file mode 100644 (file)
index b2c3c23..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-use crate::ty::fold::{TypeFoldable, TypeVisitor};
-use crate::ty::{self, AdtDef, Ty, TyCtxt};
-
-use rustc::infer::InferCtxt;
-use rustc::traits::ObligationCause;
-use rustc::traits::{self, ConstPatternStructural, TraitEngine};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_span::Span;
-
-#[derive(Debug)]
-pub enum NonStructuralMatchTy<'tcx> {
-    Adt(&'tcx AdtDef),
-    Param,
-}
-
-/// This method traverses the structure of `ty`, trying to find an
-/// instance of an ADT (i.e. struct or enum) that was declared without
-/// the `#[structural_match]` attribute, or a generic type parameter
-/// (which cannot be determined to be `structural_match`).
-///
-/// The "structure of a type" includes all components that would be
-/// considered when doing a pattern match on a constant of that
-/// type.
-///
-///  * This means this method descends into fields of structs/enums,
-///    and also descends into the inner type `T` of `&T` and `&mut T`
-///
-///  * The traversal doesn't dereference unsafe pointers (`*const T`,
-///    `*mut T`), and it does not visit the type arguments of an
-///    instantiated generic like `PhantomData<T>`.
-///
-/// The reason we do this search is Rust currently require all ADTs
-/// reachable from a constant's type to be annotated with
-/// `#[structural_match]`, an attribute which essentially says that
-/// the implementation of `PartialEq::eq` behaves *equivalently* to a
-/// comparison against the unfolded structure.
-///
-/// For more background on why Rust has this requirement, and issues
-/// that arose when the requirement was not enforced completely, see
-/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
-pub fn search_for_structural_match_violation<'tcx>(
-    id: hir::HirId,
-    span: Span,
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<NonStructuralMatchTy<'tcx>> {
-    // FIXME: we should instead pass in an `infcx` from the outside.
-    tcx.infer_ctxt().enter(|infcx| {
-        let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
-        ty.visit_with(&mut search);
-        search.found
-    })
-}
-
-/// This method returns true if and only if `adt_ty` itself has been marked as
-/// eligible for structural-match: namely, if it implements both
-/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
-/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
-///
-/// Note that this does *not* recursively check if the substructure of `adt_ty`
-/// implements the traits.
-pub fn type_marked_structural(
-    id: hir::HirId,
-    span: Span,
-    infcx: &InferCtxt<'_, 'tcx>,
-    adt_ty: Ty<'tcx>,
-) -> bool {
-    let mut fulfillment_cx = traits::FulfillmentContext::new();
-    let cause = ObligationCause::new(span, id, ConstPatternStructural);
-    // require `#[derive(PartialEq)]`
-    let structural_peq_def_id = infcx.tcx.lang_items().structural_peq_trait().unwrap();
-    fulfillment_cx.register_bound(
-        infcx,
-        ty::ParamEnv::empty(),
-        adt_ty,
-        structural_peq_def_id,
-        cause,
-    );
-    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
-    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
-    let cause = ObligationCause::new(span, id, ConstPatternStructural);
-    let structural_teq_def_id = infcx.tcx.lang_items().structural_teq_trait().unwrap();
-    fulfillment_cx.register_bound(
-        infcx,
-        ty::ParamEnv::empty(),
-        adt_ty,
-        structural_teq_def_id,
-        cause,
-    );
-
-    // We deliberately skip *reporting* fulfillment errors (via
-    // `report_fulfillment_errors`), for two reasons:
-    //
-    // 1. The error messages would mention `std::marker::StructuralPartialEq`
-    //    (a trait which is solely meant as an implementation detail
-    //    for now), and
-    //
-    // 2. We are sometimes doing future-incompatibility lints for
-    //    now, so we do not want unconditional errors here.
-    fulfillment_cx.select_all_or_error(infcx).is_ok()
-}
-
-/// This implements the traversal over the structure of a given type to try to
-/// find instances of ADTs (specifically structs or enums) that do not implement
-/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
-struct Search<'a, 'tcx> {
-    id: hir::HirId,
-    span: Span,
-
-    infcx: InferCtxt<'a, 'tcx>,
-
-    /// Records first ADT that does not implement a structural-match trait.
-    found: Option<NonStructuralMatchTy<'tcx>>,
-
-    /// Tracks ADTs previously encountered during search, so that
-    /// we will not recur on them again.
-    seen: FxHashSet<hir::def_id::DefId>,
-}
-
-impl Search<'a, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
-        type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
-    }
-}
-
-impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
-        debug!("Search visiting ty: {:?}", ty);
-
-        let (adt_def, substs) = match ty.kind {
-            ty::Adt(adt_def, substs) => (adt_def, substs),
-            ty::Param(_) => {
-                self.found = Some(NonStructuralMatchTy::Param);
-                return true; // Stop visiting.
-            }
-            ty::RawPtr(..) => {
-                // structural-match ignores substructure of
-                // `*const _`/`*mut _`, so skip `super_visit_with`.
-                //
-                // For example, if you have:
-                // ```
-                // struct NonStructural;
-                // #[derive(PartialEq, Eq)]
-                // struct T(*const NonStructural);
-                // const C: T = T(std::ptr::null());
-                // ```
-                //
-                // Even though `NonStructural` does not implement `PartialEq`,
-                // structural equality on `T` does not recur into the raw
-                // pointer. Therefore, one can still use `C` in a pattern.
-
-                // (But still tell caller to continue search.)
-                return false;
-            }
-            ty::FnDef(..) | ty::FnPtr(..) => {
-                // types of formals and return in `fn(_) -> _` are also irrelevant;
-                // so we do not recur into them via `super_visit_with`
-                //
-                // (But still tell caller to continue search.)
-                return false;
-            }
-            ty::Array(_, n)
-                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
-            {
-                // rust-lang/rust#62336: ignore type of contents
-                // for empty array.
-                return false;
-            }
-            _ => {
-                ty.super_visit_with(self);
-                return false;
-            }
-        };
-
-        if !self.seen.insert(adt_def.did) {
-            debug!("Search already seen adt_def: {:?}", adt_def);
-            // let caller continue its search
-            return false;
-        }
-
-        if !self.type_marked_structural(ty) {
-            debug!("Search found ty: {:?}", ty);
-            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
-            return true; // Halt visiting!
-        }
-
-        // structural-match does not care about the
-        // instantiation of the generics in an ADT (it
-        // instead looks directly at its fields outside
-        // this match), so we skip super_visit_with.
-        //
-        // (Must not recur on substs for `PhantomData<T>` cf
-        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
-        // want to skip substs when only uses of generic are
-        // behind unsafe pointers `*const T`/`*mut T`.)
-
-        // even though we skip super_visit_with, we must recur on
-        // fields of ADT.
-        let tcx = self.tcx();
-        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
-            if field_ty.visit_with(self) {
-                // found an ADT without structural-match; halt visiting!
-                assert!(self.found.is_some());
-                return true;
-            }
-        }
-
-        // Even though we do not want to recur on substs, we do
-        // want our caller to continue its own search.
-        false
-    }
-}
index aeda2eb1a15c0ba01133cb398f3359b78c6ea6db..842361284823dffd707ae39f5478b9e71c3cc463 100644 (file)
@@ -9,15 +9,15 @@
 use crate::middle::region;
 use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::Scalar;
+use crate::mir::Promoted;
 use crate::ty::layout::VariantIdx;
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
 use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS};
-use crate::util::captures::Captures;
+use polonius_engine::Atom;
+use rustc_data_structures::captures::Captures;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-
-use polonius_engine::Atom;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, Symbol};
@@ -2376,7 +2376,7 @@ pub fn try_eval_bits(
 
     #[inline]
     pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
-        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
+        let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
             let param_env_and_substs = param_env.with_reveal_all().and(substs);
 
             // Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
@@ -2388,11 +2388,11 @@ pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx>
 
             // try to resolve e.g. associated constants to their definition on an impl, and then
             // evaluate the const.
-            tcx.const_eval_resolve(param_env, did, substs, None).ok()
+            tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok()
         };
 
         match self.val {
-            ConstKind::Unevaluated(did, substs) => {
+            ConstKind::Unevaluated(did, substs, promoted) => {
                 // HACK(eddyb) when substs contain e.g. inference variables,
                 // attempt using identity substs instead, that will succeed
                 // when the expression doesn't depend on any parameters.
@@ -2402,12 +2402,12 @@ pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx>
                     let identity_substs = InternalSubsts::identity_for_item(tcx, did);
                     // The `ParamEnv` needs to match the `identity_substs`.
                     let identity_param_env = tcx.param_env(did);
-                    match try_const_eval(did, identity_param_env, identity_substs) {
+                    match try_const_eval(did, identity_param_env, identity_substs, promoted) {
                         Some(ct) => ct.subst(tcx, substs),
                         None => self,
                     }
                 } else {
-                    try_const_eval(did, param_env, substs).unwrap_or(self)
+                    try_const_eval(did, param_env, substs, promoted).unwrap_or(self)
                 }
             }
             _ => self,
@@ -2471,7 +2471,7 @@ pub enum ConstKind<'tcx> {
 
     /// 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>),
+    Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
 
     /// Used to hold computed value.
     Value(ConstValue<'tcx>),
index e0f4f2616017d5df10a5d3e199be37c8a7d5623a..8d22ac9dbbe97b60c704a78ad0cf274574e6789c 100644 (file)
@@ -2,23 +2,21 @@
 
 use crate::hir::map::DefPathData;
 use crate::ich::NodeIdHashingMode;
-use crate::middle::lang_items;
 use crate::mir::interpret::{sign_extend, truncate};
-use crate::traits::{self, ObligationCause};
-use crate::ty::layout::{Integer, IntegerExt};
+use crate::ty::layout::{Integer, IntegerExt, Size};
 use crate::ty::query::TyCtxtAt;
 use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use crate::ty::TyKind::*;
 use crate::ty::{self, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable};
 use crate::util::common::ErrorReported;
+use rustc_apfloat::Float as _;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use std::{cmp, fmt};
 use syntax::ast;
 use syntax::attr::{self, SignedInt, UnsignedInt};
@@ -45,26 +43,38 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+fn signed_min(size: Size) -> i128 {
+    sign_extend(1_u128 << (size.bits() - 1), size) as i128
+}
+
+fn signed_max(size: Size) -> i128 {
+    i128::max_value() >> (128 - size.bits())
+}
+
+fn unsigned_max(size: Size) -> u128 {
+    u128::max_value() >> (128 - size.bits())
+}
+
+fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) {
+    let (int, signed) = match ty.kind {
+        Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true),
+        Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false),
+        _ => bug!("non integer discriminant"),
+    };
+    (int.size(), signed)
+}
+
 impl<'tcx> Discr<'tcx> {
     /// Adds `1` to the value and wraps around if the maximum for the type is reached.
     pub fn wrap_incr(self, tcx: TyCtxt<'tcx>) -> Self {
         self.checked_add(tcx, 1).0
     }
     pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) {
-        let (int, signed) = match self.ty.kind {
-            Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true),
-            Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false),
-            _ => bug!("non integer discriminant"),
-        };
-
-        let size = int.size();
-        let bit_size = int.size().bits();
-        let shift = 128 - bit_size;
-        if signed {
-            let sext = |u| sign_extend(u, size) as i128;
-            let min = sext(1_u128 << (bit_size - 1));
-            let max = i128::max_value() >> shift;
-            let val = sext(self.val);
+        let (size, signed) = int_size_and_signed(tcx, self.ty);
+        let (val, oflo) = if signed {
+            let min = signed_min(size);
+            let max = signed_max(size);
+            let val = sign_extend(self.val, size) as i128;
             assert!(n < (i128::max_value() as u128));
             let n = n as i128;
             let oflo = val > max - n;
@@ -72,14 +82,15 @@ pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) {
             // zero the upper bits
             let val = val as u128;
             let val = truncate(val, size);
-            (Self { val: val as u128, ty: self.ty }, oflo)
+            (val, oflo)
         } else {
-            let max = u128::max_value() >> shift;
+            let max = unsigned_max(size);
             let val = self.val;
             let oflo = val > max - n;
             let val = if oflo { n - (max - val) - 1 } else { val + n };
-            (Self { val: val, ty: self.ty }, oflo)
-        }
+            (val, oflo)
+        };
+        (Self { val, ty: self.ty }, oflo)
     }
 }
 
@@ -122,13 +133,6 @@ fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option
     }
 }
 
-#[derive(Clone)]
-pub enum CopyImplementationError<'tcx> {
-    InfrigingFields(Vec<&'tcx ty::FieldDef>),
-    NotAnAdt,
-    HasDestructor,
-}
-
 /// Describes whether a type is representable. For types that are not
 /// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
 /// distinguish between types that are recursive with themselves and types that
@@ -144,65 +148,6 @@ pub enum Representability {
     SelfRecursive(Vec<Span>),
 }
 
-impl<'tcx> ty::ParamEnv<'tcx> {
-    pub fn can_type_implement_copy(
-        self,
-        tcx: TyCtxt<'tcx>,
-        self_type: Ty<'tcx>,
-    ) -> Result<(), CopyImplementationError<'tcx>> {
-        // FIXME: (@jroesch) float this code up
-        tcx.infer_ctxt().enter(|infcx| {
-            let (adt, substs) = match self_type.kind {
-                // These types used to have a builtin impl.
-                // Now libcore provides that impl.
-                ty::Uint(_)
-                | ty::Int(_)
-                | ty::Bool
-                | ty::Float(_)
-                | ty::Char
-                | ty::RawPtr(..)
-                | ty::Never
-                | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
-
-                ty::Adt(adt, substs) => (adt, substs),
-
-                _ => return Err(CopyImplementationError::NotAnAdt),
-            };
-
-            let mut infringing = Vec::new();
-            for variant in &adt.variants {
-                for field in &variant.fields {
-                    let ty = field.ty(tcx, substs);
-                    if ty.references_error() {
-                        continue;
-                    }
-                    let span = tcx.def_span(field.did);
-                    let cause = ObligationCause { span, ..ObligationCause::dummy() };
-                    let ctx = traits::FulfillmentContext::new();
-                    match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
-                        Ok(ty) => {
-                            if !infcx.type_is_copy_modulo_regions(self, ty, span) {
-                                infringing.push(field);
-                            }
-                        }
-                        Err(errors) => {
-                            infcx.report_fulfillment_errors(&errors, None, false);
-                        }
-                    };
-                }
-            }
-            if !infringing.is_empty() {
-                return Err(CopyImplementationError::InfrigingFields(infringing));
-            }
-            if adt.has_dtor(tcx) {
-                return Err(CopyImplementationError::HasDestructor);
-            }
-
-            Ok(())
-        })
-    }
-}
-
 impl<'tcx> TyCtxt<'tcx> {
     /// Creates a hash of the type `Ty` which will be the same no matter what crate
     /// context it's calculated within. This is used by the `type_id` intrinsic.
@@ -393,70 +338,6 @@ pub fn struct_lockstep_tails_with_normalize(
         (a, b)
     }
 
-    /// Given a set of predicates that apply to an object type, returns
-    /// the region bounds that the (erased) `Self` type must
-    /// outlive. Precisely *because* the `Self` type is erased, the
-    /// parameter `erased_self_ty` must be supplied to indicate what type
-    /// has been used to represent `Self` in the predicates
-    /// themselves. This should really be a unique type; `FreshTy(0)` is a
-    /// popular choice.
-    ///
-    /// N.B., in some cases, particularly around higher-ranked bounds,
-    /// this function returns a kind of conservative approximation.
-    /// That is, all regions returned by this function are definitely
-    /// required, but there may be other region bounds that are not
-    /// returned, as well as requirements like `for<'a> T: 'a`.
-    ///
-    /// Requires that trait definitions have been processed so that we can
-    /// elaborate predicates and walk supertraits.
-    //
-    // FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's
-    // what this code should accept.
-    pub fn required_region_bounds(
-        self,
-        erased_self_ty: Ty<'tcx>,
-        predicates: Vec<ty::Predicate<'tcx>>,
-    ) -> Vec<ty::Region<'tcx>> {
-        debug!(
-            "required_region_bounds(erased_self_ty={:?}, predicates={:?})",
-            erased_self_ty, predicates
-        );
-
-        assert!(!erased_self_ty.has_escaping_bound_vars());
-
-        traits::elaborate_predicates(self, predicates)
-            .filter_map(|predicate| {
-                match predicate {
-                    ty::Predicate::Projection(..)
-                    | ty::Predicate::Trait(..)
-                    | ty::Predicate::Subtype(..)
-                    | ty::Predicate::WellFormed(..)
-                    | ty::Predicate::ObjectSafe(..)
-                    | ty::Predicate::ClosureKind(..)
-                    | ty::Predicate::RegionOutlives(..)
-                    | ty::Predicate::ConstEvaluatable(..) => None,
-                    ty::Predicate::TypeOutlives(predicate) => {
-                        // Search for a bound of the form `erased_self_ty
-                        // : 'a`, but be wary of something like `for<'a>
-                        // erased_self_ty : 'a` (we interpret a
-                        // higher-ranked bound like that as 'static,
-                        // though at present the code in `fulfill.rs`
-                        // considers such bounds to be unsatisfiable, so
-                        // it's kind of a moot point since you could never
-                        // construct such an object, but this seems
-                        // correct even if that code changes).
-                        let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder();
-                        if t == &erased_self_ty && !r.has_escaping_bound_vars() {
-                            Some(*r)
-                        } else {
-                            None
-                        }
-                    }
-                }
-            })
-            .collect()
-    }
-
     /// Calculate the destructor of a given type.
     pub fn calculate_dtor(
         self,
@@ -665,8 +546,6 @@ pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> {
 
         if self.is_mutable_static(def_id) {
             self.mk_mut_ptr(static_ty)
-        } else if self.is_foreign_item(def_id) {
-            self.mk_imm_ptr(static_ty)
         } else {
             self.mk_imm_ref(self.lifetimes.re_erased, static_ty)
         }
@@ -755,6 +634,44 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
 }
 
 impl<'tcx> ty::TyS<'tcx> {
+    /// Returns the maximum value for the given numeric type (including `char`s)
+    /// or returns `None` if the type is not numeric.
+    pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
+        let val = match self.kind {
+            ty::Int(_) | ty::Uint(_) => {
+                let (size, signed) = int_size_and_signed(tcx, self);
+                let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) };
+                Some(val)
+            }
+            ty::Char => Some(std::char::MAX as u128),
+            ty::Float(fty) => Some(match fty {
+                ast::FloatTy::F32 => ::rustc_apfloat::ieee::Single::INFINITY.to_bits(),
+                ast::FloatTy::F64 => ::rustc_apfloat::ieee::Double::INFINITY.to_bits(),
+            }),
+            _ => None,
+        };
+        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+    }
+
+    /// Returns the minimum value for the given numeric type (including `char`s)
+    /// or returns `None` if the type is not numeric.
+    pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
+        let val = match self.kind {
+            ty::Int(_) | ty::Uint(_) => {
+                let (size, signed) = int_size_and_signed(tcx, self);
+                let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 };
+                Some(val)
+            }
+            ty::Char => Some(0),
+            ty::Float(fty) => Some(match fty {
+                ast::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
+                ast::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
+            }),
+            _ => None,
+        };
+        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+    }
+
     /// Checks whether values of this type `T` are *moved* or *copied*
     /// when referenced -- this amounts to a check for whether `T:
     /// Copy`, but note that we **don't** consider lifetimes when
@@ -1006,128 +923,9 @@ pub fn peel_refs(&'tcx self) -> Ty<'tcx> {
     }
 }
 
-fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
-}
-
-fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
-}
-
-fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
-}
-
-fn is_item_raw<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-    item: lang_items::LangItem,
-) -> bool {
-    let (param_env, ty) = query.into_parts();
-    let trait_def_id = tcx.require_lang_item(item, None);
-    tcx.infer_ctxt().enter(|infcx| {
-        traits::type_known_to_meet_bound_modulo_regions(
-            &infcx,
-            param_env,
-            ty,
-            trait_def_id,
-            DUMMY_SP,
-        )
-    })
-}
-
 #[derive(Clone, HashStable)]
 pub struct NeedsDrop(pub bool);
 
-fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
-    let (param_env, ty) = query.into_parts();
-
-    let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
-
-    assert!(!ty.needs_infer());
-
-    NeedsDrop(match ty.kind {
-        // Fast-path for primitive types
-        ty::Infer(ty::FreshIntTy(_))
-        | ty::Infer(ty::FreshFloatTy(_))
-        | ty::Bool
-        | ty::Int(_)
-        | ty::Uint(_)
-        | ty::Float(_)
-        | ty::Never
-        | ty::FnDef(..)
-        | ty::FnPtr(_)
-        | ty::Char
-        | ty::GeneratorWitness(..)
-        | ty::RawPtr(_)
-        | ty::Ref(..)
-        | ty::Str => false,
-
-        // Foreign types can never have destructors
-        ty::Foreign(..) => false,
-
-        // `ManuallyDrop` doesn't have a destructor regardless of field types.
-        ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
-
-        // Issue #22536: We first query `is_copy_modulo_regions`.  It sees a
-        // normalized version of the type, and therefore will definitely
-        // know whether the type implements Copy (and thus needs no
-        // cleanup/drop/zeroing) ...
-        _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
-
-        // ... (issue #22536 continued) but as an optimization, still use
-        // prior logic of asking for the structural "may drop".
-
-        // FIXME(#22815): Note that this is a conservative heuristic;
-        // it may report that the type "may drop" when actual type does
-        // not actually have a destructor associated with it. But since
-        // the type absolutely did not have the `Copy` bound attached
-        // (see above), it is sound to treat it as having a destructor.
-
-        // User destructors are the only way to have concrete drop types.
-        ty::Adt(def, _) if def.has_dtor(tcx) => true,
-
-        // Can refer to a type which may drop.
-        // FIXME(eddyb) check this against a ParamEnv.
-        ty::Dynamic(..)
-        | ty::Projection(..)
-        | ty::Param(_)
-        | ty::Bound(..)
-        | ty::Placeholder(..)
-        | ty::Opaque(..)
-        | ty::Infer(_)
-        | ty::Error => true,
-
-        ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
-        // Zero-length arrays never contain anything to drop.
-        ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
-
-        // Structural recursion.
-        ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
-
-        ty::Closure(def_id, ref substs) => {
-            substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
-        }
-
-        // Pessimistically assume that all generators will require destructors
-        // as we don't know if a destructor is a noop or not until after the MIR
-        // state transformation pass
-        ty::Generator(..) => true,
-
-        ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
-
-        // unions don't have destructors because of the child types,
-        // only if they manually implement `Drop` (handled above).
-        ty::Adt(def, _) if def.is_union() => false,
-
-        ty::Adt(def, substs) => def
-            .variants
-            .iter()
-            .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
-    })
-}
-
 pub enum ExplicitSelf<'tcx> {
     ByValue,
     ByReference(ty::Region<'tcx>, hir::Mutability),
@@ -1176,13 +974,3 @@ pub fn determine<P>(self_arg_ty: Ty<'tcx>, is_self_ty: P) -> ExplicitSelf<'tcx>
         }
     }
 }
-
-pub fn provide(providers: &mut ty::query::Providers<'_>) {
-    *providers = ty::query::Providers {
-        is_copy_raw,
-        is_sized_raw,
-        is_freeze_raw,
-        needs_drop_raw,
-        ..*providers
-    };
-}
index 9e0dd8e067a203a5d2356730a86dd93d4c68f354..da08fbcf14432f384a097ccec4c13f569b1b85cb 100644 (file)
@@ -81,7 +81,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
         | ty::Bound(..)
         | ty::Foreign(..) => {}
         ty::Array(ty, len) => {
-            if let ty::ConstKind::Unevaluated(_, substs) = len.val {
+            if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val {
+                assert!(promoted.is_none());
                 stack.extend(substs.types().rev());
             }
             stack.push(len.ty);
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
deleted file mode 100644 (file)
index 60f5973..0000000
+++ /dev/null
@@ -1,746 +0,0 @@
-use crate::infer::InferCtxt;
-use crate::middle::lang_items;
-use crate::traits::{self, AssocTypeBoundData};
-use crate::ty::subst::SubstsRef;
-use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_span::symbol::{kw, Ident};
-use rustc_span::Span;
-use std::iter::once;
-
-/// Returns the set of obligations needed to make `ty` well-formed.
-/// If `ty` contains unresolved inference variables, this may include
-/// further WF obligations. However, if `ty` IS an unresolved
-/// inference variable, returns `None`, because we are not able to
-/// make any progress at all. This is to prevent "livelock" where we
-/// say "$0 is WF if $0 is WF".
-pub fn obligations<'a, 'tcx>(
-    infcx: &InferCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
-    ty: Ty<'tcx>,
-    span: Span,
-) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
-    if wf.compute(ty) {
-        debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
-        let result = wf.normalize();
-        debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
-        Some(result)
-    } else {
-        None // no progress made, return None
-    }
-}
-
-/// Returns the obligations that make this trait reference
-/// well-formed.  For example, if there is a trait `Set` defined like
-/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
-/// if `Bar: Eq`.
-pub fn trait_obligations<'a, 'tcx>(
-    infcx: &InferCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
-    trait_ref: &ty::TraitRef<'tcx>,
-    span: Span,
-    item: Option<&'tcx hir::Item<'tcx>>,
-) -> Vec<traits::PredicateObligation<'tcx>> {
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
-    wf.compute_trait_ref(trait_ref, Elaborate::All);
-    wf.normalize()
-}
-
-pub fn predicate_obligations<'a, 'tcx>(
-    infcx: &InferCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
-    predicate: &ty::Predicate<'tcx>,
-    span: Span,
-) -> Vec<traits::PredicateObligation<'tcx>> {
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
-
-    // (*) ok to skip binders, because wf code is prepared for it
-    match *predicate {
-        ty::Predicate::Trait(ref t) => {
-            wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*)
-        }
-        ty::Predicate::RegionOutlives(..) => {}
-        ty::Predicate::TypeOutlives(ref t) => {
-            wf.compute(t.skip_binder().0);
-        }
-        ty::Predicate::Projection(ref t) => {
-            let t = t.skip_binder(); // (*)
-            wf.compute_projection(t.projection_ty);
-            wf.compute(t.ty);
-        }
-        ty::Predicate::WellFormed(t) => {
-            wf.compute(t);
-        }
-        ty::Predicate::ObjectSafe(_) => {}
-        ty::Predicate::ClosureKind(..) => {}
-        ty::Predicate::Subtype(ref data) => {
-            wf.compute(data.skip_binder().a); // (*)
-            wf.compute(data.skip_binder().b); // (*)
-        }
-        ty::Predicate::ConstEvaluatable(def_id, substs) => {
-            let obligations = wf.nominal_obligations(def_id, substs);
-            wf.out.extend(obligations);
-
-            for ty in substs.types() {
-                wf.compute(ty);
-            }
-        }
-    }
-
-    wf.normalize()
-}
-
-struct WfPredicates<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    body_id: hir::HirId,
-    span: Span,
-    out: Vec<traits::PredicateObligation<'tcx>>,
-    item: Option<&'tcx hir::Item<'tcx>>,
-}
-
-/// Controls whether we "elaborate" supertraits and so forth on the WF
-/// predicates. This is a kind of hack to address #43784. The
-/// underlying problem in that issue was a trait structure like:
-///
-/// ```
-/// trait Foo: Copy { }
-/// trait Bar: Foo { }
-/// impl<T: Bar> Foo for T { }
-/// impl<T> Bar for T { }
-/// ```
-///
-/// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but
-/// we decide that this is true because `T: Bar` is in the
-/// where-clauses (and we can elaborate that to include `T:
-/// Copy`). This wouldn't be a problem, except that when we check the
-/// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo`
-/// impl. And so nowhere did we check that `T: Copy` holds!
-///
-/// To resolve this, we elaborate the WF requirements that must be
-/// proven when checking impls. This means that (e.g.) the `impl Bar
-/// for T` will be forced to prove not only that `T: Foo` but also `T:
-/// Copy` (which it won't be able to do, because there is no `Copy`
-/// impl for `T`).
-#[derive(Debug, PartialEq, Eq, Copy, Clone)]
-enum Elaborate {
-    All,
-    None,
-}
-
-impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
-    fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
-        traits::ObligationCause::new(self.span, self.body_id, code)
-    }
-
-    fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
-        let cause = self.cause(traits::MiscObligation);
-        let infcx = &mut self.infcx;
-        let param_env = self.param_env;
-        self.out
-            .iter()
-            .inspect(|pred| assert!(!pred.has_escaping_bound_vars()))
-            .flat_map(|pred| {
-                let mut selcx = traits::SelectionContext::new(infcx);
-                let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred);
-                once(pred.value).chain(pred.obligations)
-            })
-            .collect()
-    }
-
-    /// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
-    fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
-        let tcx = self.infcx.tcx;
-        let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
-
-        let cause = self.cause(traits::MiscObligation);
-        let param_env = self.param_env;
-
-        let item = &self.item;
-        let extend_cause_with_original_assoc_item_obligation =
-            |cause: &mut traits::ObligationCause<'_>,
-             pred: &ty::Predicate<'_>,
-             trait_assoc_items: ty::AssocItemsIterator<'_>| {
-                let trait_item = tcx
-                    .hir()
-                    .as_local_hir_id(trait_ref.def_id)
-                    .and_then(|trait_id| tcx.hir().find(trait_id));
-                let (trait_name, trait_generics) = match trait_item {
-                    Some(hir::Node::Item(hir::Item {
-                        ident,
-                        kind: hir::ItemKind::Trait(.., generics, _, _),
-                        ..
-                    }))
-                    | Some(hir::Node::Item(hir::Item {
-                        ident,
-                        kind: hir::ItemKind::TraitAlias(generics, _),
-                        ..
-                    })) => (Some(ident), Some(generics)),
-                    _ => (None, None),
-                };
-
-                let item_span = item.map(|i| tcx.sess.source_map().def_span(i.span));
-                match pred {
-                    ty::Predicate::Projection(proj) => {
-                        // The obligation comes not from the current `impl` nor the `trait` being
-                        // implemented, but rather from a "second order" obligation, like in
-                        // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`:
-                        //
-                        //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
-                        //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
-                        //      |
-                        //   LL |     type Ok;
-                        //      |          -- associated type defined here
-                        //   ...
-                        //   LL | impl Bar for Foo {
-                        //      | ---------------- in this `impl` item
-                        //   LL |     type Ok = ();
-                        //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
-                        //      |
-                        //      = note: expected type `u32`
-                        //                 found type `()`
-                        //
-                        // FIXME: we would want to point a span to all places that contributed to this
-                        // obligation. In the case above, it should be closer to:
-                        //
-                        //   error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
-                        //     --> $DIR/point-at-type-on-obligation-failure.rs:13:5
-                        //      |
-                        //   LL |     type Ok;
-                        //      |          -- associated type defined here
-                        //   LL |     type Sibling: Bar2<Ok=Self::Ok>;
-                        //      |     -------------------------------- obligation set here
-                        //   ...
-                        //   LL | impl Bar for Foo {
-                        //      | ---------------- in this `impl` item
-                        //   LL |     type Ok = ();
-                        //      |     ^^^^^^^^^^^^^ expected `u32`, found `()`
-                        //   ...
-                        //   LL | impl Bar2 for Foo2 {
-                        //      | ---------------- in this `impl` item
-                        //   LL |     type Ok = u32;
-                        //      |     -------------- obligation set here
-                        //      |
-                        //      = note: expected type `u32`
-                        //                 found type `()`
-                        if let Some(hir::ItemKind::Impl(.., impl_items)) = item.map(|i| &i.kind) {
-                            let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
-                            if let Some(impl_item) = impl_items
-                                .iter()
-                                .filter(|item| item.ident == trait_assoc_item.ident)
-                                .next()
-                            {
-                                cause.span = impl_item.span;
-                                cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
-                                    impl_span: item_span,
-                                    original: trait_assoc_item.ident.span,
-                                    bounds: vec![],
-                                }));
-                            }
-                        }
-                    }
-                    ty::Predicate::Trait(proj) => {
-                        // An associated item obligation born out of the `trait` failed to be met.
-                        // Point at the `impl` that failed the obligation, the associated item that
-                        // needed to meet the obligation, and the definition of that associated item,
-                        // which should hold the obligation in most cases. An example can be seen in
-                        // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`:
-                        //
-                        //   error[E0277]: the trait bound `bool: Bar` is not satisfied
-                        //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
-                        //      |
-                        //   LL |     type Assoc: Bar;
-                        //      |          ----- associated type defined here
-                        //   ...
-                        //   LL | impl Foo for () {
-                        //      | --------------- in this `impl` item
-                        //   LL |     type Assoc = bool;
-                        //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
-                        //
-                        // If the obligation comes from the where clause in the `trait`, we point at it:
-                        //
-                        //   error[E0277]: the trait bound `bool: Bar` is not satisfied
-                        //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
-                        //      |
-                        //      | trait Foo where <Self as Foo>>::Assoc: Bar {
-                        //      |                 -------------------------- restricted in this bound
-                        //   LL |     type Assoc;
-                        //      |          ----- associated type defined here
-                        //   ...
-                        //   LL | impl Foo for () {
-                        //      | --------------- in this `impl` item
-                        //   LL |     type Assoc = bool;
-                        //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
-                        if let (
-                            ty::Projection(ty::ProjectionTy { item_def_id, .. }),
-                            Some(hir::ItemKind::Impl(.., impl_items)),
-                        ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind))
-                        {
-                            if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
-                                .filter(|i| i.def_id == *item_def_id)
-                                .next()
-                                .and_then(|trait_assoc_item| {
-                                    impl_items
-                                        .iter()
-                                        .filter(|i| i.ident == trait_assoc_item.ident)
-                                        .next()
-                                        .map(|impl_item| (impl_item, trait_assoc_item))
-                                })
-                            {
-                                let bounds = trait_generics
-                                    .map(|generics| {
-                                        get_generic_bound_spans(
-                                            &generics,
-                                            trait_name,
-                                            trait_assoc_item.ident,
-                                        )
-                                    })
-                                    .unwrap_or_else(Vec::new);
-                                cause.span = impl_item.span;
-                                cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
-                                    impl_span: item_span,
-                                    original: trait_assoc_item.ident.span,
-                                    bounds,
-                                }));
-                            }
-                        }
-                    }
-                    _ => {}
-                }
-            };
-
-        if let Elaborate::All = elaborate {
-            let trait_assoc_items = tcx.associated_items(trait_ref.def_id);
-
-            let predicates =
-                obligations.iter().map(|obligation| obligation.predicate.clone()).collect();
-            let implied_obligations = traits::elaborate_predicates(tcx, predicates);
-            let implied_obligations = implied_obligations.map(|pred| {
-                let mut cause = cause.clone();
-                extend_cause_with_original_assoc_item_obligation(
-                    &mut cause,
-                    &pred,
-                    trait_assoc_items.clone(),
-                );
-                traits::Obligation::new(cause, param_env, pred)
-            });
-            self.out.extend(implied_obligations);
-        }
-
-        self.out.extend(obligations);
-
-        self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map(
-            |ty| traits::Obligation::new(cause.clone(), param_env, ty::Predicate::WellFormed(ty)),
-        ));
-    }
-
-    /// Pushes the obligations required for `trait_ref::Item` to be WF
-    /// into `self.out`.
-    fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
-        // A projection is well-formed if (a) the trait ref itself is
-        // WF and (b) the trait-ref holds.  (It may also be
-        // normalizable and be WF that way.)
-        let trait_ref = data.trait_ref(self.infcx.tcx);
-        self.compute_trait_ref(&trait_ref, Elaborate::None);
-
-        if !data.has_escaping_bound_vars() {
-            let predicate = trait_ref.to_predicate();
-            let cause = self.cause(traits::ProjectionWf(data));
-            self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
-        }
-    }
-
-    /// Pushes the obligations required for an array length to be WF
-    /// into `self.out`.
-    fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
-        if let ty::ConstKind::Unevaluated(def_id, substs) = constant.val {
-            let obligations = self.nominal_obligations(def_id, substs);
-            self.out.extend(obligations);
-
-            let predicate = ty::Predicate::ConstEvaluatable(def_id, substs);
-            let cause = self.cause(traits::MiscObligation);
-            self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
-        }
-    }
-
-    fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
-        if !subty.has_escaping_bound_vars() {
-            let cause = self.cause(cause);
-            let trait_ref = ty::TraitRef {
-                def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
-                substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
-            };
-            self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
-        }
-    }
-
-    /// Pushes new obligations into `out`. Returns `true` if it was able
-    /// to generate all the predicates needed to validate that `ty0`
-    /// is WF. Returns false if `ty0` is an unresolved type variable,
-    /// in which case we are not able to simplify at all.
-    fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
-        let mut subtys = ty0.walk();
-        let param_env = self.param_env;
-        while let Some(ty) = subtys.next() {
-            match ty.kind {
-                ty::Bool
-                | ty::Char
-                | ty::Int(..)
-                | ty::Uint(..)
-                | ty::Float(..)
-                | ty::Error
-                | ty::Str
-                | ty::GeneratorWitness(..)
-                | ty::Never
-                | ty::Param(_)
-                | ty::Bound(..)
-                | ty::Placeholder(..)
-                | ty::Foreign(..) => {
-                    // WfScalar, WfParameter, etc
-                }
-
-                ty::Slice(subty) => {
-                    self.require_sized(subty, traits::SliceOrArrayElem);
-                }
-
-                ty::Array(subty, len) => {
-                    self.require_sized(subty, traits::SliceOrArrayElem);
-                    self.compute_array_len(*len);
-                }
-
-                ty::Tuple(ref tys) => {
-                    if let Some((_last, rest)) = tys.split_last() {
-                        for elem in rest {
-                            self.require_sized(elem.expect_ty(), traits::TupleElem);
-                        }
-                    }
-                }
-
-                ty::RawPtr(_) => {
-                    // simple cases that are WF if their type args are WF
-                }
-
-                ty::Projection(data) => {
-                    subtys.skip_current_subtree(); // subtree handled by compute_projection
-                    self.compute_projection(data);
-                }
-
-                ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
-                ty::Adt(def, substs) => {
-                    // WfNominalType
-                    let obligations = self.nominal_obligations(def.did, substs);
-                    self.out.extend(obligations);
-                }
-
-                ty::FnDef(did, substs) => {
-                    let obligations = self.nominal_obligations(did, substs);
-                    self.out.extend(obligations);
-                }
-
-                ty::Ref(r, rty, _) => {
-                    // WfReference
-                    if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
-                        let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
-                        self.out.push(traits::Obligation::new(
-                            cause,
-                            param_env,
-                            ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
-                                rty, r,
-                            ))),
-                        ));
-                    }
-                }
-
-                ty::Generator(..) => {
-                    // Walk ALL the types in the generator: this will
-                    // include the upvar types as well as the yield
-                    // type. Note that this is mildly distinct from
-                    // the closure case, where we have to be careful
-                    // about the signature of the closure. We don't
-                    // have the problem of implied bounds here since
-                    // generators don't take arguments.
-                }
-
-                ty::Closure(def_id, substs) => {
-                    // Only check the upvar types for WF, not the rest
-                    // of the types within. This is needed because we
-                    // capture the signature and it may not be WF
-                    // without the implied bounds. Consider a closure
-                    // like `|x: &'a T|` -- it may be that `T: 'a` is
-                    // not known to hold in the creator's context (and
-                    // indeed the closure may not be invoked by its
-                    // creator, but rather turned to someone who *can*
-                    // verify that).
-                    //
-                    // The special treatment of closures here really
-                    // ought not to be necessary either; the problem
-                    // is related to #25860 -- there is no way for us
-                    // to express a fn type complete with the implied
-                    // bounds that it is assuming. I think in reality
-                    // the WF rules around fn are a bit messed up, and
-                    // that is the rot problem: `fn(&'a T)` should
-                    // probably always be WF, because it should be
-                    // shorthand for something like `where(T: 'a) {
-                    // fn(&'a T) }`, as discussed in #25860.
-                    //
-                    // Note that we are also skipping the generic
-                    // types. This is consistent with the `outlives`
-                    // code, but anyway doesn't matter: within the fn
-                    // body where they are created, the generics will
-                    // always be WF, and outside of that fn body we
-                    // are not directly inspecting closure types
-                    // anyway, except via auto trait matching (which
-                    // only inspects the upvar types).
-                    subtys.skip_current_subtree(); // subtree handled by compute_projection
-                    for upvar_ty in substs.as_closure().upvar_tys(def_id, self.infcx.tcx) {
-                        self.compute(upvar_ty);
-                    }
-                }
-
-                ty::FnPtr(_) => {
-                    // let the loop iterate into the argument/return
-                    // types appearing in the fn signature
-                }
-
-                ty::Opaque(did, substs) => {
-                    // all of the requirements on type parameters
-                    // should've been checked by the instantiation
-                    // of whatever returned this exact `impl Trait`.
-
-                    // for named opaque `impl Trait` types we still need to check them
-                    if super::is_impl_trait_defn(self.infcx.tcx, did).is_none() {
-                        let obligations = self.nominal_obligations(did, substs);
-                        self.out.extend(obligations);
-                    }
-                }
-
-                ty::Dynamic(data, r) => {
-                    // WfObject
-                    //
-                    // Here, we defer WF checking due to higher-ranked
-                    // regions. This is perhaps not ideal.
-                    self.from_object_ty(ty, data, r);
-
-                    // FIXME(#27579) RFC also considers adding trait
-                    // obligations that don't refer to Self and
-                    // checking those
-
-                    let defer_to_coercion = self.infcx.tcx.features().object_safe_for_dispatch;
-
-                    if !defer_to_coercion {
-                        let cause = self.cause(traits::MiscObligation);
-                        let component_traits = data.auto_traits().chain(data.principal_def_id());
-                        self.out.extend(component_traits.map(|did| {
-                            traits::Obligation::new(
-                                cause.clone(),
-                                param_env,
-                                ty::Predicate::ObjectSafe(did),
-                            )
-                        }));
-                    }
-                }
-
-                // Inference variables are the complicated case, since we don't
-                // know what type they are. We do two things:
-                //
-                // 1. Check if they have been resolved, and if so proceed with
-                //    THAT type.
-                // 2. If not, check whether this is the type that we
-                //    started with (ty0). In that case, we've made no
-                //    progress at all, so return false. Otherwise,
-                //    we've at least simplified things (i.e., we went
-                //    from `Vec<$0>: WF` to `$0: WF`, so we can
-                //    register a pending obligation and keep
-                //    moving. (Goal is that an "inductive hypothesis"
-                //    is satisfied to ensure termination.)
-                ty::Infer(_) => {
-                    let ty = self.infcx.shallow_resolve(ty);
-                    if let ty::Infer(_) = ty.kind {
-                        // not yet resolved...
-                        if ty == ty0 {
-                            // ...this is the type we started from! no progress.
-                            return false;
-                        }
-
-                        let cause = self.cause(traits::MiscObligation);
-                        self.out.push(
-                            // ...not the type we started from, so we made progress.
-                            traits::Obligation::new(
-                                cause,
-                                self.param_env,
-                                ty::Predicate::WellFormed(ty),
-                            ),
-                        );
-                    } else {
-                        // Yes, resolved, proceed with the
-                        // result. Should never return false because
-                        // `ty` is not a Infer.
-                        assert!(self.compute(ty));
-                    }
-                }
-            }
-        }
-
-        // if we made it through that loop above, we made progress!
-        return true;
-    }
-
-    fn nominal_obligations(
-        &mut self,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-    ) -> Vec<traits::PredicateObligation<'tcx>> {
-        let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs);
-        let cause = self.cause(traits::ItemObligation(def_id));
-        predicates
-            .predicates
-            .into_iter()
-            .map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred))
-            .filter(|pred| !pred.has_escaping_bound_vars())
-            .collect()
-    }
-
-    fn from_object_ty(
-        &mut self,
-        ty: Ty<'tcx>,
-        data: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
-        region: ty::Region<'tcx>,
-    ) {
-        // Imagine a type like this:
-        //
-        //     trait Foo { }
-        //     trait Bar<'c> : 'c { }
-        //
-        //     &'b (Foo+'c+Bar<'d>)
-        //         ^
-        //
-        // In this case, the following relationships must hold:
-        //
-        //     'b <= 'c
-        //     'd <= 'c
-        //
-        // The first conditions is due to the normal region pointer
-        // rules, which say that a reference cannot outlive its
-        // referent.
-        //
-        // The final condition may be a bit surprising. In particular,
-        // you may expect that it would have been `'c <= 'd`, since
-        // usually lifetimes of outer things are conservative
-        // approximations for inner things. However, it works somewhat
-        // differently with trait objects: here the idea is that if the
-        // user specifies a region bound (`'c`, in this case) it is the
-        // "master bound" that *implies* that bounds from other traits are
-        // all met. (Remember that *all bounds* in a type like
-        // `Foo+Bar+Zed` must be met, not just one, hence if we write
-        // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
-        // 'y.)
-        //
-        // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
-        // am looking forward to the future here.
-        if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
-            let implicit_bounds = object_region_bounds(self.infcx.tcx, data);
-
-            let explicit_bound = region;
-
-            self.out.reserve(implicit_bounds.len());
-            for implicit_bound in implicit_bounds {
-                let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
-                let outlives =
-                    ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
-                self.out.push(traits::Obligation::new(
-                    cause,
-                    self.param_env,
-                    outlives.to_predicate(),
-                ));
-            }
-        }
-    }
-}
-
-/// Given an object type like `SomeTrait + Send`, computes the lifetime
-/// bounds that must hold on the elided self type. These are derived
-/// from the declarations of `SomeTrait`, `Send`, and friends -- if
-/// they declare `trait SomeTrait : 'static`, for example, then
-/// `'static` would appear in the list. The hard work is done by
-/// `ty::required_region_bounds`, see that for more information.
-pub fn object_region_bounds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>,
-) -> Vec<ty::Region<'tcx>> {
-    // Since we don't actually *know* the self type for an object,
-    // this "open(err)" serves as a kind of dummy standin -- basically
-    // a placeholder type.
-    let open_ty = tcx.mk_ty_infer(ty::FreshTy(0));
-
-    let predicates = existential_predicates
-        .iter()
-        .filter_map(|predicate| {
-            if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() {
-                None
-            } else {
-                Some(predicate.with_self_ty(tcx, open_ty))
-            }
-        })
-        .collect();
-
-    tcx.required_region_bounds(open_ty, predicates)
-}
-
-/// Find the span of a generic bound affecting an associated type.
-fn get_generic_bound_spans(
-    generics: &hir::Generics<'_>,
-    trait_name: Option<&Ident>,
-    assoc_item_name: Ident,
-) -> Vec<Span> {
-    let mut bounds = vec![];
-    for clause in generics.where_clause.predicates.iter() {
-        if let hir::WherePredicate::BoundPredicate(pred) = clause {
-            match &pred.bounded_ty.kind {
-                hir::TyKind::Path(hir::QPath::Resolved(Some(ty), path)) => {
-                    let mut s = path.segments.iter();
-                    if let (a, Some(b), None) = (s.next(), s.next(), s.next()) {
-                        if a.map(|s| &s.ident) == trait_name
-                            && b.ident == assoc_item_name
-                            && is_self_path(&ty.kind)
-                        {
-                            // `<Self as Foo>::Bar`
-                            bounds.push(pred.span);
-                        }
-                    }
-                }
-                hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => {
-                    if segment.ident == assoc_item_name {
-                        if is_self_path(&ty.kind) {
-                            // `Self::Bar`
-                            bounds.push(pred.span);
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-    }
-    bounds
-}
-
-fn is_self_path(kind: &hir::TyKind<'_>) -> bool {
-    match kind {
-        hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
-            let mut s = path.segments.iter();
-            if let (Some(segment), None) = (s.next(), s.next()) {
-                if segment.ident.name == kw::SelfUpper {
-                    // `type(Self)`
-                    return true;
-                }
-            }
-        }
-        _ => {}
-    }
-    false
-}
diff --git a/src/librustc/util/captures.rs b/src/librustc/util/captures.rs
deleted file mode 100644 (file)
index 26b90eb..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/// "Signaling" trait used in impl trait to tag lifetimes that you may
-/// need to capture but don't really need for other reasons.
-/// Basically a workaround; see [this comment] for details.
-///
-/// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
-// FIXME(eddyb) false positive, the lifetime parameter is "phantom" but needed.
-#[allow(unused_lifetimes)]
-pub trait Captures<'a> {}
-
-impl<'a, T: ?Sized> Captures<'a> for T {}
index 9574685215741baf8f7b232626a6bd58689b5ceb..19b43bfd162415089209b4c3a37f5742d021504c 100644 (file)
@@ -5,15 +5,10 @@
 use std::fmt::Debug;
 use std::time::{Duration, Instant};
 
-use rustc_span::symbol::{sym, Symbol};
-
 #[cfg(test)]
 mod tests;
 
-// The name of the associated type for `Fn` return types.
-pub const FN_OUTPUT_NAME: Symbol = sym::Output;
-
-pub use errors::ErrorReported;
+pub use rustc_errors::ErrorReported;
 
 pub fn to_readable_str(mut val: usize) -> String {
     let mut groups = vec![];
diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml
deleted file mode 100644 (file)
index df117de..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-build = "build.rs"
-name = "rustc_asan"
-version = "0.0.0"
-edition = "2018"
-
-[lib]
-name = "rustc_asan"
-path = "lib.rs"
-test = false
-
-[build-dependencies]
-build_helper = { path = "../build_helper" }
-cmake = "0.1.38"
-
-[dependencies]
-alloc = { path = "../liballoc" }
-core = { path = "../libcore" }
-compiler_builtins = "0.1.0"
diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs
deleted file mode 100644 (file)
index e276dc1..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-use build_helper::sanitizer_lib_boilerplate;
-use std::env;
-
-use cmake::Config;
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
-    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
-        return;
-    }
-    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
-        build_helper::restore_library_path();
-
-        let (native, target) = match sanitizer_lib_boilerplate("asan") {
-            Ok(native) => native,
-            _ => return,
-        };
-
-        Config::new(&native.src_dir)
-            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
-            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
-            .define("COMPILER_RT_BUILD_XRAY", "OFF")
-            .define("LLVM_CONFIG_PATH", llvm_config)
-            .out_dir(&native.out_dir)
-            .build_target(&target)
-            .build();
-        native.fixup_sanitizer_lib_name("asan");
-    }
-    println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
-}
diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs
deleted file mode 100644 (file)
index bdbc154..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#![sanitizer_runtime]
-#![feature(nll)]
-#![feature(sanitizer_runtime)]
-#![feature(staged_api)]
-#![no_std]
-#![unstable(
-    feature = "sanitizer_runtime_lib",
-    reason = "internal implementation detail of sanitizers",
-    issue = "none"
-)]
index 6c8b8b05057169c886fa9618a787214acea97155..9a229e709a5e55dd911f1038b24db78f69687016 100644 (file)
@@ -3,6 +3,7 @@
 use rustc::bug;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
@@ -10,7 +11,6 @@
 use syntax::ast::*;
 use syntax::attr;
 use syntax::ptr::P as AstP;
-use syntax::{span_err, struct_span_err};
 
 impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
@@ -202,7 +202,12 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
             ExprKind::Mac(_) => panic!("Shouldn't exist here"),
         };
 
-        hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: e.span, attrs: e.attrs.clone() }
+        hir::Expr {
+            hir_id: self.lower_node_id(e.id),
+            kind,
+            span: e.span,
+            attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
+        }
     }
 
     fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
@@ -685,12 +690,13 @@ fn generator_movability_for_fn(
         match generator_kind {
             Some(hir::GeneratorKind::Gen) => {
                 if !decl.inputs.is_empty() {
-                    span_err!(
+                    struct_span_err!(
                         self.sess,
                         fn_decl_span,
                         E0628,
                         "generators cannot have explicit parameters"
-                    );
+                    )
+                    .emit();
                 }
                 Some(movability)
             }
@@ -699,7 +705,8 @@ fn generator_movability_for_fn(
             }
             None => {
                 if movability == Movability::Static {
-                    span_err!(self.sess, fn_decl_span, E0697, "closures cannot be static");
+                    struct_span_err!(self.sess, fn_decl_span, E0697, "closures cannot be static")
+                        .emit();
                 }
                 None
             }
@@ -946,7 +953,13 @@ fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::Expr
         match self.generator_kind {
             Some(hir::GeneratorKind::Gen) => {}
             Some(hir::GeneratorKind::Async(_)) => {
-                span_err!(self.sess, span, E0727, "`async` generators are not yet supported",);
+                struct_span_err!(
+                    self.sess,
+                    span,
+                    E0727,
+                    "`async` generators are not yet supported"
+                )
+                .emit();
                 return hir::ExprKind::Err;
             }
             None => self.generator_kind = Some(hir::GeneratorKind::Gen),
index 2515ca9d9466ad4c5dbc5edcdf28c9db8ccea7d4..beb53a19ac4ffae7bdbcb5e1be8111656b919dfa 100644 (file)
@@ -4,6 +4,7 @@
 use rustc::arena::Arena;
 use rustc::bug;
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -14,7 +15,6 @@
 use rustc_target::spec::abi;
 use syntax::ast::*;
 use syntax::attr;
-use syntax::struct_span_err;
 use syntax::visit::{self, Visitor};
 
 use log::debug;
@@ -25,19 +25,16 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
     pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
 }
 
-impl<'a, 'lowering, 'hir> ItemLowerer<'a, 'lowering, 'hir> {
-    fn with_trait_impl_ref<F>(&mut self, trait_impl_ref: &Option<TraitRef>, f: F)
-    where
-        F: FnOnce(&mut Self),
-    {
+impl ItemLowerer<'_, '_, '_> {
+    fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
         let old = self.lctx.is_in_trait_impl;
-        self.lctx.is_in_trait_impl = if let &None = trait_impl_ref { false } else { true };
+        self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true };
         f(self);
         self.lctx.is_in_trait_impl = old;
     }
 }
 
-impl<'a, 'lowering, 'hir> Visitor<'a> for ItemLowerer<'a, 'lowering, 'hir> {
+impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
     fn visit_mod(&mut self, m: &'a Mod, _s: Span, _attrs: &[Attribute], n: NodeId) {
         let hir_id = self.lctx.lower_node_id(n);
 
@@ -71,6 +68,12 @@ fn visit_item(&mut self, item: &'a Item) {
             self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
                 let this = &mut ItemLowerer { lctx: this };
                 if let ItemKind::Impl(.., ref opt_trait_ref, _, _) = item.kind {
+                    if opt_trait_ref.as_ref().map(|tr| tr.constness.is_some()).unwrap_or(false) {
+                        this.lctx
+                            .diagnostic()
+                            .span_err(item.span, "const trait impls are not yet implemented");
+                    }
+
                     this.with_trait_impl_ref(opt_trait_ref, |this| visit::walk_item(this, item));
                 } else {
                     visit::walk_item(this, item);
index bc3dfecd4a6752499b15c4a1cca43760047b8448..d30d0bd8345fff22d2f00f3e77f1db27567b8166 100644 (file)
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 //! Lowers the AST to the HIR.
 //!
 //! Since the AST and HIR are fairly similar, this is mostly a simple procedure,
 //! in the HIR, especially for multiple identifiers.
 
 #![feature(array_value_iter)]
+#![feature(crate_visibility_modifier)]
 
 use rustc::arena::Arena;
 use rustc::dep_graph::DepGraph;
-use rustc::hir::intravisit;
-use rustc::hir::map::{DefKey, DefPathData, Definitions};
-use rustc::lint;
-use rustc::lint::builtin::{self, ELIDED_LIFETIMES_IN_PATHS};
-use rustc::middle::cstore::CrateStore;
-use rustc::util::captures::Captures;
-use rustc::util::common::FN_OUTPUT_NAME;
+use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions};
+use rustc::hir::map::Map;
 use rustc::{bug, span_bug};
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_error_codes::*;
-use rustc_errors::Applicability;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ParamName};
 use rustc_index::vec::IndexVec;
 use rustc_session::config::nightly_options;
+use rustc_session::lint::{builtin, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::node_id::NodeMap;
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnId;
-use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind, Spanned};
+use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 use syntax::ast;
 use syntax::ast::*;
 use syntax::attr;
 use syntax::print::pprust;
-use syntax::ptr::P as AstP;
 use syntax::sess::ParseSess;
 use syntax::token::{self, Nonterminal, Token};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::visit::{self, Visitor};
-use syntax::{help, struct_span_err, walk_list};
+use syntax::walk_list;
 
 use log::{debug, trace};
 use smallvec::{smallvec, SmallVec};
@@ -85,6 +81,8 @@ macro_rules! arena_vec {
 
 mod expr;
 mod item;
+mod pat;
+mod path;
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
@@ -172,7 +170,9 @@ struct LoweringContext<'a, 'hir: 'a> {
 }
 
 pub trait Resolver {
-    fn cstore(&self) -> &dyn CrateStore;
+    fn def_key(&mut self, id: DefId) -> DefKey;
+
+    fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize;
 
     /// Obtains resolution for a `NodeId` with a single resolution.
     fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
@@ -197,7 +197,7 @@ fn resolve_str_path(
         ns: Namespace,
     ) -> (ast::Path, Res<NodeId>);
 
-    fn lint_buffer(&mut self) -> &mut lint::LintBuffer;
+    fn lint_buffer(&mut self) -> &mut LintBuffer;
 
     fn next_node_id(&mut self) -> NodeId;
 }
@@ -267,7 +267,7 @@ pub fn lower_crate<'a, 'hir>(
     // incr. comp. yet.
     dep_graph.assert_ignored();
 
-    let _prof_timer = sess.prof.generic_activity("hir_lowering");
+    let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
 
     LoweringContext {
         crate_root: sess.parse_sess.injected_crate_name.try_get().copied(),
@@ -432,10 +432,11 @@ fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: DefIndex)
                 }
             }
 
-            fn with_hir_id_owner<F, T>(&mut self, owner: Option<NodeId>, f: F) -> T
-            where
-                F: FnOnce(&mut Self) -> T,
-            {
+            fn with_hir_id_owner<T>(
+                &mut self,
+                owner: Option<NodeId>,
+                f: impl FnOnce(&mut Self) -> T,
+            ) -> T {
                 let old = mem::replace(&mut self.hir_id_owner, owner);
                 let r = f(self);
                 self.hir_id_owner = old;
@@ -443,7 +444,7 @@ fn with_hir_id_owner<F, T>(&mut self, owner: Option<NodeId>, f: F) -> T
             }
         }
 
-        impl<'tcx, 'lowering, 'hir> Visitor<'tcx> for MiscCollector<'tcx, 'lowering, 'hir> {
+        impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> {
             fn visit_pat(&mut self, p: &'tcx Pat) {
                 if let PatKind::Paren(..) | PatKind::Rest = p.kind {
                     // Doesn't generate a HIR node
@@ -576,10 +577,11 @@ fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
         lowered
     }
 
-    fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> hir::HirId
-    where
-        F: FnOnce(&mut Self) -> hir::HirId,
-    {
+    fn lower_node_id_generic(
+        &mut self,
+        ast_node_id: NodeId,
+        alloc_hir_id: impl FnOnce(&mut Self) -> hir::HirId,
+    ) -> hir::HirId {
         if ast_node_id == DUMMY_NODE_ID {
             return hir::DUMMY_HIR_ID;
         }
@@ -603,10 +605,7 @@ fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) ->
         }
     }
 
-    fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
+    fn with_hir_id_owner<T>(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
         let counter = self
             .item_local_id_counters
             .insert(owner, HIR_ID_COUNTER_LOCKED)
@@ -735,15 +734,12 @@ fn with_anonymous_lifetime_mode<R>(
     /// Presuming that in-band lifetimes are enabled, then
     /// `self.anonymous_lifetime_mode` will be updated to match the
     /// parameter while `f` is running (and restored afterwards).
-    fn collect_in_band_defs<T, F>(
+    fn collect_in_band_defs<T>(
         &mut self,
         parent_id: DefId,
         anonymous_lifetime_mode: AnonymousLifetimeMode,
-        f: F,
-    ) -> (Vec<hir::GenericParam<'hir>>, T)
-    where
-        F: FnOnce(&mut Self) -> (Vec<hir::GenericParam<'hir>>, T),
-    {
+        f: impl FnOnce(&mut Self) -> (Vec<hir::GenericParam<'hir>>, T),
+    ) -> (Vec<hir::GenericParam<'hir>>, T) {
         assert!(!self.is_collecting_in_band_lifetimes);
         assert!(self.lifetimes_to_define.is_empty());
         let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
@@ -846,10 +842,11 @@ fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName {
     // This is used to track which lifetimes have already been defined, and
     // which are new in-band lifetimes that need to have a definition created
     // for them.
-    fn with_in_scope_lifetime_defs<T, F>(&mut self, params: &[GenericParam], f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
+    fn with_in_scope_lifetime_defs<T>(
+        &mut self,
+        params: &[GenericParam],
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> T {
         let old_len = self.in_scope_lifetimes.len();
         let lt_def_names = params.iter().filter_map(|param| match param.kind {
             GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())),
@@ -869,16 +866,13 @@ fn with_in_scope_lifetime_defs<T, F>(&mut self, params: &[GenericParam], f: F) -
     /// Presuming that in-band lifetimes are enabled, then
     /// `self.anonymous_lifetime_mode` will be updated to match the
     /// parameter while `f` is running (and restored afterwards).
-    fn add_in_band_defs<F, T>(
+    fn add_in_band_defs<T>(
         &mut self,
         generics: &Generics,
         parent_id: DefId,
         anonymous_lifetime_mode: AnonymousLifetimeMode,
-        f: F,
-    ) -> (hir::Generics<'hir>, T)
-    where
-        F: FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
-    {
+        f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
+    ) -> (hir::Generics<'hir>, T) {
         let (in_band_defs, (mut lowered_generics, res)) =
             self.with_in_scope_lifetime_defs(&generics.params, |this| {
                 this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
@@ -916,10 +910,7 @@ fn add_in_band_defs<F, T>(
         (lowered_generics, res)
     }
 
-    fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
+    fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
         let was_in_dyn_type = self.is_in_dyn_type;
         self.is_in_dyn_type = in_scope;
 
@@ -930,10 +921,7 @@ fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
         result
     }
 
-    fn with_new_scopes<T, F>(&mut self, f: F) -> T
-    where
-        F: FnOnce(&mut Self) -> T,
-    {
+    fn with_new_scopes<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
         let was_in_loop_condition = self.is_in_loop_condition;
         self.is_in_loop_condition = false;
 
@@ -948,14 +936,6 @@ fn with_new_scopes<T, F>(&mut self, f: F) -> T
         ret
     }
 
-    fn def_key(&mut self, id: DefId) -> DefKey {
-        if id.is_local() {
-            self.resolver.definitions().def_key(id.index)
-        } else {
-            self.resolver.cstore().def_key(id)
-        }
-    }
-
     fn lower_attrs(&mut self, attrs: &[Attribute]) -> &'hir [Attribute] {
         self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)))
     }
@@ -1347,10 +1327,9 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                         );
                         if pos == ImplTraitPosition::Binding && nightly_options::is_nightly_build()
                         {
-                            help!(
-                                err,
+                            err.help(
                                 "add `#![feature(impl_trait_in_bindings)]` to the crate \
-                                   attributes to enable"
+                                   attributes to enable",
                             );
                         }
                         err.emit();
@@ -1485,7 +1464,9 @@ struct ImplTraitLifetimeCollector<'r, 'a, 'hir> {
         }
 
         impl<'r, 'a, 'v, 'hir> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a, 'hir> {
-            fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
+            type Map = Map<'v>;
+
+            fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
                 intravisit::NestedVisitorMap::None
             }
 
@@ -1633,403 +1614,6 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
         )
     }
 
-    fn lower_qpath(
-        &mut self,
-        id: NodeId,
-        qself: &Option<QSelf>,
-        p: &Path,
-        param_mode: ParamMode,
-        mut itctx: ImplTraitContext<'_, 'hir>,
-    ) -> hir::QPath<'hir> {
-        let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
-
-        let partial_res =
-            self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
-
-        let proj_start = p.segments.len() - partial_res.unresolved_segments();
-        let path = self.arena.alloc(hir::Path {
-            res: self.lower_res(partial_res.base_res()),
-            segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
-                |(i, segment)| {
-                    let param_mode = match (qself_position, param_mode) {
-                        (Some(j), ParamMode::Optional) if i < j => {
-                            // This segment is part of the trait path in a
-                            // qualified path - one of `a`, `b` or `Trait`
-                            // in `<X as a::b::Trait>::T::U::method`.
-                            ParamMode::Explicit
-                        }
-                        _ => param_mode,
-                    };
-
-                    // Figure out if this is a type/trait segment,
-                    // which may need lifetime elision performed.
-                    let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
-                        krate: def_id.krate,
-                        index: this.def_key(def_id).parent.expect("missing parent"),
-                    };
-                    let type_def_id = match partial_res.base_res() {
-                        Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
-                            Some(parent_def_id(self, def_id))
-                        }
-                        Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
-                            Some(parent_def_id(self, def_id))
-                        }
-                        Res::Def(DefKind::Struct, def_id)
-                        | Res::Def(DefKind::Union, def_id)
-                        | Res::Def(DefKind::Enum, def_id)
-                        | Res::Def(DefKind::TyAlias, def_id)
-                        | Res::Def(DefKind::Trait, def_id)
-                            if i + 1 == proj_start =>
-                        {
-                            Some(def_id)
-                        }
-                        _ => None,
-                    };
-                    let parenthesized_generic_args = match partial_res.base_res() {
-                        // `a::b::Trait(Args)`
-                        Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
-                            ParenthesizedGenericArgs::Ok
-                        }
-                        // `a::b::Trait(Args)::TraitItem`
-                        Res::Def(DefKind::Method, _)
-                        | Res::Def(DefKind::AssocConst, _)
-                        | Res::Def(DefKind::AssocTy, _)
-                            if i + 2 == proj_start =>
-                        {
-                            ParenthesizedGenericArgs::Ok
-                        }
-                        // Avoid duplicated errors.
-                        Res::Err => ParenthesizedGenericArgs::Ok,
-                        // An error
-                        _ => ParenthesizedGenericArgs::Err,
-                    };
-
-                    let num_lifetimes = type_def_id.map_or(0, |def_id| {
-                        if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
-                            return n;
-                        }
-                        assert!(!def_id.is_local());
-                        let item_generics = self
-                            .resolver
-                            .cstore()
-                            .item_generics_cloned_untracked(def_id, self.sess);
-                        let n = item_generics.own_counts().lifetimes;
-                        self.type_def_lifetime_params.insert(def_id, n);
-                        n
-                    });
-                    self.lower_path_segment(
-                        p.span,
-                        segment,
-                        param_mode,
-                        num_lifetimes,
-                        parenthesized_generic_args,
-                        itctx.reborrow(),
-                        None,
-                    )
-                },
-            )),
-            span: p.span,
-        });
-
-        // Simple case, either no projections, or only fully-qualified.
-        // E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
-        if partial_res.unresolved_segments() == 0 {
-            return hir::QPath::Resolved(qself, path);
-        }
-
-        // Create the innermost type that we're projecting from.
-        let mut ty = if path.segments.is_empty() {
-            // If the base path is empty that means there exists a
-            // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`.
-            qself.expect("missing QSelf for <T>::...")
-        } else {
-            // Otherwise, the base path is an implicit `Self` type path,
-            // e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in
-            // `<I as Iterator>::Item::default`.
-            let new_id = self.next_id();
-            self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)))
-        };
-
-        // Anything after the base path are associated "extensions",
-        // out of which all but the last one are associated types,
-        // e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`:
-        // * base path is `std::vec::Vec<T>`
-        // * "extensions" are `IntoIter`, `Item` and `clone`
-        // * type nodes are:
-        //   1. `std::vec::Vec<T>` (created above)
-        //   2. `<std::vec::Vec<T>>::IntoIter`
-        //   3. `<<std::vec::Vec<T>>::IntoIter>::Item`
-        // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
-        for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
-            let segment = self.arena.alloc(self.lower_path_segment(
-                p.span,
-                segment,
-                param_mode,
-                0,
-                ParenthesizedGenericArgs::Err,
-                itctx.reborrow(),
-                None,
-            ));
-            let qpath = hir::QPath::TypeRelative(ty, segment);
-
-            // It's finished, return the extension of the right node type.
-            if i == p.segments.len() - 1 {
-                return qpath;
-            }
-
-            // Wrap the associated extension in another type node.
-            let new_id = self.next_id();
-            ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath));
-        }
-
-        // We should've returned in the for loop above.
-        span_bug!(
-            p.span,
-            "lower_qpath: no final extension segment in {}..{}",
-            proj_start,
-            p.segments.len()
-        )
-    }
-
-    fn lower_path_extra(
-        &mut self,
-        res: Res,
-        p: &Path,
-        param_mode: ParamMode,
-        explicit_owner: Option<NodeId>,
-    ) -> &'hir hir::Path<'hir> {
-        self.arena.alloc(hir::Path {
-            res,
-            segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
-                self.lower_path_segment(
-                    p.span,
-                    segment,
-                    param_mode,
-                    0,
-                    ParenthesizedGenericArgs::Err,
-                    ImplTraitContext::disallowed(),
-                    explicit_owner,
-                )
-            })),
-            span: p.span,
-        })
-    }
-
-    fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> &'hir hir::Path<'hir> {
-        let res = self.expect_full_res(id);
-        let res = self.lower_res(res);
-        self.lower_path_extra(res, p, param_mode, None)
-    }
-
-    fn lower_path_segment(
-        &mut self,
-        path_span: Span,
-        segment: &PathSegment,
-        param_mode: ParamMode,
-        expected_lifetimes: usize,
-        parenthesized_generic_args: ParenthesizedGenericArgs,
-        itctx: ImplTraitContext<'_, 'hir>,
-        explicit_owner: Option<NodeId>,
-    ) -> hir::PathSegment<'hir> {
-        let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
-            let msg = "parenthesized type parameters may only be used with a `Fn` trait";
-            match **generic_args {
-                GenericArgs::AngleBracketed(ref data) => {
-                    self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
-                }
-                GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
-                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
-                    ParenthesizedGenericArgs::Err => {
-                        let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
-                        err.span_label(data.span, "only `Fn` traits may use parentheses");
-                        if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
-                            // Do not suggest going from `Trait()` to `Trait<>`
-                            if data.inputs.len() > 0 {
-                                if let Some(split) = snippet.find('(') {
-                                    let trait_name = &snippet[0..split];
-                                    let args = &snippet[split + 1..snippet.len() - 1];
-                                    err.span_suggestion(
-                                        data.span,
-                                        "use angle brackets instead",
-                                        format!("{}<{}>", trait_name, args),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            }
-                        };
-                        err.emit();
-                        (
-                            self.lower_angle_bracketed_parameter_data(
-                                &data.as_angle_bracketed_args(),
-                                param_mode,
-                                itctx,
-                            )
-                            .0,
-                            false,
-                        )
-                    }
-                },
-            }
-        } else {
-            self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
-        };
-
-        let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
-            GenericArg::Lifetime(_) => true,
-            _ => false,
-        });
-        let first_generic_span = generic_args
-            .args
-            .iter()
-            .map(|a| a.span())
-            .chain(generic_args.bindings.iter().map(|b| b.span))
-            .next();
-        if !generic_args.parenthesized && !has_lifetimes {
-            generic_args.args = self
-                .elided_path_lifetimes(path_span, expected_lifetimes)
-                .map(|lt| GenericArg::Lifetime(lt))
-                .chain(generic_args.args.into_iter())
-                .collect();
-            if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
-                let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
-                let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
-                let no_bindings = generic_args.bindings.is_empty();
-                let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
-                    // If there are no (non-implicit) generic args or associated type
-                    // bindings, our suggestion includes the angle brackets.
-                    (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
-                } else {
-                    // Otherwise (sorry, this is kind of gross) we need to infer the
-                    // place to splice in the `'_, ` from the generics that do exist.
-                    let first_generic_span = first_generic_span
-                        .expect("already checked that non-lifetime args or bindings exist");
-                    (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
-                };
-                match self.anonymous_lifetime_mode {
-                    // In create-parameter mode we error here because we don't want to support
-                    // deprecated impl elision in new features like impl elision and `async fn`,
-                    // both of which work using the `CreateParameter` mode:
-                    //
-                    //     impl Foo for std::cell::Ref<u32> // note lack of '_
-                    //     async fn foo(_: std::cell::Ref<u32>) { ... }
-                    AnonymousLifetimeMode::CreateParameter => {
-                        let mut err = struct_span_err!(
-                            self.sess,
-                            path_span,
-                            E0726,
-                            "implicit elided lifetime not allowed here"
-                        );
-                        crate::lint::builtin::add_elided_lifetime_in_path_suggestion(
-                            &self.sess,
-                            &mut err,
-                            expected_lifetimes,
-                            path_span,
-                            incl_angl_brckt,
-                            insertion_sp,
-                            suggestion,
-                        );
-                        err.emit();
-                    }
-                    AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
-                        self.resolver.lint_buffer().buffer_lint_with_diagnostic(
-                            ELIDED_LIFETIMES_IN_PATHS,
-                            CRATE_NODE_ID,
-                            path_span,
-                            "hidden lifetime parameters in types are deprecated",
-                            builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
-                                expected_lifetimes,
-                                path_span,
-                                incl_angl_brckt,
-                                insertion_sp,
-                                suggestion,
-                            ),
-                        );
-                    }
-                }
-            }
-        }
-
-        let res = self.expect_full_res(segment.id);
-        let id = if let Some(owner) = explicit_owner {
-            self.lower_node_id_with_owner(segment.id, owner)
-        } else {
-            self.lower_node_id(segment.id)
-        };
-        debug!(
-            "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
-            segment.ident, segment.id, id,
-        );
-
-        hir::PathSegment {
-            ident: segment.ident,
-            hir_id: Some(id),
-            res: Some(self.lower_res(res)),
-            infer_args,
-            args: if generic_args.is_empty() {
-                None
-            } else {
-                Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
-            },
-        }
-    }
-
-    fn lower_angle_bracketed_parameter_data(
-        &mut self,
-        data: &AngleBracketedArgs,
-        param_mode: ParamMode,
-        mut itctx: ImplTraitContext<'_, 'hir>,
-    ) -> (GenericArgsCtor<'hir>, bool) {
-        let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
-        let has_non_lt_args = args.iter().any(|arg| match arg {
-            ast::GenericArg::Lifetime(_) => false,
-            ast::GenericArg::Type(_) => true,
-            ast::GenericArg::Const(_) => true,
-        });
-        (
-            GenericArgsCtor {
-                args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
-                bindings: self.arena.alloc_from_iter(
-                    constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
-                ),
-                parenthesized: false,
-            },
-            !has_non_lt_args && param_mode == ParamMode::Optional,
-        )
-    }
-
-    fn lower_parenthesized_parameter_data(
-        &mut self,
-        data: &ParenthesizedArgs,
-    ) -> (GenericArgsCtor<'hir>, bool) {
-        // Switch to `PassThrough` mode for anonymous lifetimes; this
-        // means that we permit things like `&Ref<T>`, where `Ref` has
-        // a hidden lifetime parameter. This is needed for backwards
-        // compatibility, even in contexts like an impl header where
-        // we generally don't permit such things (see #51008).
-        self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
-            let &ParenthesizedArgs { ref inputs, ref output, span } = data;
-            let inputs = this.arena.alloc_from_iter(
-                inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
-            );
-            let output_ty = match output {
-                FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
-                FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])),
-            };
-            let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))];
-            let binding = hir::TypeBinding {
-                hir_id: this.next_id(),
-                ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
-                span: output_ty.span,
-                kind: hir::TypeBindingKind::Equality { ty: output_ty },
-            };
-            (
-                GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
-                false,
-            )
-        })
-    }
-
     fn lower_local(&mut self, l: &Local) -> (hir::Local<'hir>, SmallVec<[NodeId; 1]>) {
         let mut ids = SmallVec::<[NodeId; 1]>::new();
         if self.sess.features_untracked().impl_trait_in_bindings {
@@ -2385,12 +1969,7 @@ fn lower_async_fn_output_type_to_future_bound(
         // "<Output = T>"
         let future_params = self.arena.alloc(hir::GenericArgs {
             args: &[],
-            bindings: arena_vec![self; hir::TypeBinding {
-                ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
-                kind: hir::TypeBindingKind::Equality { ty: output_ty },
-                hir_id: self.next_id(),
-                span,
-            }],
+            bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
             parenthesized: false,
         });
 
@@ -2577,6 +2156,10 @@ fn lower_poly_trait_ref(
         p: &PolyTraitRef,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::PolyTraitRef<'hir> {
+        if p.trait_ref.constness.is_some() {
+            self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented");
+        }
+
         let bound_generic_params = self.lower_generic_params(
             &p.bound_generic_params,
             &NodeMap::default(),
@@ -2646,250 +2229,6 @@ fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> {
         self.expr_block(block, AttrVec::new())
     }
 
-    fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
-        let node = match p.kind {
-            PatKind::Wild => hir::PatKind::Wild,
-            PatKind::Ident(ref binding_mode, ident, ref sub) => {
-                let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
-                let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub);
-                node
-            }
-            PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
-            PatKind::TupleStruct(ref path, ref pats) => {
-                let qpath = self.lower_qpath(
-                    p.id,
-                    &None,
-                    path,
-                    ParamMode::Optional,
-                    ImplTraitContext::disallowed(),
-                );
-                let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
-                hir::PatKind::TupleStruct(qpath, pats, ddpos)
-            }
-            PatKind::Or(ref pats) => {
-                hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))))
-            }
-            PatKind::Path(ref qself, ref path) => {
-                let qpath = self.lower_qpath(
-                    p.id,
-                    qself,
-                    path,
-                    ParamMode::Optional,
-                    ImplTraitContext::disallowed(),
-                );
-                hir::PatKind::Path(qpath)
-            }
-            PatKind::Struct(ref path, ref fields, etc) => {
-                let qpath = self.lower_qpath(
-                    p.id,
-                    &None,
-                    path,
-                    ParamMode::Optional,
-                    ImplTraitContext::disallowed(),
-                );
-
-                let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat {
-                    hir_id: self.next_id(),
-                    ident: f.ident,
-                    pat: self.lower_pat(&f.pat),
-                    is_shorthand: f.is_shorthand,
-                    span: f.span,
-                }));
-                hir::PatKind::Struct(qpath, fs, etc)
-            }
-            PatKind::Tuple(ref pats) => {
-                let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
-                hir::PatKind::Tuple(pats, ddpos)
-            }
-            PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
-            PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl),
-            PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range(
-                self.lower_expr(e1),
-                self.lower_expr(e2),
-                self.lower_range_end(end),
-            ),
-            PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
-            PatKind::Rest => {
-                // If we reach here the `..` pattern is not semantically allowed.
-                self.ban_illegal_rest_pat(p.span)
-            }
-            PatKind::Paren(ref inner) => return self.lower_pat(inner),
-            PatKind::Mac(_) => panic!("Shouldn't exist here"),
-        };
-
-        self.pat_with_node_id_of(p, node)
-    }
-
-    fn lower_pat_tuple(
-        &mut self,
-        pats: &[AstP<Pat>],
-        ctx: &str,
-    ) -> (&'hir [&'hir hir::Pat<'hir>], Option<usize>) {
-        let mut elems = Vec::with_capacity(pats.len());
-        let mut rest = None;
-
-        let mut iter = pats.iter().enumerate();
-        for (idx, pat) in iter.by_ref() {
-            // Interpret the first `..` pattern as a sub-tuple pattern.
-            // Note that unlike for slice patterns,
-            // where `xs @ ..` is a legal sub-slice pattern,
-            // it is not a legal sub-tuple pattern.
-            if pat.is_rest() {
-                rest = Some((idx, pat.span));
-                break;
-            }
-            // It was not a sub-tuple pattern so lower it normally.
-            elems.push(self.lower_pat(pat));
-        }
-
-        for (_, pat) in iter {
-            // There was a previous sub-tuple pattern; make sure we don't allow more...
-            if pat.is_rest() {
-                // ...but there was one again, so error.
-                self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
-            } else {
-                elems.push(self.lower_pat(pat));
-            }
-        }
-
-        (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
-    }
-
-    /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
-    /// `hir::PatKind::Slice(before, slice, after)`.
-    ///
-    /// When encountering `($binding_mode $ident @)? ..` (`slice`),
-    /// this is interpreted as a sub-slice pattern semantically.
-    /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
-    fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind<'hir> {
-        let mut before = Vec::new();
-        let mut after = Vec::new();
-        let mut slice = None;
-        let mut prev_rest_span = None;
-
-        let mut iter = pats.iter();
-        // Lower all the patterns until the first occurence of a sub-slice pattern.
-        for pat in iter.by_ref() {
-            match pat.kind {
-                // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
-                PatKind::Rest => {
-                    prev_rest_span = Some(pat.span);
-                    slice = Some(self.pat_wild_with_node_id_of(pat));
-                    break;
-                }
-                // Found a sub-slice pattern `$binding_mode $ident @ ..`.
-                // Record, lower it to `$binding_mode $ident @ _`, and stop here.
-                PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
-                    prev_rest_span = Some(sub.span);
-                    let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
-                    let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
-                    slice = Some(self.pat_with_node_id_of(pat, node));
-                    break;
-                }
-                // It was not a subslice pattern so lower it normally.
-                _ => before.push(self.lower_pat(pat)),
-            }
-        }
-
-        // Lower all the patterns after the first sub-slice pattern.
-        for pat in iter {
-            // There was a previous subslice pattern; make sure we don't allow more.
-            let rest_span = match pat.kind {
-                PatKind::Rest => Some(pat.span),
-                PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
-                    // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
-                    after.push(self.pat_wild_with_node_id_of(pat));
-                    Some(sub.span)
-                }
-                _ => None,
-            };
-            if let Some(rest_span) = rest_span {
-                // We have e.g., `[a, .., b, ..]`. That's no good, error!
-                self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
-            } else {
-                // Lower the pattern normally.
-                after.push(self.lower_pat(pat));
-            }
-        }
-
-        hir::PatKind::Slice(
-            self.arena.alloc_from_iter(before),
-            slice,
-            self.arena.alloc_from_iter(after),
-        )
-    }
-
-    fn lower_pat_ident(
-        &mut self,
-        p: &Pat,
-        binding_mode: &BindingMode,
-        ident: Ident,
-        lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
-    ) -> hir::PatKind<'hir> {
-        match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
-            // `None` can occur in body-less function signatures
-            res @ None | res @ Some(Res::Local(_)) => {
-                let canonical_id = match res {
-                    Some(Res::Local(id)) => id,
-                    _ => p.id,
-                };
-
-                hir::PatKind::Binding(
-                    self.lower_binding_mode(binding_mode),
-                    self.lower_node_id(canonical_id),
-                    ident,
-                    lower_sub(self),
-                )
-            }
-            Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
-                None,
-                self.arena.alloc(hir::Path {
-                    span: ident.span,
-                    res: self.lower_res(res),
-                    segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
-                }),
-            )),
-        }
-    }
-
-    fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
-        self.pat_with_node_id_of(p, hir::PatKind::Wild)
-    }
-
-    /// Construct a `Pat` with the `HirId` of `p.id` lowered.
-    fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
-        self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
-    }
-
-    /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
-    fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
-        self.diagnostic()
-            .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
-            .span_label(sp, &format!("can only be used once per {} pattern", ctx))
-            .span_label(prev_sp, "previously used here")
-            .emit();
-    }
-
-    /// Used to ban the `..` pattern in places it shouldn't be semantically.
-    fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
-        self.diagnostic()
-            .struct_span_err(sp, "`..` patterns are not allowed here")
-            .note("only allowed in tuple, tuple struct, and slice patterns")
-            .emit();
-
-        // We're not in a list context so `..` can be reasonably treated
-        // as `_` because it should always be valid and roughly matches the
-        // intent of `..` (notice that the rest of a single slot is that slot).
-        hir::PatKind::Wild
-    }
-
-    fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
-        match *e {
-            RangeEnd::Included(_) => hir::RangeEnd::Included,
-            RangeEnd::Excluded => hir::RangeEnd::Excluded,
-        }
-    }
-
     fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
         self.with_new_scopes(|this| hir::AnonConst {
             hir_id: this.lower_node_id(c.id),
@@ -2949,15 +2288,6 @@ fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode
         }
     }
 
-    fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
-        match *b {
-            BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
-            BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
-            BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
-            BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
-        }
-    }
-
     fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
         match u {
             CompilerGenerated => hir::UnsafeSource::CompilerGenerated,
@@ -3286,7 +2616,7 @@ fn maybe_lint_bare_trait(&mut self, span: Span, id: NodeId, is_global: bool) {
                 id,
                 span,
                 "trait objects without an explicit `dyn` are deprecated",
-                builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
+                BuiltinLintDiagnostics::BareTraitObject(span, is_global),
             )
         }
     }
diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs
new file mode 100644 (file)
index 0000000..6cf640a
--- /dev/null
@@ -0,0 +1,263 @@
+use super::{ImplTraitContext, LoweringContext, ParamMode};
+
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_span::{source_map::Spanned, Span};
+use syntax::ast::*;
+use syntax::ptr::P;
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+    crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
+        let node = match p.kind {
+            PatKind::Wild => hir::PatKind::Wild,
+            PatKind::Ident(ref binding_mode, ident, ref sub) => {
+                let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
+                let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub);
+                node
+            }
+            PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
+            PatKind::TupleStruct(ref path, ref pats) => {
+                let qpath = self.lower_qpath(
+                    p.id,
+                    &None,
+                    path,
+                    ParamMode::Optional,
+                    ImplTraitContext::disallowed(),
+                );
+                let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
+                hir::PatKind::TupleStruct(qpath, pats, ddpos)
+            }
+            PatKind::Or(ref pats) => {
+                hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))))
+            }
+            PatKind::Path(ref qself, ref path) => {
+                let qpath = self.lower_qpath(
+                    p.id,
+                    qself,
+                    path,
+                    ParamMode::Optional,
+                    ImplTraitContext::disallowed(),
+                );
+                hir::PatKind::Path(qpath)
+            }
+            PatKind::Struct(ref path, ref fields, etc) => {
+                let qpath = self.lower_qpath(
+                    p.id,
+                    &None,
+                    path,
+                    ParamMode::Optional,
+                    ImplTraitContext::disallowed(),
+                );
+
+                let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat {
+                    hir_id: self.next_id(),
+                    ident: f.ident,
+                    pat: self.lower_pat(&f.pat),
+                    is_shorthand: f.is_shorthand,
+                    span: f.span,
+                }));
+                hir::PatKind::Struct(qpath, fs, etc)
+            }
+            PatKind::Tuple(ref pats) => {
+                let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
+                hir::PatKind::Tuple(pats, ddpos)
+            }
+            PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
+            PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl),
+            PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range(
+                e1.as_deref().map(|e| self.lower_expr(e)),
+                e2.as_deref().map(|e| self.lower_expr(e)),
+                self.lower_range_end(end, e2.is_some()),
+            ),
+            PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
+            PatKind::Rest => {
+                // If we reach here the `..` pattern is not semantically allowed.
+                self.ban_illegal_rest_pat(p.span)
+            }
+            PatKind::Paren(ref inner) => return self.lower_pat(inner),
+            PatKind::Mac(_) => panic!("Shouldn't exist here"),
+        };
+
+        self.pat_with_node_id_of(p, node)
+    }
+
+    fn lower_pat_tuple(
+        &mut self,
+        pats: &[P<Pat>],
+        ctx: &str,
+    ) -> (&'hir [&'hir hir::Pat<'hir>], Option<usize>) {
+        let mut elems = Vec::with_capacity(pats.len());
+        let mut rest = None;
+
+        let mut iter = pats.iter().enumerate();
+        for (idx, pat) in iter.by_ref() {
+            // Interpret the first `..` pattern as a sub-tuple pattern.
+            // Note that unlike for slice patterns,
+            // where `xs @ ..` is a legal sub-slice pattern,
+            // it is not a legal sub-tuple pattern.
+            if pat.is_rest() {
+                rest = Some((idx, pat.span));
+                break;
+            }
+            // It was not a sub-tuple pattern so lower it normally.
+            elems.push(self.lower_pat(pat));
+        }
+
+        for (_, pat) in iter {
+            // There was a previous sub-tuple pattern; make sure we don't allow more...
+            if pat.is_rest() {
+                // ...but there was one again, so error.
+                self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
+            } else {
+                elems.push(self.lower_pat(pat));
+            }
+        }
+
+        (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
+    }
+
+    /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
+    /// `hir::PatKind::Slice(before, slice, after)`.
+    ///
+    /// When encountering `($binding_mode $ident @)? ..` (`slice`),
+    /// this is interpreted as a sub-slice pattern semantically.
+    /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
+    fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
+        let mut before = Vec::new();
+        let mut after = Vec::new();
+        let mut slice = None;
+        let mut prev_rest_span = None;
+
+        let mut iter = pats.iter();
+        // Lower all the patterns until the first occurence of a sub-slice pattern.
+        for pat in iter.by_ref() {
+            match pat.kind {
+                // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
+                PatKind::Rest => {
+                    prev_rest_span = Some(pat.span);
+                    slice = Some(self.pat_wild_with_node_id_of(pat));
+                    break;
+                }
+                // Found a sub-slice pattern `$binding_mode $ident @ ..`.
+                // Record, lower it to `$binding_mode $ident @ _`, and stop here.
+                PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+                    prev_rest_span = Some(sub.span);
+                    let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
+                    let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
+                    slice = Some(self.pat_with_node_id_of(pat, node));
+                    break;
+                }
+                // It was not a subslice pattern so lower it normally.
+                _ => before.push(self.lower_pat(pat)),
+            }
+        }
+
+        // Lower all the patterns after the first sub-slice pattern.
+        for pat in iter {
+            // There was a previous subslice pattern; make sure we don't allow more.
+            let rest_span = match pat.kind {
+                PatKind::Rest => Some(pat.span),
+                PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
+                    // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
+                    after.push(self.pat_wild_with_node_id_of(pat));
+                    Some(sub.span)
+                }
+                _ => None,
+            };
+            if let Some(rest_span) = rest_span {
+                // We have e.g., `[a, .., b, ..]`. That's no good, error!
+                self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
+            } else {
+                // Lower the pattern normally.
+                after.push(self.lower_pat(pat));
+            }
+        }
+
+        hir::PatKind::Slice(
+            self.arena.alloc_from_iter(before),
+            slice,
+            self.arena.alloc_from_iter(after),
+        )
+    }
+
+    fn lower_pat_ident(
+        &mut self,
+        p: &Pat,
+        binding_mode: &BindingMode,
+        ident: Ident,
+        lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
+    ) -> hir::PatKind<'hir> {
+        match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
+            // `None` can occur in body-less function signatures
+            res @ None | res @ Some(Res::Local(_)) => {
+                let canonical_id = match res {
+                    Some(Res::Local(id)) => id,
+                    _ => p.id,
+                };
+
+                hir::PatKind::Binding(
+                    self.lower_binding_mode(binding_mode),
+                    self.lower_node_id(canonical_id),
+                    ident,
+                    lower_sub(self),
+                )
+            }
+            Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
+                None,
+                self.arena.alloc(hir::Path {
+                    span: ident.span,
+                    res: self.lower_res(res),
+                    segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
+                }),
+            )),
+        }
+    }
+
+    fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
+        match *b {
+            BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
+            BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
+            BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
+            BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
+        }
+    }
+
+    fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
+        self.pat_with_node_id_of(p, hir::PatKind::Wild)
+    }
+
+    /// Construct a `Pat` with the `HirId` of `p.id` lowered.
+    fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
+        self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
+    }
+
+    /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
+    fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
+        self.diagnostic()
+            .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
+            .span_label(sp, &format!("can only be used once per {} pattern", ctx))
+            .span_label(prev_sp, "previously used here")
+            .emit();
+    }
+
+    /// Used to ban the `..` pattern in places it shouldn't be semantically.
+    fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
+        self.diagnostic()
+            .struct_span_err(sp, "`..` patterns are not allowed here")
+            .note("only allowed in tuple, tuple struct, and slice patterns")
+            .emit();
+
+        // We're not in a list context so `..` can be reasonably treated
+        // as `_` because it should always be valid and roughly matches the
+        // intent of `..` (notice that the rest of a single slot is that slot).
+        hir::PatKind::Wild
+    }
+
+    fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
+        match *e {
+            RangeEnd::Excluded if has_end => hir::RangeEnd::Excluded,
+            // No end; so `X..` behaves like `RangeFrom`.
+            RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,
+        }
+    }
+}
diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs
new file mode 100644 (file)
index 0000000..65347d3
--- /dev/null
@@ -0,0 +1,423 @@
+use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode};
+use super::{GenericArgsCtor, ParenthesizedGenericArgs};
+
+use rustc::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
+use rustc::span_bug;
+use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, Applicability};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, PartialRes, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::GenericArg;
+use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::Span;
+use syntax::ast::{self, *};
+
+use log::debug;
+use smallvec::smallvec;
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+    crate fn lower_qpath(
+        &mut self,
+        id: NodeId,
+        qself: &Option<QSelf>,
+        p: &Path,
+        param_mode: ParamMode,
+        mut itctx: ImplTraitContext<'_, 'hir>,
+    ) -> hir::QPath<'hir> {
+        let qself_position = qself.as_ref().map(|q| q.position);
+        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
+
+        let partial_res =
+            self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
+
+        let proj_start = p.segments.len() - partial_res.unresolved_segments();
+        let path = self.arena.alloc(hir::Path {
+            res: self.lower_res(partial_res.base_res()),
+            segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
+                |(i, segment)| {
+                    let param_mode = match (qself_position, param_mode) {
+                        (Some(j), ParamMode::Optional) if i < j => {
+                            // This segment is part of the trait path in a
+                            // qualified path - one of `a`, `b` or `Trait`
+                            // in `<X as a::b::Trait>::T::U::method`.
+                            ParamMode::Explicit
+                        }
+                        _ => param_mode,
+                    };
+
+                    // Figure out if this is a type/trait segment,
+                    // which may need lifetime elision performed.
+                    let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
+                        krate: def_id.krate,
+                        index: this.resolver.def_key(def_id).parent.expect("missing parent"),
+                    };
+                    let type_def_id = match partial_res.base_res() {
+                        Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
+                            Some(parent_def_id(self, def_id))
+                        }
+                        Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
+                            Some(parent_def_id(self, def_id))
+                        }
+                        Res::Def(DefKind::Struct, def_id)
+                        | Res::Def(DefKind::Union, def_id)
+                        | Res::Def(DefKind::Enum, def_id)
+                        | Res::Def(DefKind::TyAlias, def_id)
+                        | Res::Def(DefKind::Trait, def_id)
+                            if i + 1 == proj_start =>
+                        {
+                            Some(def_id)
+                        }
+                        _ => None,
+                    };
+                    let parenthesized_generic_args = match partial_res.base_res() {
+                        // `a::b::Trait(Args)`
+                        Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
+                            ParenthesizedGenericArgs::Ok
+                        }
+                        // `a::b::Trait(Args)::TraitItem`
+                        Res::Def(DefKind::Method, _)
+                        | Res::Def(DefKind::AssocConst, _)
+                        | Res::Def(DefKind::AssocTy, _)
+                            if i + 2 == proj_start =>
+                        {
+                            ParenthesizedGenericArgs::Ok
+                        }
+                        // Avoid duplicated errors.
+                        Res::Err => ParenthesizedGenericArgs::Ok,
+                        // An error
+                        _ => ParenthesizedGenericArgs::Err,
+                    };
+
+                    let num_lifetimes = type_def_id.map_or(0, |def_id| {
+                        if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
+                            return n;
+                        }
+                        assert!(!def_id.is_local());
+                        let n = self.resolver.item_generics_num_lifetimes(def_id, self.sess);
+                        self.type_def_lifetime_params.insert(def_id, n);
+                        n
+                    });
+                    self.lower_path_segment(
+                        p.span,
+                        segment,
+                        param_mode,
+                        num_lifetimes,
+                        parenthesized_generic_args,
+                        itctx.reborrow(),
+                        None,
+                    )
+                },
+            )),
+            span: p.span,
+        });
+
+        // Simple case, either no projections, or only fully-qualified.
+        // E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
+        if partial_res.unresolved_segments() == 0 {
+            return hir::QPath::Resolved(qself, path);
+        }
+
+        // Create the innermost type that we're projecting from.
+        let mut ty = if path.segments.is_empty() {
+            // If the base path is empty that means there exists a
+            // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`.
+            qself.expect("missing QSelf for <T>::...")
+        } else {
+            // Otherwise, the base path is an implicit `Self` type path,
+            // e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in
+            // `<I as Iterator>::Item::default`.
+            let new_id = self.next_id();
+            self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)))
+        };
+
+        // Anything after the base path are associated "extensions",
+        // out of which all but the last one are associated types,
+        // e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`:
+        // * base path is `std::vec::Vec<T>`
+        // * "extensions" are `IntoIter`, `Item` and `clone`
+        // * type nodes are:
+        //   1. `std::vec::Vec<T>` (created above)
+        //   2. `<std::vec::Vec<T>>::IntoIter`
+        //   3. `<<std::vec::Vec<T>>::IntoIter>::Item`
+        // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
+        for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
+            let segment = self.arena.alloc(self.lower_path_segment(
+                p.span,
+                segment,
+                param_mode,
+                0,
+                ParenthesizedGenericArgs::Err,
+                itctx.reborrow(),
+                None,
+            ));
+            let qpath = hir::QPath::TypeRelative(ty, segment);
+
+            // It's finished, return the extension of the right node type.
+            if i == p.segments.len() - 1 {
+                return qpath;
+            }
+
+            // Wrap the associated extension in another type node.
+            let new_id = self.next_id();
+            ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath));
+        }
+
+        // We should've returned in the for loop above.
+        span_bug!(
+            p.span,
+            "lower_qpath: no final extension segment in {}..{}",
+            proj_start,
+            p.segments.len()
+        )
+    }
+
+    crate fn lower_path_extra(
+        &mut self,
+        res: Res,
+        p: &Path,
+        param_mode: ParamMode,
+        explicit_owner: Option<NodeId>,
+    ) -> &'hir hir::Path<'hir> {
+        self.arena.alloc(hir::Path {
+            res,
+            segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
+                self.lower_path_segment(
+                    p.span,
+                    segment,
+                    param_mode,
+                    0,
+                    ParenthesizedGenericArgs::Err,
+                    ImplTraitContext::disallowed(),
+                    explicit_owner,
+                )
+            })),
+            span: p.span,
+        })
+    }
+
+    crate fn lower_path(
+        &mut self,
+        id: NodeId,
+        p: &Path,
+        param_mode: ParamMode,
+    ) -> &'hir hir::Path<'hir> {
+        let res = self.expect_full_res(id);
+        let res = self.lower_res(res);
+        self.lower_path_extra(res, p, param_mode, None)
+    }
+
+    crate fn lower_path_segment(
+        &mut self,
+        path_span: Span,
+        segment: &PathSegment,
+        param_mode: ParamMode,
+        expected_lifetimes: usize,
+        parenthesized_generic_args: ParenthesizedGenericArgs,
+        itctx: ImplTraitContext<'_, 'hir>,
+        explicit_owner: Option<NodeId>,
+    ) -> hir::PathSegment<'hir> {
+        let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
+            let msg = "parenthesized type parameters may only be used with a `Fn` trait";
+            match **generic_args {
+                GenericArgs::AngleBracketed(ref data) => {
+                    self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
+                }
+                GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
+                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
+                    ParenthesizedGenericArgs::Err => {
+                        let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
+                        err.span_label(data.span, "only `Fn` traits may use parentheses");
+                        if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
+                            // Do not suggest going from `Trait()` to `Trait<>`
+                            if data.inputs.len() > 0 {
+                                if let Some(split) = snippet.find('(') {
+                                    let trait_name = &snippet[0..split];
+                                    let args = &snippet[split + 1..snippet.len() - 1];
+                                    err.span_suggestion(
+                                        data.span,
+                                        "use angle brackets instead",
+                                        format!("{}<{}>", trait_name, args),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
+                            }
+                        };
+                        err.emit();
+                        (
+                            self.lower_angle_bracketed_parameter_data(
+                                &data.as_angle_bracketed_args(),
+                                param_mode,
+                                itctx,
+                            )
+                            .0,
+                            false,
+                        )
+                    }
+                },
+            }
+        } else {
+            self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
+        };
+
+        let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
+            GenericArg::Lifetime(_) => true,
+            _ => false,
+        });
+        let first_generic_span = generic_args
+            .args
+            .iter()
+            .map(|a| a.span())
+            .chain(generic_args.bindings.iter().map(|b| b.span))
+            .next();
+        if !generic_args.parenthesized && !has_lifetimes {
+            generic_args.args = self
+                .elided_path_lifetimes(path_span, expected_lifetimes)
+                .map(|lt| GenericArg::Lifetime(lt))
+                .chain(generic_args.args.into_iter())
+                .collect();
+            if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
+                let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
+                let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
+                let no_bindings = generic_args.bindings.is_empty();
+                let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
+                    // If there are no (non-implicit) generic args or associated type
+                    // bindings, our suggestion includes the angle brackets.
+                    (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
+                } else {
+                    // Otherwise (sorry, this is kind of gross) we need to infer the
+                    // place to splice in the `'_, ` from the generics that do exist.
+                    let first_generic_span = first_generic_span
+                        .expect("already checked that non-lifetime args or bindings exist");
+                    (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
+                };
+                match self.anonymous_lifetime_mode {
+                    // In create-parameter mode we error here because we don't want to support
+                    // deprecated impl elision in new features like impl elision and `async fn`,
+                    // both of which work using the `CreateParameter` mode:
+                    //
+                    //     impl Foo for std::cell::Ref<u32> // note lack of '_
+                    //     async fn foo(_: std::cell::Ref<u32>) { ... }
+                    AnonymousLifetimeMode::CreateParameter => {
+                        let mut err = struct_span_err!(
+                            self.sess,
+                            path_span,
+                            E0726,
+                            "implicit elided lifetime not allowed here"
+                        );
+                        rustc::lint::add_elided_lifetime_in_path_suggestion(
+                            &self.sess,
+                            &mut err,
+                            expected_lifetimes,
+                            path_span,
+                            incl_angl_brckt,
+                            insertion_sp,
+                            suggestion,
+                        );
+                        err.emit();
+                    }
+                    AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
+                        self.resolver.lint_buffer().buffer_lint_with_diagnostic(
+                            ELIDED_LIFETIMES_IN_PATHS,
+                            CRATE_NODE_ID,
+                            path_span,
+                            "hidden lifetime parameters in types are deprecated",
+                            BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+                                expected_lifetimes,
+                                path_span,
+                                incl_angl_brckt,
+                                insertion_sp,
+                                suggestion,
+                            ),
+                        );
+                    }
+                }
+            }
+        }
+
+        let res = self.expect_full_res(segment.id);
+        let id = if let Some(owner) = explicit_owner {
+            self.lower_node_id_with_owner(segment.id, owner)
+        } else {
+            self.lower_node_id(segment.id)
+        };
+        debug!(
+            "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
+            segment.ident, segment.id, id,
+        );
+
+        hir::PathSegment {
+            ident: segment.ident,
+            hir_id: Some(id),
+            res: Some(self.lower_res(res)),
+            infer_args,
+            args: if generic_args.is_empty() {
+                None
+            } else {
+                Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
+            },
+        }
+    }
+
+    fn lower_angle_bracketed_parameter_data(
+        &mut self,
+        data: &AngleBracketedArgs,
+        param_mode: ParamMode,
+        mut itctx: ImplTraitContext<'_, 'hir>,
+    ) -> (GenericArgsCtor<'hir>, bool) {
+        let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
+        let has_non_lt_args = args.iter().any(|arg| match arg {
+            ast::GenericArg::Lifetime(_) => false,
+            ast::GenericArg::Type(_) => true,
+            ast::GenericArg::Const(_) => true,
+        });
+        (
+            GenericArgsCtor {
+                args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
+                bindings: self.arena.alloc_from_iter(
+                    constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
+                ),
+                parenthesized: false,
+            },
+            !has_non_lt_args && param_mode == ParamMode::Optional,
+        )
+    }
+
+    fn lower_parenthesized_parameter_data(
+        &mut self,
+        data: &ParenthesizedArgs,
+    ) -> (GenericArgsCtor<'hir>, bool) {
+        // Switch to `PassThrough` mode for anonymous lifetimes; this
+        // means that we permit things like `&Ref<T>`, where `Ref` has
+        // a hidden lifetime parameter. This is needed for backwards
+        // compatibility, even in contexts like an impl header where
+        // we generally don't permit such things (see #51008).
+        self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
+            let &ParenthesizedArgs { ref inputs, ref output, span } = data;
+            let inputs = this.arena.alloc_from_iter(
+                inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
+            );
+            let output_ty = match output {
+                FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
+                FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])),
+            };
+            let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))];
+            let binding = this.output_ty_binding(output_ty.span, output_ty);
+            (
+                GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
+                false,
+            )
+        })
+    }
+
+    /// An associated type binding `Output = $ty`.
+    crate fn output_ty_binding(
+        &mut self,
+        span: Span,
+        ty: &'hir hir::Ty<'hir>,
+    ) -> hir::TypeBinding<'hir> {
+        let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
+        let kind = hir::TypeBindingKind::Equality { ty };
+        hir::TypeBinding { hir_id: self.next_id(), span, ident, kind }
+    }
+}
diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml
new file mode 100644 (file)
index 0000000..2d45e28
--- /dev/null
@@ -0,0 +1,20 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_ast_passes"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_ast_passes"
+path = "lib.rs"
+
+[dependencies]
+log = "0.4"
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_error_codes = { path = "../librustc_error_codes" }
+rustc_feature = { path = "../librustc_feature" }
+rustc_parse = { path = "../librustc_parse" }
+rustc_session = { path = "../librustc_session" }
+rustc_span = { path = "../librustc_span" }
+syntax = { path = "../libsyntax" }
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
new file mode 100644 (file)
index 0000000..c915b7b
--- /dev/null
@@ -0,0 +1,1038 @@
+// Validate AST before lowering it to HIR.
+//
+// This pass is supposed to catch things that fit into AST data structures,
+// but not permitted by the language. It runs after expansion when AST is frozen,
+// so it can check for erroneous constructions produced by syntax extensions.
+// This pass is supposed to perform only simple checks not requiring name resolution
+// or type checking or some other kind of complex analysis.
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{struct_span_err, Applicability, FatalError};
+use rustc_parse::validate_attr;
+use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
+use rustc_session::lint::LintBuffer;
+use rustc_session::Session;
+use rustc_span::source_map::Spanned;
+use rustc_span::symbol::{kw, sym};
+use rustc_span::Span;
+use std::mem;
+use syntax::ast::*;
+use syntax::attr;
+use syntax::expand::is_proc_macro_attr;
+use syntax::print::pprust;
+use syntax::visit::{self, Visitor};
+use syntax::walk_list;
+
+use rustc_error_codes::*;
+
+/// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
+#[derive(Clone, Copy)]
+enum BoundContext {
+    ImplTrait,
+    TraitBounds,
+    TraitObject,
+}
+
+impl BoundContext {
+    fn description(&self) -> &'static str {
+        match self {
+            Self::ImplTrait => "`impl Trait`",
+            Self::TraitBounds => "supertraits",
+            Self::TraitObject => "trait objects",
+        }
+    }
+}
+
+struct AstValidator<'a> {
+    session: &'a Session,
+    has_proc_macro_decls: bool,
+
+    /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
+    /// Nested `impl Trait` _is_ allowed in associated type position,
+    /// e.g., `impl Iterator<Item = impl Debug>`.
+    outer_impl_trait: Option<Span>,
+
+    /// Keeps track of the `BoundContext` as we recurse.
+    ///
+    /// This is used to forbid `?const Trait` bounds in, e.g.,
+    /// `impl Iterator<Item = Box<dyn ?const Trait>`.
+    bound_context: Option<BoundContext>,
+
+    /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
+    /// or `Foo::Bar<impl Trait>`
+    is_impl_trait_banned: bool,
+
+    /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
+    /// certain positions.
+    is_assoc_ty_bound_banned: bool,
+
+    lint_buffer: &'a mut LintBuffer,
+}
+
+impl<'a> AstValidator<'a> {
+    fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.is_impl_trait_banned, true);
+        f(self);
+        self.is_impl_trait_banned = old;
+    }
+
+    fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
+        f(self);
+        self.is_assoc_ty_bound_banned = old;
+    }
+
+    fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.outer_impl_trait, outer);
+        if outer.is_some() {
+            self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
+        } else {
+            f(self)
+        }
+        self.outer_impl_trait = old;
+    }
+
+    fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
+        let old = self.bound_context.replace(ctx);
+        f(self);
+        self.bound_context = old;
+    }
+
+    fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
+        match constraint.kind {
+            AssocTyConstraintKind::Equality { .. } => {}
+            AssocTyConstraintKind::Bound { .. } => {
+                if self.is_assoc_ty_bound_banned {
+                    self.err_handler().span_err(
+                        constraint.span,
+                        "associated type bounds are not allowed within structs, enums, or unions",
+                    );
+                }
+            }
+        }
+        self.visit_assoc_ty_constraint(constraint);
+    }
+
+    // Mirrors `visit::walk_ty`, but tracks relevant state.
+    fn walk_ty(&mut self, t: &'a Ty) {
+        match t.kind {
+            TyKind::ImplTrait(..) => {
+                self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
+            }
+            TyKind::TraitObject(..) => {
+                self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
+            }
+            TyKind::Path(ref qself, ref path) => {
+                // We allow these:
+                //  - `Option<impl Trait>`
+                //  - `option::Option<impl Trait>`
+                //  - `option::Option<T>::Foo<impl Trait>
+                //
+                // But not these:
+                //  - `<impl Trait>::Foo`
+                //  - `option::Option<impl Trait>::Foo`.
+                //
+                // To implement this, we disallow `impl Trait` from `qself`
+                // (for cases like `<impl Trait>::Foo>`)
+                // but we allow `impl Trait` in `GenericArgs`
+                // iff there are no more PathSegments.
+                if let Some(ref qself) = *qself {
+                    // `impl Trait` in `qself` is always illegal
+                    self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
+                }
+
+                // Note that there should be a call to visit_path here,
+                // so if any logic is added to process `Path`s a call to it should be
+                // added both in visit_path and here. This code mirrors visit::walk_path.
+                for (i, segment) in path.segments.iter().enumerate() {
+                    // Allow `impl Trait` iff we're on the final path segment
+                    if i == path.segments.len() - 1 {
+                        self.visit_path_segment(path.span, segment);
+                    } else {
+                        self.with_banned_impl_trait(|this| {
+                            this.visit_path_segment(path.span, segment)
+                        });
+                    }
+                }
+            }
+            _ => visit::walk_ty(self, t),
+        }
+    }
+
+    fn err_handler(&self) -> &rustc_errors::Handler {
+        &self.session.diagnostic()
+    }
+
+    fn check_lifetime(&self, ident: Ident) {
+        let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
+        if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
+            self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
+        }
+    }
+
+    fn check_label(&self, ident: Ident) {
+        if ident.without_first_quote().is_reserved() {
+            self.err_handler()
+                .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
+        }
+    }
+
+    fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
+        if let VisibilityKind::Inherited = vis.node {
+            return;
+        }
+
+        let mut err =
+            struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
+        if vis.node.is_pub() {
+            err.span_label(vis.span, "`pub` not permitted here because it's implied");
+        }
+        if let Some(note) = note {
+            err.note(note);
+        }
+        err.emit();
+    }
+
+    fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
+        for Param { pat, .. } in &decl.inputs {
+            match pat.kind {
+                PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
+                PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
+                    report_err(pat.span, true)
+                }
+                _ => report_err(pat.span, false),
+            }
+        }
+    }
+
+    fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
+        if asyncness.is_async() {
+            struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`")
+                .note("`async` trait functions are not currently supported")
+                .note(
+                    "consider using the `async-trait` crate: \
+                       https://crates.io/crates/async-trait",
+                )
+                .emit();
+        }
+    }
+
+    fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
+        if constness.node == Constness::Const {
+            struct_span_err!(
+                self.session,
+                constness.span,
+                E0379,
+                "trait fns cannot be declared const"
+            )
+            .span_label(constness.span, "trait fns cannot be const")
+            .emit();
+        }
+    }
+
+    // FIXME(ecstaticmorse): Instead, use `bound_context` to check this in `visit_param_bound`.
+    fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
+        for bound in bounds {
+            if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
+                let mut err = self.err_handler().struct_span_err(
+                    poly.span,
+                    &format!("`?Trait` is not permitted in {}", where_),
+                );
+                if is_trait {
+                    let path_str = pprust::path_to_string(&poly.trait_ref.path);
+                    err.note(&format!("traits are `?{}` by default", path_str));
+                }
+                err.emit();
+            }
+        }
+    }
+
+    /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
+    /// or paths for ranges.
+    //
+    // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
+    // That means making this work:
+    //
+    // ```rust,ignore (FIXME)
+    // struct S;
+    // macro_rules! m {
+    //     ($a:expr) => {
+    //         let $a = S;
+    //     }
+    // }
+    // m!(S);
+    // ```
+    fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
+        match expr.kind {
+            ExprKind::Lit(..) | ExprKind::Err => {}
+            ExprKind::Path(..) if allow_paths => {}
+            ExprKind::Unary(UnOp::Neg, ref inner)
+                if match inner.kind {
+                    ExprKind::Lit(_) => true,
+                    _ => false,
+                } => {}
+            _ => self.err_handler().span_err(
+                expr.span,
+                "arbitrary expressions aren't allowed \
+                                                         in patterns",
+            ),
+        }
+    }
+
+    fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
+        // Check only lifetime parameters are present and that the lifetime
+        // parameters that are present have no bounds.
+        let non_lt_param_spans: Vec<_> = params
+            .iter()
+            .filter_map(|param| match param.kind {
+                GenericParamKind::Lifetime { .. } => {
+                    if !param.bounds.is_empty() {
+                        let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
+                        self.err_handler()
+                            .span_err(spans, "lifetime bounds cannot be used in this context");
+                    }
+                    None
+                }
+                _ => Some(param.ident.span),
+            })
+            .collect();
+        if !non_lt_param_spans.is_empty() {
+            self.err_handler().span_err(
+                non_lt_param_spans,
+                "only lifetime parameters can be used in this context",
+            );
+        }
+    }
+
+    fn check_fn_decl(&self, fn_decl: &FnDecl) {
+        match &*fn_decl.inputs {
+            [Param { ty, span, .. }] => {
+                if let TyKind::CVarArgs = ty.kind {
+                    self.err_handler().span_err(
+                        *span,
+                        "C-variadic function must be declared with at least one named argument",
+                    );
+                }
+            }
+            [ps @ .., _] => {
+                for Param { ty, span, .. } in ps {
+                    if let TyKind::CVarArgs = ty.kind {
+                        self.err_handler().span_err(
+                            *span,
+                            "`...` must be the last argument of a C-variadic function",
+                        );
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        fn_decl
+            .inputs
+            .iter()
+            .flat_map(|i| i.attrs.as_ref())
+            .filter(|attr| {
+                let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
+                !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr)
+            })
+            .for_each(|attr| {
+                if attr.is_doc_comment() {
+                    self.err_handler()
+                        .struct_span_err(
+                            attr.span,
+                            "documentation comments cannot be applied to function parameters",
+                        )
+                        .span_label(attr.span, "doc comments are not allowed here")
+                        .emit();
+                } else {
+                    self.err_handler().span_err(
+                        attr.span,
+                        "allow, cfg, cfg_attr, deny, \
+                forbid, and warn are the only allowed built-in attributes in function parameters",
+                    )
+                }
+            });
+    }
+
+    fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
+        if let Defaultness::Default = defaultness {
+            self.err_handler()
+                .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
+                .emit();
+        }
+    }
+
+    fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
+        if body.is_some() {
+            return;
+        }
+
+        self.err_handler()
+            .struct_span_err(sp, &format!("associated {} in `impl` without body", ctx))
+            .span_suggestion(
+                self.session.source_map().end_point(sp),
+                &format!("provide a definition for the {}", ctx),
+                sugg.to_string(),
+                Applicability::HasPlaceholders,
+            )
+            .emit();
+    }
+
+    fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
+        let span = match bounds {
+            [] => return,
+            [b0] => b0.span(),
+            [b0, .., bl] => b0.span().to(bl.span()),
+        };
+        self.err_handler()
+            .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
+            .emit();
+    }
+
+    fn check_c_varadic_type(&self, decl: &FnDecl) {
+        for Param { ty, span, .. } in &decl.inputs {
+            if let TyKind::CVarArgs = ty.kind {
+                self.err_handler()
+                    .struct_span_err(
+                        *span,
+                        "only foreign or `unsafe extern \"C\" functions may be C-variadic",
+                    )
+                    .emit();
+            }
+        }
+    }
+}
+
+enum GenericPosition {
+    Param,
+    Arg,
+}
+
+fn validate_generics_order<'a>(
+    sess: &Session,
+    handler: &rustc_errors::Handler,
+    generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
+    pos: GenericPosition,
+    span: Span,
+) {
+    let mut max_param: Option<ParamKindOrd> = None;
+    let mut out_of_order = FxHashMap::default();
+    let mut param_idents = vec![];
+    let mut found_type = false;
+    let mut found_const = false;
+
+    for (kind, bounds, span, ident) in generics {
+        if let Some(ident) = ident {
+            param_idents.push((kind, bounds, param_idents.len(), ident));
+        }
+        let max_param = &mut max_param;
+        match max_param {
+            Some(max_param) if *max_param > kind => {
+                let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
+                entry.1.push(span);
+            }
+            Some(_) | None => *max_param = Some(kind),
+        };
+        match kind {
+            ParamKindOrd::Type => found_type = true,
+            ParamKindOrd::Const => found_const = true,
+            _ => {}
+        }
+    }
+
+    let mut ordered_params = "<".to_string();
+    if !out_of_order.is_empty() {
+        param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
+        let mut first = true;
+        for (_, bounds, _, ident) in param_idents {
+            if !first {
+                ordered_params += ", ";
+            }
+            ordered_params += &ident;
+            if let Some(bounds) = bounds {
+                if !bounds.is_empty() {
+                    ordered_params += ": ";
+                    ordered_params += &pprust::bounds_to_string(&bounds);
+                }
+            }
+            first = false;
+        }
+    }
+    ordered_params += ">";
+
+    let pos_str = match pos {
+        GenericPosition::Param => "parameter",
+        GenericPosition::Arg => "argument",
+    };
+
+    for (param_ord, (max_param, spans)) in &out_of_order {
+        let mut err = handler.struct_span_err(
+            spans.clone(),
+            &format!(
+                "{} {pos}s must be declared prior to {} {pos}s",
+                param_ord,
+                max_param,
+                pos = pos_str,
+            ),
+        );
+        if let GenericPosition::Param = pos {
+            err.span_suggestion(
+                span,
+                &format!(
+                    "reorder the {}s: lifetimes, then types{}",
+                    pos_str,
+                    if sess.features_untracked().const_generics { ", then consts" } else { "" },
+                ),
+                ordered_params.clone(),
+                Applicability::MachineApplicable,
+            );
+        }
+        err.emit();
+    }
+
+    // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
+    // if we don't. Const parameters and type parameters can currently conflict if they
+    // are out-of-order.
+    if !out_of_order.is_empty() && found_type && found_const {
+        FatalError.raise();
+    }
+}
+
+impl<'a> Visitor<'a> for AstValidator<'a> {
+    fn visit_attribute(&mut self, attr: &Attribute) {
+        validate_attr::check_meta(&self.session.parse_sess, attr);
+    }
+
+    fn visit_expr(&mut self, expr: &'a Expr) {
+        match &expr.kind {
+            ExprKind::Closure(_, _, _, fn_decl, _, _) => {
+                self.check_fn_decl(fn_decl);
+            }
+            ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
+                struct_span_err!(
+                    self.session,
+                    expr.span,
+                    E0472,
+                    "asm! is unsupported on this target"
+                )
+                .emit();
+            }
+            _ => {}
+        }
+
+        visit::walk_expr(self, expr);
+    }
+
+    fn visit_ty(&mut self, ty: &'a Ty) {
+        match ty.kind {
+            TyKind::BareFn(ref bfty) => {
+                self.check_fn_decl(&bfty.decl);
+                Self::check_decl_no_pat(&bfty.decl, |span, _| {
+                    struct_span_err!(
+                        self.session,
+                        span,
+                        E0561,
+                        "patterns aren't allowed in function pointer types"
+                    )
+                    .emit();
+                });
+                self.check_late_bound_lifetime_defs(&bfty.generic_params);
+            }
+            TyKind::TraitObject(ref bounds, ..) => {
+                let mut any_lifetime_bounds = false;
+                for bound in bounds {
+                    if let GenericBound::Outlives(ref lifetime) = *bound {
+                        if any_lifetime_bounds {
+                            struct_span_err!(
+                                self.session,
+                                lifetime.ident.span,
+                                E0226,
+                                "only a single explicit lifetime bound is permitted"
+                            )
+                            .emit();
+                            break;
+                        }
+                        any_lifetime_bounds = true;
+                    }
+                }
+                self.no_questions_in_bounds(bounds, "trait object types", false);
+            }
+            TyKind::ImplTrait(_, ref bounds) => {
+                if self.is_impl_trait_banned {
+                    struct_span_err!(
+                        self.session,
+                        ty.span,
+                        E0667,
+                        "`impl Trait` is not allowed in path parameters"
+                    )
+                    .emit();
+                }
+
+                if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
+                    struct_span_err!(
+                        self.session,
+                        ty.span,
+                        E0666,
+                        "nested `impl Trait` is not allowed"
+                    )
+                    .span_label(outer_impl_trait_sp, "outer `impl Trait`")
+                    .span_label(ty.span, "nested `impl Trait` here")
+                    .emit();
+                }
+
+                if !bounds
+                    .iter()
+                    .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
+                {
+                    self.err_handler().span_err(ty.span, "at least one trait must be specified");
+                }
+
+                self.walk_ty(ty);
+                return;
+            }
+            _ => {}
+        }
+
+        self.walk_ty(ty)
+    }
+
+    fn visit_label(&mut self, label: &'a Label) {
+        self.check_label(label.ident);
+        visit::walk_label(self, label);
+    }
+
+    fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
+        self.check_lifetime(lifetime.ident);
+        visit::walk_lifetime(self, lifetime);
+    }
+
+    fn visit_item(&mut self, item: &'a Item) {
+        if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
+            self.has_proc_macro_decls = true;
+        }
+
+        match item.kind {
+            ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => {
+                self.invalid_visibility(&item.vis, None);
+                if let TyKind::Err = ty.kind {
+                    self.err_handler()
+                        .struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax")
+                        .help("use `auto trait Trait {}` instead")
+                        .emit();
+                }
+                if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
+                    struct_span_err!(
+                        self.session,
+                        item.span,
+                        E0198,
+                        "negative impls cannot be unsafe"
+                    )
+                    .emit();
+                }
+                for impl_item in impl_items {
+                    self.invalid_visibility(&impl_item.vis, None);
+                    if let AssocItemKind::Fn(ref sig, _) = impl_item.kind {
+                        self.check_trait_fn_not_const(sig.header.constness);
+                        self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
+                    }
+                }
+            }
+            ItemKind::Impl(unsafety, polarity, defaultness, _, None, _, _) => {
+                self.invalid_visibility(
+                    &item.vis,
+                    Some("place qualifiers on individual impl items instead"),
+                );
+                if unsafety == Unsafety::Unsafe {
+                    struct_span_err!(
+                        self.session,
+                        item.span,
+                        E0197,
+                        "inherent impls cannot be unsafe"
+                    )
+                    .emit();
+                }
+                if polarity == ImplPolarity::Negative {
+                    self.err_handler().span_err(item.span, "inherent impls cannot be negative");
+                }
+                if defaultness == Defaultness::Default {
+                    self.err_handler()
+                        .struct_span_err(item.span, "inherent impls cannot be default")
+                        .note("only trait implementations may be annotated with default")
+                        .emit();
+                }
+            }
+            ItemKind::Fn(ref sig, ref generics, _) => {
+                self.visit_fn_header(&sig.header);
+                self.check_fn_decl(&sig.decl);
+                // We currently do not permit const generics in `const fn`, as
+                // this is tantamount to allowing compile-time dependent typing.
+                if sig.header.constness.node == Constness::Const {
+                    // Look for const generics and error if we find any.
+                    for param in &generics.params {
+                        match param.kind {
+                            GenericParamKind::Const { .. } => {
+                                self.err_handler()
+                                    .struct_span_err(
+                                        item.span,
+                                        "const parameters are not permitted in `const fn`",
+                                    )
+                                    .emit();
+                            }
+                            _ => {}
+                        }
+                    }
+                }
+                // Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
+                match sig.header.ext {
+                    Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. })
+                    | Extern::Implicit
+                        if sig.header.unsafety == Unsafety::Unsafe => {}
+                    _ => self.check_c_varadic_type(&sig.decl),
+                }
+            }
+            ItemKind::ForeignMod(..) => {
+                self.invalid_visibility(
+                    &item.vis,
+                    Some("place qualifiers on individual foreign items instead"),
+                );
+            }
+            ItemKind::Enum(ref def, _) => {
+                for variant in &def.variants {
+                    self.invalid_visibility(&variant.vis, None);
+                    for field in variant.data.fields() {
+                        self.invalid_visibility(&field.vis, None);
+                    }
+                }
+            }
+            ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
+                if is_auto == IsAuto::Yes {
+                    // Auto traits cannot have generics, super traits nor contain items.
+                    if !generics.params.is_empty() {
+                        struct_span_err!(
+                            self.session,
+                            item.span,
+                            E0567,
+                            "auto traits cannot have generic parameters"
+                        )
+                        .emit();
+                    }
+                    if !bounds.is_empty() {
+                        struct_span_err!(
+                            self.session,
+                            item.span,
+                            E0568,
+                            "auto traits cannot have super traits"
+                        )
+                        .emit();
+                    }
+                    if !trait_items.is_empty() {
+                        struct_span_err!(
+                            self.session,
+                            item.span,
+                            E0380,
+                            "auto traits cannot have methods or associated items"
+                        )
+                        .emit();
+                    }
+                }
+                self.no_questions_in_bounds(bounds, "supertraits", true);
+
+                // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
+                // context for the supertraits.
+                self.visit_vis(&item.vis);
+                self.visit_ident(item.ident);
+                self.visit_generics(generics);
+                self.with_bound_context(BoundContext::TraitBounds, |this| {
+                    walk_list!(this, visit_param_bound, bounds);
+                });
+                walk_list!(self, visit_trait_item, trait_items);
+                walk_list!(self, visit_attribute, &item.attrs);
+                return;
+            }
+            ItemKind::Mod(_) => {
+                // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
+                attr::first_attr_value_str_by_name(&item.attrs, sym::path);
+            }
+            ItemKind::Union(ref vdata, _) => {
+                if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
+                    self.err_handler()
+                        .span_err(item.span, "tuple and unit unions are not permitted");
+                }
+                if vdata.fields().is_empty() {
+                    self.err_handler().span_err(item.span, "unions cannot have zero fields");
+                }
+            }
+            _ => {}
+        }
+
+        visit::walk_item(self, item)
+    }
+
+    fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
+        match fi.kind {
+            ForeignItemKind::Fn(ref decl, _) => {
+                self.check_fn_decl(decl);
+                Self::check_decl_no_pat(decl, |span, _| {
+                    struct_span_err!(
+                        self.session,
+                        span,
+                        E0130,
+                        "patterns aren't allowed in foreign function declarations"
+                    )
+                    .span_label(span, "pattern not allowed in foreign function")
+                    .emit();
+                });
+            }
+            ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
+        }
+
+        visit::walk_foreign_item(self, fi)
+    }
+
+    // Mirrors `visit::walk_generic_args`, but tracks relevant state.
+    fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
+        match *generic_args {
+            GenericArgs::AngleBracketed(ref data) => {
+                walk_list!(self, visit_generic_arg, &data.args);
+                validate_generics_order(
+                    self.session,
+                    self.err_handler(),
+                    data.args.iter().map(|arg| {
+                        (
+                            match arg {
+                                GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
+                                GenericArg::Type(..) => ParamKindOrd::Type,
+                                GenericArg::Const(..) => ParamKindOrd::Const,
+                            },
+                            None,
+                            arg.span(),
+                            None,
+                        )
+                    }),
+                    GenericPosition::Arg,
+                    generic_args.span(),
+                );
+
+                // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
+                // are allowed to contain nested `impl Trait`.
+                self.with_impl_trait(None, |this| {
+                    walk_list!(
+                        this,
+                        visit_assoc_ty_constraint_from_generic_args,
+                        &data.constraints
+                    );
+                });
+            }
+            GenericArgs::Parenthesized(ref data) => {
+                walk_list!(self, visit_ty, &data.inputs);
+                if let FunctionRetTy::Ty(ty) = &data.output {
+                    // `-> Foo` syntax is essentially an associated type binding,
+                    // so it is also allowed to contain nested `impl Trait`.
+                    self.with_impl_trait(None, |this| this.visit_ty(ty));
+                }
+            }
+        }
+    }
+
+    fn visit_generics(&mut self, generics: &'a Generics) {
+        let mut prev_ty_default = None;
+        for param in &generics.params {
+            if let GenericParamKind::Type { ref default, .. } = param.kind {
+                if default.is_some() {
+                    prev_ty_default = Some(param.ident.span);
+                } else if let Some(span) = prev_ty_default {
+                    self.err_handler()
+                        .span_err(span, "type parameters with a default must be trailing");
+                    break;
+                }
+            }
+        }
+
+        validate_generics_order(
+            self.session,
+            self.err_handler(),
+            generics.params.iter().map(|param| {
+                let ident = Some(param.ident.to_string());
+                let (kind, ident) = match &param.kind {
+                    GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
+                    GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
+                    GenericParamKind::Const { ref ty } => {
+                        let ty = pprust::ty_to_string(ty);
+                        (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
+                    }
+                };
+                (kind, Some(&*param.bounds), param.ident.span, ident)
+            }),
+            GenericPosition::Param,
+            generics.span,
+        );
+
+        for predicate in &generics.where_clause.predicates {
+            if let WherePredicate::EqPredicate(ref predicate) = *predicate {
+                self.err_handler()
+                    .struct_span_err(
+                        predicate.span,
+                        "equality constraints are not yet supported in `where` clauses",
+                    )
+                    .span_label(predicate.span, "not supported")
+                    .note(
+                        "for more information, see https://github.com/rust-lang/rust/issues/20041",
+                    )
+                    .emit();
+            }
+        }
+
+        visit::walk_generics(self, generics)
+    }
+
+    fn visit_generic_param(&mut self, param: &'a GenericParam) {
+        if let GenericParamKind::Lifetime { .. } = param.kind {
+            self.check_lifetime(param.ident);
+        }
+        visit::walk_generic_param(self, param);
+    }
+
+    fn visit_param_bound(&mut self, bound: &'a GenericBound) {
+        if let GenericBound::Trait(poly, maybe_bound) = bound {
+            match poly.trait_ref.constness {
+                Some(Constness::NotConst) => {
+                    if *maybe_bound == TraitBoundModifier::Maybe {
+                        self.err_handler()
+                            .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
+                    }
+
+                    if let Some(ctx) = self.bound_context {
+                        let msg = format!("`?const` is not permitted in {}", ctx.description());
+                        self.err_handler().span_err(bound.span(), &msg);
+                    }
+                }
+
+                Some(Constness::Const) => panic!("Parser should reject bare `const` on bounds"),
+                None => {}
+            }
+        }
+
+        visit::walk_param_bound(self, bound)
+    }
+
+    fn visit_pat(&mut self, pat: &'a Pat) {
+        match pat.kind {
+            PatKind::Lit(ref expr) => {
+                self.check_expr_within_pat(expr, false);
+            }
+            PatKind::Range(ref start, ref end, _) => {
+                if let Some(expr) = start {
+                    self.check_expr_within_pat(expr, true);
+                }
+                if let Some(expr) = end {
+                    self.check_expr_within_pat(expr, true);
+                }
+            }
+            _ => {}
+        }
+
+        visit::walk_pat(self, pat)
+    }
+
+    fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
+        if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
+            // A type binding, eg `for<'c> Foo: Send+Clone+'c`
+            self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
+        }
+        visit::walk_where_predicate(self, p);
+    }
+
+    fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
+        self.check_late_bound_lifetime_defs(&t.bound_generic_params);
+        visit::walk_poly_trait_ref(self, t, m);
+    }
+
+    fn visit_variant_data(&mut self, s: &'a VariantData) {
+        self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
+    }
+
+    fn visit_enum_def(
+        &mut self,
+        enum_definition: &'a EnumDef,
+        generics: &'a Generics,
+        item_id: NodeId,
+        _: Span,
+    ) {
+        self.with_banned_assoc_ty_bound(|this| {
+            visit::walk_enum_def(this, enum_definition, generics, item_id)
+        })
+    }
+
+    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
+        match &ii.kind {
+            AssocItemKind::Const(_, body) => {
+                self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
+            }
+            AssocItemKind::Fn(sig, body) => {
+                self.check_impl_item_provided(ii.span, body, "function", " { <body> }");
+                self.check_fn_decl(&sig.decl);
+            }
+            AssocItemKind::TyAlias(bounds, body) => {
+                self.check_impl_item_provided(ii.span, body, "type", " = <type>;");
+                self.check_impl_assoc_type_no_bounds(bounds);
+            }
+            _ => {}
+        }
+        visit::walk_impl_item(self, ii);
+    }
+
+    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
+        self.invalid_visibility(&ti.vis, None);
+        self.check_defaultness(ti.span, ti.defaultness);
+
+        if let AssocItemKind::Fn(sig, block) = &ti.kind {
+            self.check_fn_decl(&sig.decl);
+            self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node);
+            self.check_trait_fn_not_const(sig.header.constness);
+            if block.is_none() {
+                Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
+                    if mut_ident {
+                        self.lint_buffer.buffer_lint(
+                            PATTERNS_IN_FNS_WITHOUT_BODY,
+                            ti.id,
+                            span,
+                            "patterns aren't allowed in methods without bodies",
+                        );
+                    } else {
+                        struct_span_err!(
+                            self.session,
+                            span,
+                            E0642,
+                            "patterns aren't allowed in methods without bodies"
+                        )
+                        .emit();
+                    }
+                });
+            }
+        }
+
+        visit::walk_trait_item(self, ti);
+    }
+
+    fn visit_assoc_item(&mut self, item: &'a AssocItem) {
+        if let AssocItemKind::Fn(sig, _) = &item.kind {
+            self.check_c_varadic_type(&sig.decl);
+        }
+        visit::walk_assoc_item(self, item);
+    }
+}
+
+pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
+    let mut validator = AstValidator {
+        session,
+        has_proc_macro_decls: false,
+        outer_impl_trait: None,
+        bound_context: None,
+        is_impl_trait_banned: false,
+        is_assoc_ty_bound_banned: false,
+        lint_buffer: lints,
+    };
+    visit::walk_crate(&mut validator, krate);
+
+    validator.has_proc_macro_decls
+}
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
new file mode 100644 (file)
index 0000000..e6f4535
--- /dev/null
@@ -0,0 +1,702 @@
+use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, Handler};
+use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{Features, GateIssue, UnstableFeatures};
+use rustc_span::source_map::Spanned;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
+use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
+use syntax::attr;
+use syntax::sess::{feature_err, feature_err_issue, ParseSess};
+use syntax::visit::{self, FnKind, Visitor};
+
+use log::debug;
+
+macro_rules! gate_feature_fn {
+    ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
+        let (cx, has_feature, span, name, explain) = (&*$cx, $has_feature, $span, $name, $explain);
+        let has_feature: bool = has_feature(&$cx.features);
+        debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
+        if !has_feature && !span.allows_unstable($name) {
+            feature_err_issue(cx.parse_sess, name, span, GateIssue::Language, explain).emit();
+        }
+    }};
+}
+
+macro_rules! gate_feature_post {
+    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
+        gate_feature_fn!($cx, |x: &Features| x.$feature, $span, sym::$feature, $explain)
+    };
+}
+
+pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
+    PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
+}
+
+struct PostExpansionVisitor<'a> {
+    parse_sess: &'a ParseSess,
+    features: &'a Features,
+}
+
+impl<'a> PostExpansionVisitor<'a> {
+    fn check_abi(&self, abi: ast::StrLit) {
+        let ast::StrLit { symbol_unescaped, span, .. } = abi;
+
+        match &*symbol_unescaped.as_str() {
+            // Stable
+            "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
+            | "system" => {}
+            "rust-intrinsic" => {
+                gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change");
+            }
+            "platform-intrinsic" => {
+                gate_feature_post!(
+                    &self,
+                    platform_intrinsics,
+                    span,
+                    "platform intrinsics are experimental and possibly buggy"
+                );
+            }
+            "vectorcall" => {
+                gate_feature_post!(
+                    &self,
+                    abi_vectorcall,
+                    span,
+                    "vectorcall is experimental and subject to change"
+                );
+            }
+            "thiscall" => {
+                gate_feature_post!(
+                    &self,
+                    abi_thiscall,
+                    span,
+                    "thiscall is experimental and subject to change"
+                );
+            }
+            "rust-call" => {
+                gate_feature_post!(
+                    &self,
+                    unboxed_closures,
+                    span,
+                    "rust-call ABI is subject to change"
+                );
+            }
+            "ptx-kernel" => {
+                gate_feature_post!(
+                    &self,
+                    abi_ptx,
+                    span,
+                    "PTX ABIs are experimental and subject to change"
+                );
+            }
+            "unadjusted" => {
+                gate_feature_post!(
+                    &self,
+                    abi_unadjusted,
+                    span,
+                    "unadjusted ABI is an implementation detail and perma-unstable"
+                );
+            }
+            "msp430-interrupt" => {
+                gate_feature_post!(
+                    &self,
+                    abi_msp430_interrupt,
+                    span,
+                    "msp430-interrupt ABI is experimental and subject to change"
+                );
+            }
+            "x86-interrupt" => {
+                gate_feature_post!(
+                    &self,
+                    abi_x86_interrupt,
+                    span,
+                    "x86-interrupt ABI is experimental and subject to change"
+                );
+            }
+            "amdgpu-kernel" => {
+                gate_feature_post!(
+                    &self,
+                    abi_amdgpu_kernel,
+                    span,
+                    "amdgpu-kernel ABI is experimental and subject to change"
+                );
+            }
+            "efiapi" => {
+                gate_feature_post!(
+                    &self,
+                    abi_efiapi,
+                    span,
+                    "efiapi ABI is experimental and subject to change"
+                );
+            }
+            abi => self
+                .parse_sess
+                .span_diagnostic
+                .delay_span_bug(span, &format!("unrecognized ABI not caught in lowering: {}", abi)),
+        }
+    }
+
+    fn check_extern(&self, ext: ast::Extern) {
+        if let ast::Extern::Explicit(abi) = ext {
+            self.check_abi(abi);
+        }
+    }
+
+    fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
+        let has_fields = variants.iter().any(|variant| match variant.data {
+            VariantData::Tuple(..) | VariantData::Struct(..) => true,
+            VariantData::Unit(..) => false,
+        });
+
+        let discriminant_spans = variants
+            .iter()
+            .filter(|variant| match variant.data {
+                VariantData::Tuple(..) | VariantData::Struct(..) => false,
+                VariantData::Unit(..) => true,
+            })
+            .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
+            .collect::<Vec<_>>();
+
+        if !discriminant_spans.is_empty() && has_fields {
+            let mut err = feature_err(
+                self.parse_sess,
+                sym::arbitrary_enum_discriminant,
+                discriminant_spans.clone(),
+                "custom discriminant values are not allowed in enums with tuple or struct variants",
+            );
+            for sp in discriminant_spans {
+                err.span_label(sp, "disallowed custom discriminant");
+            }
+            for variant in variants.iter() {
+                match &variant.data {
+                    VariantData::Struct(..) => {
+                        err.span_label(variant.span, "struct variant defined here");
+                    }
+                    VariantData::Tuple(..) => {
+                        err.span_label(variant.span, "tuple variant defined here");
+                    }
+                    VariantData::Unit(..) => {}
+                }
+            }
+            err.emit();
+        }
+    }
+
+    fn check_gat(&self, generics: &ast::Generics, span: Span) {
+        if !generics.params.is_empty() {
+            gate_feature_post!(
+                &self,
+                generic_associated_types,
+                span,
+                "generic associated types are unstable"
+            );
+        }
+        if !generics.where_clause.predicates.is_empty() {
+            gate_feature_post!(
+                &self,
+                generic_associated_types,
+                span,
+                "where clauses on associated types are unstable"
+            );
+        }
+    }
+
+    /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
+    fn check_impl_trait(&self, ty: &ast::Ty) {
+        struct ImplTraitVisitor<'a> {
+            vis: &'a PostExpansionVisitor<'a>,
+        }
+        impl Visitor<'_> for ImplTraitVisitor<'_> {
+            fn visit_ty(&mut self, ty: &ast::Ty) {
+                if let ast::TyKind::ImplTrait(..) = ty.kind {
+                    gate_feature_post!(
+                        &self.vis,
+                        type_alias_impl_trait,
+                        ty.span,
+                        "`impl Trait` in type aliases is unstable"
+                    );
+                }
+                visit::walk_ty(self, ty);
+            }
+        }
+        ImplTraitVisitor { vis: self }.visit_ty(ty);
+    }
+}
+
+impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
+    fn visit_attribute(&mut self, attr: &ast::Attribute) {
+        let attr_info =
+            attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+        // Check feature gates for built-in attributes.
+        if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
+            gate_feature_fn!(self, has_feature, attr.span, name, descr);
+        }
+        // Check unstable flavors of the `#[doc]` attribute.
+        if attr.check_name(sym::doc) {
+            for nested_meta in attr.meta_item_list().unwrap_or_default() {
+                macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
+                    $(if nested_meta.check_name(sym::$name) {
+                        let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
+                        gate_feature_post!(self, $feature, attr.span, msg);
+                    })*
+                }}
+
+                gate_doc!(
+                    include => external_doc
+                    cfg => doc_cfg
+                    masked => doc_masked
+                    spotlight => doc_spotlight
+                    alias => doc_alias
+                    keyword => doc_keyword
+                );
+            }
+        }
+    }
+
+    fn visit_name(&mut self, sp: Span, name: ast::Name) {
+        if !name.as_str().is_ascii() {
+            gate_feature_post!(
+                &self,
+                non_ascii_idents,
+                self.parse_sess.source_map().def_span(sp),
+                "non-ascii idents are not fully supported"
+            );
+        }
+    }
+
+    fn visit_item(&mut self, i: &'a ast::Item) {
+        match i.kind {
+            ast::ItemKind::ForeignMod(ref foreign_module) => {
+                if let Some(abi) = foreign_module.abi {
+                    self.check_abi(abi);
+                }
+            }
+
+            ast::ItemKind::Fn(..) => {
+                if attr::contains_name(&i.attrs[..], sym::plugin_registrar) {
+                    gate_feature_post!(
+                        &self,
+                        plugin_registrar,
+                        i.span,
+                        "compiler plugins are experimental and possibly buggy"
+                    );
+                }
+                if attr::contains_name(&i.attrs[..], sym::start) {
+                    gate_feature_post!(
+                        &self,
+                        start,
+                        i.span,
+                        "`#[start]` functions are experimental \
+                                       and their signature may change \
+                                       over time"
+                    );
+                }
+                if attr::contains_name(&i.attrs[..], sym::main) {
+                    gate_feature_post!(
+                        &self,
+                        main,
+                        i.span,
+                        "declaration of a non-standard `#[main]` \
+                                        function may change over time, for now \
+                                        a top-level `fn main()` is required"
+                    );
+                }
+            }
+
+            ast::ItemKind::Struct(..) => {
+                for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
+                    for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
+                        if item.check_name(sym::simd) {
+                            gate_feature_post!(
+                                &self,
+                                repr_simd,
+                                attr.span,
+                                "SIMD types are experimental and possibly buggy"
+                            );
+                        }
+                    }
+                }
+            }
+
+            ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
+                for variant in variants {
+                    match (&variant.data, &variant.disr_expr) {
+                        (ast::VariantData::Unit(..), _) => {}
+                        (_, Some(disr_expr)) => gate_feature_post!(
+                            &self,
+                            arbitrary_enum_discriminant,
+                            disr_expr.value.span,
+                            "discriminants on non-unit variants are experimental"
+                        ),
+                        _ => {}
+                    }
+                }
+
+                let has_feature = self.features.arbitrary_enum_discriminant;
+                if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
+                    self.maybe_report_invalid_custom_discriminants(&variants);
+                }
+            }
+
+            ast::ItemKind::Impl(_, polarity, defaultness, ..) => {
+                if polarity == ast::ImplPolarity::Negative {
+                    gate_feature_post!(
+                        &self,
+                        optin_builtin_traits,
+                        i.span,
+                        "negative trait bounds are not yet fully implemented; \
+                                        use marker types for now"
+                    );
+                }
+
+                if let ast::Defaultness::Default = defaultness {
+                    gate_feature_post!(&self, specialization, i.span, "specialization is unstable");
+                }
+            }
+
+            ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
+                gate_feature_post!(
+                    &self,
+                    optin_builtin_traits,
+                    i.span,
+                    "auto traits are experimental and possibly buggy"
+                );
+            }
+
+            ast::ItemKind::TraitAlias(..) => {
+                gate_feature_post!(&self, trait_alias, i.span, "trait aliases are experimental");
+            }
+
+            ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
+                let msg = "`macro` is experimental";
+                gate_feature_post!(&self, decl_macro, i.span, msg);
+            }
+
+            ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty),
+
+            _ => {}
+        }
+
+        visit::walk_item(self, i);
+    }
+
+    fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
+        match i.kind {
+            ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
+                let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
+                let links_to_llvm = match link_name {
+                    Some(val) => val.as_str().starts_with("llvm."),
+                    _ => false,
+                };
+                if links_to_llvm {
+                    gate_feature_post!(
+                        &self,
+                        link_llvm_intrinsics,
+                        i.span,
+                        "linking to LLVM intrinsics is experimental"
+                    );
+                }
+            }
+            ast::ForeignItemKind::Ty => {
+                gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
+            }
+            ast::ForeignItemKind::Macro(..) => {}
+        }
+
+        visit::walk_foreign_item(self, i)
+    }
+
+    fn visit_ty(&mut self, ty: &'a ast::Ty) {
+        match ty.kind {
+            ast::TyKind::BareFn(ref bare_fn_ty) => {
+                self.check_extern(bare_fn_ty.ext);
+            }
+            ast::TyKind::Never => {
+                gate_feature_post!(&self, never_type, ty.span, "The `!` type is experimental");
+            }
+            _ => {}
+        }
+        visit::walk_ty(self, ty)
+    }
+
+    fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
+        if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
+            if let ast::TyKind::Never = output_ty.kind {
+                // Do nothing.
+            } else {
+                self.visit_ty(output_ty)
+            }
+        }
+    }
+
+    fn visit_expr(&mut self, e: &'a ast::Expr) {
+        match e.kind {
+            ast::ExprKind::Box(_) => {
+                gate_feature_post!(
+                    &self,
+                    box_syntax,
+                    e.span,
+                    "box expression syntax is experimental; you can call `Box::new` instead"
+                );
+            }
+            ast::ExprKind::Type(..) => {
+                // To avoid noise about type ascription in common syntax errors, only emit if it
+                // is the *only* error.
+                if self.parse_sess.span_diagnostic.err_count() == 0 {
+                    gate_feature_post!(
+                        &self,
+                        type_ascription,
+                        e.span,
+                        "type ascription is experimental"
+                    );
+                }
+            }
+            ast::ExprKind::TryBlock(_) => {
+                gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
+            }
+            ast::ExprKind::Block(_, opt_label) => {
+                if let Some(label) = opt_label {
+                    gate_feature_post!(
+                        &self,
+                        label_break_value,
+                        label.ident.span,
+                        "labels on blocks are unstable"
+                    );
+                }
+            }
+            _ => {}
+        }
+        visit::walk_expr(self, e)
+    }
+
+    fn visit_arm(&mut self, arm: &'a ast::Arm) {
+        visit::walk_arm(self, arm)
+    }
+
+    fn visit_pat(&mut self, pattern: &'a ast::Pat) {
+        match &pattern.kind {
+            PatKind::Slice(pats) => {
+                for pat in &*pats {
+                    let span = pat.span;
+                    let inner_pat = match &pat.kind {
+                        PatKind::Ident(.., Some(pat)) => pat,
+                        _ => pat,
+                    };
+                    if inner_pat.is_rest() {
+                        gate_feature_post!(
+                            &self,
+                            slice_patterns,
+                            span,
+                            "subslice patterns are unstable"
+                        );
+                    }
+                }
+            }
+            PatKind::Box(..) => {
+                gate_feature_post!(
+                    &self,
+                    box_patterns,
+                    pattern.span,
+                    "box pattern syntax is experimental"
+                );
+            }
+            PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
+                gate_feature_post!(
+                    &self,
+                    exclusive_range_pattern,
+                    pattern.span,
+                    "exclusive range pattern syntax is experimental"
+                );
+            }
+            _ => {}
+        }
+        visit::walk_pat(self, pattern)
+    }
+
+    fn visit_fn(
+        &mut self,
+        fn_kind: FnKind<'a>,
+        fn_decl: &'a ast::FnDecl,
+        span: Span,
+        _node_id: NodeId,
+    ) {
+        if let Some(header) = fn_kind.header() {
+            // Stability of const fn methods are covered in
+            // `visit_trait_item` and `visit_impl_item` below; this is
+            // because default methods don't pass through this point.
+            self.check_extern(header.ext);
+        }
+
+        if fn_decl.c_variadic() {
+            gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
+        }
+
+        visit::walk_fn(self, fn_kind, fn_decl, span)
+    }
+
+    fn visit_generic_param(&mut self, param: &'a GenericParam) {
+        match param.kind {
+            GenericParamKind::Const { .. } => gate_feature_post!(
+                &self,
+                const_generics,
+                param.ident.span,
+                "const generics are unstable"
+            ),
+            _ => {}
+        }
+        visit::walk_generic_param(self, param)
+    }
+
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
+        match constraint.kind {
+            AssocTyConstraintKind::Bound { .. } => gate_feature_post!(
+                &self,
+                associated_type_bounds,
+                constraint.span,
+                "associated type bounds are unstable"
+            ),
+            _ => {}
+        }
+        visit::walk_assoc_ty_constraint(self, constraint)
+    }
+
+    fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) {
+        match ti.kind {
+            ast::AssocItemKind::Fn(ref sig, ref block) => {
+                if block.is_none() {
+                    self.check_extern(sig.header.ext);
+                }
+                if sig.header.constness.node == ast::Constness::Const {
+                    gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
+                }
+            }
+            ast::AssocItemKind::TyAlias(_, ref default) => {
+                if let Some(_) = default {
+                    gate_feature_post!(
+                        &self,
+                        associated_type_defaults,
+                        ti.span,
+                        "associated type defaults are unstable"
+                    );
+                }
+            }
+            _ => {}
+        }
+        visit::walk_trait_item(self, ti)
+    }
+
+    fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) {
+        if ii.defaultness == ast::Defaultness::Default {
+            gate_feature_post!(&self, specialization, ii.span, "specialization is unstable");
+        }
+
+        match ii.kind {
+            ast::AssocItemKind::Fn(ref sig, _) => {
+                if sig.decl.c_variadic() {
+                    gate_feature_post!(
+                        &self,
+                        c_variadic,
+                        ii.span,
+                        "C-variadic functions are unstable"
+                    );
+                }
+            }
+            ast::AssocItemKind::TyAlias(_, ref ty) => {
+                if let Some(ty) = ty {
+                    self.check_impl_trait(ty);
+                }
+                self.check_gat(&ii.generics, ii.span);
+            }
+            _ => {}
+        }
+        visit::walk_assoc_item(self, ii)
+    }
+
+    fn visit_vis(&mut self, vis: &'a ast::Visibility) {
+        if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node {
+            gate_feature_post!(
+                &self,
+                crate_visibility_modifier,
+                vis.span,
+                "`crate` visibility modifier is experimental"
+            );
+        }
+        visit::walk_vis(self, vis)
+    }
+}
+
+pub fn check_crate(
+    krate: &ast::Crate,
+    parse_sess: &ParseSess,
+    features: &Features,
+    unstable: UnstableFeatures,
+) {
+    maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
+    let mut visitor = PostExpansionVisitor { parse_sess, features };
+
+    let spans = parse_sess.gated_spans.spans.borrow();
+    macro_rules! gate_all {
+        ($gate:ident, $msg:literal) => {
+            for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
+                gate_feature_post!(&visitor, $gate, *span, $msg);
+            }
+        };
+    }
+    gate_all!(let_chains, "`let` expressions in this position are experimental");
+    gate_all!(async_closure, "async closures are unstable");
+    gate_all!(generators, "yield syntax is experimental");
+    gate_all!(or_patterns, "or-patterns syntax is experimental");
+    gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
+    gate_all!(raw_ref_op, "raw address of syntax is experimental");
+    gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
+    gate_all!(const_trait_impl, "const trait impls are experimental");
+    gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
+
+    // All uses of `gate_all!` below this point were added in #65742,
+    // and subsequently disabled (with the non-early gating readded).
+    macro_rules! gate_all {
+        ($gate:ident, $msg:literal) => {
+            // FIXME(eddyb) do something more useful than always
+            // disabling these uses of early feature-gatings.
+            if false {
+                for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
+                    gate_feature_post!(&visitor, $gate, *span, $msg);
+                }
+            }
+        };
+    }
+
+    gate_all!(trait_alias, "trait aliases are experimental");
+    gate_all!(associated_type_bounds, "associated type bounds are unstable");
+    gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
+    gate_all!(const_generics, "const generics are unstable");
+    gate_all!(decl_macro, "`macro` is experimental");
+    gate_all!(box_patterns, "box pattern syntax is experimental");
+    gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
+    gate_all!(try_blocks, "`try` blocks are unstable");
+    gate_all!(label_break_value, "labels on blocks are unstable");
+    gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
+    // To avoid noise about type ascription in common syntax errors,
+    // only emit if it is the *only* error. (Also check it last.)
+    if parse_sess.span_diagnostic.err_count() == 0 {
+        gate_all!(type_ascription, "type ascription is experimental");
+    }
+
+    visit::walk_crate(&mut visitor, krate);
+}
+
+fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
+    if !unstable.is_nightly_build() {
+        for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
+            struct_span_err!(
+                span_handler,
+                attr.span,
+                E0554,
+                "`#![feature]` may not be used on the {} release channel",
+                option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
+            )
+            .emit();
+        }
+    }
+}
diff --git a/src/librustc_ast_passes/lib.rs b/src/librustc_ast_passes/lib.rs
new file mode 100644 (file)
index 0000000..eadbc48
--- /dev/null
@@ -0,0 +1,9 @@
+//! The `rustc_ast_passes` crate contains passes which validate the AST in `syntax`
+//! parsed by `rustc_parse` and then lowered, after the passes in this crate,
+//! by `rustc_ast_lowering`.
+
+#![feature(slice_patterns)]
+
+pub mod ast_validation;
+pub mod feature_gate;
+pub mod show_span;
diff --git a/src/librustc_ast_passes/show_span.rs b/src/librustc_ast_passes/show_span.rs
new file mode 100644 (file)
index 0000000..4596e8f
--- /dev/null
@@ -0,0 +1,70 @@
+//! Span debugger
+//!
+//! This module shows spans for all expressions in the crate
+//! to help with compiler debugging.
+
+use std::str::FromStr;
+
+use syntax::ast;
+use syntax::visit;
+use syntax::visit::Visitor;
+
+enum Mode {
+    Expression,
+    Pattern,
+    Type,
+}
+
+impl FromStr for Mode {
+    type Err = ();
+    fn from_str(s: &str) -> Result<Mode, ()> {
+        let mode = match s {
+            "expr" => Mode::Expression,
+            "pat" => Mode::Pattern,
+            "ty" => Mode::Type,
+            _ => return Err(()),
+        };
+        Ok(mode)
+    }
+}
+
+struct ShowSpanVisitor<'a> {
+    span_diagnostic: &'a rustc_errors::Handler,
+    mode: Mode,
+}
+
+impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
+    fn visit_expr(&mut self, e: &'a ast::Expr) {
+        if let Mode::Expression = self.mode {
+            self.span_diagnostic.span_warn(e.span, "expression");
+        }
+        visit::walk_expr(self, e);
+    }
+
+    fn visit_pat(&mut self, p: &'a ast::Pat) {
+        if let Mode::Pattern = self.mode {
+            self.span_diagnostic.span_warn(p.span, "pattern");
+        }
+        visit::walk_pat(self, p);
+    }
+
+    fn visit_ty(&mut self, t: &'a ast::Ty) {
+        if let Mode::Type = self.mode {
+            self.span_diagnostic.span_warn(t.span, "type");
+        }
+        visit::walk_ty(self, t);
+    }
+
+    fn visit_mac(&mut self, mac: &'a ast::Mac) {
+        visit::walk_mac(self, mac);
+    }
+}
+
+pub fn run(span_diagnostic: &rustc_errors::Handler, mode: &str, krate: &ast::Crate) {
+    let mode = match mode.parse().ok() {
+        Some(mode) => mode,
+        None => return,
+    };
+    let mut v = ShowSpanVisitor { span_diagnostic, mode };
+    visit::walk_crate(&mut v, krate);
+}
index f56cc938f4a2f7b720ed83f28190b5a277ab0dff..f291eaf93580bf526ecf1bb8594518ab584df985 100644 (file)
@@ -10,13 +10,14 @@ path = "lib.rs"
 doctest = false
 
 [dependencies]
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 fmt_macros = { path = "../libfmt_macros" }
 log = "0.4"
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_parse = { path = "../librustc_parse" }
 rustc_target = { path = "../librustc_target" }
+rustc_session = { path = "../librustc_session" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
 rustc_expand = { path = "../librustc_expand" }
index a136a07a40cbef371a97322c077afe28455d9866..a6b45e0567c72c23516dd6f0f387318a36b909eb 100644 (file)
@@ -2,7 +2,7 @@
 //
 use State::*;
 
-use errors::{DiagnosticBuilder, PResult};
+use rustc_errors::{struct_span_err, DiagnosticBuilder, PResult};
 use rustc_expand::base::*;
 use rustc_parse::parser::Parser;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -11,7 +11,6 @@
 use syntax::ptr::P;
 use syntax::token::{self, Token};
 use syntax::tokenstream::{self, TokenStream};
-use syntax::{span_err, struct_span_err};
 
 use rustc_error_codes::*;
 
@@ -173,12 +172,13 @@ fn parse_inline_asm<'a>(
                         Some('=') => None,
                         Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
                         _ => {
-                            span_err!(
-                                cx,
+                            struct_span_err!(
+                                cx.parse_sess.span_diagnostic,
                                 span,
                                 E0661,
                                 "output operand constraint lacks '=' or '+'"
-                            );
+                            )
+                            .emit();
                             None
                         }
                     };
@@ -202,9 +202,21 @@ fn parse_inline_asm<'a>(
                     let constraint = parse_asm_str(&mut p)?;
 
                     if constraint.as_str().starts_with("=") {
-                        span_err!(cx, p.prev_span, E0662, "input operand constraint contains '='");
+                        struct_span_err!(
+                            cx.parse_sess.span_diagnostic,
+                            p.prev_span,
+                            E0662,
+                            "input operand constraint contains '='"
+                        )
+                        .emit();
                     } else if constraint.as_str().starts_with("+") {
-                        span_err!(cx, p.prev_span, E0663, "input operand constraint contains '+'");
+                        struct_span_err!(
+                            cx.parse_sess.span_diagnostic,
+                            p.prev_span,
+                            E0663,
+                            "input operand constraint contains '+'"
+                        )
+                        .emit();
                     }
 
                     p.expect(&token::OpenDelim(token::Paren))?;
@@ -225,12 +237,13 @@ fn parse_inline_asm<'a>(
                     if OPTIONS.iter().any(|&opt| s == opt) {
                         cx.span_warn(p.prev_span, "expected a clobber, found an option");
                     } else if s.as_str().starts_with("{") || s.as_str().ends_with("}") {
-                        span_err!(
-                            cx,
+                        struct_span_err!(
+                            cx.parse_sess.span_diagnostic,
                             p.prev_span,
                             E0664,
                             "clobber should not be surrounded by braces"
-                        );
+                        )
+                        .emit();
                     }
 
                     clobs.push(s);
index 9043db4742bf7c842954275bf46d3753f8e7813f..a992b6e2662d2ec34537dce0b3e4e82425702cc5 100644 (file)
@@ -1,4 +1,4 @@
-use errors::{Applicability, DiagnosticBuilder};
+use rustc_errors::{Applicability, DiagnosticBuilder};
 
 use rustc_expand::base::*;
 use rustc_parse::parser::Parser;
@@ -106,7 +106,7 @@ fn parse_assert<'a>(
     let custom_message =
         if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind {
             let mut err = cx.struct_span_warn(parser.token.span, "unexpected string literal");
-            let comma_span = cx.source_map().next_point(parser.prev_span);
+            let comma_span = parser.prev_span.shrink_to_hi();
             err.span_suggestion_short(
                 comma_span,
                 "try adding a comma",
index 62a4dc06b1fe2b241eae6cfc4380ca51a359405f..cee62a54f0088202704eb9c3ae9b1fbbf55b94e1 100644 (file)
@@ -1,8 +1,8 @@
-/// The compiler code necessary to support the cfg! extension, which expands to
-/// a literal `true` or `false` based on whether the given cfg matches the
-/// current compilation environment.
-use errors::DiagnosticBuilder;
+//! The compiler code necessary to support the cfg! extension, which expands to
+//! a literal `true` or `false` based on whether the given cfg matches the
+//! current compilation environment.
 
+use rustc_errors::DiagnosticBuilder;
 use rustc_expand::base::{self, *};
 use rustc_span::Span;
 use syntax::ast;
index f40d6d7e424d6b5e38493e59bd266c0f5e290386..72c41ad9745c1ae505cd78f5cea9155b36135c9f 100644 (file)
@@ -2,12 +2,12 @@
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
+use rustc_errors::struct_span_err;
 use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use syntax::ast::{Expr, MetaItem};
 use syntax::ptr::P;
-use syntax::span_err;
 
 use rustc_error_codes::*;
 
@@ -74,7 +74,13 @@ fn default_substructure(
             }
         },
         StaticEnum(..) => {
-            span_err!(cx, trait_span, E0665, "`Default` cannot be derived for enums, only structs");
+            struct_span_err!(
+                cx.parse_sess.span_diagnostic,
+                trait_span,
+                E0665,
+                "`Default` cannot be derived for enums, only structs"
+            )
+            .emit();
             // let compilation continue
             DummyResult::raw_expr(trait_span, true)
         }
index e2662faab6cb5a31dac8468b6ca990f3bad863f7..6fca74e22394465646dd5fda813fd02dbdf633e7 100644 (file)
@@ -3,10 +3,8 @@
 
 use fmt_macros as parse;
 
-use errors::pluralize;
-use errors::Applicability;
-use errors::DiagnosticBuilder;
-
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
 use rustc_expand::base::{self, *};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{MultiSpan, Span};
@@ -15,7 +13,6 @@
 use syntax::token;
 use syntax::tokenstream::TokenStream;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 
index 2bcd76e669971f5b4369759b4de1f6ecb3cc0968..052e62ee9ffd3da3008a7edb451fcbfd9b056b43 100644 (file)
@@ -1,14 +1,14 @@
-/// Module-level assembly support.
-///
-/// The macro defined here allows you to specify "top-level",
-/// "file-scoped", or "module-level" assembly. These synonyms
-/// all correspond to LLVM's module-level inline assembly instruction.
-///
-/// For example, `global_asm!("some assembly here")` codegens to
-/// LLVM's `module asm "some assembly here"`. All of LLVM's caveats
-/// therefore apply.
-use errors::DiagnosticBuilder;
+//! Module-level assembly support.
+//!
+//! The macro defined here allows you to specify "top-level",
+//! "file-scoped", or "module-level" assembly. These synonyms
+//! all correspond to LLVM's module-level inline assembly instruction.
+//!
+//! For example, `global_asm!("some assembly here")` codegens to
+//! LLVM's `module asm "some assembly here"`. All of LLVM's caveats
+//! therefore apply.
 
+use rustc_errors::DiagnosticBuilder;
 use rustc_expand::base::{self, *};
 use rustc_span::source_map::respan;
 use rustc_span::Span;
index 44968d6df96934654513d20f3d6b48f52781fe94..ae70608505130ad2420c5ad37c16e03e7ee184ee 100644 (file)
@@ -40,7 +40,7 @@ enum ProcMacro {
 struct CollectProcMacros<'a> {
     macros: Vec<ProcMacro>,
     in_root: bool,
-    handler: &'a errors::Handler,
+    handler: &'a rustc_errors::Handler,
     is_proc_macro_crate: bool,
     is_test_crate: bool,
 }
@@ -53,7 +53,7 @@ pub fn inject(
     has_proc_macro_decls: bool,
     is_test_crate: bool,
     num_crate_types: usize,
-    handler: &errors::Handler,
+    handler: &rustc_errors::Handler,
 ) -> ast::Crate {
     let ecfg = ExpansionConfig::default("proc_macro".to_string());
     let mut cx = ExtCtxt::new(sess, ecfg, resolver);
index 19a766de1f47f59b0e12d089bfefbcff5aa94294..dc85a92d272c48bb21d047cbdb4f873b8e5b3150 100644 (file)
@@ -1,15 +1,15 @@
 use rustc_expand::base::{self, *};
 use rustc_expand::panictry;
 use rustc_parse::{self, new_sub_parser_from_file, parser::Parser, DirectoryOwnership};
+use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
 use rustc_span::symbol::Symbol;
+use rustc_span::{self, Pos, Span};
 use syntax::ast;
-use syntax::early_buffered_lints::INCOMPLETE_INCLUDE;
 use syntax::print::pprust;
 use syntax::ptr::P;
 use syntax::token;
 use syntax::tokenstream::TokenStream;
 
-use rustc_span::{self, Pos, Span};
 use smallvec::SmallVec;
 
 use rustc_data_structures::sync::Lrc;
index eddf492720336db2eee9662833a34512a4fb73aa..17d180da6bfda7c1b6587902463412a1326f8b98 100644 (file)
@@ -40,7 +40,7 @@ pub fn inject(
     resolver: &mut dyn Resolver,
     should_test: bool,
     krate: &mut ast::Crate,
-    span_diagnostic: &errors::Handler,
+    span_diagnostic: &rustc_errors::Handler,
     features: &Features,
     panic_strategy: PanicStrategy,
     platform_panic_strategy: PanicStrategy,
@@ -351,7 +351,7 @@ fn is_test_case(i: &ast::Item) -> bool {
     attr::contains_name(&i.attrs, sym::rustc_test_marker)
 }
 
-fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
+fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
     let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
     test_attr.meta_item_list().map(|meta_list| {
         if meta_list.len() != 1 {
index 2d9232bc19255503fda75bfb18eedde8b25d8c1e..3ff5495e2913681871ecda549a1d5d05e0bc6e5f 100644 (file)
@@ -31,5 +31,4 @@ rustc_session = { path = "../librustc_session" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
-rustc_expand = { path = "../librustc_expand" }
 rustc_span = { path = "../librustc_span" }
index 3134ae5922c9abd9c79fb6f90795e5aafa859a2c..b5895b53698dcdd213413a94a57f3669620a3bef 100644 (file)
@@ -120,12 +120,13 @@ fn prepare_lto(
                 info!("adding bytecode {}", name);
                 let bc_encoded = data.data();
 
-                let (bc, id) = cgcx.prof.generic_pass(&format!("decode {}", name)).run(|| {
-                    match DecodedBytecode::new(bc_encoded) {
+                let (bc, id) = cgcx
+                    .prof
+                    .extra_verbose_generic_activity(&format!("decode {}", name))
+                    .run(|| match DecodedBytecode::new(bc_encoded) {
                         Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
                         Err(e) => Err(diag_handler.fatal(&e)),
-                    }
-                })?;
+                    })?;
                 let bc = SerializedModule::FromRlib(bc);
                 upstream_modules.push((bc, CString::new(id).unwrap()));
             }
@@ -280,8 +281,9 @@ fn fat_lto(
         // save and persist everything with the original module.
         let mut linker = Linker::new(llmod);
         for (bc_decoded, name) in serialized_modules {
+            let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_link_module");
             info!("linking {:?}", name);
-            cgcx.prof.generic_pass(&format!("ll link {:?}", name)).run(|| {
+            cgcx.prof.extra_verbose_generic_activity(&format!("ll link {:?}", name)).run(|| {
                 let data = bc_decoded.data();
                 linker.add(&data).map_err(|()| {
                     let msg = format!("failed to load bc of {:?}", name);
@@ -633,7 +635,7 @@ pub(crate) fn run_pass_manager(
         }
 
         cgcx.prof
-            .generic_pass("LTO passes")
+            .extra_verbose_generic_activity("LTO_passes")
             .run(|| llvm::LLVMRunPassManager(pm, module.module_llvm.llmod()));
 
         llvm::LLVMDisposePassManager(pm);
index afdfb36c2a9f6536cb43c8737a7e268c56f32474..4be7b84660d0994fb98b5b878bdae95cf751de74 100644 (file)
@@ -424,13 +424,23 @@ pub(crate) unsafe fn optimize(
 
         // Finally, run the actual optimization passes
         {
+            let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_function_passes");
             let desc = &format!("llvm function passes [{}]", module_name.unwrap());
-            let _timer = if config.time_module { Some(cgcx.prof.generic_pass(desc)) } else { None };
+            let _timer = if config.time_module {
+                Some(cgcx.prof.extra_verbose_generic_activity(desc))
+            } else {
+                None
+            };
             llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
         }
         {
+            let _timer = cgcx.prof.generic_activity("LLVM_module_optimize_module_passes");
             let desc = &format!("llvm module passes [{}]", module_name.unwrap());
-            let _timer = if config.time_module { Some(cgcx.prof.generic_pass(desc)) } else { None };
+            let _timer = if config.time_module {
+                Some(cgcx.prof.extra_verbose_generic_activity(desc))
+            } else {
+                None
+            };
             llvm::LLVMRunPassManager(mpm, llmod);
         }
 
@@ -556,7 +566,11 @@ unsafe fn with_codegen<'ll, F, R>(
 
         {
             let desc = &format!("codegen passes [{}]", module_name.unwrap());
-            let _timer = if config.time_module { Some(cgcx.prof.generic_pass(desc)) } else { None };
+            let _timer = if config.time_module {
+                Some(cgcx.prof.extra_verbose_generic_activity(desc))
+            } else {
+                None
+            };
 
             if config.emit_ir {
                 let _timer = cgcx.prof.generic_activity("LLVM_module_codegen_emit_ir");
index cb44a56d0751636b6535bc77ea1f0c26e56bb004..d3b524c1a1e70023fe3bd43eddd16a4244630d9c 100644 (file)
@@ -13,7 +13,7 @@
 //!   but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
 //!   int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
 
-use super::{LlvmCodegenBackend, ModuleLlvm};
+use super::ModuleLlvm;
 
 use crate::builder::Builder;
 use crate::common;
@@ -29,7 +29,6 @@
 use rustc::mir::mono::{Linkage, Visibility};
 use rustc::session::config::DebugInfo;
 use rustc::ty::TyCtxt;
-use rustc_codegen_ssa::back::write::submit_codegened_module_to_llvm;
 use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
 use rustc_codegen_ssa::mono_item::MonoItemExt;
 use rustc_codegen_ssa::traits::*;
@@ -100,8 +99,7 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
 pub fn compile_codegen_unit(
     tcx: TyCtxt<'tcx>,
     cgu_name: Symbol,
-    tx_to_llvm_workers: &std::sync::mpsc::Sender<Box<dyn std::any::Any + Send>>,
-) {
+) -> (ModuleCodegen<ModuleLlvm>, u64) {
     let prof_timer = tcx.prof.generic_activity("codegen_module");
     let start_time = Instant::now();
 
@@ -115,8 +113,6 @@ pub fn compile_codegen_unit(
     // the time we needed for codegenning it.
     let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
 
-    submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tx_to_llvm_workers, module, cost);
-
     fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
         let cgu = tcx.codegen_unit(cgu_name);
         // Instantiate monomorphizations without filling out definitions yet...
@@ -164,6 +160,8 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm
             kind: ModuleKind::Regular,
         }
     }
+
+    (module, cost)
 }
 
 pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
index f07601ed383fed42881f83be5ed001d424a3728e..50a35fe3dcf1db17f988566c0de2b0bc54de926b 100644 (file)
@@ -143,6 +143,10 @@ fn strip_function_ptr_alignment(data_layout: String) -> String {
     data_layout.replace("-Fi8-", "-")
 }
 
+fn strip_x86_address_spaces(data_layout: String) -> String {
+    data_layout.replace("-p270:32:32-p271:32:32-p272:64:64-", "-")
+}
+
 pub unsafe fn create_module(
     tcx: TyCtxt<'_>,
     llcx: &'ll llvm::Context,
@@ -156,6 +160,11 @@ pub unsafe fn create_module(
     if llvm_util::get_major_version() < 9 {
         target_data_layout = strip_function_ptr_alignment(target_data_layout);
     }
+    if llvm_util::get_major_version() < 10 {
+        if sess.target.target.arch == "x86" || sess.target.target.arch == "x86_64" {
+            target_data_layout = strip_x86_address_spaces(target_data_layout);
+        }
+    }
 
     // Ensure the data-layout values hardcoded remain the defaults.
     if sess.target.target.options.is_builtin {
index 8d8e86de4d464fb27af8594400b10623d49bb87f..d1f70ad43bd2888622e7b9ff283f35d7a56917dd 100644 (file)
@@ -1286,9 +1286,9 @@ fn generator_layout_and_saved_local_names(
     let generator_layout = body.generator_layout.as_ref().unwrap();
     let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);
 
-    let state_arg = mir::PlaceBase::Local(mir::Local::new(1));
+    let state_arg = mir::Local::new(1);
     for var in &body.var_debug_info {
-        if var.place.base != state_arg {
+        if var.place.local != state_arg {
             continue;
         }
         match var.place.projection[..] {
index 349cff79c784399a9f9f5c92f76c7a24633d9ced..a6168128c4d44611eb45a5be8f9234e687dfcfc8 100644 (file)
@@ -19,6 +19,7 @@
 #![feature(link_args)]
 #![feature(static_nobundle)]
 #![feature(trusted_len)]
+#![recursion_limit = "256"]
 
 use back::write::{create_informational_target_machine, create_target_machine};
 use rustc_span::symbol::Symbol;
@@ -108,9 +109,8 @@ fn compile_codegen_unit(
         &self,
         tcx: TyCtxt<'_>,
         cgu_name: Symbol,
-        tx: &std::sync::mpsc::Sender<Box<dyn Any + Send>>,
-    ) {
-        base::compile_codegen_unit(tcx, cgu_name, tx);
+    ) -> (ModuleCodegen<ModuleLlvm>, u64) {
+        base::compile_codegen_unit(tcx, cgu_name)
     }
     fn target_machine_factory(
         &self,
@@ -283,7 +283,7 @@ fn join_codegen_and_link(
             rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results);
         }
 
-        sess.time("serialize work products", move || {
+        sess.time("serialize_work_products", move || {
             rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)
         });
 
@@ -300,7 +300,7 @@ fn join_codegen_and_link(
 
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
-        sess.time("linking", || {
+        sess.time("link_crate", || {
             use crate::back::archive::LlvmArchiveBuilder;
             use rustc_codegen_ssa::back::link::link_binary;
 
index b3c58b2402065fdf3ef6afaf1d28d22afe8306a4..52613fef7e612b0def79aa7d451130e96adbc9c1 100644 (file)
@@ -46,7 +46,7 @@ fn require_inited() {
 }
 
 unsafe fn configure_llvm(sess: &Session) {
-    let n_args = sess.opts.cg.llvm_args.len();
+    let n_args = sess.opts.cg.llvm_args.len() + sess.target.target.options.llvm_args.len();
     let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
     let mut llvm_args = Vec::with_capacity(n_args + 1);
 
@@ -56,14 +56,11 @@ fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
         full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
     }
 
-    let user_specified_args: FxHashSet<_> = sess
-        .opts
-        .cg
-        .llvm_args
-        .iter()
-        .map(|s| llvm_arg_to_arg_name(s))
-        .filter(|s| s.len() > 0)
-        .collect();
+    let cg_opts = sess.opts.cg.llvm_args.iter();
+    let tg_opts = sess.target.target.options.llvm_args.iter();
+
+    let user_specified_args: FxHashSet<_> =
+        cg_opts.chain(tg_opts).map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect();
 
     {
         // This adds the given argument to LLVM. Unless `force` is true
index a53402ebb5c7daf54fab8f0277dcaa76f2cd613d..53ee5996432ceb4aec7cf7b0d0732a7fae9f0337 100644 (file)
@@ -53,6 +53,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
     crate_name: &str,
     target_cpu: &str,
 ) {
+    let _timer = sess.timer("link_binary");
     let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
     for &crate_type in sess.crate_types.borrow().iter() {
         // Ignore executable crates if we have -Z no-codegen, as they will error.
@@ -71,9 +72,11 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
             );
         }
 
-        for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
-            check_file_is_writeable(obj, sess);
-        }
+        sess.time("link_binary_check_files_are_writeable", || {
+            for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
+                check_file_is_writeable(obj, sess);
+            }
+        });
 
         let tmpdir = TempFileBuilder::new()
             .prefix("rustc")
@@ -84,6 +87,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
             let out_filename = out_filename(sess, crate_type, outputs, crate_name);
             match crate_type {
                 config::CrateType::Rlib => {
+                    let _timer = sess.timer("link_rlib");
                     link_rlib::<B>(
                         sess,
                         codegen_results,
@@ -118,29 +122,34 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
     }
 
     // Remove the temporary object file and metadata if we aren't saving temps
-    if !sess.opts.cg.save_temps {
-        if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) {
-            for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
-                remove(sess, obj);
+    sess.time("link_binary_remove_temps", || {
+        if !sess.opts.cg.save_temps {
+            if sess.opts.output_types.should_codegen()
+                && !preserve_objects_for_their_debuginfo(sess)
+            {
+                for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
+                    remove(sess, obj);
+                }
             }
-        }
-        for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
-            remove(sess, obj);
-        }
-        if let Some(ref metadata_module) = codegen_results.metadata_module {
-            if let Some(ref obj) = metadata_module.object {
+            for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref())
+            {
                 remove(sess, obj);
             }
-        }
-        if let Some(ref allocator_module) = codegen_results.allocator_module {
-            if let Some(ref obj) = allocator_module.object {
-                remove(sess, obj);
+            if let Some(ref metadata_module) = codegen_results.metadata_module {
+                if let Some(ref obj) = metadata_module.object {
+                    remove(sess, obj);
+                }
             }
-            if let Some(ref bc) = allocator_module.bytecode_compressed {
-                remove(sess, bc);
+            if let Some(ref allocator_module) = codegen_results.allocator_module {
+                if let Some(ref obj) = allocator_module.object {
+                    remove(sess, obj);
+                }
+                if let Some(ref bc) = allocator_module.bytecode_compressed {
+                    remove(sess, bc);
+                }
             }
         }
-    }
+    });
 }
 
 // The third parameter is for env vars, used on windows to set up the
@@ -531,6 +540,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
     {
         let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu);
+        link_sanitizer_runtime(sess, crate_type, &mut *linker);
         link_args::<B>(
             &mut *linker,
             flavor,
@@ -577,7 +587,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     let mut i = 0;
     loop {
         i += 1;
-        prog = sess.time("running linker", || exec_linker(sess, &mut cmd, out_filename, tmpdir));
+        prog = sess.time("run_linker", || exec_linker(sess, &mut cmd, out_filename, tmpdir));
         let output = match prog {
             Ok(ref output) => output,
             Err(_) => break,
@@ -735,6 +745,47 @@ fn escape_string(s: &[u8]) -> String {
     }
 }
 
+fn link_sanitizer_runtime(sess: &Session, crate_type: config::CrateType, linker: &mut dyn Linker) {
+    let sanitizer = match &sess.opts.debugging_opts.sanitizer {
+        Some(s) => s,
+        None => return,
+    };
+
+    if crate_type != config::CrateType::Executable {
+        return;
+    }
+
+    let name = match sanitizer {
+        Sanitizer::Address => "asan",
+        Sanitizer::Leak => "lsan",
+        Sanitizer::Memory => "msan",
+        Sanitizer::Thread => "tsan",
+    };
+
+    let default_sysroot = filesearch::get_or_default_sysroot();
+    let default_tlib =
+        filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
+
+    match sess.opts.target_triple.triple() {
+        "x86_64-apple-darwin" => {
+            // On Apple platforms, the sanitizer is always built as a dylib, and
+            // LLVM will link to `@rpath/*.dylib`, so we need to specify an
+            // rpath to the library as well (the rpath should be absolute, see
+            // PR #41352 for details).
+            let libname = format!("rustc_rt.{}", name);
+            let rpath = default_tlib.to_str().expect("non-utf8 component in path");
+            linker.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]);
+            linker.link_dylib(Symbol::intern(&libname));
+        }
+        "x86_64-unknown-linux-gnu" => {
+            let filename = format!("librustc_rt.{}.a", name);
+            let path = default_tlib.join(&filename);
+            linker.link_whole_rlib(&path);
+        }
+        _ => {}
+    }
+}
+
 /// Returns a boolean indicating whether the specified crate should be ignored
 /// during LTO.
 ///
@@ -1415,12 +1466,6 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
             _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
                 add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
             }
-            _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum)
-                && crate_type == config::CrateType::Executable =>
-            {
-                // Link the sanitizer runtimes only if we are actually producing an executable
-                link_sanitizer_runtime::<B>(cmd, sess, codegen_results, tmpdir, cnum);
-            }
             // compiler-builtins are always placed last to ensure that they're
             // linked correctly.
             _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => {
@@ -1457,47 +1502,6 @@ fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str {
         }
     }
 
-    // We must link the sanitizer runtime using -Wl,--whole-archive but since
-    // it's packed in a .rlib, it contains stuff that are not objects that will
-    // make the linker error. So we must remove those bits from the .rlib before
-    // linking it.
-    fn link_sanitizer_runtime<'a, B: ArchiveBuilder<'a>>(
-        cmd: &mut dyn Linker,
-        sess: &'a Session,
-        codegen_results: &CodegenResults,
-        tmpdir: &Path,
-        cnum: CrateNum,
-    ) {
-        let src = &codegen_results.crate_info.used_crate_source[&cnum];
-        let cratepath = &src.rlib.as_ref().unwrap().0;
-
-        if sess.target.target.options.is_like_osx {
-            // On Apple platforms, the sanitizer is always built as a dylib, and
-            // LLVM will link to `@rpath/*.dylib`, so we need to specify an
-            // rpath to the library as well (the rpath should be absolute, see
-            // PR #41352 for details).
-            //
-            // FIXME: Remove this logic into librustc_*san once Cargo supports it
-            let rpath = cratepath.parent().unwrap();
-            let rpath = rpath.to_str().expect("non-utf8 component in path");
-            cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]);
-        }
-
-        let dst = tmpdir.join(cratepath.file_name().unwrap());
-        let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
-        archive.update_symbols();
-
-        for f in archive.src_files() {
-            if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
-                archive.remove_file(&f);
-            }
-        }
-
-        archive.build();
-
-        cmd.link_whole_rlib(&dst);
-    }
-
     // Adds the static "rlib" versions of all crates to the command line.
     // There's a bit of magic which happens here specifically related to LTO and
     // dynamic libraries. Specifically:
@@ -1562,7 +1566,7 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
         let name = cratepath.file_name().unwrap().to_str().unwrap();
         let name = &name[3..name.len() - 5]; // chop off lib/.rlib
 
-        sess.prof.generic_pass(&format!("altering {}.rlib", name)).run(|| {
+        sess.prof.extra_verbose_generic_activity(&format!("altering {}.rlib", name)).run(|| {
             let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
             archive.update_symbols();
 
index edd0fa504270703235960026b05e81e7207c5489..a406b5f103b9d2f85f73109b6bb4cb33e7625699 100644 (file)
@@ -345,7 +345,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
     if is_extern && !std_internal {
         let target = &tcx.sess.target.target.llvm_target;
         // WebAssembly cannot export data symbols, so reduce their export level
-        if target.contains("wasm32") || target.contains("emscripten") {
+        if target.contains("emscripten") {
             if let Some(Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. })) =
                 tcx.hir().get_if_local(sym_def_id)
             {
index 075374fd8a951ed6030e9099bc18efbaf3e0d448..801bfdea70d6cbe5d6fb4eb154ee38169c46597b 100644 (file)
@@ -479,6 +479,8 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
         return work_products;
     }
 
+    let _timer = sess.timer("incr_comp_copy_cgu_workproducts");
+
     for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
         let mut files = vec![];
 
@@ -900,7 +902,7 @@ pub enum Message<B: WriteBackendMethods> {
         worker_id: usize,
     },
     Done {
-        result: Result<CompiledModule, ()>,
+        result: Result<CompiledModule, Option<WorkerFatalError>>,
         worker_id: usize,
     },
     CodegenDone {
@@ -1472,9 +1474,12 @@ fn start_executing_work<B: ExtraBackendMethods>(
                     main_thread_worker_state = MainThreadWorkerState::Idle;
                 }
                 // If the thread failed that means it panicked, so we abort immediately.
-                Message::Done { result: Err(()), worker_id: _ } => {
+                Message::Done { result: Err(None), worker_id: _ } => {
                     bug!("worker thread panicked");
                 }
+                Message::Done { result: Err(Some(WorkerFatalError)), worker_id: _ } => {
+                    return Err(());
+                }
                 Message::CodegenItem => bug!("the coordinator should not receive codegen requests"),
             }
         }
@@ -1511,36 +1516,43 @@ fn maybe_start_llvm_timer<'a>(
         llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
     ) {
         if config.time_module && llvm_start_time.is_none() {
-            *llvm_start_time = Some(prof.generic_pass("LLVM passes"));
+            *llvm_start_time = Some(prof.extra_verbose_generic_activity("LLVM_passes"));
         }
     }
 }
 
 pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
 
+/// `FatalError` is explicitly not `Send`.
+#[must_use]
+pub struct WorkerFatalError;
+
 fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
     thread::spawn(move || {
         // Set up a destructor which will fire off a message that we're done as
         // we exit.
         struct Bomb<B: ExtraBackendMethods> {
             coordinator_send: Sender<Box<dyn Any + Send>>,
-            result: Option<WorkItemResult<B>>,
+            result: Option<Result<WorkItemResult<B>, FatalError>>,
             worker_id: usize,
         }
         impl<B: ExtraBackendMethods> Drop for Bomb<B> {
             fn drop(&mut self) {
                 let worker_id = self.worker_id;
                 let msg = match self.result.take() {
-                    Some(WorkItemResult::Compiled(m)) => {
+                    Some(Ok(WorkItemResult::Compiled(m))) => {
                         Message::Done::<B> { result: Ok(m), worker_id }
                     }
-                    Some(WorkItemResult::NeedsFatLTO(m)) => {
+                    Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
                         Message::NeedsFatLTO::<B> { result: m, worker_id }
                     }
-                    Some(WorkItemResult::NeedsThinLTO(name, thin_buffer)) => {
+                    Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
                         Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
                     }
-                    None => Message::Done::<B> { result: Err(()), worker_id },
+                    Some(Err(FatalError)) => {
+                        Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
+                    }
+                    None => Message::Done::<B> { result: Err(None), worker_id },
                 };
                 drop(self.coordinator_send.send(Box::new(msg)));
             }
@@ -1560,7 +1572,7 @@ fn drop(&mut self) {
         // surface that there was an error in this worker.
         bomb.result = {
             let _prof_timer = cgcx.prof.generic_activity(work.profiling_event_id());
-            execute_work_item(&cgcx, work).ok()
+            Some(execute_work_item(&cgcx, work))
         };
     });
 }
@@ -1679,7 +1691,6 @@ pub fn check(&self, sess: &Session, blocking: bool) {
                         d.code(code);
                     }
                     handler.emit_diagnostic(&d);
-                    handler.abort_if_errors_and_should_abort();
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => {
                     sess.span_err(ExpnId::from_u32(cookie).expn_data().call_site, &msg)
@@ -1715,8 +1726,11 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> {
 
 impl<B: ExtraBackendMethods> OngoingCodegen<B> {
     pub fn join(self, sess: &Session) -> (CodegenResults, FxHashMap<WorkProductId, WorkProduct>) {
+        let _timer = sess.timer("finish_ongoing_codegen");
+
         self.shared_emitter_main.check(sess, true);
-        let compiled_modules = match self.future.join() {
+        let future = self.future;
+        let compiled_modules = sess.time("join_worker_thread", || match future.join() {
             Ok(Ok(compiled_modules)) => compiled_modules,
             Ok(Err(())) => {
                 sess.abort_if_errors();
@@ -1725,7 +1739,7 @@ pub fn join(self, sess: &Session) -> (CodegenResults, FxHashMap<WorkProductId, W
             Err(_) => {
                 bug!("panic during codegen/LLVM phase");
             }
-        };
+        });
 
         sess.cgu_reuse_tracker.check_expected_reuse(sess.diagnostic());
 
index ededb36c7127f355fcfea16a62950d03d4902bf7..efd560071202cd7aa1ebbc5cf6d3a32553933091 100644 (file)
@@ -14,8 +14,8 @@
 //!   int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
 
 use crate::back::write::{
-    start_async_codegen, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
-    OngoingCodegen,
+    start_async_codegen, submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm,
+    submit_pre_lto_module_to_llvm, OngoingCodegen,
 };
 use crate::common::{IntPredicate, RealPredicate, TypeKind};
 use crate::meth;
@@ -40,6 +40,7 @@
 use rustc_codegen_utils::{check_for_rustc_errors_attr, symbol_names_test};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::print_time_passes_entry;
+use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_index::vec::Idx;
@@ -85,7 +86,7 @@ pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicat
         }
         op => bug!(
             "comparison_op_to_icmp_predicate: expected comparison operator, \
-                  found {:?}",
+             found {:?}",
             op
         ),
     }
@@ -102,7 +103,7 @@ pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> RealPredicate {
         op => {
             bug!(
                 "comparison_op_to_fcmp_predicate: expected comparison operator, \
-                  found {:?}",
+                 found {:?}",
                 op
             );
         }
@@ -519,7 +520,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 
         ongoing_codegen.codegen_finished(tcx);
 
-        assert_and_save_dep_graph(tcx);
+        finalize_tcx(tcx);
 
         ongoing_codegen.check_for_errors(tcx.sess);
 
@@ -566,7 +567,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
         let mut modules = backend.new_metadata(tcx, &llmod_id);
         tcx.sess
-            .time("write allocator module", || backend.codegen_allocator(tcx, &mut modules, kind));
+            .time("write_allocator_module", || backend.codegen_allocator(tcx, &mut modules, kind));
 
         Some(ModuleCodegen { name: llmod_id, module_llvm: modules, kind: ModuleKind::Allocator })
     } else {
@@ -582,7 +583,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         let metadata_cgu_name =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string();
         let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
-        tcx.sess.time("write compressed metadata", || {
+        tcx.sess.time("write_compressed_metadata", || {
             backend.write_compressed_metadata(
                 tcx,
                 &ongoing_codegen.metadata,
@@ -606,20 +607,83 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         codegen_units
     };
 
-    let mut total_codegen_time = Duration::new(0, 0);
+    let total_codegen_time = Lock::new(Duration::new(0, 0));
 
-    for cgu in codegen_units.into_iter() {
+    // The non-parallel compiler can only translate codegen units to LLVM IR
+    // on a single thread, leading to a staircase effect where the N LLVM
+    // threads have to wait on the single codegen threads to generate work
+    // for them. The parallel compiler does not have this restriction, so
+    // we can pre-load the LLVM queue in parallel before handing off
+    // coordination to the OnGoingCodegen scheduler.
+    //
+    // This likely is a temporary measure. Once we don't have to support the
+    // non-parallel compiler anymore, we can compile CGUs end-to-end in
+    // parallel and get rid of the complicated scheduling logic.
+    let pre_compile_cgus = |cgu_reuse: &[CguReuse]| {
+        if cfg!(parallel_compiler) {
+            tcx.sess.time("compile_first_CGU_batch", || {
+                // Try to find one CGU to compile per thread.
+                let cgus: Vec<_> = cgu_reuse
+                    .iter()
+                    .enumerate()
+                    .filter(|&(_, reuse)| reuse == &CguReuse::No)
+                    .take(tcx.sess.threads())
+                    .collect();
+
+                // Compile the found CGUs in parallel.
+                par_iter(cgus)
+                    .map(|(i, _)| {
+                        let start_time = Instant::now();
+                        let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
+                        let mut time = total_codegen_time.lock();
+                        *time += start_time.elapsed();
+                        (i, module)
+                    })
+                    .collect()
+            })
+        } else {
+            FxHashMap::default()
+        }
+    };
+
+    let mut cgu_reuse = Vec::new();
+    let mut pre_compiled_cgus: Option<FxHashMap<usize, _>> = None;
+
+    for (i, cgu) in codegen_units.iter().enumerate() {
         ongoing_codegen.wait_for_signal_to_codegen_item();
         ongoing_codegen.check_for_errors(tcx.sess);
 
-        let cgu_reuse = determine_cgu_reuse(tcx, &cgu);
+        // Do some setup work in the first iteration
+        if pre_compiled_cgus.is_none() {
+            // Calculate the CGU reuse
+            cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
+                codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect()
+            });
+            // Pre compile some CGUs
+            pre_compiled_cgus = Some(pre_compile_cgus(&cgu_reuse));
+        }
+
+        let cgu_reuse = cgu_reuse[i];
         tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
 
         match cgu_reuse {
             CguReuse::No => {
-                let start_time = Instant::now();
-                backend.compile_codegen_unit(tcx, cgu.name(), &ongoing_codegen.coordinator_send);
-                total_codegen_time += start_time.elapsed();
+                let (module, cost) =
+                    if let Some(cgu) = pre_compiled_cgus.as_mut().unwrap().remove(&i) {
+                        cgu
+                    } else {
+                        let start_time = Instant::now();
+                        let module = backend.compile_codegen_unit(tcx, cgu.name());
+                        let mut time = total_codegen_time.lock();
+                        *time += start_time.elapsed();
+                        module
+                    };
+                submit_codegened_module_to_llvm(
+                    &backend,
+                    &ongoing_codegen.coordinator_send,
+                    module,
+                    cost,
+                );
                 false
             }
             CguReuse::PreLto => {
@@ -652,7 +716,11 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 
     // Since the main thread is sometimes blocked during codegen, we keep track
     // -Ztime-passes output manually.
-    print_time_passes_entry(tcx.sess.time_passes(), "codegen to LLVM IR", total_codegen_time);
+    print_time_passes_entry(
+        tcx.sess.time_passes(),
+        "codegen_to_LLVM_IR",
+        total_codegen_time.into_inner(),
+    );
 
     ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
 
@@ -660,7 +728,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
 
     ongoing_codegen.check_for_errors(tcx.sess);
 
-    assert_and_save_dep_graph(tcx);
+    finalize_tcx(tcx);
+
     ongoing_codegen.into_inner()
 }
 
@@ -711,10 +780,16 @@ fn drop(&mut self) {
     }
 }
 
-fn assert_and_save_dep_graph(tcx: TyCtxt<'_>) {
-    tcx.sess.time("assert dep graph", || ::rustc_incremental::assert_dep_graph(tcx));
+fn finalize_tcx(tcx: TyCtxt<'_>) {
+    tcx.sess.time("assert_dep_graph", || ::rustc_incremental::assert_dep_graph(tcx));
+    tcx.sess.time("serialize_dep_graph", || ::rustc_incremental::save_dep_graph(tcx));
 
-    tcx.sess.time("serialize dep graph", || ::rustc_incremental::save_dep_graph(tcx));
+    // We assume that no queries are run past here. If there are new queries
+    // after this point, they'll show up as "<unknown>" in self-profiling data.
+    {
+        let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
+        tcx.alloc_self_profile_query_strings();
+    }
 }
 
 impl CrateInfo {
@@ -723,7 +798,6 @@ pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
             panic_runtime: None,
             compiler_builtins: None,
             profiler_runtime: None,
-            sanitizer_runtime: None,
             is_no_builtins: Default::default(),
             native_libraries: Default::default(),
             used_libraries: tcx.native_libraries(LOCAL_CRATE),
@@ -759,9 +833,6 @@ pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
             if tcx.is_profiler_runtime(cnum) {
                 info.profiler_runtime = Some(cnum);
             }
-            if tcx.is_sanitizer_runtime(cnum) {
-                info.sanitizer_runtime = Some(cnum);
-            }
             if tcx.is_no_builtins(cnum) {
                 info.is_no_builtins.insert(cnum);
             }
index 299a6d95272f7942dd22cab87466bfb7ba4f7cea..e4531a77656a3bfb4d28fd69bfbdeed4bcd75ef1 100644 (file)
@@ -2,6 +2,7 @@
 
 use rustc::session::Session;
 use rustc::ty::{Ty, TyCtxt};
+use rustc_errors::struct_span_err;
 use rustc_span::Span;
 
 use crate::base;
@@ -196,5 +197,5 @@ pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 }
 
 pub fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
-    span_err!(a, b, E0511, "{}", c);
+    struct_span_err!(a, b, E0511, "{}", c).emit();
 }
index b476fd952004b0a3452bd5de5e1e3059998ad309..ee527ecb509b27417013717381c78cfc2c9b70e4 100644 (file)
@@ -21,8 +21,6 @@
 extern crate log;
 #[macro_use]
 extern crate rustc;
-#[macro_use]
-extern crate syntax;
 
 use rustc::dep_graph::WorkProduct;
 use rustc::middle::cstore::{CrateSource, LibSource, NativeLibrary};
@@ -124,7 +122,6 @@ pub struct CrateInfo {
     pub panic_runtime: Option<CrateNum>,
     pub compiler_builtins: Option<CrateNum>,
     pub profiler_runtime: Option<CrateNum>,
-    pub sanitizer_runtime: Option<CrateNum>,
     pub is_no_builtins: FxHashSet<CrateNum>,
     pub native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLibrary>>>,
     pub crate_name: FxHashMap<CrateNum, String>,
index 0ceb44d019b64efa925c052cbb4e45be1cec95c7..c3affd233f8e3b00fc1b7693543505c0a7120aff 100644 (file)
@@ -14,7 +14,6 @@
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_span::DUMMY_SP;
 
 pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fx: &FunctionCx<'a, 'tcx, Bx>,
@@ -129,17 +128,13 @@ fn process_place(
             };
             if is_consume {
                 let base_ty =
-                    mir::Place::ty_from(place_ref.base, proj_base, *self.fx.mir, cx.tcx());
+                    mir::Place::ty_from(place_ref.local, proj_base, *self.fx.mir, cx.tcx());
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
                 let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty;
                 let elem_ty = self.fx.monomorphize(&elem_ty);
-                let span = if let mir::PlaceBase::Local(index) = place_ref.base {
-                    self.fx.mir.local_decls[*index].source_info.span
-                } else {
-                    DUMMY_SP
-                };
+                let span = self.fx.mir.local_decls[*place_ref.local].source_info.span;
                 if cx.spanned_layout_of(elem_ty, span).is_zst() {
                     return;
                 }
@@ -179,9 +174,7 @@ fn process_place(
                     // We use `NonUseContext::VarDebugInfo` for the base,
                     // which might not force the base local to memory,
                     // so we have to do it manually.
-                    if let mir::PlaceBase::Local(local) = place_ref.base {
-                        self.visit_local(&local, context, location);
-                    }
+                    self.visit_local(place_ref.local, context, location);
                 }
             }
 
@@ -192,7 +185,7 @@ fn process_place(
             }
 
             self.process_place(
-                &mir::PlaceRef { base: place_ref.base, projection: proj_base },
+                &mir::PlaceRef { local: place_ref.local, projection: proj_base },
                 base_context,
                 location,
             );
@@ -219,8 +212,8 @@ fn process_place(
                 };
             }
 
-            self.visit_place_base(place_ref.base, context, location);
-            self.visit_projection(place_ref.base, place_ref.projection, context, location);
+            self.visit_place_base(place_ref.local, context, location);
+            self.visit_projection(place_ref.local, place_ref.projection, context, location);
         }
     }
 }
index a1d4c0c820bc6dd389c1c38015d3a4676d79de28..9169010da88019412ee851aba349f765aad454db 100644 (file)
@@ -10,8 +10,8 @@
 use crate::MemFlags;
 
 use rustc::middle::lang_items;
+use rustc::mir;
 use rustc::mir::interpret::PanicInfo;
-use rustc::mir::{self, PlaceBase, Static, StaticKind};
 use rustc::ty::layout::{self, FnAbiExt, HasTyCtxt, LayoutOf};
 use rustc::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_index::vec::Idx;
@@ -609,53 +609,17 @@ fn codegen_call_terminator(
                     // checked by const-qualification, which also
                     // promotes any complex rvalues to constants.
                     if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
-                        match arg {
-                            // The shuffle array argument is usually not an explicit constant,
-                            // but specified directly in the code. This means it gets promoted
-                            // and we can then extract the value by evaluating the promoted.
-                            mir::Operand::Copy(place) | mir::Operand::Move(place) => {
-                                if let mir::PlaceRef {
-                                    base:
-                                        &PlaceBase::Static(box Static {
-                                            kind: StaticKind::Promoted(promoted, substs),
-                                            ty,
-                                            def_id,
-                                        }),
-                                    projection: &[],
-                                } = place.as_ref()
-                                {
-                                    let c = bx.tcx().const_eval_promoted(
-                                        Instance::new(def_id, self.monomorphize(&substs)),
-                                        promoted,
-                                    );
-                                    let (llval, ty) = self.simd_shuffle_indices(
-                                        &bx,
-                                        terminator.source_info.span,
-                                        ty,
-                                        c,
-                                    );
-                                    return OperandRef {
-                                        val: Immediate(llval),
-                                        layout: bx.layout_of(ty),
-                                    };
-                                } else {
-                                    span_bug!(span, "shuffle indices must be constant");
-                                }
-                            }
-
-                            mir::Operand::Constant(constant) => {
-                                let c = self.eval_mir_constant(constant);
-                                let (llval, ty) = self.simd_shuffle_indices(
-                                    &bx,
-                                    constant.span,
-                                    constant.literal.ty,
-                                    c,
-                                );
-                                return OperandRef {
-                                    val: Immediate(llval),
-                                    layout: bx.layout_of(ty),
-                                };
-                            }
+                        if let mir::Operand::Constant(constant) = arg {
+                            let c = self.eval_mir_constant(constant);
+                            let (llval, ty) = self.simd_shuffle_indices(
+                                &bx,
+                                constant.span,
+                                constant.literal.ty,
+                                c,
+                            );
+                            return OperandRef { val: Immediate(llval), layout: bx.layout_of(ty) };
+                        } else {
+                            span_bug!(span, "shuffle indices must be constant");
                         }
                     }
 
@@ -1147,7 +1111,7 @@ fn make_return_dest(
         } else {
             self.codegen_place(
                 bx,
-                &mir::PlaceRef { base: &dest.base, projection: &dest.projection },
+                &mir::PlaceRef { local: &dest.local, projection: &dest.projection },
             )
         };
         if fn_ret.is_indirect() {
index f508ed90de42df1ad2bc216fb1ffd3a4529b5590..3ce916d78127922251c64a89d0476440e81c8441 100644 (file)
@@ -20,7 +20,7 @@ pub fn eval_mir_constant_to_operand(
             // use `get_static` to get at their id.
             // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
             // always produce `&STATIC`. This may also simplify how const eval works with statics.
-            ty::ConstKind::Unevaluated(def_id, substs) if self.cx.tcx().is_static(def_id) => {
+            ty::ConstKind::Unevaluated(def_id, substs, None) if self.cx.tcx().is_static(def_id) => {
                 assert!(substs.is_empty(), "we don't support generic statics yet");
                 let static_ = bx.get_static(def_id);
                 // we treat operands referring to statics as if they were `&STATIC` instead
@@ -40,16 +40,18 @@ pub fn eval_mir_constant(
         constant: &mir::Constant<'tcx>,
     ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
         match constant.literal.val {
-            ty::ConstKind::Unevaluated(def_id, substs) => {
+            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
                 let substs = self.monomorphize(&substs);
                 self.cx
                     .tcx()
-                    .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None)
+                    .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
                     .map_err(|err| {
-                        self.cx
-                            .tcx()
-                            .sess
-                            .span_err(constant.span, "erroneous constant encountered");
+                        if promoted.is_none() {
+                            self.cx
+                                .tcx()
+                                .sess
+                                .span_err(constant.span, "erroneous constant encountered");
+                        }
                         err
                     })
             }
index 6c17a01eb913367e7f93a3afb623482bc4bac479..e0aec5d6dd512038aca6502b570d1c1d0241522e 100644 (file)
@@ -258,9 +258,7 @@ pub fn per_local_var_debug_info(
     if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
         let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
         for var in &body.var_debug_info {
-            if let mir::PlaceBase::Local(local) = var.place.base {
-                per_local[local].push(var);
-            }
+            per_local[var.place.local].push(var);
         }
         Some(per_local)
     } else {
index d53069654372043656f83d1a8e0662df2330e6b6..a155a6e78f7c3e3e6dd708501256b3460011b495 100644 (file)
@@ -373,44 +373,40 @@ fn maybe_codegen_consume_direct(
     ) -> Option<OperandRef<'tcx, Bx::Value>> {
         debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
 
-        if let mir::PlaceBase::Local(index) = place_ref.base {
-            match self.locals[*index] {
-                LocalRef::Operand(Some(mut o)) => {
-                    // Moves out of scalar and scalar pair fields are trivial.
-                    for elem in place_ref.projection.iter() {
-                        match elem {
-                            mir::ProjectionElem::Field(ref f, _) => {
-                                o = o.extract_field(bx, f.index());
-                            }
-                            mir::ProjectionElem::Index(_)
-                            | mir::ProjectionElem::ConstantIndex { .. } => {
-                                // ZSTs don't require any actual memory access.
-                                // FIXME(eddyb) deduplicate this with the identical
-                                // checks in `codegen_consume` and `extract_field`.
-                                let elem = o.layout.field(bx.cx(), 0);
-                                if elem.is_zst() {
-                                    o = OperandRef::new_zst(bx, elem);
-                                } else {
-                                    return None;
-                                }
+        match self.locals[*place_ref.local] {
+            LocalRef::Operand(Some(mut o)) => {
+                // Moves out of scalar and scalar pair fields are trivial.
+                for elem in place_ref.projection.iter() {
+                    match elem {
+                        mir::ProjectionElem::Field(ref f, _) => {
+                            o = o.extract_field(bx, f.index());
+                        }
+                        mir::ProjectionElem::Index(_)
+                        | mir::ProjectionElem::ConstantIndex { .. } => {
+                            // ZSTs don't require any actual memory access.
+                            // FIXME(eddyb) deduplicate this with the identical
+                            // checks in `codegen_consume` and `extract_field`.
+                            let elem = o.layout.field(bx.cx(), 0);
+                            if elem.is_zst() {
+                                o = OperandRef::new_zst(bx, elem);
+                            } else {
+                                return None;
                             }
-                            _ => return None,
                         }
+                        _ => return None,
                     }
-
-                    Some(o)
-                }
-                LocalRef::Operand(None) => {
-                    bug!("use of {:?} before def", place_ref);
-                }
-                LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
-                    // watch out for locals that do not have an
-                    // alloca; they are handled somewhat differently
-                    None
                 }
+
+                Some(o)
+            }
+            LocalRef::Operand(None) => {
+                bug!("use of {:?} before def", place_ref);
+            }
+            LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => {
+                // watch out for locals that do not have an
+                // alloca; they are handled somewhat differently
+                None
             }
-        } else {
-            None
         }
     }
 
index 7399db1f2b950661d5ed8c09ded2cac0bfb5e2c3..5e03a35b8a6fd662cde4077f3e4f54b91e79b7af 100644 (file)
@@ -9,7 +9,7 @@
 use rustc::mir;
 use rustc::mir::tcx::PlaceTy;
 use rustc::ty::layout::{self, Align, HasTyCtxt, LayoutOf, TyLayout, VariantIdx};
-use rustc::ty::{self, Instance, Ty};
+use rustc::ty::{self, Ty};
 
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceRef<'tcx, V> {
@@ -37,15 +37,6 @@ pub fn new_sized_aligned(llval: V, layout: TyLayout<'tcx>, align: Align) -> Plac
         PlaceRef { llval, llextra: None, layout, align }
     }
 
-    fn new_thin_place<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
-        bx: &mut Bx,
-        llval: V,
-        layout: TyLayout<'tcx>,
-    ) -> PlaceRef<'tcx, V> {
-        assert!(!bx.cx().type_has_metadata(layout.ty));
-        PlaceRef { llval, llextra: None, layout, align: layout.align.abi }
-    }
-
     // FIXME(eddyb) pass something else for the name so no work is done
     // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
     pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
@@ -424,76 +415,26 @@ pub fn codegen_place(
         let tcx = self.cx.tcx();
 
         let result = match place_ref {
-            mir::PlaceRef { base: mir::PlaceBase::Local(index), projection: [] } => {
-                match self.locals[*index] {
-                    LocalRef::Place(place) => {
-                        return place;
-                    }
-                    LocalRef::UnsizedPlace(place) => {
-                        return bx.load_operand(place).deref(cx);
-                    }
-                    LocalRef::Operand(..) => {
-                        bug!("using operand local {:?} as place", place_ref);
-                    }
+            mir::PlaceRef { local, projection: [] } => match self.locals[**local] {
+                LocalRef::Place(place) => {
+                    return place;
                 }
-            }
-            mir::PlaceRef {
-                base:
-                    mir::PlaceBase::Static(box mir::Static {
-                        ty,
-                        kind: mir::StaticKind::Promoted(promoted, substs),
-                        def_id,
-                    }),
-                projection: [],
-            } => {
-                let instance = Instance::new(*def_id, self.monomorphize(substs));
-                let layout = cx.layout_of(self.monomorphize(&ty));
-                match bx.tcx().const_eval_promoted(instance, *promoted) {
-                    Ok(val) => match val.val {
-                        ty::ConstKind::Value(mir::interpret::ConstValue::ByRef {
-                            alloc,
-                            offset,
-                        }) => bx.cx().from_const_alloc(layout, alloc, offset),
-                        _ => bug!("promoteds should have an allocation: {:?}", val),
-                    },
-                    Err(_) => {
-                        // This is unreachable as long as runtime
-                        // and compile-time agree perfectly.
-                        // With floats that won't always be true,
-                        // so we generate a (safe) abort.
-                        bx.abort();
-                        // We still have to return a place but it doesn't matter,
-                        // this code is unreachable.
-                        let llval =
-                            bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout)));
-                        PlaceRef::new_sized(llval, layout)
-                    }
+                LocalRef::UnsizedPlace(place) => {
+                    return bx.load_operand(place).deref(cx);
                 }
-            }
-            mir::PlaceRef {
-                base:
-                    mir::PlaceBase::Static(box mir::Static {
-                        ty,
-                        kind: mir::StaticKind::Static,
-                        def_id,
-                    }),
-                projection: [],
-            } => {
-                // NB: The layout of a static may be unsized as is the case when working
-                // with a static that is an extern_type.
-                let layout = cx.layout_of(self.monomorphize(&ty));
-                let static_ = bx.get_static(*def_id);
-                PlaceRef::new_thin_place(bx, static_, layout)
-            }
-            mir::PlaceRef { base, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
+                LocalRef::Operand(..) => {
+                    bug!("using operand local {:?} as place", place_ref);
+                }
+            },
+            mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
                 // Load the pointer from its location.
-                self.codegen_consume(bx, &mir::PlaceRef { base, projection: proj_base })
+                self.codegen_consume(bx, &mir::PlaceRef { local, projection: proj_base })
                     .deref(bx.cx())
             }
-            mir::PlaceRef { base, projection: [proj_base @ .., elem] } => {
+            mir::PlaceRef { local, projection: [proj_base @ .., elem] } => {
                 // FIXME turn this recursion into iteration
                 let cg_base =
-                    self.codegen_place(bx, &mir::PlaceRef { base, projection: proj_base });
+                    self.codegen_place(bx, &mir::PlaceRef { local, projection: proj_base });
 
                 match elem {
                     mir::ProjectionElem::Deref => bug!(),
@@ -558,7 +499,7 @@ pub fn codegen_place(
 
     pub fn monomorphized_place_ty(&self, place_ref: &mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> {
         let tcx = self.cx.tcx();
-        let place_ty = mir::Place::ty_from(place_ref.base, place_ref.projection, *self.mir, tcx);
+        let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, *self.mir, tcx);
         self.monomorphize(&place_ty.ty)
     }
 }
index 48ba64143a708ccbdfd7703e6fd47ddb501eeae9..574c06d9ceb419d6b1b8d892fc1ac22474dae324 100644 (file)
@@ -1,4 +1,5 @@
 use rustc::mir;
+use rustc_errors::struct_span_err;
 
 use super::FunctionCx;
 use super::LocalRef;
@@ -81,12 +82,13 @@ pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>
                         if let OperandValue::Immediate(_) = op.val {
                             acc.push(op.immediate());
                         } else {
-                            span_err!(
+                            struct_span_err!(
                                 bx.sess(),
                                 span.to_owned(),
                                 E0669,
                                 "invalid value for constraint in inline assembly"
-                            );
+                            )
+                            .emit();
                         }
                         acc
                     },
@@ -100,12 +102,13 @@ pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>
                         statement.source_info.span,
                     );
                     if !res {
-                        span_err!(
+                        struct_span_err!(
                             bx.sess(),
                             statement.source_info.span,
                             E0668,
                             "malformed inline assembly"
-                        );
+                        )
+                        .emit();
                     }
                 }
                 bx
index e0d0a2f32f33183acabea4fd038a353896507225..bc3a75250bf703f0b20606c8113c2f3831ea1979 100644 (file)
@@ -1,5 +1,6 @@
 use super::write::WriteBackendMethods;
 use super::CodegenObject;
+use crate::ModuleCodegen;
 
 use rustc::middle::cstore::EncodedMetadata;
 use rustc::session::{config, Session};
@@ -10,7 +11,6 @@
 use rustc_span::symbol::Symbol;
 use syntax::expand::allocator::AllocatorKind;
 
-use std::sync::mpsc;
 use std::sync::Arc;
 
 pub trait BackendTypes {
@@ -34,7 +34,7 @@ impl<'tcx, T> Backend<'tcx> for T where
 {
 }
 
-pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
+pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
     fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module;
     fn write_compressed_metadata<'tcx>(
         &self,
@@ -48,12 +48,13 @@ fn codegen_allocator<'tcx>(
         mods: &mut Self::Module,
         kind: AllocatorKind,
     );
+    /// This generates the codegen unit and returns it along with
+    /// a `u64` giving an estimate of the unit's processing cost.
     fn compile_codegen_unit(
         &self,
         tcx: TyCtxt<'_>,
         cgu_name: Symbol,
-        tx_to_llvm_workers: &mpsc::Sender<Box<dyn std::any::Any + Send>>,
-    );
+    ) -> (ModuleCodegen<Self::Module>, u64);
     // If find_features is true this won't access `sess.crate_types` by assuming
     // that `is_pie_binary` is false. When we discover LLVM target features
     // `sess.crate_types` is uninitialized so we cannot access it.
index 7fa40b8a869058670ebf03669d40930b75c0c081..19db9834fd48e69921715c8aca5ef56c77155a07 100644 (file)
@@ -26,7 +26,7 @@ rustc-hash = "1.0.1"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_index = { path = "../librustc_index", package = "rustc_index" }
 bitflags = "1.2.1"
-measureme = "0.5"
+measureme = "0.7.1"
 
 [dependencies.parking_lot]
 version = "0.9"
index 6d1e1abbcef1d0c9692bd733f11c443be83a18d2..ede5757a479de273216921e6ec9e04ee8b8b8ce9 100644 (file)
@@ -14,35 +14,55 @@ pub fn binary_search_slice<E, K>(data: &'d [E], key_fn: impl Fn(&E) -> K, key: &
         Ok(mid) => mid,
         Err(_) => return &[],
     };
+    let size = data.len();
 
-    // We get back *some* element with the given key -- so
-    // search backwards to find the *first* one.
-    //
-    // (It'd be more efficient to use a "galloping" search
-    // here, but it's not really worth it for small-ish
-    // amounts of data.)
+    // We get back *some* element with the given key -- so do
+    // a galloping search backwards to find the *first* one.
     let mut start = mid;
-    while start > 0 {
-        if key_fn(&data[start - 1]) == *key {
-            start -= 1;
-        } else {
+    let mut previous = mid;
+    let mut step = 1;
+    loop {
+        start = start.saturating_sub(step);
+        if start == 0 || key_fn(&data[start]) != *key {
             break;
         }
+        previous = start;
+        step *= 2;
+    }
+    step = previous - start;
+    while step > 1 {
+        let half = step / 2;
+        let mid = start + half;
+        if key_fn(&data[mid]) != *key {
+            start = mid;
+        }
+        step -= half;
+    }
+    // adjust by one if we have overshot
+    if start < size && key_fn(&data[start]) != *key {
+        start += 1;
     }
 
     // Now search forward to find the *last* one.
-    //
-    // (It'd be more efficient to use a "galloping" search
-    // here, but it's not really worth it for small-ish
-    // amounts of data.)
-    let mut end = mid + 1;
-    let max = data.len();
-    while end < max {
-        if key_fn(&data[end]) == *key {
-            end += 1;
-        } else {
+    let mut end = mid;
+    let mut previous = mid;
+    let mut step = 1;
+    loop {
+        end = end.saturating_add(step).min(size);
+        if end == size || key_fn(&data[end]) != *key {
             break;
         }
+        previous = end;
+        step *= 2;
+    }
+    step = end - previous;
+    while step > 1 {
+        let half = step / 2;
+        let mid = end - half;
+        if key_fn(&data[mid]) != *key {
+            end = mid;
+        }
+        step -= half;
     }
 
     &data[start..end]
diff --git a/src/librustc_data_structures/captures.rs b/src/librustc_data_structures/captures.rs
new file mode 100644 (file)
index 0000000..26b90eb
--- /dev/null
@@ -0,0 +1,10 @@
+/// "Signaling" trait used in impl trait to tag lifetimes that you may
+/// need to capture but don't really need for other reasons.
+/// Basically a workaround; see [this comment] for details.
+///
+/// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
+// FIXME(eddyb) false positive, the lifetime parameter is "phantom" but needed.
+#[allow(unused_lifetimes)]
+pub trait Captures<'a> {}
+
+impl<'a, T: ?Sized> Captures<'a> for T {}
index d1b7ee9e83e76717ab315f77e7fc183bc6fa3755..51a38a7d2ab9ce84a82f0b37d5faf8034a2bbb5e 100644 (file)
@@ -67,6 +67,7 @@ macro_rules! unlikely {
 pub mod base_n;
 pub mod binary_search_util;
 pub mod box_region;
+pub mod captures;
 pub mod const_cstr;
 pub mod flock;
 pub mod fx;
index 840a2603deb79f7a03e655400621b2e2bd98836a..8deb43d50f93874641512387261eeaf2ddbde0b1 100644 (file)
@@ -1,6 +1,90 @@
+//! # Rust Compiler Self-Profiling
+//!
+//! This module implements the basic framework for the compiler's self-
+//! profiling support. It provides the `SelfProfiler` type which enables
+//! recording "events". An event is something that starts and ends at a given
+//! point in time and has an ID and a kind attached to it. This allows for
+//! tracing the compiler's activity.
+//!
+//! Internally this module uses the custom tailored [measureme][mm] crate for
+//! efficiently recording events to disk in a compact format that can be
+//! post-processed and analyzed by the suite of tools in the `measureme`
+//! project. The highest priority for the tracing framework is on incurring as
+//! little overhead as possible.
+//!
+//!
+//! ## Event Overview
+//!
+//! Events have a few properties:
+//!
+//! - The `event_kind` designates the broad category of an event (e.g. does it
+//!   correspond to the execution of a query provider or to loading something
+//!   from the incr. comp. on-disk cache, etc).
+//! - The `event_id` designates the query invocation or function call it
+//!   corresponds to, possibly including the query key or function arguments.
+//! - Each event stores the ID of the thread it was recorded on.
+//! - The timestamp stores beginning and end of the event, or the single point
+//!   in time it occurred at for "instant" events.
+//!
+//!
+//! ## Event Filtering
+//!
+//! Event generation can be filtered by event kind. Recording all possible
+//! events generates a lot of data, much of which is not needed for most kinds
+//! of analysis. So, in order to keep overhead as low as possible for a given
+//! use case, the `SelfProfiler` will only record the kinds of events that
+//! pass the filter specified as a command line argument to the compiler.
+//!
+//!
+//! ## `event_id` Assignment
+//!
+//! As far as `measureme` is concerned, `event_id`s are just strings. However,
+//! it would incur too much overhead to generate and persist each `event_id`
+//! string at the point where the event is recorded. In order to make this more
+//! efficient `measureme` has two features:
+//!
+//! - Strings can share their content, so that re-occurring parts don't have to
+//!   be copied over and over again. One allocates a string in `measureme` and
+//!   gets back a `StringId`. This `StringId` is then used to refer to that
+//!   string. `measureme` strings are actually DAGs of string components so that
+//!   arbitrary sharing of substrings can be done efficiently. This is useful
+//!   because `event_id`s contain lots of redundant text like query names or
+//!   def-path components.
+//!
+//! - `StringId`s can be "virtual" which means that the client picks a numeric
+//!   ID according to some application-specific scheme and can later make that
+//!   ID be mapped to an actual string. This is used to cheaply generate
+//!   `event_id`s while the events actually occur, causing little timing
+//!   distortion, and then later map those `StringId`s, in bulk, to actual
+//!   `event_id` strings. This way the largest part of the tracing overhead is
+//!   localized to one contiguous chunk of time.
+//!
+//! How are these `event_id`s generated in the compiler? For things that occur
+//! infrequently (e.g. "generic activities"), we just allocate the string the
+//! first time it is used and then keep the `StringId` in a hash table. This
+//! is implemented in `SelfProfiler::get_or_alloc_cached_string()`.
+//!
+//! For queries it gets more interesting: First we need a unique numeric ID for
+//! each query invocation (the `QueryInvocationId`). This ID is used as the
+//! virtual `StringId` we use as `event_id` for a given event. This ID has to
+//! be available both when the query is executed and later, together with the
+//! query key, when we allocate the actual `event_id` strings in bulk.
+//!
+//! We could make the compiler generate and keep track of such an ID for each
+//! query invocation but luckily we already have something that fits all the
+//! the requirements: the query's `DepNodeIndex`. So we use the numeric value
+//! of the `DepNodeIndex` as `event_id` when recording the event and then,
+//! just before the query context is dropped, we walk the entire query cache
+//! (which stores the `DepNodeIndex` along with the query key for each
+//! invocation) and allocate the corresponding strings together with a mapping
+//! for `DepNodeIndex as StringId`.
+//!
+//! [mm]: https://github.com/rust-lang/measureme/
+
+use crate::fx::FxHashMap;
+
 use std::error::Error;
 use std::fs;
-use std::mem::{self, Discriminant};
 use std::path::Path;
 use std::process;
 use std::sync::Arc;
@@ -8,9 +92,8 @@
 use std::time::{Duration, Instant};
 use std::u32;
 
-use crate::cold_path;
-
-use measureme::StringId;
+use measureme::{EventId, EventIdBuilder, SerializableString, StringId};
+use parking_lot::RwLock;
 
 /// MmapSerializatioSink is faster on macOS and Linux
 /// but FileSerializationSink is faster on Windows
 
 type Profiler = measureme::Profiler<SerializationSink>;
 
-pub trait QueryName: Sized + Copy {
-    fn discriminant(self) -> Discriminant<Self>;
-    fn as_str(self) -> &'static str;
-}
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
 pub enum ProfileCategory {
     Parsing,
@@ -44,15 +122,13 @@ struct EventFilter: u32 {
         const QUERY_CACHE_HITS   = 1 << 2;
         const QUERY_BLOCKED      = 1 << 3;
         const INCR_CACHE_LOADS   = 1 << 4;
-        const SPARSE_PASS   = 1 << 5;
-        const GENERIC_PASS   = 1 << 6;
+
+        const QUERY_KEYS         = 1 << 5;
 
         const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
                         Self::QUERY_PROVIDERS.bits |
                         Self::QUERY_BLOCKED.bits |
-                        Self::INCR_CACHE_LOADS.bits |
-                        Self::SPARSE_PASS.bits |
-                        Self::GENERIC_PASS.bits;
+                        Self::INCR_CACHE_LOADS.bits;
 
         // empty() and none() aren't const-fns unfortunately
         const NONE = 0;
@@ -63,19 +139,21 @@ struct EventFilter: u32 {
 const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
     ("none", EventFilter::NONE),
     ("all", EventFilter::ALL),
-    ("sparse-pass", EventFilter::SPARSE_PASS),
-    ("generic-pass", EventFilter::GENERIC_PASS),
     ("generic-activity", EventFilter::GENERIC_ACTIVITIES),
     ("query-provider", EventFilter::QUERY_PROVIDERS),
     ("query-cache-hit", EventFilter::QUERY_CACHE_HITS),
     ("query-blocked", EventFilter::QUERY_BLOCKED),
     ("incr-cache-load", EventFilter::INCR_CACHE_LOADS),
+    ("query-keys", EventFilter::QUERY_KEYS),
 ];
 
 fn thread_id_to_u32(tid: ThreadId) -> u32 {
-    unsafe { mem::transmute::<ThreadId, u64>(tid) as u32 }
+    unsafe { std::mem::transmute::<ThreadId, u64>(tid) as u32 }
 }
 
+/// Something that uniquely identifies a query invocation.
+pub struct QueryInvocationId(pub u32);
+
 /// A reference to the SelfProfiler. It can be cloned and sent across thread
 /// boundaries at will.
 #[derive(Clone)]
@@ -89,110 +167,99 @@ pub struct SelfProfilerRef {
     // actually enabled.
     event_filter_mask: EventFilter,
 
-    // Print sparse passes to stdout
-    verbose_sparse: bool,
+    // Print verbose generic activities to stdout
+    print_verbose_generic_activities: bool,
 
-    // Print generic passes to stdout
-    verbose_generic: bool,
+    // Print extra verbose generic activities to stdout
+    print_extra_verbose_generic_activities: bool,
 }
 
 impl SelfProfilerRef {
     pub fn new(
         profiler: Option<Arc<SelfProfiler>>,
-        verbose_sparse: bool,
-        verbose_generic: bool,
+        print_verbose_generic_activities: bool,
+        print_extra_verbose_generic_activities: bool,
     ) -> SelfProfilerRef {
         // If there is no SelfProfiler then the filter mask is set to NONE,
         // ensuring that nothing ever tries to actually access it.
-        let mut event_filter_mask =
+        let event_filter_mask =
             profiler.as_ref().map(|p| p.event_filter_mask).unwrap_or(EventFilter::NONE);
 
-        if verbose_sparse {
-            event_filter_mask |= EventFilter::SPARSE_PASS;
-        }
-
-        if verbose_generic {
-            event_filter_mask |= EventFilter::GENERIC_PASS;
+        SelfProfilerRef {
+            profiler,
+            event_filter_mask,
+            print_verbose_generic_activities,
+            print_extra_verbose_generic_activities,
         }
-
-        SelfProfilerRef { profiler, event_filter_mask, verbose_sparse, verbose_generic }
     }
 
+    // This shim makes sure that calls only get executed if the filter mask
+    // lets them pass. It also contains some trickery to make sure that
+    // code is optimized for non-profiling compilation sessions, i.e. anything
+    // past the filter check is never inlined so it doesn't clutter the fast
+    // path.
     #[inline(always)]
     fn exec<F>(&self, event_filter: EventFilter, f: F) -> TimingGuard<'_>
     where
         F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
     {
-        self.handle_event(
-            event_filter,
-            || f(self.profiler.as_ref().unwrap()),
-            || TimingGuard::none(),
-        )
-    }
+        #[inline(never)]
+        fn cold_call<F>(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_>
+        where
+            F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
+        {
+            let profiler = profiler_ref.profiler.as_ref().unwrap();
+            f(&**profiler)
+        }
 
-    // This shim makes sure that cold calls only get executed if the filter mask
-    // lets them pass. It also contains some trickery to make sure that
-    // code is optimized for non-profiling compilation sessions, i.e. anything
-    // past the filter check is never inlined so it doesn't clutter the fast
-    // path.
-    #[inline(always)]
-    fn handle_event<R>(
-        &self,
-        event_filter: EventFilter,
-        cold: impl FnOnce() -> R,
-        hot: impl FnOnce() -> R,
-    ) -> R {
         if unlikely!(self.event_filter_mask.contains(event_filter)) {
-            cold_path(|| cold())
+            cold_call(self, f)
         } else {
-            hot()
+            TimingGuard::none()
         }
     }
 
-    /// Start profiling a sparse pass. Profiling continues until the
-    /// VerboseTimingGuard returned from this call is dropped.
+    /// Start profiling a verbose generic activity. Profiling continues until the
+    /// VerboseTimingGuard returned from this call is dropped. In addition to recording
+    /// a measureme event, "verbose" generic activities also print a timing entry to
+    /// stdout if the compiler is invoked with -Ztime or -Ztime-passes.
     #[inline(always)]
-    pub fn sparse_pass<'a>(&'a self, event_id: &'a str) -> VerboseTimingGuard<'a> {
-        self.handle_event(
-            EventFilter::SPARSE_PASS,
-            || {
-                VerboseTimingGuard::start(
-                    self.profiler
-                        .as_ref()
-                        .map(|profiler| (&**profiler, profiler.sparse_pass_event_kind)),
-                    event_id,
-                    self.verbose_sparse,
-                )
-            },
-            || VerboseTimingGuard::none(),
+    pub fn verbose_generic_activity<'a>(
+        &'a self,
+        event_id: &'static str,
+    ) -> VerboseTimingGuard<'a> {
+        VerboseTimingGuard::start(
+            event_id,
+            self.print_verbose_generic_activities,
+            self.generic_activity(event_id),
         )
     }
 
-    /// Start profiling a generic pass. Profiling continues until the
-    /// VerboseTimingGuard returned from this call is dropped.
+    /// Start profiling a extra verbose generic activity. Profiling continues until the
+    /// VerboseTimingGuard returned from this call is dropped. In addition to recording
+    /// a measureme event, "extra verbose" generic activities also print a timing entry to
+    /// stdout if the compiler is invoked with -Ztime-passes.
     #[inline(always)]
-    pub fn generic_pass<'a>(&'a self, event_id: &'a str) -> VerboseTimingGuard<'a> {
-        self.handle_event(
-            EventFilter::GENERIC_PASS,
-            || {
-                VerboseTimingGuard::start(
-                    self.profiler
-                        .as_ref()
-                        .map(|profiler| (&**profiler, profiler.generic_pass_event_kind)),
-                    event_id,
-                    self.verbose_generic,
-                )
-            },
-            || VerboseTimingGuard::none(),
+    pub fn extra_verbose_generic_activity<'a>(
+        &'a self,
+        event_id: &'a str,
+    ) -> VerboseTimingGuard<'a> {
+        // FIXME: This does not yet emit a measureme event
+        // because callers encode arguments into `event_id`.
+        VerboseTimingGuard::start(
+            event_id,
+            self.print_extra_verbose_generic_activities,
+            TimingGuard::none(),
         )
     }
 
     /// Start profiling a generic activity. Profiling continues until the
     /// TimingGuard returned from this call is dropped.
     #[inline(always)]
-    pub fn generic_activity(&self, event_id: &str) -> TimingGuard<'_> {
+    pub fn generic_activity(&self, event_id: &'static str) -> TimingGuard<'_> {
         self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| {
-            let event_id = profiler.profiler.alloc_string(event_id);
+            let event_id = profiler.get_or_alloc_cached_string(event_id);
+            let event_id = EventId::from_label(event_id);
             TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id)
         })
     }
@@ -200,19 +267,18 @@ pub fn generic_activity(&self, event_id: &str) -> TimingGuard<'_> {
     /// Start profiling a query provider. Profiling continues until the
     /// TimingGuard returned from this call is dropped.
     #[inline(always)]
-    pub fn query_provider(&self, query_name: impl QueryName) -> TimingGuard<'_> {
+    pub fn query_provider(&self) -> TimingGuard<'_> {
         self.exec(EventFilter::QUERY_PROVIDERS, |profiler| {
-            let event_id = SelfProfiler::get_query_name_string_id(query_name);
-            TimingGuard::start(profiler, profiler.query_event_kind, event_id)
+            TimingGuard::start(profiler, profiler.query_event_kind, EventId::INVALID)
         })
     }
 
     /// Record a query in-memory cache hit.
     #[inline(always)]
-    pub fn query_cache_hit(&self, query_name: impl QueryName) {
+    pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) {
         self.instant_query_event(
             |profiler| profiler.query_cache_hit_event_kind,
-            query_name,
+            query_invocation_id,
             EventFilter::QUERY_CACHE_HITS,
         );
     }
@@ -221,10 +287,9 @@ pub fn query_cache_hit(&self, query_name: impl QueryName) {
     /// Profiling continues until the TimingGuard returned from this call is
     /// dropped.
     #[inline(always)]
-    pub fn query_blocked(&self, query_name: impl QueryName) -> TimingGuard<'_> {
+    pub fn query_blocked(&self) -> TimingGuard<'_> {
         self.exec(EventFilter::QUERY_BLOCKED, |profiler| {
-            let event_id = SelfProfiler::get_query_name_string_id(query_name);
-            TimingGuard::start(profiler, profiler.query_blocked_event_kind, event_id)
+            TimingGuard::start(profiler, profiler.query_blocked_event_kind, EventId::INVALID)
         })
     }
 
@@ -232,10 +297,13 @@ pub fn query_blocked(&self, query_name: impl QueryName) -> TimingGuard<'_> {
     /// incremental compilation on-disk cache. Profiling continues until the
     /// TimingGuard returned from this call is dropped.
     #[inline(always)]
-    pub fn incr_cache_loading(&self, query_name: impl QueryName) -> TimingGuard<'_> {
+    pub fn incr_cache_loading(&self) -> TimingGuard<'_> {
         self.exec(EventFilter::INCR_CACHE_LOADS, |profiler| {
-            let event_id = SelfProfiler::get_query_name_string_id(query_name);
-            TimingGuard::start(profiler, profiler.incremental_load_result_event_kind, event_id)
+            TimingGuard::start(
+                profiler,
+                profiler.incremental_load_result_event_kind,
+                EventId::INVALID,
+            )
         })
     }
 
@@ -243,32 +311,42 @@ pub fn incr_cache_loading(&self, query_name: impl QueryName) -> TimingGuard<'_>
     fn instant_query_event(
         &self,
         event_kind: fn(&SelfProfiler) -> StringId,
-        query_name: impl QueryName,
+        query_invocation_id: QueryInvocationId,
         event_filter: EventFilter,
     ) {
         drop(self.exec(event_filter, |profiler| {
-            let event_id = SelfProfiler::get_query_name_string_id(query_name);
+            let event_id = StringId::new_virtual(query_invocation_id.0);
             let thread_id = thread_id_to_u32(std::thread::current().id());
 
-            profiler.profiler.record_instant_event(event_kind(profiler), event_id, thread_id);
+            profiler.profiler.record_instant_event(
+                event_kind(profiler),
+                EventId::from_virtual(event_id),
+                thread_id,
+            );
 
             TimingGuard::none()
         }));
     }
 
-    pub fn register_queries(&self, f: impl FnOnce(&SelfProfiler)) {
+    pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) {
         if let Some(profiler) = &self.profiler {
             f(&profiler)
         }
     }
+
+    #[inline]
+    pub fn enabled(&self) -> bool {
+        self.profiler.is_some()
+    }
 }
 
 pub struct SelfProfiler {
     profiler: Profiler,
     event_filter_mask: EventFilter,
+
+    string_cache: RwLock<FxHashMap<&'static str, StringId>>,
+
     query_event_kind: StringId,
-    sparse_pass_event_kind: StringId,
-    generic_pass_event_kind: StringId,
     generic_activity_event_kind: StringId,
     incremental_load_result_event_kind: StringId,
     query_blocked_event_kind: StringId,
@@ -289,8 +367,6 @@ pub fn new(
         let profiler = Profiler::new(&path)?;
 
         let query_event_kind = profiler.alloc_string("Query");
-        let sparse_pass_event_kind = profiler.alloc_string("SparsePass");
-        let generic_pass_event_kind = profiler.alloc_string("GenericPass");
         let generic_activity_event_kind = profiler.alloc_string("GenericActivity");
         let incremental_load_result_event_kind = profiler.alloc_string("IncrementalLoadResult");
         let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
@@ -332,9 +408,8 @@ pub fn new(
         Ok(SelfProfiler {
             profiler,
             event_filter_mask,
+            string_cache: RwLock::new(FxHashMap::default()),
             query_event_kind,
-            sparse_pass_event_kind,
-            generic_pass_event_kind,
             generic_activity_event_kind,
             incremental_load_result_event_kind,
             query_blocked_event_kind,
@@ -342,16 +417,51 @@ pub fn new(
         })
     }
 
-    fn get_query_name_string_id(query_name: impl QueryName) -> StringId {
-        let discriminant =
-            unsafe { mem::transmute::<Discriminant<_>, u64>(query_name.discriminant()) };
+    /// Allocates a new string in the profiling data. Does not do any caching
+    /// or deduplication.
+    pub fn alloc_string<STR: SerializableString + ?Sized>(&self, s: &STR) -> StringId {
+        self.profiler.alloc_string(s)
+    }
+
+    /// Gets a `StringId` for the given string. This method makes sure that
+    /// any strings going through it will only be allocated once in the
+    /// profiling data.
+    pub fn get_or_alloc_cached_string(&self, s: &'static str) -> StringId {
+        // Only acquire a read-lock first since we assume that the string is
+        // already present in the common case.
+        {
+            let string_cache = self.string_cache.read();
+
+            if let Some(&id) = string_cache.get(s) {
+                return id;
+            }
+        }
+
+        let mut string_cache = self.string_cache.write();
+        // Check if the string has already been added in the small time window
+        // between dropping the read lock and acquiring the write lock.
+        *string_cache.entry(s).or_insert_with(|| self.profiler.alloc_string(s))
+    }
+
+    pub fn map_query_invocation_id_to_string(&self, from: QueryInvocationId, to: StringId) {
+        let from = StringId::new_virtual(from.0);
+        self.profiler.map_virtual_to_concrete_string(from, to);
+    }
+
+    pub fn bulk_map_query_invocation_id_to_single_string<I>(&self, from: I, to: StringId)
+    where
+        I: Iterator<Item = QueryInvocationId> + ExactSizeIterator,
+    {
+        let from = from.map(|qid| StringId::new_virtual(qid.0));
+        self.profiler.bulk_map_virtual_to_single_concrete_string(from, to);
+    }
 
-        StringId::reserved(discriminant as u32)
+    pub fn query_key_recording_enabled(&self) -> bool {
+        self.event_filter_mask.contains(EventFilter::QUERY_KEYS)
     }
 
-    pub fn register_query_name(&self, query_name: impl QueryName) {
-        let id = SelfProfiler::get_query_name_string_id(query_name);
-        self.profiler.alloc_string_with_reserved_id(id, query_name.as_str());
+    pub fn event_id_builder(&self) -> EventIdBuilder<'_, SerializationSink> {
+        EventIdBuilder::new(&self.profiler)
     }
 }
 
@@ -363,7 +473,7 @@ impl<'a> TimingGuard<'a> {
     pub fn start(
         profiler: &'a SelfProfiler,
         event_kind: StringId,
-        event_id: StringId,
+        event_id: EventId,
     ) -> TimingGuard<'a> {
         let thread_id = thread_id_to_u32(std::thread::current().id());
         let raw_profiler = &profiler.profiler;
@@ -372,10 +482,25 @@ pub fn start(
         TimingGuard(Some(timing_guard))
     }
 
+    #[inline]
+    pub fn finish_with_query_invocation_id(self, query_invocation_id: QueryInvocationId) {
+        if let Some(guard) = self.0 {
+            let event_id = StringId::new_virtual(query_invocation_id.0);
+            let event_id = EventId::from_virtual(event_id);
+            guard.finish_with_override_event_id(event_id);
+        }
+    }
+
     #[inline]
     pub fn none() -> TimingGuard<'a> {
         TimingGuard(None)
     }
+
+    #[inline(always)]
+    pub fn run<R>(self, f: impl FnOnce() -> R) -> R {
+        let _timer = self;
+        f()
+    }
 }
 
 #[must_use]
@@ -386,19 +511,11 @@ pub struct VerboseTimingGuard<'a> {
 }
 
 impl<'a> VerboseTimingGuard<'a> {
-    pub fn start(
-        profiler: Option<(&'a SelfProfiler, StringId)>,
-        event_id: &'a str,
-        verbose: bool,
-    ) -> Self {
-        let _guard = profiler.map_or(TimingGuard::none(), |(profiler, event_kind)| {
-            let event = profiler.profiler.alloc_string(event_id);
-            TimingGuard::start(profiler, event_kind, event)
-        });
+    pub fn start(event_id: &'a str, verbose: bool, _guard: TimingGuard<'a>) -> Self {
         VerboseTimingGuard {
             event_id,
             _guard,
-            start: if verbose { Some(Instant::now()) } else { None },
+            start: if unlikely!(verbose) { Some(Instant::now()) } else { None },
         }
     }
 
@@ -407,10 +524,6 @@ pub fn run<R>(self, f: impl FnOnce() -> R) -> R {
         let _timer = self;
         f()
     }
-
-    fn none() -> Self {
-        VerboseTimingGuard { event_id: "", start: None, _guard: TimingGuard::none() }
-    }
 }
 
 impl Drop for VerboseTimingGuard<'_> {
@@ -485,8 +598,8 @@ fn GetProcessMemoryInfo(
             cb: DWORD,
         ) -> BOOL;
     }
-    let mut pmc: PROCESS_MEMORY_COUNTERS = unsafe { mem::zeroed() };
-    pmc.cb = mem::size_of_val(&pmc) as DWORD;
+    let mut pmc: PROCESS_MEMORY_COUNTERS = unsafe { std::mem::zeroed() };
+    pmc.cb = std::mem::size_of_val(&pmc) as DWORD;
     match unsafe { GetProcessMemoryInfo(GetCurrentProcess(), &mut pmc, pmc.cb) } {
         0 => None,
         _ => Some(pmc.WorkingSetSize as usize),
index ed742ed1ca0a3c66ab4f341f4ede51404746ba37..37449f9402eff6b2d8955f5afa16567248bdef10 100644 (file)
@@ -10,7 +10,6 @@ path = "lib.rs"
 crate-type = ["dylib"]
 
 [dependencies]
-graphviz = { path = "../libgraphviz" }
 lazy_static = "1.0"
 log = "0.4"
 env_logger = { version = "0.7", default-features = false }
@@ -18,7 +17,7 @@ rustc = { path = "../librustc" }
 rustc_target = { path = "../librustc_target" }
 rustc_lint = { path = "../librustc_lint" }
 rustc_data_structures = { path = "../librustc_data_structures" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_metadata = { path = "../librustc_metadata" }
@@ -30,7 +29,6 @@ rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_interface = { path = "../librustc_interface" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
-rustc_resolve = { path = "../librustc_resolve" }
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
 
index dece0a55edd18850dfcca1d4ae4ce05adca2838e..072b85d716d74d17367f2e668fc1d1762f35bc52 100644 (file)
 
 pub extern crate rustc_plugin_impl as plugin;
 
-//use rustc_resolve as resolve;
-use errors::{registry::Registry, PResult};
-use rustc::lint;
-use rustc::lint::Lint;
+use rustc::lint::{Lint, LintId};
 use rustc::middle::cstore::MetadataLoader;
 use rustc::session::config::nightly_options;
 use rustc::session::config::{ErrorOutputType, Input, OutputType, PrintRequest};
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_data_structures::profiling::print_time_passes_entry;
 use rustc_data_structures::sync::SeqCst;
+use rustc_errors::{registry::Registry, PResult};
 use rustc_feature::{find_gated_cfg, UnstableFeatures};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::util::get_builtin_codegen_backend;
 use rustc_interface::{interface, Queries};
+use rustc_lint::LintStore;
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
@@ -369,7 +368,7 @@ pub fn run_compiler(
                 queries.global_ctxt()?.peek_mut().enter(|tcx| {
                     let result = tcx.analysis(LOCAL_CRATE);
 
-                    sess.time("save analysis", || {
+                    sess.time("save_analysis", || {
                         save::process_crate(
                             tcx,
                             &expanded_crate,
@@ -389,6 +388,7 @@ pub fn run_compiler(
                 })?;
             } else {
                 // Drop AST after creating GlobalCtxt to free memory
+                let _timer = sess.prof.generic_activity("drop_ast");
                 mem::drop(queries.expansion()?.take());
             }
 
@@ -413,6 +413,7 @@ pub fn run_compiler(
         })?;
 
         if let Some(linker) = linker {
+            let _timer = sess.timer("link");
             linker.link()?
         }
 
@@ -809,7 +810,7 @@ fn print_wall_help() {
     );
 }
 
-fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
+fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
     println!(
         "
 Available lint options:
@@ -830,8 +831,8 @@ fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lin
     }
 
     fn sort_lint_groups(
-        lints: Vec<(&'static str, Vec<lint::LintId>, bool)>,
-    ) -> Vec<(&'static str, Vec<lint::LintId>)> {
+        lints: Vec<(&'static str, Vec<LintId>, bool)>,
+    ) -> Vec<(&'static str, Vec<LintId>)> {
         let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
         lints.sort_by_key(|l| l.0);
         lints
@@ -890,7 +891,7 @@ fn sort_lint_groups(
     println!("    {}  {}", padded("----"), "---------");
     println!("    {}  {}", padded("warnings"), "all lints that are set to issue warnings");
 
-    let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
+    let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
         for (name, to) in lints {
             let name = name.to_lowercase().replace("_", "-");
             let desc = to
@@ -1134,7 +1135,7 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
 /// the panic into a `Result` instead.
 pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
     catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
-        if value.is::<errors::FatalErrorMarker>() {
+        if value.is::<rustc_errors::FatalErrorMarker>() {
             ErrorReported
         } else {
             panic::resume_unwind(value);
@@ -1163,22 +1164,21 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     // Separate the output with an empty line
     eprintln!();
 
-    let emitter = Box::new(errors::emitter::EmitterWriter::stderr(
-        errors::ColorConfig::Auto,
+    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
+        rustc_errors::ColorConfig::Auto,
         None,
         false,
         false,
         None,
         false,
     ));
-    let handler = errors::Handler::with_emitter(true, None, emitter);
+    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
 
     // a .span_bug or .bug call has already printed what
     // it wants to print.
-    if !info.payload().is::<errors::ExplicitBug>() {
-        let d = errors::Diagnostic::new(errors::Level::Bug, "unexpected panic");
+    if !info.payload().is::<rustc_errors::ExplicitBug>() {
+        let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
         handler.emit_diagnostic(&d);
-        handler.abort_if_errors_and_should_abort();
     }
 
     let mut xs: Vec<Cow<'static, str>> = vec![
index 25e380b02e647f0a1d7b45e43cd87ec142cb796c..b2cc2a2273af25514dcbf5d3749f9a446646d2bf 100644 (file)
@@ -136,7 +136,7 @@ type parameters, the number of monomorphized implementations the compiler
 generates does not grow drastically, since the compiler will only generate an
 implementation if the function is called with unparametrized substitutions
 (i.e., substitutions where none of the substituted types are themselves
-parametrized).
+parameterized).
 
 However, with trait objects we have to make a table containing _every_ object
 that implements the trait. Now, if it has type parameters, we need to add
index 2388bc635d9f5a433756d6150eb20581e80d7b52..38ce9b43d0a2a5f869267c71f5bb5365bb132bae 100644 (file)
@@ -20,7 +20,7 @@ enum NightsWatch {
 }
 ```
 
-or you remove the integer represention of your enum:
+or you remove the integer representation of your enum:
 
 ```
 enum NightsWatch {}
index e7fa8dfd8313e7be690d7e42b3c246da49700a0a..4624f9e5b853112406f712328392b4541ff4bfee 100644 (file)
@@ -1,6 +1,20 @@
-Explicitly implementing both Drop and Copy for a type is currently disallowed.
-This feature can make some sense in theory, but the current implementation is
-incorrect and can lead to memory unsafety (see [issue #20126][iss20126]), so
-it has been disabled for now.
+The `Copy` trait was implemented on a type with a `Drop` implementation.
+
+Erroneous code example:
+
+```compile_fail,E0184
+#[derive(Copy)]
+struct Foo; // error!
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+    }
+}
+```
+
+Explicitly implementing both `Drop` and `Copy` trait on a type is currently
+disallowed. This feature can make some sense in theory, but the current
+implementation is incorrect and can lead to memory unsafety (see
+[issue #20126][iss20126]), so it has been disabled for now.
 
 [iss20126]: https://github.com/rust-lang/rust/issues/20126
index f0ad2af144aa00fe42d92d47df79d0aa7b3f20f4..944a93ed14e6c699c7f9a1c10cbad556dfaa7273 100644 (file)
@@ -2,7 +2,7 @@ An associated function for a trait was defined to be static, but an
 implementation of the trait declared the same function to be a method (i.e., to
 take a `self` parameter).
 
-Here's an example of this error:
+Erroneous code example:
 
 ```compile_fail,E0185
 trait Foo {
@@ -17,3 +17,19 @@ impl Foo for Bar {
     fn foo(&self) {}
 }
 ```
+
+When a type implements a trait's associated function, it has to use the same
+signature. So in this case, since `Foo::foo` does not take any argument and
+does not return anything, its implementation on `Bar` should be the same:
+
+```
+trait Foo {
+    fn foo();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo() {} // ok!
+}
+```
index 9135d5c1d5e9ad13f16b78109f9abf0bf61a489f..7db1e843323872a1b6d4ecc19b08d5967e5ac132 100644 (file)
@@ -2,7 +2,7 @@ An associated function for a trait was defined to be a method (i.e., to take a
 `self` parameter), but an implementation of the trait declared the same function
 to be static.
 
-Here's an example of this error:
+Erroneous code example:
 
 ```compile_fail,E0186
 trait Foo {
@@ -17,3 +17,19 @@ impl Foo for Bar {
     fn foo() {}
 }
 ```
+
+When a type implements a trait's associated function, it has to use the same
+signature. So in this case, since `Foo::foo` takes `self` as argument and
+does not return anything, its implementation on `Bar` should be the same:
+
+```
+trait Foo {
+    fn foo(&self);
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo(&self) {} // ok!
+}
+```
index 1779e5dbb30e7dbbb68534a442f94399f2db79a1..c628d176836f985b912d4abe1098773c8c54016b 100644 (file)
@@ -36,7 +36,7 @@ impl Trait for Foo {
 }
 ```
 
-E0307 will be emitted by the compiler when using an invalid reciver type,
+E0307 will be emitted by the compiler when using an invalid receiver type,
 like in the following example:
 
 ```compile_fail,E0307
index 47e3a48f0317247a653dd707c1b4bc49b8134ff8..808363e6eb04180b1d94df6179d11102faa34c82 100644 (file)
@@ -31,7 +31,7 @@ Since our new thread runs in parallel, the stack frame containing `x` and `y`
 may well have disappeared by the time we try to use them. Even if we call
 `thr.join()` within foo (which blocks until `thr` has completed, ensuring the
 stack frame won't disappear), we will not succeed: the compiler cannot prove
-that this behaviour is safe, and so won't let us do it.
+that this behavior is safe, and so won't let us do it.
 
 The solution to this problem is usually to switch to using a `move` closure.
 This approach moves (or copies, where possible) data into the closure, rather
index 15e7fb04738353ca95225555566ea5e1d9c5adc0..275a83e606e400b4945220ffeef9c44d9dc0d0c7 100644 (file)
@@ -8,7 +8,7 @@ loop {
 }
 ```
 
-Please verify you spelt or declare the label correctly. Example:
+Please verify you spelled or declared the label correctly. Example:
 
 ```
 'a: loop {
index 9cc62b2ba6d0afb88ebf021181d93ca672267c6d..e6a28a9c2c460e1413fc170d26537933079ccf82 100644 (file)
@@ -12,6 +12,8 @@ trait Foo {
 pub trait Bar : Foo {} // error: private trait in public interface
 pub struct Bar2<T: Foo>(pub T); // same error
 pub fn foo<T: Foo> (t: T) {} // same error
+
+fn main() {}
 ```
 
 To solve this error, please ensure that the trait is also public. The trait
@@ -26,4 +28,6 @@ pub trait Foo { // we set the Foo trait public
 pub trait Bar : Foo {} // ok!
 pub struct Bar2<T: Foo>(pub T); // ok!
 pub fn foo<T: Foo> (t: T) {} // ok!
+
+fn main() {}
 ```
index d0144478dbfe0c617c7d00a7e54500adb0c90a3c..77a1834ece42f74758c3cf85f284bf43d0c98e94 100644 (file)
@@ -12,6 +12,8 @@ mod Foo {
         Bar(0)
     }
 }
+
+fn main() {}
 ```
 
 To solve this error, please ensure that the type is also public. The type
@@ -27,4 +29,6 @@ mod Foo {
         Bar(0)
     }
 }
+
+fn main() {}
 ```
index 1ccaf71257b8b47e21c81082b08abea73abac758..d45663f3a5347732b302d9a637c68dcd9b07f5ed 100644 (file)
@@ -3,30 +3,34 @@ A reference has a longer lifetime than the data it references.
 Erroneous code example:
 
 ```compile_fail,E0491
-trait SomeTrait<'a> {
-    type Output;
+struct Foo<'a> {
+    x: fn(&'a i32),
 }
 
-impl<'a, T> SomeTrait<'a> for T {
-    type Output = &'a T; // compile error E0491
+trait Trait<'a, 'b> {
+    type Out;
+}
+
+impl<'a, 'b> Trait<'a, 'b> for usize {
+    type Out = &'a Foo<'b>; // error!
 }
 ```
 
-Here, the problem is that a reference type like `&'a T` is only valid
-if all the data in T outlives the lifetime `'a`. But this impl as written
-is applicable to any lifetime `'a` and any type `T` -- we have no guarantee
-that `T` outlives `'a`. To fix this, you can add a where clause like
-`where T: 'a`.
+Here, the problem is that the compiler cannot be sure that the `'b` lifetime
+will live longer than `'a`, which should be mandatory in order to be sure that
+`Trait::Out` will always have a reference pointing to an existing type. So in
+this case, we just need to tell the compiler than `'b` must outlive `'a`:
 
 ```
-trait SomeTrait<'a> {
-    type Output;
+struct Foo<'a> {
+    x: fn(&'a i32),
+}
+
+trait Trait<'a, 'b> {
+    type Out;
 }
 
-impl<'a, T> SomeTrait<'a> for T
-where
-    T: 'a,
-{
-    type Output = &'a T; // compile error E0491
+impl<'a, 'b: 'a> Trait<'a, 'b> for usize { // we added the lifetime enforcement
+    type Out = &'a Foo<'b>; // it now works!
 }
 ```
index 62fb66f61497683d32beda4a5c8d81b0815111f1..3dcd801a21a6d8ba4eabbe61d605cd24ddf65447 100644 (file)
@@ -2,8 +2,8 @@ Conflicting representation hints have been used on a same item.
 
 Erroneous code example:
 
-```
-#[repr(u32, u64)] // warning!
+```compile_fail,E0566
+#[repr(u32, u64)]
 enum Repr { A }
 ```
 
index 79ec9ad7b03297812b3550a0677bc7513728c170..73f66d550374050c4be7cc0eef6a3eceacfa1549 100644 (file)
@@ -385,3 +385,22 @@ fn drop(&mut self) {
         }
     }
 }
+
+#[macro_export]
+macro_rules! struct_span_err {
+    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
+        $session.struct_span_err_with_code(
+            $span,
+            &format!($($message)*),
+            $crate::error_code!($code),
+        )
+    })
+}
+
+#[macro_export]
+macro_rules! error_code {
+    ($code:ident) => {{
+        let _ = $code;
+        $crate::DiagnosticId::Error(stringify!($code).to_owned())
+    }};
+}
index 2279ed859540811d6d45d536323493ba0cf08c87..e24e8719133a987574b2d9def7200801d42a9b93 100644 (file)
@@ -182,7 +182,7 @@ fn push_trailing(
 
                 // Find the bounding span.
                 let lo = substitution.parts.iter().map(|part| part.span.lo()).min().unwrap();
-                let hi = substitution.parts.iter().map(|part| part.span.hi()).min().unwrap();
+                let hi = substitution.parts.iter().map(|part| part.span.hi()).max().unwrap();
                 let bounding_span = Span::with_root_ctxt(lo, hi);
                 let lines = cm.span_to_lines(bounding_span).unwrap();
                 assert!(!lines.lines.is_empty());
@@ -278,7 +278,6 @@ struct HandlerInner {
     err_count: usize,
     deduplicated_err_count: usize,
     emitter: Box<dyn Emitter + sync::Send>,
-    continue_after_error: bool,
     delayed_span_bugs: Vec<Diagnostic>,
 
     /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
@@ -402,7 +401,6 @@ pub fn with_emitter_and_flags(
                 err_count: 0,
                 deduplicated_err_count: 0,
                 emitter,
-                continue_after_error: true,
                 delayed_span_bugs: Vec::new(),
                 taught_diagnostics: Default::default(),
                 emitted_diagnostic_codes: Default::default(),
@@ -412,10 +410,6 @@ pub fn with_emitter_and_flags(
         }
     }
 
-    pub fn set_continue_after_error(&self, continue_after_error: bool) {
-        self.inner.borrow_mut().continue_after_error = continue_after_error;
-    }
-
     // This is here to not allow mutation of flags;
     // as of this writing it's only used in tests in librustc.
     pub fn can_emit_warnings(&self) -> bool {
@@ -672,10 +666,6 @@ pub fn abort_if_errors(&self) {
         self.inner.borrow_mut().abort_if_errors()
     }
 
-    pub fn abort_if_errors_and_should_abort(&self) {
-        self.inner.borrow_mut().abort_if_errors_and_should_abort()
-    }
-
     /// `true` if we haven't taught a diagnostic with this code already.
     /// The caller must then teach the user about such a diagnostic.
     ///
@@ -696,7 +686,6 @@ pub fn emit_diagnostic(&self, diagnostic: &Diagnostic) {
     fn emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
         let mut inner = self.inner.borrow_mut();
         inner.emit_diagnostic(diag.set_span(sp));
-        inner.abort_if_errors_and_should_abort();
     }
 
     pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
@@ -830,14 +819,6 @@ fn has_errors_or_delayed_span_bugs(&self) -> bool {
         self.has_errors() || !self.delayed_span_bugs.is_empty()
     }
 
-    fn abort_if_errors_and_should_abort(&mut self) {
-        self.emit_stashed_diagnostics();
-
-        if self.has_errors() && !self.continue_after_error {
-            FatalError.raise();
-        }
-    }
-
     fn abort_if_errors(&mut self) {
         self.emit_stashed_diagnostics();
 
@@ -853,7 +834,6 @@ fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
 
     fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
         self.emit_diagnostic(diag.set_span(sp));
-        self.abort_if_errors_and_should_abort();
     }
 
     fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
index f9c15fbed362f5edc223aefee5cd3c1491eb1baa..d04dd079be75dda338d6e3de0a247604c1bb1364 100644 (file)
@@ -14,10 +14,12 @@ doctest = false
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 log = "0.4"
 rustc_span = { path = "../librustc_span" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
+rustc_ast_passes = { path = "../librustc_ast_passes" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_lexer = { path = "../librustc_lexer" }
 rustc_parse = { path = "../librustc_parse" }
+rustc_session = { path = "../librustc_session" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
index fe08c85249a2ed0cea8fd3d0651e3ed9bc312199..52ba14dbc3df06a7294da48e9252bea4b6223b20 100644 (file)
@@ -1,9 +1,15 @@
 use crate::expand::{self, AstFragment, Invocation};
 
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::{self, Lrc};
+use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use rustc_parse::{self, parser, DirectoryOwnership, MACRO_ARGUMENTS};
 use rustc_span::edition::Edition;
+use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{FileName, MultiSpan, Span, DUMMY_SP};
+use smallvec::{smallvec, SmallVec};
 use syntax::ast::{self, Attribute, Name, NodeId, PatKind};
 use syntax::attr::{self, Deprecation, HasAttrs, Stability};
 use syntax::mut_visit::{self, MutVisitor};
 use syntax::tokenstream::{self, TokenStream};
 use syntax::visit::Visitor;
 
-use errors::{DiagnosticBuilder, DiagnosticId};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::{self, Lrc};
-use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
-use rustc_span::{FileName, MultiSpan, Span, DUMMY_SP};
-use smallvec::{smallvec, SmallVec};
-
 use std::default::Default;
 use std::iter;
 use std::path::PathBuf;
index 11f94ab2e627980b0445e92a50967bc442e46b68..bd3d6b589d00acfb210de183690e5f1f95fdae5d 100644 (file)
@@ -110,7 +110,7 @@ pub fn typaram(
     }
 
     pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
-        ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID }
+        ast::TraitRef { path, constness: None, ref_id: ast::DUMMY_NODE_ID }
     }
 
     pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
index 6eead11ccb7bad63bf698d7b844aab107e73f3ff..3254d0c913da3a2c9305688e3511a6d73531626d 100644 (file)
@@ -5,6 +5,8 @@
 use crate::placeholders::{placeholder, PlaceholderExpander};
 use crate::proc_macro::collect_derives;
 
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, FatalError, PResult};
 use rustc_feature::Features;
 use rustc_parse::configure;
 use rustc_parse::parser::Parser;
 use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
 use syntax::ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind};
 use syntax::attr::{self, is_builtin_attr, HasAttrs};
-use syntax::feature_gate::{self, feature_err};
 use syntax::mut_visit::*;
 use syntax::print::pprust;
 use syntax::ptr::P;
-use syntax::sess::ParseSess;
+use syntax::sess::{feature_err, ParseSess};
 use syntax::token;
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::util::map_in_place::MapInPlace;
 use syntax::visit::{self, Visitor};
 
-use errors::{Applicability, FatalError, PResult};
 use smallvec::{smallvec, SmallVec};
-
-use rustc_data_structures::sync::Lrc;
 use std::io::ErrorKind;
 use std::ops::DerefMut;
 use std::path::PathBuf;
@@ -1063,7 +1061,7 @@ fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
     fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
         let features = self.cx.ecfg.features.unwrap();
         for attr in attrs.iter() {
-            feature_gate::check_attribute(attr, self.cx.parse_sess, features);
+            rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.parse_sess, features);
             validate_attr::check_meta(self.cx.parse_sess, attr);
 
             // macros are expanded before any lint passes so this warning has to be hardcoded
index feba7f633ed80c98fa8efee93f079feee8fb58c9..4fe7c268c4f0b47e90fe4e8911b9ec89990d734c 100644 (file)
@@ -13,7 +13,7 @@
 #[macro_export]
 macro_rules! panictry {
     ($e:expr) => {{
-        use errors::FatalError;
+        use rustc_errors::FatalError;
         use std::result::Result::{Err, Ok};
         match $e {
             Ok(e) => e,
index 992764ab6a41d9daa9c1c6b1610d2e67510421e0..47865b2fb9fc36338c1dea2fdfbf4cb37392ae01 100644 (file)
 //! bound.
 use crate::mbe::{KleeneToken, TokenTree};
 
+use rustc_data_structures::fx::FxHashMap;
+use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
+use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{kw, sym};
+use rustc_span::{symbol::Ident, MultiSpan, Span};
 use syntax::ast::NodeId;
-use syntax::early_buffered_lints::META_VARIABLE_MISUSE;
-use syntax::sess::ParseSess;
 use syntax::token::{DelimToken, Token, TokenKind};
 
-use rustc_data_structures::fx::FxHashMap;
-use rustc_span::{symbol::Ident, MultiSpan, Span};
 use smallvec::SmallVec;
 
 /// Stack represented as linked list.
index c0e34a30c54e99d3195cd0eeee225aa3f5124206..246f66084b813b1d6c7660bf3bc09929d62a3fdd 100644 (file)
@@ -85,7 +85,7 @@
 use syntax::token::{self, DocComment, Nonterminal, Token};
 use syntax::tokenstream::TokenStream;
 
-use errors::{FatalError, PResult};
+use rustc_errors::{FatalError, PResult};
 use rustc_span::Span;
 use smallvec::{smallvec, SmallVec};
 
@@ -696,7 +696,7 @@ pub(super) fn parse(
                         if parser.token.span.is_dummy() {
                             parser.token.span
                         } else {
-                            sess.source_map().next_point(parser.token.span)
+                            parser.token.span.shrink_to_hi()
                         },
                     ),
                     "missing tokens in macro arguments",
index 6e965346d30e9bf7948bbebd0314317059f3568e..d72317af9eb67a956f89bf31f3e35f1fd7df0636 100644 (file)
@@ -8,6 +8,9 @@
 use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
 use crate::mbe::transcribe::transcribe;
 
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, DiagnosticBuilder, FatalError};
 use rustc_feature::Features;
 use rustc_parse::parser::Parser;
 use rustc_parse::Directory;
 use syntax::token::{self, NtTT, Token, TokenKind::*};
 use syntax::tokenstream::{DelimSpan, TokenStream};
 
-use errors::{DiagnosticBuilder, FatalError};
 use log::debug;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 use std::{mem, slice};
 
-use errors::Applicability;
-
 const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
                                         `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
                                         `literal`, `path`, `meta`, `tt`, `item` and `vis`";
index 4fd68a80de81d275f535f473d95c9beeefda4ce0..104a5233c9d8c193dee36a7be0d802b837b8ddc1 100644 (file)
@@ -2,19 +2,17 @@
 use crate::mbe;
 use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
 
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::pluralize;
+use rustc_span::hygiene::{ExpnId, Transparency};
+use rustc_span::Span;
 use syntax::ast::{Ident, Mac};
 use syntax::mut_visit::{self, MutVisitor};
 use syntax::token::{self, NtTT, Token};
 use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
 
 use smallvec::{smallvec, SmallVec};
-
-use errors::pluralize;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
-use rustc_span::hygiene::{ExpnId, Transparency};
-use rustc_span::Span;
-
 use std::mem;
 
 // A Marker adds the given mark to the syntax context.
index 835f0b0108ead65a52d83799f7b8b268b5ae6feb..2ef81d80a1412062b41d95f279327425f571057f 100644 (file)
@@ -1,4 +1,5 @@
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::{emitter::EmitterWriter, Handler};
 use rustc_parse::lexer::StringReader;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::symbol::Symbol;
@@ -8,7 +9,6 @@
 use syntax::util::comments::is_doc_comment;
 use syntax::with_default_globals;
 
-use errors::{emitter::EmitterWriter, Handler};
 use std::io;
 use std::path::PathBuf;
 
index 25cd5dabe57ec3e45adb304a2e0baa0952cde513..b79e2894126dd8d8954403c7713558f5d36270cb 100644 (file)
@@ -1,6 +1,6 @@
 use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse};
 
-use errors::PResult;
+use rustc_errors::PResult;
 use rustc_parse::new_parser_from_source_str;
 use rustc_span::source_map::FilePathMapping;
 use rustc_span::symbol::{kw, sym, Symbol};
index 25e2bbb34678e344ae26297e0a397b531fd50c75..cb6249e936976e8ba5399fd256a5ba8c657a22a5 100644 (file)
@@ -1,15 +1,14 @@
 use crate::base::{self, *};
 use crate::proc_macro_server;
 
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, FatalError};
 use rustc_span::symbol::sym;
+use rustc_span::{Span, DUMMY_SP};
 use syntax::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
-use syntax::errors::{Applicability, FatalError};
 use syntax::token;
 use syntax::tokenstream::{self, TokenStream};
 
-use rustc_data_structures::sync::Lrc;
-use rustc_span::{Span, DUMMY_SP};
-
 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
 
 pub struct BangProcMacro {
index cf5749f506856b065bfd9d0bf46bc594710dcdb6..d441613ac58f4f702ab46bd9b8af281fa053de00 100644 (file)
@@ -1,5 +1,7 @@
 use crate::base::ExtCtxt;
 
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::Diagnostic;
 use rustc_parse::lexer::nfc_normalize;
 use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -11,9 +13,6 @@
 use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
 use syntax::util::comments;
 
-use errors::Diagnostic;
-use rustc_data_structures::sync::Lrc;
-
 use pm::bridge::{server, TokenTree};
 use pm::{Delimiter, Level, LineColumn, Spacing};
 use std::ops::Bound;
@@ -265,13 +264,13 @@ fn to_internal(self) -> TokenStream {
     }
 }
 
-impl ToInternal<errors::Level> for Level {
-    fn to_internal(self) -> errors::Level {
+impl ToInternal<rustc_errors::Level> for Level {
+    fn to_internal(self) -> rustc_errors::Level {
         match self {
-            Level::Error => errors::Level::Error,
-            Level::Warning => errors::Level::Warning,
-            Level::Note => errors::Level::Note,
-            Level::Help => errors::Level::Help,
+            Level::Error => rustc_errors::Level::Error,
+            Level::Warning => rustc_errors::Level::Warning,
+            Level::Note => rustc_errors::Level::Note,
+            Level::Help => rustc_errors::Level::Help,
             _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
         }
     }
index 18dc605c9e754003e5564d7eeefa39cff919a473..82ab74ac1500493ee5040cc30d553e08e33e9a3f 100644 (file)
@@ -6,9 +6,9 @@
 use syntax::tokenstream::TokenStream;
 use syntax::with_default_globals;
 
-use errors::emitter::EmitterWriter;
-use errors::{Handler, PResult};
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::emitter::EmitterWriter;
+use rustc_errors::{Handler, PResult};
 
 use std::io;
 use std::io::prelude::*;
index 8cb1684491bb8a230e4a685390acb989d3ffb525..319cd88f24586e4d174264682a8d4d88bafd4001 100644 (file)
@@ -192,9 +192,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows using the `unadjusted` ABI; perma-unstable.
     (active, abi_unadjusted, "1.16.0", None, None),
 
-    /// Allows identifying crates that contain sanitizer runtimes.
-    (active, sanitizer_runtime, "1.17.0", None, None),
-
     /// Used to identify crates that contain the profiler runtime.
     (active, profiler_runtime, "1.18.0", None, None),
 
@@ -534,6 +531,9 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
     (active, cfg_sanitize, "1.41.0", Some(39699), None),
 
+    /// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
+    (active, half_open_range_patterns, "1.41.0", Some(67264), None),
+
     /// Allows using `&mut` in constant functions.
     (active, const_mut_refs, "1.41.0", Some(57349), None),
 
@@ -544,6 +544,12 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// For example, you can write `x @ Some(y)`.
     (active, bindings_after_at, "1.41.0", Some(65490), None),
 
+    /// Allows `impl const Trait for T` syntax.
+    (active, const_trait_impl, "1.42.0", Some(67792), None),
+
+    /// Allows `T: ?const Trait` syntax in bounds.
+    (active, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -559,4 +565,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     sym::or_patterns,
     sym::let_chains,
     sym::raw_dylib,
+    sym::const_trait_impl,
+    sym::const_trait_bound_opt_out,
 ];
index 3cbf96b6d29a18b4bac15a3d33e8ed5f1b5fdd86..a38726e3de81fad8a3e7ff5173de7513600785e7 100644 (file)
@@ -409,11 +409,6 @@ macro_rules! experimental {
         "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
         which contains compiler-rt intrinsics and will never be stable",
     ),
-    gated!(
-        sanitizer_runtime, Whitelisted, template!(Word),
-        "the `#[sanitizer_runtime]` attribute is used to identify crates that contain the runtime \
-        of a sanitizer and will never be stable",
-    ),
     gated!(
         profiler_runtime, Whitelisted, template!(Word),
         "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
index 71a464279253b12ef817d8f50159da82cd787ac7..01546f78257746cbaaeb8f4eb443ca266d116880 100644 (file)
@@ -1,7 +1,8 @@
 //! # Feature gates
 //!
 //! This crate declares the set of past and present unstable features in the compiler.
-//! Feature gate checking itself is done in `libsyntax/feature_gate/check.rs` at the moment.
+//! Feature gate checking itself is done in `librustc_ast_passes/feature_gate.rs`
+//! at the moment.
 //!
 //! Features are enabled in programs via the crate-level attributes of
 //! `#![feature(...)]` with a comma-separated list of features.
index 1eeedd77214167ca5e5b24eb9c66e5350a371dce..d5b6fe81c7be8af0091b2bd55cc16af77291fc37 100644 (file)
@@ -74,6 +74,8 @@ macro_rules! declare_features {
     (removed, pushpop_unsafe, "1.2.0", None, None, None),
     (removed, needs_allocator, "1.4.0", Some(27389), None,
      Some("subsumed by `#![feature(allocator_internals)]`")),
+    /// Allows identifying crates that contain sanitizer runtimes.
+    (removed, sanitizer_runtime, "1.17.0", None, None, None),
     (removed, proc_macro_mod, "1.27.0", Some(54727), None,
      Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
     (removed, proc_macro_expr, "1.27.0", Some(54727), None,
index 2303a85df4acfb56ee7e16b5e422d36dbedad54c..550e3654d0800965d890d96ea4850048272c3c9d 100644 (file)
@@ -905,7 +905,7 @@ pub enum PatKind<'hir> {
     Lit(&'hir Expr<'hir>),
 
     /// A range pattern (e.g., `1..=2` or `1..2`).
-    Range(&'hir Expr<'hir>, &'hir Expr<'hir>, RangeEnd),
+    Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd),
 
     /// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
     ///
@@ -1875,6 +1875,9 @@ pub enum ImplItemKind<'hir> {
     OpaqueTy(GenericBounds<'hir>),
 }
 
+// The name of the associated type for `Fn` return types.
+pub const FN_OUTPUT_NAME: Symbol = sym::Output;
+
 /// Bind a type to an associated type (i.e., `A = Foo`).
 ///
 /// Bindings like `A: Debug` are represented as a special type `A =
diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs
new file mode 100644 (file)
index 0000000..3dbc525
--- /dev/null
@@ -0,0 +1,1165 @@
+//! HIR walker for walking the contents of nodes.
+//!
+//! **For an overview of the visitor strategy, see the docs on the
+//! `super::itemlikevisit::ItemLikeVisitor` trait.**
+//!
+//! If you have decided to use this visitor, here are some general
+//! notes on how to do so:
+//!
+//! Each overridden visit method has full control over what
+//! happens with its node, it can do its own traversal of the node's children,
+//! call `intravisit::walk_*` to apply the default traversal algorithm, or prevent
+//! deeper traversal by doing nothing.
+//!
+//! When visiting the HIR, the contents of nested items are NOT visited
+//! by default. This is different from the AST visitor, which does a deep walk.
+//! Hence this module is called `intravisit`; see the method `visit_nested_item`
+//! for more details.
+//!
+//! Note: it is an important invariant that the default visitor walks
+//! the body of a function in "execution order" - more concretely, if
+//! we consider the reverse post-order (RPO) of the CFG implied by the HIR,
+//! then a pre-order traversal of the HIR is consistent with the CFG RPO
+//! on the *initial CFG point* of each HIR node, while a post-order traversal
+//! of the HIR is consistent with the CFG RPO on each *final CFG point* of
+//! each CFG node.
+//!
+//! One thing that follows is that if HIR node A always starts/ends executing
+//! before HIR node B, then A appears in traversal pre/postorder before B,
+//! respectively. (This follows from RPO respecting CFG domination).
+//!
+//! This order consistency is required in a few places in rustc, for
+//! example generator inference, and possibly also HIR borrowck.
+
+use crate::hir::*;
+use crate::hir_id::CRATE_HIR_ID;
+use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
+use rustc_span::Span;
+use syntax::ast::{Attribute, Ident, Label, Name};
+use syntax::walk_list;
+
+pub struct DeepVisitor<'v, V> {
+    visitor: &'v mut V,
+}
+
+impl<'v, V> DeepVisitor<'v, V> {
+    pub fn new(base: &'v mut V) -> Self {
+        DeepVisitor { visitor: base }
+    }
+}
+
+impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
+where
+    V: Visitor<'hir>,
+{
+    fn visit_item(&mut self, item: &'hir Item<'hir>) {
+        self.visitor.visit_item(item);
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>) {
+        self.visitor.visit_trait_item(trait_item);
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) {
+        self.visitor.visit_impl_item(impl_item);
+    }
+}
+
+pub trait IntoVisitor<'hir> {
+    type Visitor: Visitor<'hir>;
+    fn into_visitor(&self) -> Self::Visitor;
+}
+
+pub struct ParDeepVisitor<V>(pub V);
+
+impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor<V>
+where
+    V: IntoVisitor<'hir>,
+{
+    fn visit_item(&self, item: &'hir Item<'hir>) {
+        self.0.into_visitor().visit_item(item);
+    }
+
+    fn visit_trait_item(&self, trait_item: &'hir TraitItem<'hir>) {
+        self.0.into_visitor().visit_trait_item(trait_item);
+    }
+
+    fn visit_impl_item(&self, impl_item: &'hir ImplItem<'hir>) {
+        self.0.into_visitor().visit_impl_item(impl_item);
+    }
+}
+
+#[derive(Copy, Clone)]
+pub enum FnKind<'a> {
+    /// `#[xxx] pub async/const/extern "Abi" fn foo()`
+    ItemFn(Ident, &'a Generics<'a>, FnHeader, &'a Visibility<'a>, &'a [Attribute]),
+
+    /// `fn foo(&self)`
+    Method(Ident, &'a FnSig<'a>, Option<&'a Visibility<'a>>, &'a [Attribute]),
+
+    /// `|x, y| {}`
+    Closure(&'a [Attribute]),
+}
+
+impl<'a> FnKind<'a> {
+    pub fn attrs(&self) -> &'a [Attribute] {
+        match *self {
+            FnKind::ItemFn(.., attrs) => attrs,
+            FnKind::Method(.., attrs) => attrs,
+            FnKind::Closure(attrs) => attrs,
+        }
+    }
+
+    pub fn header(&self) -> Option<&FnHeader> {
+        match *self {
+            FnKind::ItemFn(_, _, ref header, _, _) => Some(header),
+            FnKind::Method(_, ref sig, _, _) => Some(&sig.header),
+            FnKind::Closure(_) => None,
+        }
+    }
+}
+
+/// An abstract representation of the HIR `rustc::hir::map::Map`.
+pub trait Map<'hir> {
+    fn body(&self, id: BodyId) -> &'hir Body<'hir>;
+    fn item(&self, id: HirId) -> &'hir Item<'hir>;
+    fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
+    fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>;
+}
+
+/// Specifies what nested things a visitor wants to visit. The most
+/// common choice is `OnlyBodies`, which will cause the visitor to
+/// visit fn bodies for fns that it encounters, but skip over nested
+/// item-like things.
+///
+/// See the comments on `ItemLikeVisitor` for more details on the overall
+/// visit strategy.
+pub enum NestedVisitorMap<'this, M> {
+    /// Do not visit any nested things. When you add a new
+    /// "non-nested" thing, you will want to audit such uses to see if
+    /// they remain valid.
+    ///
+    /// Use this if you are only walking some particular kind of tree
+    /// (i.e., a type, or fn signature) and you don't want to thread a
+    /// HIR map around.
+    None,
+
+    /// Do not visit nested item-like things, but visit nested things
+    /// that are inside of an item-like.
+    ///
+    /// **This is the most common choice.** A very common pattern is
+    /// to use `visit_all_item_likes()` as an outer loop,
+    /// and to have the visitor that visits the contents of each item
+    /// using this setting.
+    OnlyBodies(&'this M),
+
+    /// Visits all nested things, including item-likes.
+    ///
+    /// **This is an unusual choice.** It is used when you want to
+    /// process everything within their lexical context. Typically you
+    /// kick off the visit by doing `walk_krate()`.
+    All(&'this M),
+}
+
+impl<'this, M> NestedVisitorMap<'this, M> {
+    /// Returns the map to use for an "intra item-like" thing (if any).
+    /// E.g., function body.
+    fn intra(self) -> Option<&'this M> {
+        match self {
+            NestedVisitorMap::None => None,
+            NestedVisitorMap::OnlyBodies(map) => Some(map),
+            NestedVisitorMap::All(map) => Some(map),
+        }
+    }
+
+    /// Returns the map to use for an "item-like" thing (if any).
+    /// E.g., item, impl-item.
+    fn inter(self) -> Option<&'this M> {
+        match self {
+            NestedVisitorMap::None => None,
+            NestedVisitorMap::OnlyBodies(_) => None,
+            NestedVisitorMap::All(map) => Some(map),
+        }
+    }
+}
+
+/// Each method of the Visitor trait is a hook to be potentially
+/// overridden. Each method's default implementation recursively visits
+/// the substructure of the input via the corresponding `walk` method;
+/// e.g., the `visit_mod` method by default calls `intravisit::walk_mod`.
+///
+/// Note that this visitor does NOT visit nested items by default
+/// (this is why the module is called `intravisit`, to distinguish it
+/// from the AST's `visit` module, which acts differently). If you
+/// simply want to visit all items in the crate in some order, you
+/// should call `Crate::visit_all_items`. Otherwise, see the comment
+/// on `visit_nested_item` for details on how to visit nested items.
+///
+/// If you want to ensure that your code handles every variant
+/// explicitly, you need to override each method. (And you also need
+/// to monitor future changes to `Visitor` in case a new method with a
+/// new default implementation gets introduced.)
+pub trait Visitor<'v>: Sized {
+    type Map: Map<'v>;
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Nested items.
+
+    /// The default versions of the `visit_nested_XXX` routines invoke
+    /// this method to get a map to use. By selecting an enum variant,
+    /// you control which kinds of nested HIR are visited; see
+    /// `NestedVisitorMap` for details. By "nested HIR", we are
+    /// referring to bits of HIR that are not directly embedded within
+    /// one another but rather indirectly, through a table in the
+    /// crate. This is done to control dependencies during incremental
+    /// compilation: the non-inline bits of HIR can be tracked and
+    /// hashed separately.
+    ///
+    /// **If for some reason you want the nested behavior, but don't
+    /// have a `Map` at your disposal:** then you should override the
+    /// `visit_nested_XXX` methods, and override this method to
+    /// `panic!()`. This way, if a new `visit_nested_XXX` variant is
+    /// added in the future, we will see the panic in your code and
+    /// fix it appropriately.
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map>;
+
+    /// Invoked when a nested item is encountered. By default does
+    /// nothing unless you override `nested_visit_map` to return other than
+    /// `None`, in which case it will walk the item. **You probably
+    /// don't want to override this method** -- instead, override
+    /// `nested_visit_map` or use the "shallow" or "deep" visit
+    /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only
+    /// reason to override this method is if you want a nested pattern
+    /// but cannot supply a `Map`; see `nested_visit_map` for advice.
+    #[allow(unused_variables)]
+    fn visit_nested_item(&mut self, id: ItemId) {
+        let opt_item = self.nested_visit_map().inter().map(|map| map.item(id.id));
+        walk_list!(self, visit_item, opt_item);
+    }
+
+    /// Like `visit_nested_item()`, but for trait items. See
+    /// `visit_nested_item()` for advice on when to override this
+    /// method.
+    #[allow(unused_variables)]
+    fn visit_nested_trait_item(&mut self, id: TraitItemId) {
+        let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
+        walk_list!(self, visit_trait_item, opt_item);
+    }
+
+    /// Like `visit_nested_item()`, but for impl items. See
+    /// `visit_nested_item()` for advice on when to override this
+    /// method.
+    #[allow(unused_variables)]
+    fn visit_nested_impl_item(&mut self, id: ImplItemId) {
+        let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id));
+        walk_list!(self, visit_impl_item, opt_item);
+    }
+
+    /// Invoked to visit the body of a function, method or closure. Like
+    /// visit_nested_item, does nothing by default unless you override
+    /// `nested_visit_map` to return other than `None`, in which case it will walk
+    /// the body.
+    fn visit_nested_body(&mut self, id: BodyId) {
+        let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
+        walk_list!(self, visit_body, opt_body);
+    }
+
+    fn visit_param(&mut self, param: &'v Param<'v>) {
+        walk_param(self, param)
+    }
+
+    /// Visits the top-level item and (optionally) nested items / impl items. See
+    /// `visit_nested_item` for details.
+    fn visit_item(&mut self, i: &'v Item<'v>) {
+        walk_item(self, i)
+    }
+
+    fn visit_body(&mut self, b: &'v Body<'v>) {
+        walk_body(self, b);
+    }
+
+    /// When invoking `visit_all_item_likes()`, you need to supply an
+    /// item-like visitor. This method converts a "intra-visit"
+    /// visitor into an item-like visitor that walks the entire tree.
+    /// If you use this, you probably don't want to process the
+    /// contents of nested item-like things, since the outer loop will
+    /// visit them as well.
+    fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> {
+        DeepVisitor::new(self)
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    fn visit_id(&mut self, _hir_id: HirId) {
+        // Nothing to do.
+    }
+    fn visit_name(&mut self, _span: Span, _name: Name) {
+        // Nothing to do.
+    }
+    fn visit_ident(&mut self, ident: Ident) {
+        walk_ident(self, ident)
+    }
+    fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) {
+        walk_mod(self, m, n)
+    }
+    fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) {
+        walk_foreign_item(self, i)
+    }
+    fn visit_local(&mut self, l: &'v Local<'v>) {
+        walk_local(self, l)
+    }
+    fn visit_block(&mut self, b: &'v Block<'v>) {
+        walk_block(self, b)
+    }
+    fn visit_stmt(&mut self, s: &'v Stmt<'v>) {
+        walk_stmt(self, s)
+    }
+    fn visit_arm(&mut self, a: &'v Arm<'v>) {
+        walk_arm(self, a)
+    }
+    fn visit_pat(&mut self, p: &'v Pat<'v>) {
+        walk_pat(self, p)
+    }
+    fn visit_anon_const(&mut self, c: &'v AnonConst) {
+        walk_anon_const(self, c)
+    }
+    fn visit_expr(&mut self, ex: &'v Expr<'v>) {
+        walk_expr(self, ex)
+    }
+    fn visit_ty(&mut self, t: &'v Ty<'v>) {
+        walk_ty(self, t)
+    }
+    fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) {
+        walk_generic_param(self, p)
+    }
+    fn visit_generics(&mut self, g: &'v Generics<'v>) {
+        walk_generics(self, g)
+    }
+    fn visit_where_predicate(&mut self, predicate: &'v WherePredicate<'v>) {
+        walk_where_predicate(self, predicate)
+    }
+    fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) {
+        walk_fn_decl(self, fd)
+    }
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, s: Span, id: HirId) {
+        walk_fn(self, fk, fd, b, s, id)
+    }
+    fn visit_use(&mut self, path: &'v Path<'v>, hir_id: HirId) {
+        walk_use(self, path, hir_id)
+    }
+    fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) {
+        walk_trait_item(self, ti)
+    }
+    fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) {
+        walk_trait_item_ref(self, ii)
+    }
+    fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) {
+        walk_impl_item(self, ii)
+    }
+    fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef<'v>) {
+        walk_impl_item_ref(self, ii)
+    }
+    fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) {
+        walk_trait_ref(self, t)
+    }
+    fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) {
+        walk_param_bound(self, bounds)
+    }
+    fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>, m: TraitBoundModifier) {
+        walk_poly_trait_ref(self, t, m)
+    }
+    fn visit_variant_data(
+        &mut self,
+        s: &'v VariantData<'v>,
+        _: Name,
+        _: &'v Generics<'v>,
+        _parent_id: HirId,
+        _: Span,
+    ) {
+        walk_struct_def(self, s)
+    }
+    fn visit_struct_field(&mut self, s: &'v StructField<'v>) {
+        walk_struct_field(self, s)
+    }
+    fn visit_enum_def(
+        &mut self,
+        enum_definition: &'v EnumDef<'v>,
+        generics: &'v Generics<'v>,
+        item_id: HirId,
+        _: Span,
+    ) {
+        walk_enum_def(self, enum_definition, generics, item_id)
+    }
+    fn visit_variant(&mut self, v: &'v Variant<'v>, g: &'v Generics<'v>, item_id: HirId) {
+        walk_variant(self, v, g, item_id)
+    }
+    fn visit_label(&mut self, label: &'v Label) {
+        walk_label(self, label)
+    }
+    fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) {
+        match generic_arg {
+            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
+            GenericArg::Type(ty) => self.visit_ty(ty),
+            GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
+        }
+    }
+    fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
+        walk_lifetime(self, lifetime)
+    }
+    fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, span: Span) {
+        walk_qpath(self, qpath, id, span)
+    }
+    fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) {
+        walk_path(self, path)
+    }
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment<'v>) {
+        walk_path_segment(self, path_span, path_segment)
+    }
+    fn visit_generic_args(&mut self, path_span: Span, generic_args: &'v GenericArgs<'v>) {
+        walk_generic_args(self, path_span, generic_args)
+    }
+    fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding<'v>) {
+        walk_assoc_type_binding(self, type_binding)
+    }
+    fn visit_attribute(&mut self, _attr: &'v Attribute) {}
+    fn visit_macro_def(&mut self, macro_def: &'v MacroDef<'v>) {
+        walk_macro_def(self, macro_def)
+    }
+    fn visit_vis(&mut self, vis: &'v Visibility<'v>) {
+        walk_vis(self, vis)
+    }
+    fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) {
+        walk_associated_item_kind(self, kind);
+    }
+    fn visit_defaultness(&mut self, defaultness: &'v Defaultness) {
+        walk_defaultness(self, defaultness);
+    }
+}
+
+/// Walks the contents of a crate. See also `Crate::visit_all_items`.
+pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) {
+    visitor.visit_mod(&krate.module, krate.span, CRATE_HIR_ID);
+    walk_list!(visitor, visit_attribute, krate.attrs);
+    walk_list!(visitor, visit_macro_def, krate.exported_macros);
+}
+
+pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef<'v>) {
+    visitor.visit_id(macro_def.hir_id);
+    visitor.visit_name(macro_def.span, macro_def.name);
+    walk_list!(visitor, visit_attribute, macro_def.attrs);
+}
+
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
+    visitor.visit_id(mod_hir_id);
+    for &item_id in module.item_ids {
+        visitor.visit_nested_item(item_id);
+    }
+}
+
+pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
+    walk_list!(visitor, visit_param, body.params);
+    visitor.visit_expr(&body.value);
+}
+
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
+    // Intentionally visiting the expr first - the initialization expr
+    // dominates the local's definition.
+    walk_list!(visitor, visit_expr, &local.init);
+    walk_list!(visitor, visit_attribute, local.attrs.iter());
+    visitor.visit_id(local.hir_id);
+    visitor.visit_pat(&local.pat);
+    walk_list!(visitor, visit_ty, &local.ty);
+}
+
+pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) {
+    visitor.visit_name(ident.span, ident.name);
+}
+
+pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
+    visitor.visit_ident(label.ident);
+}
+
+pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
+    visitor.visit_id(lifetime.hir_id);
+    match lifetime.name {
+        LifetimeName::Param(ParamName::Plain(ident)) => {
+            visitor.visit_ident(ident);
+        }
+        LifetimeName::Param(ParamName::Fresh(_))
+        | LifetimeName::Param(ParamName::Error)
+        | LifetimeName::Static
+        | LifetimeName::Error
+        | LifetimeName::Implicit
+        | LifetimeName::ImplicitObjectLifetimeDefault
+        | LifetimeName::Underscore => {}
+    }
+}
+
+pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    trait_ref: &'v PolyTraitRef<'v>,
+    _modifier: TraitBoundModifier,
+) {
+    walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
+    visitor.visit_trait_ref(&trait_ref.trait_ref);
+}
+
+pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) {
+    visitor.visit_id(trait_ref.hir_ref_id);
+    visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
+}
+
+pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) {
+    visitor.visit_id(param.hir_id);
+    visitor.visit_pat(&param.pat);
+    walk_list!(visitor, visit_attribute, param.attrs);
+}
+
+pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
+    visitor.visit_vis(&item.vis);
+    visitor.visit_ident(item.ident);
+    match item.kind {
+        ItemKind::ExternCrate(orig_name) => {
+            visitor.visit_id(item.hir_id);
+            if let Some(orig_name) = orig_name {
+                visitor.visit_name(item.span, orig_name);
+            }
+        }
+        ItemKind::Use(ref path, _) => {
+            visitor.visit_use(path, item.hir_id);
+        }
+        ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => {
+            visitor.visit_id(item.hir_id);
+            visitor.visit_ty(typ);
+            visitor.visit_nested_body(body);
+        }
+        ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn(
+            FnKind::ItemFn(item.ident, generics, sig.header, &item.vis, &item.attrs),
+            &sig.decl,
+            body_id,
+            item.span,
+            item.hir_id,
+        ),
+        ItemKind::Mod(ref module) => {
+            // `visit_mod()` takes care of visiting the `Item`'s `HirId`.
+            visitor.visit_mod(module, item.span, item.hir_id)
+        }
+        ItemKind::ForeignMod(ref foreign_module) => {
+            visitor.visit_id(item.hir_id);
+            walk_list!(visitor, visit_foreign_item, foreign_module.items);
+        }
+        ItemKind::GlobalAsm(_) => {
+            visitor.visit_id(item.hir_id);
+        }
+        ItemKind::TyAlias(ref ty, ref generics) => {
+            visitor.visit_id(item.hir_id);
+            visitor.visit_ty(ty);
+            visitor.visit_generics(generics)
+        }
+        ItemKind::OpaqueTy(OpaqueTy { ref generics, bounds, .. }) => {
+            visitor.visit_id(item.hir_id);
+            walk_generics(visitor, generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+        ItemKind::Enum(ref enum_definition, ref generics) => {
+            visitor.visit_generics(generics);
+            // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
+            visitor.visit_enum_def(enum_definition, generics, item.hir_id, item.span)
+        }
+        ItemKind::Impl(.., ref generics, ref opt_trait_reference, ref typ, impl_item_refs) => {
+            visitor.visit_id(item.hir_id);
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_trait_ref, opt_trait_reference);
+            visitor.visit_ty(typ);
+            walk_list!(visitor, visit_impl_item_ref, impl_item_refs);
+        }
+        ItemKind::Struct(ref struct_definition, ref generics)
+        | ItemKind::Union(ref struct_definition, ref generics) => {
+            visitor.visit_generics(generics);
+            visitor.visit_id(item.hir_id);
+            visitor.visit_variant_data(
+                struct_definition,
+                item.ident.name,
+                generics,
+                item.hir_id,
+                item.span,
+            );
+        }
+        ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
+            visitor.visit_id(item.hir_id);
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
+        }
+        ItemKind::TraitAlias(ref generics, bounds) => {
+            visitor.visit_id(item.hir_id);
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+    }
+    walk_list!(visitor, visit_attribute, item.attrs);
+}
+
+pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
+    visitor.visit_id(hir_id);
+    visitor.visit_path(path, hir_id);
+}
+
+pub fn walk_enum_def<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    enum_definition: &'v EnumDef<'v>,
+    generics: &'v Generics<'v>,
+    item_id: HirId,
+) {
+    visitor.visit_id(item_id);
+    walk_list!(visitor, visit_variant, enum_definition.variants, generics, item_id);
+}
+
+pub fn walk_variant<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    variant: &'v Variant<'v>,
+    generics: &'v Generics<'v>,
+    parent_item_id: HirId,
+) {
+    visitor.visit_ident(variant.ident);
+    visitor.visit_id(variant.id);
+    visitor.visit_variant_data(
+        &variant.data,
+        variant.ident.name,
+        generics,
+        parent_item_id,
+        variant.span,
+    );
+    walk_list!(visitor, visit_anon_const, &variant.disr_expr);
+    walk_list!(visitor, visit_attribute, variant.attrs);
+}
+
+pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
+    visitor.visit_id(typ.hir_id);
+
+    match typ.kind {
+        TyKind::Slice(ref ty) => visitor.visit_ty(ty),
+        TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
+        TyKind::Rptr(ref lifetime, ref mutable_type) => {
+            visitor.visit_lifetime(lifetime);
+            visitor.visit_ty(&mutable_type.ty)
+        }
+        TyKind::Never => {}
+        TyKind::Tup(tuple_element_types) => {
+            walk_list!(visitor, visit_ty, tuple_element_types);
+        }
+        TyKind::BareFn(ref function_declaration) => {
+            walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
+            visitor.visit_fn_decl(&function_declaration.decl);
+        }
+        TyKind::Path(ref qpath) => {
+            visitor.visit_qpath(qpath, typ.hir_id, typ.span);
+        }
+        TyKind::Def(item_id, lifetimes) => {
+            visitor.visit_nested_item(item_id);
+            walk_list!(visitor, visit_generic_arg, lifetimes);
+        }
+        TyKind::Array(ref ty, ref length) => {
+            visitor.visit_ty(ty);
+            visitor.visit_anon_const(length)
+        }
+        TyKind::TraitObject(bounds, ref lifetime) => {
+            for bound in bounds {
+                visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None);
+            }
+            visitor.visit_lifetime(lifetime);
+        }
+        TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
+        TyKind::Infer | TyKind::Err => {}
+    }
+}
+
+pub fn walk_qpath<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    qpath: &'v QPath<'v>,
+    id: HirId,
+    span: Span,
+) {
+    match *qpath {
+        QPath::Resolved(ref maybe_qself, ref path) => {
+            walk_list!(visitor, visit_ty, maybe_qself);
+            visitor.visit_path(path, id)
+        }
+        QPath::TypeRelative(ref qself, ref segment) => {
+            visitor.visit_ty(qself);
+            visitor.visit_path_segment(span, segment);
+        }
+    }
+}
+
+pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) {
+    for segment in path.segments {
+        visitor.visit_path_segment(path.span, segment);
+    }
+}
+
+pub fn walk_path_segment<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    path_span: Span,
+    segment: &'v PathSegment<'v>,
+) {
+    visitor.visit_ident(segment.ident);
+    walk_list!(visitor, visit_id, segment.hir_id);
+    if let Some(ref args) = segment.args {
+        visitor.visit_generic_args(path_span, args);
+    }
+}
+
+pub fn walk_generic_args<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    _path_span: Span,
+    generic_args: &'v GenericArgs<'v>,
+) {
+    walk_list!(visitor, visit_generic_arg, generic_args.args);
+    walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings);
+}
+
+pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    type_binding: &'v TypeBinding<'v>,
+) {
+    visitor.visit_id(type_binding.hir_id);
+    visitor.visit_ident(type_binding.ident);
+    match type_binding.kind {
+        TypeBindingKind::Equality { ref ty } => {
+            visitor.visit_ty(ty);
+        }
+        TypeBindingKind::Constraint { bounds } => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+    }
+}
+
+pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
+    visitor.visit_id(pattern.hir_id);
+    match pattern.kind {
+        PatKind::TupleStruct(ref qpath, children, _) => {
+            visitor.visit_qpath(qpath, pattern.hir_id, pattern.span);
+            walk_list!(visitor, visit_pat, children);
+        }
+        PatKind::Path(ref qpath) => {
+            visitor.visit_qpath(qpath, pattern.hir_id, pattern.span);
+        }
+        PatKind::Struct(ref qpath, fields, _) => {
+            visitor.visit_qpath(qpath, pattern.hir_id, pattern.span);
+            for field in fields {
+                visitor.visit_id(field.hir_id);
+                visitor.visit_ident(field.ident);
+                visitor.visit_pat(&field.pat)
+            }
+        }
+        PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats),
+        PatKind::Tuple(tuple_elements, _) => {
+            walk_list!(visitor, visit_pat, tuple_elements);
+        }
+        PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) => {
+            visitor.visit_pat(subpattern)
+        }
+        PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
+            visitor.visit_ident(ident);
+            walk_list!(visitor, visit_pat, optional_subpattern);
+        }
+        PatKind::Lit(ref expression) => visitor.visit_expr(expression),
+        PatKind::Range(ref lower_bound, ref upper_bound, _) => {
+            walk_list!(visitor, visit_expr, lower_bound);
+            walk_list!(visitor, visit_expr, upper_bound);
+        }
+        PatKind::Wild => (),
+        PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
+            walk_list!(visitor, visit_pat, prepatterns);
+            walk_list!(visitor, visit_pat, slice_pattern);
+            walk_list!(visitor, visit_pat, postpatterns);
+        }
+    }
+}
+
+pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
+    visitor.visit_id(foreign_item.hir_id);
+    visitor.visit_vis(&foreign_item.vis);
+    visitor.visit_ident(foreign_item.ident);
+
+    match foreign_item.kind {
+        ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => {
+            visitor.visit_generics(generics);
+            visitor.visit_fn_decl(function_declaration);
+            for &param_name in param_names {
+                visitor.visit_ident(param_name);
+            }
+        }
+        ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
+        ForeignItemKind::Type => (),
+    }
+
+    walk_list!(visitor, visit_attribute, foreign_item.attrs);
+}
+
+pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) {
+    match *bound {
+        GenericBound::Trait(ref typ, modifier) => {
+            visitor.visit_poly_trait_ref(typ, modifier);
+        }
+        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+    }
+}
+
+pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam<'v>) {
+    visitor.visit_id(param.hir_id);
+    walk_list!(visitor, visit_attribute, param.attrs);
+    match param.name {
+        ParamName::Plain(ident) => visitor.visit_ident(ident),
+        ParamName::Error | ParamName::Fresh(_) => {}
+    }
+    match param.kind {
+        GenericParamKind::Lifetime { .. } => {}
+        GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
+        GenericParamKind::Const { ref ty } => visitor.visit_ty(ty),
+    }
+    walk_list!(visitor, visit_param_bound, param.bounds);
+}
+
+pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) {
+    walk_list!(visitor, visit_generic_param, generics.params);
+    walk_list!(visitor, visit_where_predicate, generics.where_clause.predicates);
+}
+
+pub fn walk_where_predicate<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    predicate: &'v WherePredicate<'v>,
+) {
+    match predicate {
+        &WherePredicate::BoundPredicate(WhereBoundPredicate {
+            ref bounded_ty,
+            bounds,
+            bound_generic_params,
+            ..
+        }) => {
+            visitor.visit_ty(bounded_ty);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_generic_param, bound_generic_params);
+        }
+        &WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, bounds, .. }) => {
+            visitor.visit_lifetime(lifetime);
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+        &WherePredicate::EqPredicate(WhereEqPredicate {
+            hir_id, ref lhs_ty, ref rhs_ty, ..
+        }) => {
+            visitor.visit_id(hir_id);
+            visitor.visit_ty(lhs_ty);
+            visitor.visit_ty(rhs_ty);
+        }
+    }
+}
+
+pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy<'v>) {
+    if let FunctionRetTy::Return(ref output_ty) = *ret_ty {
+        visitor.visit_ty(output_ty)
+    }
+}
+
+pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl<'v>) {
+    for ty in function_declaration.inputs {
+        visitor.visit_ty(ty)
+    }
+    walk_fn_ret_ty(visitor, &function_declaration.output)
+}
+
+pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
+    match function_kind {
+        FnKind::ItemFn(_, generics, ..) => {
+            visitor.visit_generics(generics);
+        }
+        FnKind::Method(..) | FnKind::Closure(_) => {}
+    }
+}
+
+pub fn walk_fn<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    function_kind: FnKind<'v>,
+    function_declaration: &'v FnDecl<'v>,
+    body_id: BodyId,
+    _span: Span,
+    id: HirId,
+) {
+    visitor.visit_id(id);
+    visitor.visit_fn_decl(function_declaration);
+    walk_fn_kind(visitor, function_kind);
+    visitor.visit_nested_body(body_id)
+}
+
+pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
+    visitor.visit_ident(trait_item.ident);
+    walk_list!(visitor, visit_attribute, trait_item.attrs);
+    visitor.visit_generics(&trait_item.generics);
+    match trait_item.kind {
+        TraitItemKind::Const(ref ty, default) => {
+            visitor.visit_id(trait_item.hir_id);
+            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_nested_body, default);
+        }
+        TraitItemKind::Method(ref sig, TraitMethod::Required(param_names)) => {
+            visitor.visit_id(trait_item.hir_id);
+            visitor.visit_fn_decl(&sig.decl);
+            for &param_name in param_names {
+                visitor.visit_ident(param_name);
+            }
+        }
+        TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => {
+            visitor.visit_fn(
+                FnKind::Method(trait_item.ident, sig, None, &trait_item.attrs),
+                &sig.decl,
+                body_id,
+                trait_item.span,
+                trait_item.hir_id,
+            );
+        }
+        TraitItemKind::Type(bounds, ref default) => {
+            visitor.visit_id(trait_item.hir_id);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_ty, default);
+        }
+    }
+}
+
+pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
+    // N.B., deliberately force a compilation error if/when new fields are added.
+    let TraitItemRef { id, ident, ref kind, span: _, ref defaultness } = *trait_item_ref;
+    visitor.visit_nested_trait_item(id);
+    visitor.visit_ident(ident);
+    visitor.visit_associated_item_kind(kind);
+    visitor.visit_defaultness(defaultness);
+}
+
+pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
+    // N.B., deliberately force a compilation error if/when new fields are added.
+    let ImplItem {
+        hir_id: _,
+        ident,
+        ref vis,
+        ref defaultness,
+        attrs,
+        ref generics,
+        ref kind,
+        span: _,
+    } = *impl_item;
+
+    visitor.visit_ident(ident);
+    visitor.visit_vis(vis);
+    visitor.visit_defaultness(defaultness);
+    walk_list!(visitor, visit_attribute, attrs);
+    visitor.visit_generics(generics);
+    match *kind {
+        ImplItemKind::Const(ref ty, body) => {
+            visitor.visit_id(impl_item.hir_id);
+            visitor.visit_ty(ty);
+            visitor.visit_nested_body(body);
+        }
+        ImplItemKind::Method(ref sig, body_id) => {
+            visitor.visit_fn(
+                FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), &impl_item.attrs),
+                &sig.decl,
+                body_id,
+                impl_item.span,
+                impl_item.hir_id,
+            );
+        }
+        ImplItemKind::TyAlias(ref ty) => {
+            visitor.visit_id(impl_item.hir_id);
+            visitor.visit_ty(ty);
+        }
+        ImplItemKind::OpaqueTy(bounds) => {
+            visitor.visit_id(impl_item.hir_id);
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+    }
+}
+
+pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef<'v>) {
+    // N.B., deliberately force a compilation error if/when new fields are added.
+    let ImplItemRef { id, ident, ref kind, span: _, ref vis, ref defaultness } = *impl_item_ref;
+    visitor.visit_nested_impl_item(id);
+    visitor.visit_ident(ident);
+    visitor.visit_associated_item_kind(kind);
+    visitor.visit_vis(vis);
+    visitor.visit_defaultness(defaultness);
+}
+
+pub fn walk_struct_def<'v, V: Visitor<'v>>(
+    visitor: &mut V,
+    struct_definition: &'v VariantData<'v>,
+) {
+    walk_list!(visitor, visit_id, struct_definition.ctor_hir_id());
+    walk_list!(visitor, visit_struct_field, struct_definition.fields());
+}
+
+pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField<'v>) {
+    visitor.visit_id(struct_field.hir_id);
+    visitor.visit_vis(&struct_field.vis);
+    visitor.visit_ident(struct_field.ident);
+    visitor.visit_ty(&struct_field.ty);
+    walk_list!(visitor, visit_attribute, struct_field.attrs);
+}
+
+pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
+    visitor.visit_id(block.hir_id);
+    walk_list!(visitor, visit_stmt, block.stmts);
+    walk_list!(visitor, visit_expr, &block.expr);
+}
+
+pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
+    visitor.visit_id(statement.hir_id);
+    match statement.kind {
+        StmtKind::Local(ref local) => visitor.visit_local(local),
+        StmtKind::Item(item) => visitor.visit_nested_item(item),
+        StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
+            visitor.visit_expr(expression)
+        }
+    }
+}
+
+pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
+    visitor.visit_id(constant.hir_id);
+    visitor.visit_nested_body(constant.body);
+}
+
+pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
+    visitor.visit_id(expression.hir_id);
+    walk_list!(visitor, visit_attribute, expression.attrs.iter());
+    match expression.kind {
+        ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
+        ExprKind::Array(subexpressions) => {
+            walk_list!(visitor, visit_expr, subexpressions);
+        }
+        ExprKind::Repeat(ref element, ref count) => {
+            visitor.visit_expr(element);
+            visitor.visit_anon_const(count)
+        }
+        ExprKind::Struct(ref qpath, fields, ref optional_base) => {
+            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
+            for field in fields {
+                visitor.visit_id(field.hir_id);
+                visitor.visit_ident(field.ident);
+                visitor.visit_expr(&field.expr)
+            }
+            walk_list!(visitor, visit_expr, optional_base);
+        }
+        ExprKind::Tup(subexpressions) => {
+            walk_list!(visitor, visit_expr, subexpressions);
+        }
+        ExprKind::Call(ref callee_expression, arguments) => {
+            visitor.visit_expr(callee_expression);
+            walk_list!(visitor, visit_expr, arguments);
+        }
+        ExprKind::MethodCall(ref segment, _, arguments) => {
+            visitor.visit_path_segment(expression.span, segment);
+            walk_list!(visitor, visit_expr, arguments);
+        }
+        ExprKind::Binary(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(left_expression);
+            visitor.visit_expr(right_expression)
+        }
+        ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
+            visitor.visit_expr(subexpression)
+        }
+        ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_ty(typ)
+        }
+        ExprKind::DropTemps(ref subexpression) => {
+            visitor.visit_expr(subexpression);
+        }
+        ExprKind::Loop(ref block, ref opt_label, _) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_block(block);
+        }
+        ExprKind::Match(ref subexpression, arms, _) => {
+            visitor.visit_expr(subexpression);
+            walk_list!(visitor, visit_arm, arms);
+        }
+        ExprKind::Closure(_, ref function_declaration, body, _fn_decl_span, _gen) => visitor
+            .visit_fn(
+                FnKind::Closure(&expression.attrs),
+                function_declaration,
+                body,
+                expression.span,
+                expression.hir_id,
+            ),
+        ExprKind::Block(ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_block(block);
+        }
+        ExprKind::Assign(ref lhs, ref rhs, _) => {
+            visitor.visit_expr(rhs);
+            visitor.visit_expr(lhs)
+        }
+        ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(right_expression);
+            visitor.visit_expr(left_expression);
+        }
+        ExprKind::Field(ref subexpression, ident) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_ident(ident);
+        }
+        ExprKind::Index(ref main_expression, ref index_expression) => {
+            visitor.visit_expr(main_expression);
+            visitor.visit_expr(index_expression)
+        }
+        ExprKind::Path(ref qpath) => {
+            visitor.visit_qpath(qpath, expression.hir_id, expression.span);
+        }
+        ExprKind::Break(ref destination, ref opt_expr) => {
+            walk_list!(visitor, visit_label, &destination.label);
+            walk_list!(visitor, visit_expr, opt_expr);
+        }
+        ExprKind::Continue(ref destination) => {
+            walk_list!(visitor, visit_label, &destination.label);
+        }
+        ExprKind::Ret(ref optional_expression) => {
+            walk_list!(visitor, visit_expr, optional_expression);
+        }
+        ExprKind::InlineAsm(ref asm) => {
+            walk_list!(visitor, visit_expr, asm.outputs_exprs);
+            walk_list!(visitor, visit_expr, asm.inputs_exprs);
+        }
+        ExprKind::Yield(ref subexpression, _) => {
+            visitor.visit_expr(subexpression);
+        }
+        ExprKind::Lit(_) | ExprKind::Err => {}
+    }
+}
+
+pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
+    visitor.visit_id(arm.hir_id);
+    visitor.visit_pat(&arm.pat);
+    if let Some(ref g) = arm.guard {
+        match g {
+            Guard::If(ref e) => visitor.visit_expr(e),
+        }
+    }
+    visitor.visit_expr(&arm.body);
+    walk_list!(visitor, visit_attribute, arm.attrs);
+}
+
+pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility<'v>) {
+    if let VisibilityKind::Restricted { ref path, hir_id } = vis.node {
+        visitor.visit_id(hir_id);
+        visitor.visit_path(path, hir_id)
+    }
+}
+
+pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) {
+    // No visitable content here: this fn exists so you can call it if
+    // the right thing to do, should content be added in the future,
+    // would be to walk it.
+}
+
+pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) {
+    // No visitable content here: this fn exists so you can call it if
+    // the right thing to do, should content be added in the future,
+    // would be to walk it.
+}
index 8bf2e6299a9d3c081bfeac8897c95a003368a64e..f54fa291bd6e81e7c3620a8f044864ebdf37d345 100644 (file)
@@ -3,7 +3,7 @@
 //! [rustc guide]: https://rust-lang.github.io/rustc-guide/hir.html
 
 #![feature(crate_visibility_modifier)]
-#![feature(const_fn)]
+#![feature(const_fn)] // For the unsizing cast on `&[]`
 #![feature(in_band_lifetimes)]
 #![feature(specialization)]
 #![recursion_limit = "256"]
@@ -15,6 +15,7 @@
 pub mod def_id;
 mod hir;
 pub mod hir_id;
+pub mod intravisit;
 pub mod itemlikevisit;
 pub mod pat_util;
 pub mod print;
index 571bab2cb83f288869707bbfc7c80cfc2c3b156a..759f423070aa0b35019e0840b47403f8266f8327 100644 (file)
@@ -1767,13 +1767,17 @@ pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
             }
             PatKind::Lit(ref e) => self.print_expr(&e),
             PatKind::Range(ref begin, ref end, ref end_kind) => {
-                self.print_expr(&begin);
-                self.s.space();
+                if let Some(expr) = begin {
+                    self.print_expr(expr);
+                    self.s.space();
+                }
                 match *end_kind {
                     RangeEnd::Included => self.s.word("..."),
                     RangeEnd::Excluded => self.s.word(".."),
                 }
-                self.print_expr(&end);
+                if let Some(expr) = end {
+                    self.print_expr(expr);
+                }
             }
             PatKind::Slice(ref before, ref slice, ref after) => {
                 self.s.word("[");
index 64547845e74f1478a9235c6231fc1efddad5f30d..9490128e32d6a3e6eed9edcb46c2e0dc2f89a939 100644 (file)
 use graphviz as dot;
 use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter};
 use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode};
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use syntax::ast;
@@ -159,7 +160,9 @@ fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) {
 }
 
 impl Visitor<'tcx> for IfThisChanged<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
index 40dd4c88a02b2bf44df79c43774fd9fc5114a77d..ddfed53fa33491895e08504ae7727129af63ad74 100644 (file)
 //! the required condition is not met.
 
 use rustc::dep_graph::{label_strs, DepNode};
-use rustc::hir::intravisit;
+use rustc::hir::map::Map;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Node as HirNode;
 use rustc_hir::{ImplItemKind, ItemKind as HirItem, TraitItemKind};
@@ -547,7 +548,9 @@ fn report_unchecked_attrs(&self, checked_attrs: &FxHashSet<ast::AttrId>) {
 }
 
 impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> {
         intravisit::NestedVisitorMap::All(&self.tcx.hir())
     }
 
index adf8f57f01d089404b3cad3a2047735332fb5ef4..ba20006d73cccf0f4866140bc8dd52379bf0a5de 100644 (file)
@@ -190,6 +190,8 @@ pub fn prepare_session_directory(
         return;
     }
 
+    let _timer = sess.timer("incr_comp_prepare_session_directory");
+
     debug!("prepare_session_directory");
 
     // {incr-comp-dir}/{crate-name-and-disambiguator}
@@ -306,6 +308,8 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) {
         return;
     }
 
+    let _timer = sess.timer("incr_comp_finalize_session_directory");
+
     let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone();
 
     if sess.has_errors_or_delayed_span_bugs() {
index cb06dae6ac9197ffb275b04acf3a49d188c9cca7..6c57f79e1a7fb911e03edc5ce52a1ce7a249a2e4 100644 (file)
@@ -102,6 +102,8 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
         return MaybeAsync::Sync(LoadResult::Ok { data: Default::default() });
     }
 
+    let _timer = sess.prof.generic_activity("incr_comp_prepare_load_dep_graph");
+
     // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
     // Fortunately, we just checked that this isn't the case.
     let path = dep_graph_path_from(&sess.incr_comp_session_dir());
@@ -159,7 +161,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     }
 
     MaybeAsync::Async(std::thread::spawn(move || {
-        let _prof_timer = prof.generic_pass("background load prev dep-graph");
+        let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
 
         match load_data(report_incremental_info, &path) {
             LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
index 9487f02aa8e08ff03fb476832b507c9134c73958..588e639f28946f7ef3134318db1c55a0a51659c4 100644 (file)
@@ -32,15 +32,15 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
         join(
             move || {
                 if tcx.sess.opts.debugging_opts.incremental_queries {
-                    sess.time("persist query result cache", || {
+                    sess.time("incr_comp_persist_result_cache", || {
                         save_in(sess, query_cache_path, |e| encode_query_cache(tcx, e));
                     });
                 }
             },
             || {
-                sess.time("persist dep-graph", || {
+                sess.time("incr_comp_persist_dep_graph", || {
                     save_in(sess, dep_graph_path, |e| {
-                        sess.time("encode dep-graph", || encode_dep_graph(tcx, e))
+                        sess.time("incr_comp_encode_dep_graph", || encode_dep_graph(tcx, e))
                     });
                 });
             },
@@ -142,7 +142,8 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
     tcx.sess.opts.dep_tracking_hash().encode(encoder).unwrap();
 
     // Encode the graph data.
-    let serialized_graph = tcx.sess.time("getting serialized graph", || tcx.dep_graph.serialize());
+    let serialized_graph =
+        tcx.sess.time("incr_comp_serialize_dep_graph", || tcx.dep_graph.serialize());
 
     if tcx.sess.opts.debugging_opts.incremental_info {
         #[derive(Clone)]
@@ -223,7 +224,7 @@ struct Stat {
         println!("[incremental]");
     }
 
-    tcx.sess.time("encoding serialized graph", || {
+    tcx.sess.time("incr_comp_encode_serialized_dep_graph", || {
         serialized_graph.encode(encoder).unwrap();
     });
 }
@@ -244,7 +245,7 @@ fn encode_work_product_index(
 }
 
 fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
-    tcx.sess.time("serialize query result cache", || {
+    tcx.sess.time("incr_comp_serialize_result_cache", || {
         tcx.serialize_query_result_cache(encoder).unwrap();
     })
 }
index be60b75bc47eb26171ebda49bb8037eb6802019e..98f7def7e36cbabca54f6c4e698a6593ee8f7f81 100644 (file)
@@ -17,10 +17,12 @@ syntax = { path = "../libsyntax" }
 rustc_builtin_macros = { path = "../librustc_builtin_macros" }
 rustc_expand = { path = "../librustc_expand" }
 rustc_parse = { path = "../librustc_parse" }
+rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 rustc = { path = "../librustc" }
 rustc_ast_lowering = { path = "../librustc_ast_lowering" }
+rustc_ast_passes = { path = "../librustc_ast_passes" }
 rustc_incremental = { path = "../librustc_incremental" }
 rustc_traits = { path = "../librustc_traits" }
 rustc_data_structures = { path = "../librustc_data_structures" }
@@ -30,6 +32,7 @@ rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true }
 rustc_hir = { path = "../librustc_hir" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
+rustc_mir_build = { path = "../librustc_mir_build" }
 rustc_passes = { path = "../librustc_passes" }
 rustc_typeck = { path = "../librustc_typeck" }
 rustc_lint = { path = "../librustc_lint" }
index c4449945dd19d784b6ac2b21fac0c92fd278cbdc..9cd9eb66cf6c1f0b304385a0ec22323790c53b0f 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::OnDrop;
 use rustc_errors::registry::Registry;
+use rustc_lint::LintStore;
 use rustc_parse::new_parser_from_source_str;
 use rustc_span::edition;
 use rustc_span::source_map::{FileLoader, FileName, SourceMap};
@@ -36,7 +37,7 @@ pub struct Compiler {
     pub(crate) output_dir: Option<PathBuf>,
     pub(crate) output_file: Option<PathBuf>,
     pub(crate) crate_name: Option<String>,
-    pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
+    pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
     pub(crate) override_queries:
         Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>,
 }
@@ -136,7 +137,7 @@ pub struct Config {
     ///
     /// Note that if you find a Some here you probably want to call that function in the new
     /// function being registered.
-    pub register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
+    pub register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
 
     /// This is a callback from the driver that is called just after we have populated
     /// the list of queries.
@@ -177,11 +178,17 @@ pub fn run_compiler_in_existing_thread_pool<R>(
         override_queries: config.override_queries,
     };
 
-    let _sess_abort_error = OnDrop(|| {
-        compiler.sess.diagnostic().print_error_count(registry);
-    });
+    let r = {
+        let _sess_abort_error = OnDrop(|| {
+            compiler.sess.diagnostic().print_error_count(registry);
+        });
 
-    f(&compiler)
+        f(&compiler)
+    };
+
+    let prof = compiler.sess.prof.clone();
+    prof.generic_activity("drop_compiler").run(move || drop(compiler));
+    r
 }
 
 pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
index 432f79bba030a81af719c093df836e07acca117a..5f0d9ed5bdf0d945d7e0b2edb9f1a251dbf6faae 100644 (file)
 use rustc_expand::base::ExtCtxt;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_incremental;
+use rustc_lint::LintStore;
 use rustc_mir as mir;
+use rustc_mir_build as mir_build;
 use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
-use rustc_passes::{self, ast_validation, hir_stats, layout_test};
+use rustc_passes::{self, hir_stats, layout_test};
 use rustc_plugin_impl as plugin;
 use rustc_privacy;
 use rustc_resolve::{Resolver, ResolverArenas};
@@ -37,7 +39,6 @@
 use rustc_span::FileName;
 use rustc_traits;
 use rustc_typeck as typeck;
-use syntax::early_buffered_lints::BufferedEarlyLint;
 use syntax::mut_visit::MutVisitor;
 use syntax::util::node_count::NodeCounter;
 use syntax::{self, ast, visit};
 use std::{env, fs, iter, mem};
 
 pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
-    sess.diagnostic().set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error);
-    let krate = sess.time("parsing", || match input {
+    let krate = sess.time("parse_crate", || match input {
         Input::File(file) => parse_crate_from_file(file, &sess.parse_sess),
         Input::Str { input, name } => {
             parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess)
         }
     })?;
 
-    sess.diagnostic().set_continue_after_error(true);
-
     if sess.opts.debugging_opts.ast_json_noexpand {
         println!("{}", json::as_json(&krate));
     }
@@ -74,7 +72,7 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
     }
 
     if let Some(ref s) = sess.opts.debugging_opts.show_span {
-        syntax::show_span::run(sess.diagnostic(), s, &krate);
+        rustc_ast_passes::show_span::run(sess.diagnostic(), s, &krate);
     }
 
     if sess.opts.debugging_opts.hir_stats {
@@ -104,7 +102,7 @@ fn count_nodes(krate: &ast::Crate) -> usize {
 /// Returns `None` if we're aborting after handling -W help.
 pub fn configure_and_expand(
     sess: Lrc<Session>,
-    lint_store: Lrc<lint::LintStore>,
+    lint_store: Lrc<LintStore>,
     metadata_loader: Box<MetadataLoaderDyn>,
     krate: ast::Crate,
     crate_name: &str,
@@ -154,11 +152,11 @@ pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutp
 pub fn register_plugins<'a>(
     sess: &'a Session,
     metadata_loader: &'a dyn MetadataLoader,
-    register_lints: impl Fn(&Session, &mut lint::LintStore),
+    register_lints: impl Fn(&Session, &mut LintStore),
     mut krate: ast::Crate,
     crate_name: &str,
-) -> Result<(ast::Crate, Lrc<lint::LintStore>)> {
-    krate = sess.time("attributes injection", || {
+) -> Result<(ast::Crate, Lrc<LintStore>)> {
+    krate = sess.time("attributes_injection", || {
         rustc_builtin_macros::cmdline_attrs::inject(
             krate,
             &sess.parse_sess,
@@ -183,9 +181,7 @@ pub fn register_plugins<'a>(
     rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
 
     if sess.opts.incremental.is_some() {
-        sess.time("garbage-collect incremental cache directory", || {
-            let _prof_timer =
-                sess.prof.generic_activity("incr_comp_garbage_collect_session_directories");
+        sess.time("incr_comp_garbage_collect_session_directories", || {
             if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
                 warn!(
                     "Error while trying to garbage collect incremental \
@@ -196,7 +192,7 @@ pub fn register_plugins<'a>(
         });
     }
 
-    sess.time("recursion limit", || {
+    sess.time("recursion_limit", || {
         middle::recursion_limit::update_limits(sess, &krate);
     });
 
@@ -207,8 +203,8 @@ pub fn register_plugins<'a>(
     register_lints(&sess, &mut lint_store);
 
     let registrars =
-        sess.time("plugin loading", || plugin::load::load_plugins(sess, metadata_loader, &krate));
-    sess.time("plugin registration", || {
+        sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate));
+    sess.time("plugin_registration", || {
         let mut registry = plugin::Registry { lint_store: &mut lint_store };
         for registrar in registrars {
             registrar(&mut registry);
@@ -220,13 +216,13 @@ pub fn register_plugins<'a>(
 
 fn configure_and_expand_inner<'a>(
     sess: &'a Session,
-    lint_store: &'a lint::LintStore,
+    lint_store: &'a LintStore,
     mut krate: ast::Crate,
     crate_name: &str,
     resolver_arenas: &'a ResolverArenas<'a>,
     metadata_loader: &'a MetadataLoaderDyn,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
-    sess.time("pre-AST-expansion lint checks", || {
+    sess.time("pre_AST_expansion_lint_checks", || {
         rustc_lint::check_ast_crate(
             sess,
             lint_store,
@@ -240,7 +236,7 @@ fn configure_and_expand_inner<'a>(
     let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
     rustc_builtin_macros::register_builtin_macros(&mut resolver, sess.edition());
 
-    krate = sess.time("crate injection", || {
+    krate = sess.time("crate_injection", || {
         let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
         let (krate, name) = rustc_builtin_macros::standard_library_imports::inject(
             krate,
@@ -257,7 +253,7 @@ fn configure_and_expand_inner<'a>(
     util::check_attr_crate_type(&krate.attrs, &mut resolver.lint_buffer());
 
     // Expand all macros
-    krate = sess.time("expansion", || {
+    krate = sess.time("macro_expand_crate", || {
         // Windows dlls do not have rpaths, so they don't know how to find their
         // dependencies. It's up to us to tell the system where to find all the
         // dependent dlls. Note that this uses cfg!(windows) as opposed to
@@ -302,11 +298,11 @@ fn configure_and_expand_inner<'a>(
         let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver);
 
         // Expand macros now!
-        let krate = sess.time("expand crate", || ecx.monotonic_expander().expand_crate(krate));
+        let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
 
         // The rest is error reporting
 
-        sess.time("check unused macros", || {
+        sess.time("check_unused_macros", || {
             ecx.check_unused_macros();
         });
 
@@ -325,7 +321,7 @@ fn configure_and_expand_inner<'a>(
         krate
     });
 
-    sess.time("maybe building test harness", || {
+    sess.time("maybe_building_test_harness", || {
         rustc_builtin_macros::test_harness::inject(
             &sess.parse_sess,
             &mut resolver,
@@ -349,8 +345,8 @@ fn configure_and_expand_inner<'a>(
         util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
     }
 
-    let has_proc_macro_decls = sess.time("AST validation", || {
-        ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer())
+    let has_proc_macro_decls = sess.time("AST_validation", || {
+        rustc_ast_passes::ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer())
     });
 
     let crate_types = sess.crate_types.borrow();
@@ -371,7 +367,7 @@ fn configure_and_expand_inner<'a>(
         msg.warn("The generated documentation may be incorrect");
         msg.emit()
     } else {
-        krate = sess.time("maybe creating a macro crate", || {
+        krate = sess.time("maybe_create_a_macro_crate", || {
             let num_crate_types = crate_types.len();
             let is_test_crate = sess.opts.test;
             rustc_builtin_macros::proc_macro_harness::inject(
@@ -401,13 +397,11 @@ fn configure_and_expand_inner<'a>(
         println!("{}", json::as_json(&krate));
     }
 
-    sess.time("name resolution", || {
-        resolver.resolve_crate(&krate);
-    });
+    resolver.resolve_crate(&krate);
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
-    sess.time("complete gated feature checking", || {
-        syntax::feature_gate::check_crate(
+    sess.time("complete_gated_feature_checking", || {
+        rustc_ast_passes::feature_gate::check_crate(
             &krate,
             &sess.parse_sess,
             &sess.features_untracked(),
@@ -418,8 +412,8 @@ fn configure_and_expand_inner<'a>(
     // Add all buffered lints from the `ParseSess` to the `Session`.
     sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
         info!("{} parse sess buffered_lints", buffered_lints.len());
-        for BufferedEarlyLint { id, span, msg, lint_id } in buffered_lints.drain(..) {
-            resolver.lint_buffer().buffer_lint(lint_id, id, span, &msg);
+        for early_lint in buffered_lints.drain(..) {
+            resolver.lint_buffer().add_early_lint(early_lint);
         }
     });
 
@@ -428,31 +422,29 @@ fn configure_and_expand_inner<'a>(
 
 pub fn lower_to_hir<'res, 'tcx>(
     sess: &'tcx Session,
-    lint_store: &lint::LintStore,
+    lint_store: &LintStore,
     resolver: &'res mut Resolver<'_>,
     dep_graph: &'res DepGraph,
     krate: &'res ast::Crate,
     arena: &'tcx Arena<'tcx>,
 ) -> Result<map::Forest<'tcx>> {
     // Lower AST to HIR.
-    let hir_forest = sess.time("lowering AST -> HIR", || {
-        let hir_crate = rustc_ast_lowering::lower_crate(
-            sess,
-            &dep_graph,
-            &krate,
-            resolver,
-            rustc_parse::nt_to_tokenstream,
-            arena,
-        );
+    let hir_crate = rustc_ast_lowering::lower_crate(
+        sess,
+        &dep_graph,
+        &krate,
+        resolver,
+        rustc_parse::nt_to_tokenstream,
+        arena,
+    );
 
-        if sess.opts.debugging_opts.hir_stats {
-            hir_stats::print_hir_stats(&hir_crate);
-        }
+    if sess.opts.debugging_opts.hir_stats {
+        hir_stats::print_hir_stats(&hir_crate);
+    }
 
-        map::Forest::new(hir_crate, &dep_graph)
-    });
+    let hir_forest = map::Forest::new(hir_crate, &dep_graph);
 
-    sess.time("early lint checks", || {
+    sess.time("early_lint_checks", || {
         rustc_lint::check_ast_crate(
             sess,
             lint_store,
@@ -620,6 +612,8 @@ pub fn prepare_outputs(
     boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
     crate_name: &str,
 ) -> Result<OutputFilenames> {
+    let _timer = sess.timer("prepare_outputs");
+
     // FIXME: rustdoc passes &[] instead of &krate.attrs here
     let outputs = util::build_output_filenames(
         &compiler.input,
@@ -678,6 +672,7 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
     plugin::build::provide(providers);
     rustc::hir::provide(providers);
     mir::provide(providers);
+    mir_build::provide(providers);
     rustc_privacy::provide(providers);
     typeck::provide(providers);
     ty::provide(providers);
@@ -713,7 +708,7 @@ pub fn print_stats(&self) {
 
 pub fn create_global_ctxt<'tcx>(
     compiler: &'tcx Compiler,
-    lint_store: Lrc<lint::LintStore>,
+    lint_store: Lrc<LintStore>,
     hir_forest: &'tcx map::Forest<'tcx>,
     mut resolver_outputs: ResolverOutputs,
     outputs: OutputFilenames,
@@ -726,12 +721,9 @@ pub fn create_global_ctxt<'tcx>(
     let defs = mem::take(&mut resolver_outputs.definitions);
 
     // Construct the HIR map.
-    let hir_map = sess.time("indexing HIR", || {
-        map::map_crate(sess, &*resolver_outputs.cstore, &hir_forest, defs)
-    });
+    let hir_map = map::map_crate(sess, &*resolver_outputs.cstore, &hir_forest, defs);
 
-    let query_result_on_disk_cache =
-        sess.time("load query result cache", || rustc_incremental::load_query_result_cache(sess));
+    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();
@@ -746,25 +738,27 @@ pub fn create_global_ctxt<'tcx>(
         callback(sess, &mut local_providers, &mut extern_providers);
     }
 
-    let gcx = global_ctxt.init_locking(|| {
-        TyCtxt::create_global_ctxt(
-            sess,
-            lint_store,
-            local_providers,
-            extern_providers,
-            &all_arenas,
-            arena,
-            resolver_outputs,
-            hir_map,
-            query_result_on_disk_cache,
-            &crate_name,
-            &outputs,
-        )
+    let gcx = sess.time("setup_global_ctxt", || {
+        global_ctxt.init_locking(|| {
+            TyCtxt::create_global_ctxt(
+                sess,
+                lint_store,
+                local_providers,
+                extern_providers,
+                &all_arenas,
+                arena,
+                resolver_outputs,
+                hir_map,
+                query_result_on_disk_cache,
+                &crate_name,
+                &outputs,
+            )
+        })
     });
 
     // Do some initialization of the DepGraph that can only be done with the tcx available.
     ty::tls::enter_global(&gcx, |tcx| {
-        tcx.sess.time("dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
+        tcx.sess.time("dep_graph_tcx_init", || rustc_incremental::dep_graph_tcx_init(tcx));
     });
 
     QueryContext(gcx)
@@ -778,17 +772,17 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
     let sess = tcx.sess;
     let mut entry_point = None;
 
-    sess.time("misc checking 1", || {
+    sess.time("misc_checking_1", || {
         parallel!(
             {
                 entry_point = sess
-                    .time("looking for entry point", || rustc_passes::entry::find_entry_point(tcx));
+                    .time("looking_for_entry_point", || rustc_passes::entry::find_entry_point(tcx));
 
-                sess.time("looking for plugin registrar", || {
+                sess.time("looking_for_plugin_registrar", || {
                     plugin::build::find_plugin_registrar(tcx)
                 });
 
-                sess.time("looking for derive registrar", || proc_macro_decls::find(tcx));
+                sess.time("looking_for_derive_registrar", || proc_macro_decls::find(tcx));
             },
             {
                 par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
@@ -805,17 +799,17 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
     // passes are timed inside typeck
     typeck::check_crate(tcx)?;
 
-    sess.time("misc checking 2", || {
+    sess.time("misc_checking_2", || {
         parallel!(
             {
-                sess.time("match checking", || {
+                sess.time("match_checking", || {
                     tcx.par_body_owners(|def_id| {
                         tcx.ensure().check_match(def_id);
                     });
                 });
             },
             {
-                sess.time("liveness checking + intrinsic checking", || {
+                sess.time("liveness_and_intrinsic_checking", || {
                     par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
                         // this must run before MIR dump, because
                         // "not all control paths return a value" is reported here.
@@ -831,21 +825,21 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
         );
     });
 
-    sess.time("MIR borrow checking", || {
+    sess.time("MIR_borrow_checking", || {
         tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
     });
 
-    sess.time("dumping Chalk-like clauses", || {
+    sess.time("dumping_chalk_like_clauses", || {
         rustc_traits::lowering::dump_program_clauses(tcx);
     });
 
-    sess.time("MIR effect checking", || {
+    sess.time("MIR_effect_checking", || {
         for def_id in tcx.body_owners() {
             mir::transform::check_unsafety::check_unsafety(tcx, def_id)
         }
     });
 
-    sess.time("layout testing", || layout_test::test_layout(tcx));
+    sess.time("layout_testing", || layout_test::test_layout(tcx));
 
     // Avoid overwhelming user with errors if borrow checking failed.
     // I'm not sure how helpful this is, to be honest, but it avoids a
@@ -856,28 +850,25 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
         return Err(ErrorReported);
     }
 
-    sess.time("misc checking 3", || {
+    sess.time("misc_checking_3", || {
         parallel!(
             {
-                sess.time("privacy access levels", || {
-                    tcx.ensure().privacy_access_levels(LOCAL_CRATE);
-                });
+                tcx.ensure().privacy_access_levels(LOCAL_CRATE);
+
                 parallel!(
                     {
-                        sess.time("private in public", || {
-                            tcx.ensure().check_private_in_public(LOCAL_CRATE);
-                        });
+                        tcx.ensure().check_private_in_public(LOCAL_CRATE);
                     },
                     {
-                        sess.time("death checking", || rustc_passes::dead::check_crate(tcx));
+                        sess.time("death_checking", || rustc_passes::dead::check_crate(tcx));
                     },
                     {
-                        sess.time("unused lib feature checking", || {
+                        sess.time("unused_lib_feature_checking", || {
                             rustc_passes::stability::check_unused_or_stable_features(tcx)
                         });
                     },
                     {
-                        sess.time("lint checking", || {
+                        sess.time("lint_checking", || {
                             rustc_lint::check_crate(tcx, || {
                                 rustc_lint::BuiltinCombinedLateLintPass::new()
                             });
@@ -886,7 +877,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
                 );
             },
             {
-                sess.time("privacy checking modules", || {
+                sess.time("privacy_checking_modules", || {
                     par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
                         tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
                     });
@@ -929,6 +920,8 @@ enum MetadataKind {
         MetadataKind::Uncompressed | MetadataKind::Compressed => tcx.encode_metadata(),
     };
 
+    let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
+
     let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
     if need_metadata_file {
         let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str();
@@ -971,10 +964,9 @@ pub fn start_codegen<'tcx>(
         tcx.print_debug_stats();
     }
 
-    let (metadata, need_metadata_module) =
-        tcx.sess.time("metadata encoding and writing", || encode_and_write_metadata(tcx, outputs));
+    let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs);
 
-    let codegen = tcx.sess.time("codegen", move || {
+    let codegen = tcx.sess.time("codegen_crate", move || {
         codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
     });
 
index 2de0e1ecccc83e39897134939642784359d1775b..bd9717d3f3d0253bb6b158244821460b6cfd371b 100644 (file)
@@ -4,8 +4,6 @@
 use rustc::arena::Arena;
 use rustc::dep_graph::DepGraph;
 use rustc::hir::map;
-use rustc::lint;
-use rustc::lint::LintStore;
 use rustc::session::config::{OutputFilenames, OutputType};
 use rustc::session::Session;
 use rustc::ty::steal::Steal;
@@ -15,6 +13,7 @@
 use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_incremental::DepGraphFuture;
+use rustc_lint::LintStore;
 use std::any::Any;
 use std::cell::{Ref, RefCell, RefMut};
 use std::mem;
@@ -133,7 +132,7 @@ pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
             let crate_name = self.crate_name()?.peek().clone();
             let krate = self.parse()?.take();
 
-            let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {};
+            let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
             let result = passes::register_plugins(
                 self.session(),
                 &*self.codegen_backend().metadata_loader(),
@@ -176,6 +175,7 @@ pub fn expansion(
         self.expansion.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let (krate, lint_store) = self.register_plugins()?.take();
+            let _timer = self.session().timer("configure_and_expand");
             passes::configure_and_expand(
                 self.session().clone(),
                 lint_store.clone(),
@@ -195,7 +195,7 @@ pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
                 None => DepGraph::new_disabled(),
                 Some(future) => {
                     let (prev_graph, prev_work_products) =
-                        self.session().time("blocked while dep-graph loading finishes", || {
+                        self.session().time("blocked_on_dep_graph_loading", || {
                             future
                                 .open()
                                 .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
@@ -256,6 +256,7 @@ pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
             let lint_store = self.expansion()?.peek().2.clone();
             let hir = self.lower_to_hir()?.peek();
             let (ref hir_forest, ref resolver_outputs) = &*hir;
+            let _timer = self.session().timer("create_global_ctxt");
             Ok(passes::create_global_ctxt(
                 self.compiler,
                 lint_store,
@@ -312,14 +313,19 @@ pub struct Linker {
 
 impl Linker {
     pub fn link(self) -> Result<()> {
-        self.codegen_backend
+        let r = self
+            .codegen_backend
             .join_codegen_and_link(
                 self.ongoing_codegen,
                 &self.sess,
                 &self.dep_graph,
                 &self.prepare_outputs,
             )
-            .map_err(|_| ErrorReported)
+            .map_err(|_| ErrorReported);
+        let prof = self.sess.prof.clone();
+        let dep_graph = self.dep_graph;
+        prof.generic_activity("drop_dep_graph").run(move || drop(dep_graph));
+        r
     }
 }
 
@@ -328,6 +334,7 @@ pub fn enter<F, T>(&self, f: F) -> T
     where
         F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T,
     {
+        let mut _timer = None;
         let queries = Queries::new(&self);
         let ret = f(&queries);
 
@@ -337,6 +344,8 @@ pub fn enter<F, T>(&self, f: F) -> T
             }
         }
 
+        _timer = Some(self.session().timer("free_global_ctxt"));
+
         ret
     }
 
index 25ab7650b0ec2e28fd21e04efbc406e19bd68ad6..ec75a1c6a3938d92df5d95ee847cf19270997473 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::interface::parse_cfgspecs;
 
-use rustc::lint;
+use rustc::lint::Level;
 use rustc::middle::cstore;
 use rustc::session::config::{build_configuration, build_session_options, to_crate_config};
 use rustc::session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
@@ -186,24 +186,24 @@ fn test_lints_tracking_hash_different_values() {
     let mut v3 = Options::default();
 
     v1.lint_opts = vec![
-        (String::from("a"), lint::Allow),
-        (String::from("b"), lint::Warn),
-        (String::from("c"), lint::Deny),
-        (String::from("d"), lint::Forbid),
+        (String::from("a"), Level::Allow),
+        (String::from("b"), Level::Warn),
+        (String::from("c"), Level::Deny),
+        (String::from("d"), Level::Forbid),
     ];
 
     v2.lint_opts = vec![
-        (String::from("a"), lint::Allow),
-        (String::from("b"), lint::Warn),
-        (String::from("X"), lint::Deny),
-        (String::from("d"), lint::Forbid),
+        (String::from("a"), Level::Allow),
+        (String::from("b"), Level::Warn),
+        (String::from("X"), Level::Deny),
+        (String::from("d"), Level::Forbid),
     ];
 
     v3.lint_opts = vec![
-        (String::from("a"), lint::Allow),
-        (String::from("b"), lint::Warn),
-        (String::from("c"), lint::Forbid),
-        (String::from("d"), lint::Deny),
+        (String::from("a"), Level::Allow),
+        (String::from("b"), Level::Warn),
+        (String::from("c"), Level::Forbid),
+        (String::from("d"), Level::Deny),
     ];
 
     assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
@@ -222,17 +222,17 @@ fn test_lints_tracking_hash_different_construction_order() {
     let mut v2 = Options::default();
 
     v1.lint_opts = vec![
-        (String::from("a"), lint::Allow),
-        (String::from("b"), lint::Warn),
-        (String::from("c"), lint::Deny),
-        (String::from("d"), lint::Forbid),
+        (String::from("a"), Level::Allow),
+        (String::from("b"), Level::Warn),
+        (String::from("c"), Level::Deny),
+        (String::from("d"), Level::Forbid),
     ];
 
     v2.lint_opts = vec![
-        (String::from("a"), lint::Allow),
-        (String::from("c"), lint::Deny),
-        (String::from("b"), lint::Warn),
-        (String::from("d"), lint::Forbid),
+        (String::from("a"), Level::Allow),
+        (String::from("c"), Level::Deny),
+        (String::from("b"), Level::Warn),
+        (String::from("d"), Level::Forbid),
     ];
 
     assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
@@ -601,10 +601,6 @@ fn test_debugging_options_tracking_hash() {
     opts.debugging_opts.report_delayed_bugs = true;
     assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
 
-    opts = reference.clone();
-    opts.debugging_opts.continue_parse_after_error = true;
-    assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
-
     opts = reference.clone();
     opts.debugging_opts.force_overflow_checks = Some(true);
     assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
index c15dc2fe704b9aa21d98c603c997610946cbd421..2fafd3af7a5ff2d406b1d0386fd95debe2c30110 100644 (file)
@@ -1,8 +1,5 @@
 use log::info;
 use rustc::lint;
-use rustc::session::config::{ErrorOutputType, Input, OutputFilenames};
-use rustc::session::CrateDisambiguator;
-use rustc::session::{self, config, early_error, filesearch, DiagnosticOutput, Session};
 use rustc::ty;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_errors::registry::Registry;
 use rustc_metadata::dynamic_lib::DynamicLibrary;
 use rustc_resolve::{self, Resolver};
+use rustc_session as session;
+use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
+use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
+use rustc_session::CrateDisambiguator;
+use rustc_session::{config, early_error, filesearch, DiagnosticOutput, Session};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap};
 use rustc_span::symbol::{sym, Symbol};
@@ -71,10 +73,6 @@ pub fn create_session(
         lint_caps,
     );
 
-    sess.prof.register_queries(|profiler| {
-        rustc::ty::query::QueryName::register_with_profiler(&profiler);
-    });
-
     let codegen_backend = get_codegen_backend(&sess);
 
     let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
@@ -424,7 +422,7 @@ pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguat
     CrateDisambiguator::from(hasher.finish::<Fingerprint>())
 }
 
-pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut lint::LintBuffer) {
+pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut LintBuffer) {
     // Unconditionally collect crate types from attributes to make them used
     for a in attrs.iter() {
         if a.check_name(sym::crate_type) {
@@ -446,7 +444,7 @@ pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut
                             ast::CRATE_NODE_ID,
                             span,
                             "invalid `crate_type` value",
-                            lint::builtin::BuiltinLintDiagnostics::UnknownCrateTypes(
+                            BuiltinLintDiagnostics::UnknownCrateTypes(
                                 span,
                                 "did you mean".to_string(),
                                 format!("\"{}\"", candidate),
index 820064cb5b6f8b1d5aacb693248626b641509c2d..abf9f96e6475b26e464dddf33271f8696f9e448c 100644 (file)
@@ -12,6 +12,8 @@ path = "lib.rs"
 log = "0.4"
 unicode-security = "0.0.2"
 rustc = { path = "../librustc" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
@@ -19,5 +21,4 @@ rustc_span = { path = "../librustc_span" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_index = { path = "../librustc_index" }
-rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_session = { path = "../librustc_session" }
index 46202cda16d50aefc7786c487db42092cd669d5f..fb11b6771e9caceec027973e4b905751b3330c98 100644 (file)
@@ -1,10 +1,10 @@
-use crate::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
-use rustc::lint::FutureIncompatibleInfo;
+use crate::{LateContext, LateLintPass, LintContext};
 use rustc::ty;
 use rustc::ty::adjustment::{Adjust, Adjustment};
+use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_session::lint::FutureIncompatibleInfo;
 use rustc_span::symbol::sym;
-use syntax::errors::Applicability;
 
 declare_lint! {
     pub ARRAY_INTO_ITER,
index 59b87afe2160b1fd003d4bfffe5ae871cca532d5..6aa809a706ebc62524a5e8bb4c20a572119d7d18 100644 (file)
 //! If you define a new `LateLintPass`, you will also need to add it to the
 //! `late_lint_methods!` invocation in `lib.rs`.
 
-use std::fmt::Write;
-
-use lint::{EarlyContext, EarlyLintPass, LateLintPass, LintPass};
-use lint::{LateContext, LintArray, LintContext};
-use rustc::lint;
-use rustc::lint::FutureIncompatibleInfo;
+use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc::hir::map::Map;
+use rustc::traits::misc::can_type_implement_copy;
 use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_feature::Stability;
 use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{GenericParamKind, PatKind};
 use rustc_hir::{HirIdSet, Node};
+use rustc_session::lint::FutureIncompatibleInfo;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{BytePos, Span};
 use syntax::ast::{self, Expr};
 use syntax::attr::{self, HasAttrs};
-use syntax::errors::{Applicability, DiagnosticBuilder};
 use syntax::print::pprust::{self, expr_to_string};
-use syntax::ptr::P;
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::visit::FnKind;
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
 use log::debug;
+use std::fmt::Write;
 
 // hardwired lints from librustc
-pub use lint::builtin::*;
+pub use rustc_session::lint::builtin::*;
 
 declare_lint! {
     WHILE_TRUE,
@@ -555,7 +553,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
         if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
             return;
         }
-        if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
+        if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
             cx.span_lint(
                 MISSING_COPY_IMPLEMENTATIONS,
                 item.span,
@@ -1087,12 +1085,14 @@ fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut DiagnosticBuilder<'_
         // bound.  Let's see if this type does that.
 
         // We use a HIR visitor to walk the type.
-        use rustc::hir::intravisit::{self, Visitor};
+        use rustc_hir::intravisit::{self, Visitor};
         struct WalkAssocTypes<'a, 'db> {
             err: &'a mut DiagnosticBuilder<'db>,
         }
         impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> {
-            fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
+            type Map = Map<'v>;
+
+            fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
                 intravisit::NestedVisitorMap::None
             }
 
@@ -1305,11 +1305,13 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
 
         /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
         /// corresponding to the ellipsis.
-        fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P<Expr>, &P<Expr>, Span)> {
+        fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)> {
             match &pat.kind {
-                PatKind::Range(a, b, Spanned { span, node: RangeEnd::Included(DotDotDot), .. }) => {
-                    Some((a, b, *span))
-                }
+                PatKind::Range(
+                    a,
+                    Some(b),
+                    Spanned { span, node: RangeEnd::Included(DotDotDot) },
+                ) => Some((a.as_deref(), b, *span)),
                 _ => None,
             }
         }
@@ -1324,11 +1326,16 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P<Expr>, &P<Expr>, Span)> {
             let suggestion = "use `..=` for an inclusive range";
             if parenthesise {
                 self.node_id = Some(pat.id);
+                let end = expr_to_string(&end);
+                let replace = match start {
+                    Some(start) => format!("&({}..={})", expr_to_string(&start), end),
+                    None => format!("&(..={})", end),
+                };
                 let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg);
                 err.span_suggestion(
                     pat.span,
                     suggestion,
-                    format!("&({}..={})", expr_to_string(&start), expr_to_string(&end)),
+                    replace,
                     Applicability::MachineApplicable,
                 );
                 err.emit();
@@ -1805,7 +1812,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>)
 }
 
 declare_lint_pass!(
-    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `feature_gate.rs`.
+    /// Check for used feature gates in `INCOMPLETE_FEATURES` in `librustc_feature/active.rs`.
     IncompleteFeatures => [INCOMPLETE_FEATURES]
 );
 
diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs
new file mode 100644 (file)
index 0000000..2b514c3
--- /dev/null
@@ -0,0 +1,842 @@
+//! Implementation of lint checking.
+//!
+//! The lint checking is mostly consolidated into one pass which runs
+//! after all other analyses. Throughout compilation, lint warnings
+//! can be added via the `add_lint` method on the Session structure. This
+//! requires a span and an ID of the node that the lint is being added to. The
+//! lint isn't actually emitted at that time because it is unknown what the
+//! actual lint level at that location is.
+//!
+//! To actually emit lint warnings/errors, a separate pass is used.
+//! A context keeps track of the current state of all lint levels.
+//! Upon entering a node of the ast which can modify the lint settings, the
+//! previous lint state is pushed onto a stack and the ast is then recursed
+//! upon. As the ast is traversed, this keeps track of the current lint level
+//! for all lint attributes.
+
+use self::TargetLint::*;
+
+use crate::levels::LintLevelsBuilder;
+use crate::passes::{EarlyLintPassObject, LateLintPassObject};
+use rustc::hir::map::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc::lint::add_elided_lifetime_in_path_suggestion;
+use rustc::middle::privacy::AccessLevels;
+use rustc::middle::stability;
+use rustc::ty::layout::{LayoutError, LayoutOf, TyLayout};
+use rustc::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync;
+use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_hir as hir;
+use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
+use rustc_session::Session;
+use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
+use syntax::ast;
+use syntax::util::lev_distance::find_best_match_for_name;
+
+use std::slice;
+
+/// Information about the registered lints.
+///
+/// This is basically the subset of `Context` that we can
+/// build early in the compile pipeline.
+pub struct LintStore {
+    /// Registered lints.
+    lints: Vec<&'static Lint>,
+
+    /// Constructor functions for each variety of lint pass.
+    ///
+    /// These should only be called once, but since we want to avoid locks or
+    /// interior mutability, we don't enforce this (and lints should, in theory,
+    /// be compatible with being constructed more than once, though not
+    /// necessarily in a sane manner. This is safe though.)
+    pub pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
+    pub early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
+    pub late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
+    /// This is unique in that we construct them per-module, so not once.
+    pub late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
+
+    /// Lints indexed by name.
+    by_name: FxHashMap<String, TargetLint>,
+
+    /// Map of registered lint groups to what lints they expand to.
+    lint_groups: FxHashMap<&'static str, LintGroup>,
+}
+
+/// The target of the `by_name` map, which accounts for renaming/deprecation.
+enum TargetLint {
+    /// A direct lint target
+    Id(LintId),
+
+    /// Temporary renaming, used for easing migration pain; see #16545
+    Renamed(String, LintId),
+
+    /// Lint with this name existed previously, but has been removed/deprecated.
+    /// The string argument is the reason for removal.
+    Removed(String),
+}
+
+pub enum FindLintError {
+    NotFound,
+    Removed,
+}
+
+struct LintAlias {
+    name: &'static str,
+    /// Whether deprecation warnings should be suppressed for this alias.
+    silent: bool,
+}
+
+struct LintGroup {
+    lint_ids: Vec<LintId>,
+    from_plugin: bool,
+    depr: Option<LintAlias>,
+}
+
+pub enum CheckLintNameResult<'a> {
+    Ok(&'a [LintId]),
+    /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
+    NoLint(Option<Symbol>),
+    /// The lint is either renamed or removed. This is the warning
+    /// message, and an optional new name (`None` if removed).
+    Warning(String, Option<String>),
+    /// The lint is from a tool. If the Option is None, then either
+    /// the lint does not exist in the tool or the code was not
+    /// compiled with the tool and therefore the lint was never
+    /// added to the `LintStore`. Otherwise the `LintId` will be
+    /// returned as if it where a rustc lint.
+    Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>),
+}
+
+impl LintStore {
+    pub fn new() -> LintStore {
+        LintStore {
+            lints: vec![],
+            pre_expansion_passes: vec![],
+            early_passes: vec![],
+            late_passes: vec![],
+            late_module_passes: vec![],
+            by_name: Default::default(),
+            lint_groups: Default::default(),
+        }
+    }
+
+    pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
+        &self.lints
+    }
+
+    pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
+        self.lint_groups
+            .iter()
+            .filter(|(_, LintGroup { depr, .. })| {
+                // Don't display deprecated lint groups.
+                depr.is_none()
+            })
+            .map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
+                (*k, lint_ids.clone(), *from_plugin)
+            })
+            .collect()
+    }
+
+    pub fn register_early_pass(
+        &mut self,
+        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
+    ) {
+        self.early_passes.push(Box::new(pass));
+    }
+
+    pub fn register_pre_expansion_pass(
+        &mut self,
+        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
+    ) {
+        self.pre_expansion_passes.push(Box::new(pass));
+    }
+
+    pub fn register_late_pass(
+        &mut self,
+        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+    ) {
+        self.late_passes.push(Box::new(pass));
+    }
+
+    pub fn register_late_mod_pass(
+        &mut self,
+        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+    ) {
+        self.late_module_passes.push(Box::new(pass));
+    }
+
+    // Helper method for register_early/late_pass
+    pub fn register_lints(&mut self, lints: &[&'static Lint]) {
+        for lint in lints {
+            self.lints.push(lint);
+
+            let id = LintId::of(lint);
+            if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
+                bug!("duplicate specification of lint {}", lint.name_lower())
+            }
+
+            if let Some(FutureIncompatibleInfo { edition, .. }) = lint.future_incompatible {
+                if let Some(edition) = edition {
+                    self.lint_groups
+                        .entry(edition.lint_name())
+                        .or_insert(LintGroup {
+                            lint_ids: vec![],
+                            from_plugin: lint.is_plugin,
+                            depr: None,
+                        })
+                        .lint_ids
+                        .push(id);
+                }
+
+                self.lint_groups
+                    .entry("future_incompatible")
+                    .or_insert(LintGroup {
+                        lint_ids: vec![],
+                        from_plugin: lint.is_plugin,
+                        depr: None,
+                    })
+                    .lint_ids
+                    .push(id);
+            }
+        }
+    }
+
+    pub fn register_group_alias(&mut self, lint_name: &'static str, alias: &'static str) {
+        self.lint_groups.insert(
+            alias,
+            LintGroup {
+                lint_ids: vec![],
+                from_plugin: false,
+                depr: Some(LintAlias { name: lint_name, silent: true }),
+            },
+        );
+    }
+
+    pub fn register_group(
+        &mut self,
+        from_plugin: bool,
+        name: &'static str,
+        deprecated_name: Option<&'static str>,
+        to: Vec<LintId>,
+    ) {
+        let new = self
+            .lint_groups
+            .insert(name, LintGroup { lint_ids: to, from_plugin, depr: None })
+            .is_none();
+        if let Some(deprecated) = deprecated_name {
+            self.lint_groups.insert(
+                deprecated,
+                LintGroup {
+                    lint_ids: vec![],
+                    from_plugin,
+                    depr: Some(LintAlias { name, silent: false }),
+                },
+            );
+        }
+
+        if !new {
+            bug!("duplicate specification of lint group {}", name);
+        }
+    }
+
+    pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
+        let target = match self.by_name.get(new_name) {
+            Some(&Id(lint_id)) => lint_id.clone(),
+            _ => bug!("invalid lint renaming of {} to {}", old_name, new_name),
+        };
+        self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
+    }
+
+    pub fn register_removed(&mut self, name: &str, reason: &str) {
+        self.by_name.insert(name.into(), Removed(reason.into()));
+    }
+
+    pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
+        match self.by_name.get(lint_name) {
+            Some(&Id(lint_id)) => Ok(vec![lint_id]),
+            Some(&Renamed(_, lint_id)) => Ok(vec![lint_id]),
+            Some(&Removed(_)) => Err(FindLintError::Removed),
+            None => loop {
+                return match self.lint_groups.get(lint_name) {
+                    Some(LintGroup { lint_ids, depr, .. }) => {
+                        if let Some(LintAlias { name, .. }) = depr {
+                            lint_name = name;
+                            continue;
+                        }
+                        Ok(lint_ids.clone())
+                    }
+                    None => Err(FindLintError::Removed),
+                };
+            },
+        }
+    }
+
+    /// Checks the validity of lint names derived from the command line
+    pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
+        let db = match self.check_lint_name(lint_name, None) {
+            CheckLintNameResult::Ok(_) => None,
+            CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
+            CheckLintNameResult::NoLint(suggestion) => {
+                let mut err =
+                    struct_span_err!(sess, DUMMY_SP, E0602, "unknown lint: `{}`", lint_name);
+
+                if let Some(suggestion) = suggestion {
+                    err.help(&format!("did you mean: `{}`", suggestion));
+                }
+
+                Some(err)
+            }
+            CheckLintNameResult::Tool(result) => match result {
+                Err((Some(_), new_name)) => Some(sess.struct_warn(&format!(
+                    "lint name `{}` is deprecated \
+                     and does not have an effect anymore. \
+                     Use: {}",
+                    lint_name, new_name
+                ))),
+                _ => None,
+            },
+        };
+
+        if let Some(mut db) = db {
+            let msg = format!(
+                "requested on the command line with `{} {}`",
+                match level {
+                    Level::Allow => "-A",
+                    Level::Warn => "-W",
+                    Level::Deny => "-D",
+                    Level::Forbid => "-F",
+                },
+                lint_name
+            );
+            db.note(&msg);
+            db.emit();
+        }
+    }
+
+    /// Checks the name of a lint for its existence, and whether it was
+    /// renamed or removed. Generates a DiagnosticBuilder containing a
+    /// warning for renamed and removed lints. This is over both lint
+    /// names from attributes and those passed on the command line. Since
+    /// it emits non-fatal warnings and there are *two* lint passes that
+    /// inspect attributes, this is only run from the late pass to avoid
+    /// printing duplicate warnings.
+    pub fn check_lint_name(
+        &self,
+        lint_name: &str,
+        tool_name: Option<Symbol>,
+    ) -> CheckLintNameResult<'_> {
+        let complete_name = if let Some(tool_name) = tool_name {
+            format!("{}::{}", tool_name, lint_name)
+        } else {
+            lint_name.to_string()
+        };
+        // If the lint was scoped with `tool::` check if the tool lint exists
+        if let Some(_) = tool_name {
+            match self.by_name.get(&complete_name) {
+                None => match self.lint_groups.get(&*complete_name) {
+                    None => return CheckLintNameResult::Tool(Err((None, String::new()))),
+                    Some(LintGroup { lint_ids, .. }) => {
+                        return CheckLintNameResult::Tool(Ok(&lint_ids));
+                    }
+                },
+                Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
+                // If the lint was registered as removed or renamed by the lint tool, we don't need
+                // to treat tool_lints and rustc lints different and can use the code below.
+                _ => {}
+            }
+        }
+        match self.by_name.get(&complete_name) {
+            Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
+                format!("lint `{}` has been renamed to `{}`", complete_name, new_name),
+                Some(new_name.to_owned()),
+            ),
+            Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
+                format!("lint `{}` has been removed: `{}`", complete_name, reason),
+                None,
+            ),
+            None => match self.lint_groups.get(&*complete_name) {
+                // If neither the lint, nor the lint group exists check if there is a `clippy::`
+                // variant of this lint
+                None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
+                Some(LintGroup { lint_ids, depr, .. }) => {
+                    // Check if the lint group name is deprecated
+                    if let Some(LintAlias { name, silent }) = depr {
+                        let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
+                        return if *silent {
+                            CheckLintNameResult::Ok(&lint_ids)
+                        } else {
+                            CheckLintNameResult::Tool(Err((Some(&lint_ids), name.to_string())))
+                        };
+                    }
+                    CheckLintNameResult::Ok(&lint_ids)
+                }
+            },
+            Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
+        }
+    }
+
+    fn check_tool_name_for_backwards_compat(
+        &self,
+        lint_name: &str,
+        tool_name: &str,
+    ) -> CheckLintNameResult<'_> {
+        let complete_name = format!("{}::{}", tool_name, lint_name);
+        match self.by_name.get(&complete_name) {
+            None => match self.lint_groups.get(&*complete_name) {
+                // Now we are sure, that this lint exists nowhere
+                None => {
+                    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);
+
+                    CheckLintNameResult::NoLint(suggestion)
+                }
+                Some(LintGroup { lint_ids, depr, .. }) => {
+                    // Reaching this would be weird, but let's cover this case anyway
+                    if let Some(LintAlias { name, silent }) = depr {
+                        let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
+                        return if *silent {
+                            CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
+                        } else {
+                            CheckLintNameResult::Tool(Err((Some(&lint_ids), name.to_string())))
+                        };
+                    }
+                    CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
+                }
+            },
+            Some(&Id(ref id)) => {
+                CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
+            }
+            _ => CheckLintNameResult::NoLint(None),
+        }
+    }
+}
+
+/// Context for lint checking after type checking.
+pub struct LateContext<'a, 'tcx> {
+    /// Type context we're checking in.
+    pub tcx: TyCtxt<'tcx>,
+
+    /// Side-tables for the body we are in.
+    // FIXME: Make this lazy to avoid running the TypeckTables query?
+    pub tables: &'a ty::TypeckTables<'tcx>,
+
+    /// Parameter environment for the item we are in.
+    pub param_env: ty::ParamEnv<'tcx>,
+
+    /// Items accessible from the crate being checked.
+    pub access_levels: &'a AccessLevels,
+
+    /// The store of registered lints and the lint levels.
+    pub lint_store: &'tcx LintStore,
+
+    pub last_node_with_lint_attrs: hir::HirId,
+
+    /// Generic type parameters in scope for the item we are in.
+    pub generics: Option<&'tcx hir::Generics<'tcx>>,
+
+    /// We are only looking at one module
+    pub only_module: bool,
+}
+
+/// Context for lint checking of the AST, after expansion, before lowering to
+/// HIR.
+pub struct EarlyContext<'a> {
+    /// Type context we're checking in.
+    pub sess: &'a Session,
+
+    /// The crate being checked.
+    pub krate: &'a ast::Crate,
+
+    pub builder: LintLevelsBuilder<'a>,
+
+    /// The store of registered lints and the lint levels.
+    pub lint_store: &'a LintStore,
+
+    pub buffered: LintBuffer,
+}
+
+pub trait LintPassObject: Sized {}
+
+impl LintPassObject for EarlyLintPassObject {}
+
+impl LintPassObject for LateLintPassObject {}
+
+pub trait LintContext: Sized {
+    type PassObject: LintPassObject;
+
+    fn sess(&self) -> &Session;
+    fn lints(&self) -> &LintStore;
+
+    fn lookup_and_emit<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: Option<S>, msg: &str) {
+        self.lookup(lint, span, msg).emit();
+    }
+
+    fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(
+        &self,
+        lint: &'static Lint,
+        span: Option<S>,
+        msg: &str,
+        diagnostic: BuiltinLintDiagnostics,
+    ) {
+        let mut db = self.lookup(lint, span, msg);
+
+        let sess = self.sess();
+        match diagnostic {
+            BuiltinLintDiagnostics::Normal => (),
+            BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
+                let (sugg, app) = match sess.source_map().span_to_snippet(span) {
+                    Ok(s) if is_global => {
+                        (format!("dyn ({})", s), Applicability::MachineApplicable)
+                    }
+                    Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
+                    Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders),
+                };
+                db.span_suggestion(span, "use `dyn`", sugg, app);
+            }
+            BuiltinLintDiagnostics::AbsPathWithModule(span) => {
+                let (sugg, app) = match sess.source_map().span_to_snippet(span) {
+                    Ok(ref s) => {
+                        // FIXME(Manishearth) ideally the emitting code
+                        // can tell us whether or not this is global
+                        let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" };
+
+                        (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable)
+                    }
+                    Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
+                };
+                db.span_suggestion(span, "use `crate`", sugg, app);
+            }
+            BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => {
+                db.span_label(
+                    span,
+                    "names from parent modules are not accessible without an explicit import",
+                );
+            }
+            BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
+                db.span_note(span_def, "the macro is defined here");
+            }
+            BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+                n,
+                path_span,
+                incl_angl_brckt,
+                insertion_span,
+                anon_lts,
+            ) => {
+                add_elided_lifetime_in_path_suggestion(
+                    sess,
+                    &mut db,
+                    n,
+                    path_span,
+                    incl_angl_brckt,
+                    insertion_span,
+                    anon_lts,
+                );
+            }
+            BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
+                db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
+            }
+            BuiltinLintDiagnostics::UnusedImports(message, replaces) => {
+                if !replaces.is_empty() {
+                    db.tool_only_multipart_suggestion(
+                        &message,
+                        replaces,
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+            BuiltinLintDiagnostics::RedundantImport(spans, ident) => {
+                for (span, is_imported) in spans {
+                    let introduced = if is_imported { "imported" } else { "defined" };
+                    db.span_label(
+                        span,
+                        format!("the item `{}` is already {} here", ident, introduced),
+                    );
+                }
+            }
+            BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => {
+                stability::deprecation_suggestion(&mut db, suggestion, span)
+            }
+        }
+
+        db.emit();
+    }
+
+    fn lookup<S: Into<MultiSpan>>(
+        &self,
+        lint: &'static Lint,
+        span: Option<S>,
+        msg: &str,
+    ) -> DiagnosticBuilder<'_>;
+
+    /// Emit a lint at the appropriate level, for a particular span.
+    fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
+        self.lookup_and_emit(lint, Some(span), msg);
+    }
+
+    fn struct_span_lint<S: Into<MultiSpan>>(
+        &self,
+        lint: &'static Lint,
+        span: S,
+        msg: &str,
+    ) -> DiagnosticBuilder<'_> {
+        self.lookup(lint, Some(span), msg)
+    }
+
+    /// Emit a lint and note at the appropriate level, for a particular span.
+    fn span_lint_note(
+        &self,
+        lint: &'static Lint,
+        span: Span,
+        msg: &str,
+        note_span: Span,
+        note: &str,
+    ) {
+        let mut err = self.lookup(lint, Some(span), msg);
+        if note_span == span {
+            err.note(note);
+        } else {
+            err.span_note(note_span, note);
+        }
+        err.emit();
+    }
+
+    /// Emit a lint and help at the appropriate level, for a particular span.
+    fn span_lint_help(&self, lint: &'static Lint, span: Span, msg: &str, help: &str) {
+        let mut err = self.lookup(lint, Some(span), msg);
+        self.span_lint(lint, span, msg);
+        err.span_help(span, help);
+        err.emit();
+    }
+
+    /// Emit a lint at the appropriate level, with no associated span.
+    fn lint(&self, lint: &'static Lint, msg: &str) {
+        self.lookup_and_emit(lint, None as Option<Span>, msg);
+    }
+}
+
+impl<'a> EarlyContext<'a> {
+    pub fn new(
+        sess: &'a Session,
+        lint_store: &'a LintStore,
+        krate: &'a ast::Crate,
+        buffered: LintBuffer,
+        warn_about_weird_lints: bool,
+    ) -> EarlyContext<'a> {
+        EarlyContext {
+            sess,
+            krate,
+            lint_store,
+            builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store),
+            buffered,
+        }
+    }
+}
+
+impl LintContext for LateContext<'_, '_> {
+    type PassObject = LateLintPassObject;
+
+    /// Gets the overall compiler `Session` object.
+    fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+
+    fn lints(&self) -> &LintStore {
+        &*self.lint_store
+    }
+
+    fn lookup<S: Into<MultiSpan>>(
+        &self,
+        lint: &'static Lint,
+        span: Option<S>,
+        msg: &str,
+    ) -> DiagnosticBuilder<'_> {
+        let hir_id = self.last_node_with_lint_attrs;
+
+        match span {
+            Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg),
+            None => self.tcx.struct_lint_node(lint, hir_id, msg),
+        }
+    }
+}
+
+impl LintContext for EarlyContext<'_> {
+    type PassObject = EarlyLintPassObject;
+
+    /// Gets the overall compiler `Session` object.
+    fn sess(&self) -> &Session {
+        &self.sess
+    }
+
+    fn lints(&self) -> &LintStore {
+        &*self.lint_store
+    }
+
+    fn lookup<S: Into<MultiSpan>>(
+        &self,
+        lint: &'static Lint,
+        span: Option<S>,
+        msg: &str,
+    ) -> DiagnosticBuilder<'_> {
+        self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
+    }
+}
+
+impl<'a, 'tcx> LateContext<'a, 'tcx> {
+    pub fn current_lint_root(&self) -> hir::HirId {
+        self.last_node_with_lint_attrs
+    }
+
+    /// Check if a `DefId`'s path matches the given absolute type path usage.
+    ///
+    /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
+    /// inherent `impl` blocks are matched with the name of the type.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore (no context or def id available)
+    /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) {
+    ///     // The given `def_id` is that of an `Option` type
+    /// }
+    /// ```
+    pub fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool {
+        let names = self.get_def_path(def_id);
+
+        names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b)
+    }
+
+    /// Gets the absolute path of `def_id` as a vector of `Symbol`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore (no context or def id available)
+    /// let def_path = cx.get_def_path(def_id);
+    /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] {
+    ///     // The given `def_id` is that of an `Option` type
+    /// }
+    /// ```
+    pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
+        pub struct AbsolutePathPrinter<'tcx> {
+            pub tcx: TyCtxt<'tcx>,
+        }
+
+        impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
+            type Error = !;
+
+            type Path = Vec<Symbol>;
+            type Region = ();
+            type Type = ();
+            type DynExistential = ();
+            type Const = ();
+
+            fn tcx(&self) -> TyCtxt<'tcx> {
+                self.tcx
+            }
+
+            fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+                Ok(())
+            }
+
+            fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+                Ok(())
+            }
+
+            fn print_dyn_existential(
+                self,
+                _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+            ) -> Result<Self::DynExistential, Self::Error> {
+                Ok(())
+            }
+
+            fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+                Ok(())
+            }
+
+            fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+                Ok(vec![self.tcx.original_crate_name(cnum)])
+            }
+
+            fn path_qualified(
+                self,
+                self_ty: Ty<'tcx>,
+                trait_ref: Option<ty::TraitRef<'tcx>>,
+            ) -> Result<Self::Path, Self::Error> {
+                if trait_ref.is_none() {
+                    if let ty::Adt(def, substs) = self_ty.kind {
+                        return self.print_def_path(def.did, substs);
+                    }
+                }
+
+                // This shouldn't ever be needed, but just in case:
+                Ok(vec![match trait_ref {
+                    Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)),
+                    None => Symbol::intern(&format!("<{}>", self_ty)),
+                }])
+            }
+
+            fn path_append_impl(
+                self,
+                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+                _disambiguated_data: &DisambiguatedDefPathData,
+                self_ty: Ty<'tcx>,
+                trait_ref: Option<ty::TraitRef<'tcx>>,
+            ) -> Result<Self::Path, Self::Error> {
+                let mut path = print_prefix(self)?;
+
+                // This shouldn't ever be needed, but just in case:
+                path.push(match trait_ref {
+                    Some(trait_ref) => Symbol::intern(&format!(
+                        "<impl {} for {}>",
+                        trait_ref.print_only_trait_path(),
+                        self_ty
+                    )),
+                    None => Symbol::intern(&format!("<impl {}>", self_ty)),
+                });
+
+                Ok(path)
+            }
+
+            fn path_append(
+                self,
+                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+                disambiguated_data: &DisambiguatedDefPathData,
+            ) -> Result<Self::Path, Self::Error> {
+                let mut path = print_prefix(self)?;
+
+                // Skip `::{{constructor}}` on tuple/unit structs.
+                match disambiguated_data.data {
+                    DefPathData::Ctor => return Ok(path),
+                    _ => {}
+                }
+
+                path.push(disambiguated_data.data.as_symbol());
+                Ok(path)
+            }
+
+            fn path_generic_args(
+                self,
+                print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+                _args: &[GenericArg<'tcx>],
+            ) -> Result<Self::Path, Self::Error> {
+                print_prefix(self)
+            }
+        }
+
+        AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap()
+    }
+}
+
+impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
+    type Ty = Ty<'tcx>;
+    type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
+
+    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
+        self.tcx.layout_of(self.param_env.and(ty))
+    }
+}
index a09956854594379bf0bfaf19060c66b13d384c99..490114b2d4d2a037d84793042d36efe05dd5df80 100644 (file)
 //! upon. As the ast is traversed, this keeps track of the current lint level
 //! for all lint attributes.
 
-use rustc::lint::{EarlyContext, LintStore};
-use rustc::lint::{EarlyLintPass, EarlyLintPassObject};
-use rustc::lint::{LintBuffer, LintContext, LintPass};
-use rustc::session::Session;
-
+use crate::context::{EarlyContext, LintContext, LintStore};
+use crate::passes::{EarlyLintPass, EarlyLintPassObject};
+use rustc_session::lint::{LintBuffer, LintPass};
+use rustc_session::Session;
 use rustc_span::Span;
-use std::slice;
 use syntax::ast;
 use syntax::visit as ast_visit;
 
 use log::debug;
+use std::slice;
 
 macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
@@ -291,7 +290,7 @@ impl EarlyLintPass for EarlyLintPassObjects<'_> {
     )
 }
 
-early_lint_methods!(early_lint_pass_impl, []);
+crate::early_lint_methods!(early_lint_pass_impl, []);
 
 fn early_lint_crate<T: EarlyLintPass>(
     sess: &Session,
@@ -350,16 +349,19 @@ pub fn check_ast_crate<T: EarlyLintPass>(
         }
     } else {
         for pass in &mut passes {
-            buffered = sess.time(&format!("running lint: {}", pass.name()), || {
-                early_lint_crate(
-                    sess,
-                    lint_store,
-                    krate,
-                    EarlyLintPassObjects { lints: slice::from_mut(pass) },
-                    buffered,
-                    pre_expansion,
-                )
-            });
+            buffered = sess
+                .prof
+                .extra_verbose_generic_activity(&format!("running lint: {}", pass.name()))
+                .run(|| {
+                    early_lint_crate(
+                        sess,
+                        lint_store,
+                        krate,
+                        EarlyLintPassObjects { lints: slice::from_mut(pass) },
+                        buffered,
+                        pre_expansion,
+                    )
+                });
         }
     }
 
diff --git a/src/librustc_lint/internal.rs b/src/librustc_lint/internal.rs
new file mode 100644 (file)
index 0000000..5a5aedc
--- /dev/null
@@ -0,0 +1,244 @@
+//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
+//! Clippy.
+
+use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::Applicability;
+use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
+use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::{sym, Symbol};
+use syntax::ast::{Ident, Item, ItemKind};
+
+declare_tool_lint! {
+    pub rustc::DEFAULT_HASH_TYPES,
+    Allow,
+    "forbid HashMap and HashSet and suggest the FxHash* variants",
+    report_in_external_macro: true
+}
+
+pub struct DefaultHashTypes {
+    map: FxHashMap<Symbol, Symbol>,
+}
+
+impl DefaultHashTypes {
+    // we are allowed to use `HashMap` and `HashSet` as identifiers for implementing the lint itself
+    #[allow(rustc::default_hash_types)]
+    pub fn new() -> Self {
+        let mut map = FxHashMap::default();
+        map.insert(sym::HashMap, sym::FxHashMap);
+        map.insert(sym::HashSet, sym::FxHashSet);
+        Self { map }
+    }
+}
+
+impl_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]);
+
+impl EarlyLintPass for DefaultHashTypes {
+    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
+        if let Some(replace) = self.map.get(&ident.name) {
+            let msg = format!("Prefer {} over {}, it has better performance", replace, ident);
+            let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg);
+            db.span_suggestion(
+                ident.span,
+                "use",
+                replace.to_string(),
+                Applicability::MaybeIncorrect, // FxHashMap, ... needs another import
+            );
+            db.note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
+                .emit();
+        }
+    }
+}
+
+declare_tool_lint! {
+    pub rustc::USAGE_OF_TY_TYKIND,
+    Allow,
+    "usage of `ty::TyKind` outside of the `ty::sty` module",
+    report_in_external_macro: true
+}
+
+declare_tool_lint! {
+    pub rustc::TY_PASS_BY_REFERENCE,
+    Allow,
+    "passing `Ty` or `TyCtxt` by reference",
+    report_in_external_macro: true
+}
+
+declare_tool_lint! {
+    pub rustc::USAGE_OF_QUALIFIED_TY,
+    Allow,
+    "using `ty::{Ty,TyCtxt}` instead of importing it",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(TyTyKind => [
+    USAGE_OF_TY_TYKIND,
+    TY_PASS_BY_REFERENCE,
+    USAGE_OF_QUALIFIED_TY,
+]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
+    fn check_path(&mut self, cx: &LateContext<'_, '_>, path: &'tcx Path<'tcx>, _: HirId) {
+        let segments = path.segments.iter().rev().skip(1).rev();
+
+        if let Some(last) = segments.last() {
+            let span = path.span.with_hi(last.ident.span.hi());
+            if lint_ty_kind_usage(cx, last) {
+                cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, "usage of `ty::TyKind::<kind>`")
+                    .span_suggestion(
+                        span,
+                        "try using ty::<kind> directly",
+                        "ty".to_string(),
+                        Applicability::MaybeIncorrect, // ty maybe needs an import
+                    )
+                    .emit();
+            }
+        }
+    }
+
+    fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty<'tcx>) {
+        match &ty.kind {
+            TyKind::Path(qpath) => {
+                if let QPath::Resolved(_, path) = qpath {
+                    if let Some(last) = path.segments.iter().last() {
+                        if lint_ty_kind_usage(cx, last) {
+                            cx.struct_span_lint(
+                                USAGE_OF_TY_TYKIND,
+                                path.span,
+                                "usage of `ty::TyKind`",
+                            )
+                            .help("try using `Ty` instead")
+                            .emit();
+                        } else {
+                            if ty.span.from_expansion() {
+                                return;
+                            }
+                            if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
+                                if path.segments.len() > 1 {
+                                    cx.struct_span_lint(
+                                        USAGE_OF_QUALIFIED_TY,
+                                        path.span,
+                                        &format!("usage of qualified `ty::{}`", t),
+                                    )
+                                    .span_suggestion(
+                                        path.span,
+                                        "try using it unqualified",
+                                        t,
+                                        // The import probably needs to be changed
+                                        Applicability::MaybeIncorrect,
+                                    )
+                                    .emit();
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => {
+                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner_def_id()) {
+                    if cx.tcx.impl_trait_ref(impl_did).is_some() {
+                        return;
+                    }
+                }
+                if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
+                    cx.struct_span_lint(
+                        TY_PASS_BY_REFERENCE,
+                        ty.span,
+                        &format!("passing `{}` by reference", t),
+                    )
+                    .span_suggestion(
+                        ty.span,
+                        "try passing by value",
+                        t,
+                        // Changing type of function argument
+                        Applicability::MaybeIncorrect,
+                    )
+                    .emit();
+                }
+            }
+            _ => {}
+        }
+    }
+}
+
+fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment<'_>) -> bool {
+    if let Some(res) = segment.res {
+        if let Some(did) = res.opt_def_id() {
+            return cx.tcx.is_diagnostic_item(sym::TyKind, did);
+        }
+    }
+
+    false
+}
+
+fn is_ty_or_ty_ctxt(cx: &LateContext<'_, '_>, ty: &Ty<'_>) -> Option<String> {
+    match &ty.kind {
+        TyKind::Path(qpath) => {
+            if let QPath::Resolved(_, path) = qpath {
+                let did = path.res.opt_def_id()?;
+                if cx.tcx.is_diagnostic_item(sym::Ty, did) {
+                    return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
+                } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
+                    return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
+                }
+            }
+        }
+        _ => {}
+    }
+
+    None
+}
+
+fn gen_args(segment: &PathSegment<'_>) -> String {
+    if let Some(args) = &segment.args {
+        let lifetimes = args
+            .args
+            .iter()
+            .filter_map(|arg| {
+                if let GenericArg::Lifetime(lt) = arg {
+                    Some(lt.name.ident().to_string())
+                } else {
+                    None
+                }
+            })
+            .collect::<Vec<_>>();
+
+        if !lifetimes.is_empty() {
+            return format!("<{}>", lifetimes.join(", "));
+        }
+    }
+
+    String::new()
+}
+
+declare_tool_lint! {
+    pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO,
+    Allow,
+    "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
+}
+
+declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
+
+impl EarlyLintPass for LintPassImpl {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        if let ItemKind::Impl(_, _, _, _, Some(lint_pass), _, _) = &item.kind {
+            if let Some(last) = lint_pass.path.segments.last() {
+                if last.ident.name == sym::LintPass {
+                    let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
+                    let call_site = expn_data.call_site;
+                    if expn_data.kind.descr() != sym::impl_lint_pass
+                        && call_site.ctxt().outer_expn_data().kind.descr() != sym::declare_lint_pass
+                    {
+                        cx.struct_span_lint(
+                            LINT_PASS_IMPL_WITHOUT_MACRO,
+                            lint_pass.path.span,
+                            "implementing `LintPass` by hand",
+                        )
+                        .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
+                        .emit();
+                    }
+                }
+            }
+        }
+    }
+}
index 2e0a201fa98e9f3f8df793f5859b0bc1935ddd1b..30a3788377508b106ff02a8f817ab6d7dc2d56c5 100644 (file)
 //! upon. As the ast is traversed, this keeps track of the current lint level
 //! for all lint attributes.
 
-use rustc::hir::intravisit as hir_visit;
-use rustc::hir::intravisit::Visitor;
-use rustc::lint::LateContext;
-use rustc::lint::LintPass;
-use rustc::lint::{LateLintPass, LateLintPassObject};
+use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
+use rustc::hir::map::Map;
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit as hir_visit;
+use rustc_hir::intravisit::Visitor;
+use rustc_session::lint::LintPass;
 use rustc_span::Span;
-use std::slice;
 use syntax::ast;
+use syntax::walk_list;
 
 use log::debug;
-use syntax::walk_list;
+use std::any::Any;
+use std::slice;
+
+/// Extract the `LintStore` from the query context.
+/// This function exists because we've erased `LintStore` as `dyn Any` in the context.
+crate fn unerased_lint_store<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx LintStore {
+    let store: &dyn Any = &*tcx.lint_store;
+    store.downcast_ref().unwrap()
+}
 
 macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
@@ -86,10 +94,12 @@ fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
 impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx>
     for LateContextAndPass<'a, 'tcx, T>
 {
+    type Map = Map<'tcx>;
+
     /// Because lints are scoped lexically, we want to walk nested
     /// items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, Self::Map> {
         hir_visit::NestedVisitorMap::All(&self.context.tcx.hir())
     }
 
@@ -339,7 +349,7 @@ impl<'a, $hir> LateLintPass<'a, $hir> for LateLintPassObjects<'_> {
     )
 }
 
-late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
+crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
 
 fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
     tcx: TyCtxt<'tcx>,
@@ -353,7 +363,7 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
         tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
-        lint_store: &tcx.lint_store,
+        lint_store: unerased_lint_store(tcx),
         last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
         generics: None,
         only_module: true,
@@ -383,7 +393,7 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
     late_lint_mod_pass(tcx, module_def_id, builtin_lints);
 
     let mut passes: Vec<_> =
-        tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
+        unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
 
     if !passes.is_empty() {
         late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
@@ -400,7 +410,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
         tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
-        lint_store: &tcx.lint_store,
+        lint_store: unerased_lint_store(tcx),
         last_node_with_lint_attrs: hir::CRATE_HIR_ID,
         generics: None,
         only_module: false,
@@ -421,7 +431,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
 }
 
 fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
-    let mut passes = tcx.lint_store.late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
+    let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
 
     if !tcx.sess.opts.debugging_opts.no_interleave_lints {
         if !passes.is_empty() {
@@ -431,18 +441,27 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b
         late_lint_pass_crate(tcx, builtin_lints);
     } else {
         for pass in &mut passes {
-            tcx.sess.time(&format!("running late lint: {}", pass.name()), || {
-                late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
-            });
+            tcx.sess
+                .prof
+                .extra_verbose_generic_activity(&format!("running late lint: {}", pass.name()))
+                .run(|| {
+                    late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
+                });
         }
 
         let mut passes: Vec<_> =
-            tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
+            unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
 
         for pass in &mut passes {
-            tcx.sess.time(&format!("running late module lint: {}", pass.name()), || {
-                late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
-            });
+            tcx.sess
+                .prof
+                .extra_verbose_generic_activity(&format!(
+                    "running late module lint: {}",
+                    pass.name()
+                ))
+                .run(|| {
+                    late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
+                });
         }
     }
 }
@@ -454,13 +473,13 @@ pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
 ) {
     join(
         || {
-            tcx.sess.time("crate lints", || {
+            tcx.sess.time("crate_lints", || {
                 // Run whole crate non-incremental lints
                 late_lint_crate(tcx, builtin_lints());
             });
         },
         || {
-            tcx.sess.time("module lints", || {
+            tcx.sess.time("module_lints", || {
                 // Run per-module lints
                 par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
                     tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
index e060d6b551ca7a2a65fe45e650463dfc3f2ddd57..bbc3e57f5dd01a38683395b1906e4b88a769c5ba 100644 (file)
@@ -1,21 +1,33 @@
-use rustc::hir::intravisit;
-use rustc::lint::{LintLevelMap, LintLevelSets, LintLevelsBuilder, LintStore};
+use crate::context::{CheckLintNameResult, LintStore};
+use crate::late::unerased_lint_store;
+use rustc::hir::map::Map;
+use rustc::lint::struct_lint_level;
+use rustc::lint::{LintLevelMap, LintLevelSets, LintSet, LintSource};
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_hir::hir_id::HirId;
+use rustc_hir::intravisit;
+use rustc_session::lint::{builtin, Level, Lint};
+use rustc_session::Session;
+use rustc_span::{sym, MultiSpan, Symbol};
 use syntax::ast;
+use syntax::attr;
+use syntax::print::pprust;
+use syntax::sess::feature_err;
+use syntax::unwrap_or;
 
-pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId};
+use std::cmp;
 
 fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
     assert_eq!(cnum, LOCAL_CRATE);
-    let store = &tcx.lint_store;
-    let mut builder = LintLevelMapBuilder {
-        levels: LintLevelSets::builder(tcx.sess, false, &store),
-        tcx: tcx,
-        store: store,
-    };
+    let store = unerased_lint_store(tcx);
+    let levels = LintLevelsBuilder::new(tcx.sess, false, &store);
+    let mut builder = LintLevelMapBuilder { levels, tcx, store };
     let krate = tcx.hir().krate();
 
     let push = builder.levels.push(&krate.attrs, &store);
@@ -29,6 +41,378 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
     tcx.arena.alloc(builder.levels.build_map())
 }
 
+pub struct LintLevelsBuilder<'a> {
+    sess: &'a Session,
+    sets: LintLevelSets,
+    id_to_set: FxHashMap<HirId, u32>,
+    cur: u32,
+    warn_about_weird_lints: bool,
+}
+
+pub struct BuilderPush {
+    prev: u32,
+    pub changed: bool,
+}
+
+impl<'a> LintLevelsBuilder<'a> {
+    pub fn new(sess: &'a Session, warn_about_weird_lints: bool, store: &LintStore) -> Self {
+        let mut builder = LintLevelsBuilder {
+            sess,
+            sets: LintLevelSets::new(),
+            cur: 0,
+            id_to_set: Default::default(),
+            warn_about_weird_lints,
+        };
+        builder.process_command_line(sess, store);
+        assert_eq!(builder.sets.list.len(), 1);
+        builder
+    }
+
+    fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
+        let mut specs = FxHashMap::default();
+        self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
+
+        for &(ref lint_name, level) in &sess.opts.lint_opts {
+            store.check_lint_name_cmdline(sess, &lint_name, level);
+
+            // If the cap is less than this specified level, e.g., if we've got
+            // `--cap-lints allow` but we've also got `-D foo` then we ignore
+            // this specification as the lint cap will set it to allow anyway.
+            let level = cmp::min(level, self.sets.lint_cap);
+
+            let lint_flag_val = Symbol::intern(lint_name);
+            let ids = match store.find_lints(&lint_name) {
+                Ok(ids) => ids,
+                Err(_) => continue, // errors handled in check_lint_name_cmdline above
+            };
+            for id in ids {
+                let src = LintSource::CommandLine(lint_flag_val);
+                specs.insert(id, (level, src));
+            }
+        }
+
+        self.sets.list.push(LintSet::CommandLine { specs });
+    }
+
+    /// Pushes a list of AST lint attributes onto this context.
+    ///
+    /// This function will return a `BuilderPush` object which should be passed
+    /// to `pop` when this scope for the attributes provided is exited.
+    ///
+    /// This function will perform a number of tasks:
+    ///
+    /// * It'll validate all lint-related attributes in `attrs`
+    /// * It'll mark all lint-related attributes as used
+    /// * Lint levels will be updated based on the attributes provided
+    /// * Lint attributes are validated, e.g., a #[forbid] can't be switched to
+    ///   #[allow]
+    ///
+    /// Don't forget to call `pop`!
+    pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
+        let mut specs = FxHashMap::default();
+        let sess = self.sess;
+        let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
+        for attr in attrs {
+            let level = match Level::from_symbol(attr.name_or_empty()) {
+                None => continue,
+                Some(lvl) => lvl,
+            };
+
+            let meta = unwrap_or!(attr.meta(), continue);
+            attr::mark_used(attr);
+
+            let mut metas = unwrap_or!(meta.meta_item_list(), continue);
+
+            if metas.is_empty() {
+                // FIXME (#55112): issue unused-attributes lint for `#[level()]`
+                continue;
+            }
+
+            // Before processing the lint names, look for a reason (RFC 2383)
+            // at the end.
+            let mut reason = None;
+            let tail_li = &metas[metas.len() - 1];
+            if let Some(item) = tail_li.meta_item() {
+                match item.kind {
+                    ast::MetaItemKind::Word => {} // actual lint names handled later
+                    ast::MetaItemKind::NameValue(ref name_value) => {
+                        if item.path == sym::reason {
+                            // found reason, reslice meta list to exclude it
+                            metas = &metas[0..metas.len() - 1];
+                            // FIXME (#55112): issue unused-attributes lint if we thereby
+                            // don't have any lint names (`#[level(reason = "foo")]`)
+                            if let ast::LitKind::Str(rationale, _) = name_value.kind {
+                                if !self.sess.features_untracked().lint_reasons {
+                                    feature_err(
+                                        &self.sess.parse_sess,
+                                        sym::lint_reasons,
+                                        item.span,
+                                        "lint reasons are experimental",
+                                    )
+                                    .emit();
+                                }
+                                reason = Some(rationale);
+                            } else {
+                                bad_attr(name_value.span)
+                                    .span_label(name_value.span, "reason must be a string literal")
+                                    .emit();
+                            }
+                        } else {
+                            bad_attr(item.span)
+                                .span_label(item.span, "bad attribute argument")
+                                .emit();
+                        }
+                    }
+                    ast::MetaItemKind::List(_) => {
+                        bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
+                    }
+                }
+            }
+
+            for li in metas {
+                let meta_item = match li.meta_item() {
+                    Some(meta_item) if meta_item.is_word() => meta_item,
+                    _ => {
+                        let sp = li.span();
+                        let mut err = bad_attr(sp);
+                        let mut add_label = true;
+                        if let Some(item) = li.meta_item() {
+                            if let ast::MetaItemKind::NameValue(_) = item.kind {
+                                if item.path == sym::reason {
+                                    err.span_label(sp, "reason in lint attribute must come last");
+                                    add_label = false;
+                                }
+                            }
+                        }
+                        if add_label {
+                            err.span_label(sp, "bad attribute argument");
+                        }
+                        err.emit();
+                        continue;
+                    }
+                };
+                let tool_name = if meta_item.path.segments.len() > 1 {
+                    let tool_ident = meta_item.path.segments[0].ident;
+                    if !attr::is_known_lint_tool(tool_ident) {
+                        struct_span_err!(
+                            sess,
+                            tool_ident.span,
+                            E0710,
+                            "an unknown tool name found in scoped lint: `{}`",
+                            pprust::path_to_string(&meta_item.path),
+                        )
+                        .emit();
+                        continue;
+                    }
+
+                    Some(tool_ident.name)
+                } else {
+                    None
+                };
+                let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
+                match store.check_lint_name(&name.as_str(), tool_name) {
+                    CheckLintNameResult::Ok(ids) => {
+                        let src = LintSource::Node(name, li.span(), reason);
+                        for id in ids {
+                            specs.insert(*id, (level, src));
+                        }
+                    }
+
+                    CheckLintNameResult::Tool(result) => {
+                        match result {
+                            Ok(ids) => {
+                                let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
+                                let src = LintSource::Node(
+                                    Symbol::intern(complete_name),
+                                    li.span(),
+                                    reason,
+                                );
+                                for id in ids {
+                                    specs.insert(*id, (level, src));
+                                }
+                            }
+                            Err((Some(ids), new_lint_name)) => {
+                                let lint = builtin::RENAMED_AND_REMOVED_LINTS;
+                                let (lvl, src) =
+                                    self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                                let msg = format!(
+                                    "lint name `{}` is deprecated \
+                                     and may not have an effect in the future. \
+                                     Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
+                                    name
+                                );
+                                struct_lint_level(
+                                    self.sess,
+                                    lint,
+                                    lvl,
+                                    src,
+                                    Some(li.span().into()),
+                                    &msg,
+                                )
+                                .span_suggestion(
+                                    li.span(),
+                                    "change it to",
+                                    new_lint_name.to_string(),
+                                    Applicability::MachineApplicable,
+                                )
+                                .emit();
+
+                                let src = LintSource::Node(
+                                    Symbol::intern(&new_lint_name),
+                                    li.span(),
+                                    reason,
+                                );
+                                for id in ids {
+                                    specs.insert(*id, (level, src));
+                                }
+                            }
+                            Err((None, _)) => {
+                                // If Tool(Err(None, _)) is returned, then either the lint does not
+                                // exist in the tool or the code was not compiled with the tool and
+                                // therefore the lint was never added to the `LintStore`. To detect
+                                // this is the responsibility of the lint tool.
+                            }
+                        }
+                    }
+
+                    _ if !self.warn_about_weird_lints => {}
+
+                    CheckLintNameResult::Warning(msg, renamed) => {
+                        let lint = builtin::RENAMED_AND_REMOVED_LINTS;
+                        let (level, src) =
+                            self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                        let mut err = struct_lint_level(
+                            self.sess,
+                            lint,
+                            level,
+                            src,
+                            Some(li.span().into()),
+                            &msg,
+                        );
+                        if let Some(new_name) = renamed {
+                            err.span_suggestion(
+                                li.span(),
+                                "use the new name",
+                                new_name,
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                        err.emit();
+                    }
+                    CheckLintNameResult::NoLint(suggestion) => {
+                        let lint = builtin::UNKNOWN_LINTS;
+                        let (level, src) =
+                            self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                        let msg = format!("unknown lint: `{}`", name);
+                        let mut db = struct_lint_level(
+                            self.sess,
+                            lint,
+                            level,
+                            src,
+                            Some(li.span().into()),
+                            &msg,
+                        );
+
+                        if let Some(suggestion) = suggestion {
+                            db.span_suggestion(
+                                li.span(),
+                                "did you mean",
+                                suggestion.to_string(),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+
+                        db.emit();
+                    }
+                }
+            }
+        }
+
+        for (id, &(level, ref src)) in specs.iter() {
+            if level == Level::Forbid {
+                continue;
+            }
+            let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) {
+                (Some(Level::Forbid), src) => src,
+                _ => continue,
+            };
+            let forbidden_lint_name = match forbid_src {
+                LintSource::Default => id.to_string(),
+                LintSource::Node(name, _, _) => name.to_string(),
+                LintSource::CommandLine(name) => name.to_string(),
+            };
+            let (lint_attr_name, lint_attr_span) = match *src {
+                LintSource::Node(name, span, _) => (name, span),
+                _ => continue,
+            };
+            let mut diag_builder = struct_span_err!(
+                self.sess,
+                lint_attr_span,
+                E0453,
+                "{}({}) overruled by outer forbid({})",
+                level.as_str(),
+                lint_attr_name,
+                forbidden_lint_name
+            );
+            diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
+            match forbid_src {
+                LintSource::Default => {}
+                LintSource::Node(_, forbid_source_span, reason) => {
+                    diag_builder.span_label(forbid_source_span, "`forbid` level set here");
+                    if let Some(rationale) = reason {
+                        diag_builder.note(&rationale.as_str());
+                    }
+                }
+                LintSource::CommandLine(_) => {
+                    diag_builder.note("`forbid` lint level was set on command line");
+                }
+            }
+            diag_builder.emit();
+            // don't set a separate error for every lint in the group
+            break;
+        }
+
+        let prev = self.cur;
+        if specs.len() > 0 {
+            self.cur = self.sets.list.len() as u32;
+            self.sets.list.push(LintSet::Node { specs: specs, parent: prev });
+        }
+
+        BuilderPush { prev: prev, changed: prev != self.cur }
+    }
+
+    /// Called after `push` when the scope of a set of attributes are exited.
+    pub fn pop(&mut self, push: BuilderPush) {
+        self.cur = push.prev;
+    }
+
+    /// Used to emit a lint-related diagnostic based on the current state of
+    /// this lint context.
+    pub fn struct_lint(
+        &self,
+        lint: &'static Lint,
+        span: Option<MultiSpan>,
+        msg: &str,
+    ) -> DiagnosticBuilder<'a> {
+        let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
+        struct_lint_level(self.sess, lint, level, src, span, msg)
+    }
+
+    /// Registers the ID provided with the current set of lints stored in
+    /// this context.
+    pub fn register_id(&mut self, id: HirId) {
+        self.id_to_set.insert(id, self.cur);
+    }
+
+    pub fn build(self) -> LintLevelSets {
+        self.sets
+    }
+
+    pub fn build_map(self) -> LintLevelMap {
+        LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
+    }
+}
+
 struct LintLevelMapBuilder<'a, 'tcx> {
     levels: LintLevelsBuilder<'tcx>,
     tcx: TyCtxt<'tcx>,
@@ -50,7 +434,9 @@ fn with_lint_attrs<F>(&mut self, id: hir::HirId, attrs: &[ast::Attribute], f: F)
 }
 
 impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> {
         intravisit::NestedVisitorMap::All(&self.tcx.hir())
     }
 
index e272c3af468244dafedd5378bc974792f1a9d54e..78e9d0f14f2deffe0a5548faf39a99ea3b2484c3 100644 (file)
@@ -1,9 +1,25 @@
-//! # Lints in the Rust compiler
+//! Lints, aka compiler warnings.
 //!
-//! This currently only contains the definitions and implementations
-//! of most of the lints that `rustc` supports directly, it does not
-//! contain the infrastructure for defining/registering lints. That is
-//! available in `rustc::lint` and `rustc_driver::plugin` respectively.
+//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
+//! want to enforce, but might reasonably want to permit as well, on a
+//! module-by-module basis. They contrast with static constraints enforced by
+//! other phases of the compiler, which are generally required to hold in order
+//! to compile the program at all.
+//!
+//! Most lints can be written as `LintPass` instances. These run after
+//! all other analyses. The `LintPass`es built into rustc are defined
+//! within `rustc_session::lint::builtin`,
+//! which has further comments on how to add such a lint.
+//! rustc can also load user-defined lint plugins via the plugin mechanism.
+//!
+//! Some of rustc's lints are defined elsewhere in the compiler and work by
+//! calling `add_lint()` on the overall `Session` object. This works when
+//! it happens before the main lint pass, which emits the lints stored by
+//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
+//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
+//! in `context.rs`.
+//!
+//! Some code also exists in `rustc_session::lint`, `rustc::lint`.
 //!
 //! ## Note
 //!
@@ -14,6 +30,8 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(crate_visibility_modifier)]
+#![feature(never_type)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 
 
 mod array_into_iter;
 pub mod builtin;
+mod context;
 mod early;
+mod internal;
 mod late;
 mod levels;
 mod non_ascii_idents;
 mod nonstandard_style;
+mod passes;
 mod redundant_semicolon;
 mod types;
 mod unused;
 
-use rustc::lint;
-use rustc::lint::builtin::{
-    BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
-    INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
-};
-use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-
+use rustc_session::lint::builtin::{
+    BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
+    INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
+};
 use rustc_span::Span;
 use syntax::ast;
 
-use lint::LintId;
-
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
+use internal::*;
 use non_ascii_idents::*;
 use nonstandard_style::*;
 use redundant_semicolon::*;
-use rustc::lint::internal::*;
 use types::*;
 use unused::*;
 
-/// Useful for other parts of the compiler.
+/// Useful for other parts of the compiler / Clippy.
 pub use builtin::SoftLints;
+pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
 pub use early::check_ast_crate;
 pub use late::check_crate;
+pub use passes::{EarlyLintPass, LateLintPass};
+pub use rustc_session::lint::Level::{self, *};
+pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
+pub use rustc_session::lint::{LintArray, LintPass};
 
 pub fn provide(providers: &mut Providers<'_>) {
     levels::provide(providers);
@@ -178,8 +199,8 @@ macro_rules! declare_combined_late_pass {
 
 late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);
 
-pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore {
-    let mut lint_store = lint::LintStore::new();
+pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintStore {
+    let mut lint_store = LintStore::new();
 
     register_builtins(&mut lint_store, no_interleave_lints);
     if internal_lints {
@@ -192,7 +213,7 @@ pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::
 /// Tell the `LintStore` about all the built-in lints (the ones
 /// defined in this crate and the ones defined in
 /// `rustc::lint::builtin`).
-fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
+fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
     macro_rules! add_lint_group {
         ($name:expr, $($lint:ident),*) => (
             store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
@@ -389,7 +410,7 @@ macro_rules! register_passes {
     store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
 }
 
-fn register_internals(store: &mut lint::LintStore) {
+fn register_internals(store: &mut LintStore) {
     store.register_lints(&DefaultHashTypes::get_lints());
     store.register_early_pass(|| box DefaultHashTypes::new());
     store.register_lints(&LintPassImpl::get_lints());
index f30d0bcbdd53fe0eb9c308cb6c34a4b0ccbaac05..3c85a1b31b2445e77e37a7533d11529c64be8718 100644 (file)
@@ -1,4 +1,4 @@
-use crate::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use crate::{EarlyContext, EarlyLintPass, LintContext};
 use syntax::ast;
 
 declare_lint! {
index d50c048301042ba107ae428fb232d0efbf13f357..a2b7884241ff7b9bbc4600aa68b64a47043b3be1 100644 (file)
@@ -1,17 +1,15 @@
-use lint::{EarlyContext, LateContext, LintArray, LintContext};
-use lint::{EarlyLintPass, LateLintPass, LintPass};
-use rustc::hir::intravisit::FnKind;
-use rustc::lint;
+use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc::ty;
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit::FnKind;
 use rustc_hir::{GenericParamKind, PatKind};
 use rustc_span::symbol::sym;
 use rustc_span::{symbol::Ident, BytePos, Span};
 use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::errors::Applicability;
 
 #[derive(PartialEq)]
 pub enum MethodLateContext {
diff --git a/src/librustc_lint/passes.rs b/src/librustc_lint/passes.rs
new file mode 100644 (file)
index 0000000..7e5d670
--- /dev/null
@@ -0,0 +1,284 @@
+use crate::context::{EarlyContext, LateContext};
+
+use rustc_data_structures::sync;
+use rustc_hir as hir;
+use rustc_session::lint::builtin::HardwiredLints;
+use rustc_session::lint::LintPass;
+use rustc_span::Span;
+use syntax::ast;
+
+#[macro_export]
+macro_rules! late_lint_methods {
+    ($macro:path, $args:tt, [$hir:tt]) => (
+        $macro!($args, [$hir], [
+            fn check_param(a: &$hir hir::Param<$hir>);
+            fn check_body(a: &$hir hir::Body<$hir>);
+            fn check_body_post(a: &$hir hir::Body<$hir>);
+            fn check_name(a: Span, b: ast::Name);
+            fn check_crate(a: &$hir hir::Crate<$hir>);
+            fn check_crate_post(a: &$hir hir::Crate<$hir>);
+            fn check_mod(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId);
+            fn check_mod_post(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId);
+            fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>);
+            fn check_foreign_item_post(a: &$hir hir::ForeignItem<$hir>);
+            fn check_item(a: &$hir hir::Item<$hir>);
+            fn check_item_post(a: &$hir hir::Item<$hir>);
+            fn check_local(a: &$hir hir::Local<$hir>);
+            fn check_block(a: &$hir hir::Block<$hir>);
+            fn check_block_post(a: &$hir hir::Block<$hir>);
+            fn check_stmt(a: &$hir hir::Stmt<$hir>);
+            fn check_arm(a: &$hir hir::Arm<$hir>);
+            fn check_pat(a: &$hir hir::Pat<$hir>);
+            fn check_expr(a: &$hir hir::Expr<$hir>);
+            fn check_expr_post(a: &$hir hir::Expr<$hir>);
+            fn check_ty(a: &$hir hir::Ty<$hir>);
+            fn check_generic_param(a: &$hir hir::GenericParam<$hir>);
+            fn check_generics(a: &$hir hir::Generics<$hir>);
+            fn check_where_predicate(a: &$hir hir::WherePredicate<$hir>);
+            fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef<$hir>, b: hir::TraitBoundModifier);
+            fn check_fn(
+                a: rustc_hir::intravisit::FnKind<$hir>,
+                b: &$hir hir::FnDecl<$hir>,
+                c: &$hir hir::Body<$hir>,
+                d: Span,
+                e: hir::HirId);
+            fn check_fn_post(
+                a: rustc_hir::intravisit::FnKind<$hir>,
+                b: &$hir hir::FnDecl<$hir>,
+                c: &$hir hir::Body<$hir>,
+                d: Span,
+                e: hir::HirId
+            );
+            fn check_trait_item(a: &$hir hir::TraitItem<$hir>);
+            fn check_trait_item_post(a: &$hir hir::TraitItem<$hir>);
+            fn check_impl_item(a: &$hir hir::ImplItem<$hir>);
+            fn check_impl_item_post(a: &$hir hir::ImplItem<$hir>);
+            fn check_struct_def(a: &$hir hir::VariantData<$hir>);
+            fn check_struct_def_post(a: &$hir hir::VariantData<$hir>);
+            fn check_struct_field(a: &$hir hir::StructField<$hir>);
+            fn check_variant(a: &$hir hir::Variant<$hir>);
+            fn check_variant_post(a: &$hir hir::Variant<$hir>);
+            fn check_lifetime(a: &$hir hir::Lifetime);
+            fn check_path(a: &$hir hir::Path<$hir>, b: hir::HirId);
+            fn check_attribute(a: &$hir ast::Attribute);
+
+            /// Called when entering a syntax node that can have lint attributes such
+            /// as `#[allow(...)]`. Called with *all* the attributes of that node.
+            fn enter_lint_attrs(a: &$hir [ast::Attribute]);
+
+            /// Counterpart to `enter_lint_attrs`.
+            fn exit_lint_attrs(a: &$hir [ast::Attribute]);
+        ]);
+    )
+}
+
+/// Trait for types providing lint checks.
+///
+/// Each `check` method checks a single syntax node, and should not
+/// invoke methods recursively (unlike `Visitor`). By default they
+/// do nothing.
+//
+// FIXME: eliminate the duplication with `Visitor`. But this also
+// contains a few lint-specific methods with no equivalent in `Visitor`.
+
+macro_rules! expand_lint_pass_methods {
+    ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+        $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
+    )
+}
+
+macro_rules! declare_late_lint_pass {
+    ([], [$hir:tt], [$($methods:tt)*]) => (
+        pub trait LateLintPass<'a, $hir>: LintPass {
+            expand_lint_pass_methods!(&LateContext<'a, $hir>, [$($methods)*]);
+        }
+    )
+}
+
+late_lint_methods!(declare_late_lint_pass, [], ['tcx]);
+
+impl LateLintPass<'_, '_> for HardwiredLints {}
+
+#[macro_export]
+macro_rules! expand_combined_late_lint_pass_method {
+    ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
+        $($self.$passes.$name $params;)*
+    })
+}
+
+#[macro_export]
+macro_rules! expand_combined_late_lint_pass_methods {
+    ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+        $(fn $name(&mut self, context: &LateContext<'a, 'tcx>, $($param: $arg),*) {
+            expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*));
+        })*
+    )
+}
+
+#[macro_export]
+macro_rules! declare_combined_late_lint_pass {
+    ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => (
+        #[allow(non_snake_case)]
+        $v struct $name {
+            $($passes: $passes,)*
+        }
+
+        impl $name {
+            $v fn new() -> Self {
+                Self {
+                    $($passes: $constructor,)*
+                }
+            }
+
+            $v fn get_lints() -> LintArray {
+                let mut lints = Vec::new();
+                $(lints.extend_from_slice(&$passes::get_lints());)*
+                lints
+            }
+        }
+
+        impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $name {
+            expand_combined_late_lint_pass_methods!([$($passes),*], $methods);
+        }
+
+        #[allow(rustc::lint_pass_impl_without_macro)]
+        impl LintPass for $name {
+            fn name(&self) -> &'static str {
+                panic!()
+            }
+        }
+    )
+}
+
+#[macro_export]
+macro_rules! early_lint_methods {
+    ($macro:path, $args:tt) => (
+        $macro!($args, [
+            fn check_param(a: &ast::Param);
+            fn check_ident(a: ast::Ident);
+            fn check_crate(a: &ast::Crate);
+            fn check_crate_post(a: &ast::Crate);
+            fn check_mod(a: &ast::Mod, b: Span, c: ast::NodeId);
+            fn check_mod_post(a: &ast::Mod, b: Span, c: ast::NodeId);
+            fn check_foreign_item(a: &ast::ForeignItem);
+            fn check_foreign_item_post(a: &ast::ForeignItem);
+            fn check_item(a: &ast::Item);
+            fn check_item_post(a: &ast::Item);
+            fn check_local(a: &ast::Local);
+            fn check_block(a: &ast::Block);
+            fn check_block_post(a: &ast::Block);
+            fn check_stmt(a: &ast::Stmt);
+            fn check_arm(a: &ast::Arm);
+            fn check_pat(a: &ast::Pat);
+            fn check_pat_post(a: &ast::Pat);
+            fn check_expr(a: &ast::Expr);
+            fn check_expr_post(a: &ast::Expr);
+            fn check_ty(a: &ast::Ty);
+            fn check_generic_param(a: &ast::GenericParam);
+            fn check_generics(a: &ast::Generics);
+            fn check_where_predicate(a: &ast::WherePredicate);
+            fn check_poly_trait_ref(a: &ast::PolyTraitRef,
+                                    b: &ast::TraitBoundModifier);
+            fn check_fn(a: syntax::visit::FnKind<'_>, b: &ast::FnDecl, c: Span, d_: ast::NodeId);
+            fn check_fn_post(
+                a: syntax::visit::FnKind<'_>,
+                b: &ast::FnDecl,
+                c: Span,
+                d: ast::NodeId
+            );
+            fn check_trait_item(a: &ast::AssocItem);
+            fn check_trait_item_post(a: &ast::AssocItem);
+            fn check_impl_item(a: &ast::AssocItem);
+            fn check_impl_item_post(a: &ast::AssocItem);
+            fn check_struct_def(a: &ast::VariantData);
+            fn check_struct_def_post(a: &ast::VariantData);
+            fn check_struct_field(a: &ast::StructField);
+            fn check_variant(a: &ast::Variant);
+            fn check_variant_post(a: &ast::Variant);
+            fn check_lifetime(a: &ast::Lifetime);
+            fn check_path(a: &ast::Path, b: ast::NodeId);
+            fn check_attribute(a: &ast::Attribute);
+            fn check_mac_def(a: &ast::MacroDef, b: ast::NodeId);
+            fn check_mac(a: &ast::Mac);
+
+            /// Called when entering a syntax node that can have lint attributes such
+            /// as `#[allow(...)]`. Called with *all* the attributes of that node.
+            fn enter_lint_attrs(a: &[ast::Attribute]);
+
+            /// Counterpart to `enter_lint_attrs`.
+            fn exit_lint_attrs(a: &[ast::Attribute]);
+        ]);
+    )
+}
+
+macro_rules! expand_early_lint_pass_methods {
+    ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+        $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
+    )
+}
+
+macro_rules! declare_early_lint_pass {
+    ([], [$($methods:tt)*]) => (
+        pub trait EarlyLintPass: LintPass {
+            expand_early_lint_pass_methods!(&EarlyContext<'_>, [$($methods)*]);
+        }
+    )
+}
+
+early_lint_methods!(declare_early_lint_pass, []);
+
+#[macro_export]
+macro_rules! expand_combined_early_lint_pass_method {
+    ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
+        $($self.$passes.$name $params;)*
+    })
+}
+
+#[macro_export]
+macro_rules! expand_combined_early_lint_pass_methods {
+    ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+        $(fn $name(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) {
+            expand_combined_early_lint_pass_method!($passes, self, $name, (context, $($param),*));
+        })*
+    )
+}
+
+#[macro_export]
+macro_rules! declare_combined_early_lint_pass {
+    ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], $methods:tt) => (
+        #[allow(non_snake_case)]
+        $v struct $name {
+            $($passes: $passes,)*
+        }
+
+        impl $name {
+            $v fn new() -> Self {
+                Self {
+                    $($passes: $constructor,)*
+                }
+            }
+
+            $v fn get_lints() -> LintArray {
+                let mut lints = Vec::new();
+                $(lints.extend_from_slice(&$passes::get_lints());)*
+                lints
+            }
+        }
+
+        impl EarlyLintPass for $name {
+            expand_combined_early_lint_pass_methods!([$($passes),*], $methods);
+        }
+
+        #[allow(rustc::lint_pass_impl_without_macro)]
+        impl LintPass for $name {
+            fn name(&self) -> &'static str {
+                panic!()
+            }
+        }
+    )
+}
+
+/// A lint pass boxed up as a trait object.
+pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>;
+pub type LateLintPassObject =
+    Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>;
index 8dbf96a155825dd78956825dbe5b1306c944aa1b..21b244ad75d4e048c52233abf670497c53ac403d 100644 (file)
@@ -1,6 +1,6 @@
-use crate::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_errors::Applicability;
 use syntax::ast::{ExprKind, Stmt, StmtKind};
-use syntax::errors::Applicability;
 
 declare_lint! {
     pub REDUNDANT_SEMICOLON,
index f740bdb2716194ed3d983513e2738da9e994a118..674a82b61961c457bf68b3f092027bbc7f301f34 100644 (file)
@@ -1,22 +1,20 @@
 #![allow(non_snake_case)]
 
-use crate::hir::def_id::DefId;
-use lint::{LateContext, LintArray, LintContext};
-use lint::{LateLintPass, LintPass};
-use rustc::lint;
+use crate::{LateContext, LateLintPass, LintContext};
 use rustc::mir::interpret::{sign_extend, truncate};
 use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx};
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_hir::{is_range_literal, ExprKind, Node};
 use rustc_index::vec::Idx;
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
-use syntax::errors::Applicability;
 use syntax::{ast, attr};
 
 use log::debug;
index 184651e3ad5649286c128466e959fb27120af509..26cbda3d97895bf04e5fc2a1a8907ce1f7ed3dbd 100644 (file)
@@ -1,21 +1,18 @@
-use lint::{EarlyContext, LateContext, LintArray, LintContext};
-use lint::{EarlyLintPass, LateLintPass, LintPass};
-use rustc::lint;
-use rustc::lint::builtin::UNUSED_ATTRIBUTES;
+use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc::ty::adjustment;
 use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{pluralize, Applicability};
 use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-
+use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
 use rustc_span::symbol::Symbol;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
 use syntax::ast;
 use syntax::attr;
-use syntax::errors::{pluralize, Applicability};
 use syntax::print::pprust;
 use syntax::util::parser;
 
diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml
deleted file mode 100644 (file)
index 9a24361..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-build = "build.rs"
-name = "rustc_lsan"
-version = "0.0.0"
-edition = "2018"
-
-[lib]
-name = "rustc_lsan"
-path = "lib.rs"
-test = false
-
-[build-dependencies]
-build_helper = { path = "../build_helper" }
-cmake = "0.1.38"
-
-[dependencies]
-alloc = { path = "../liballoc" }
-core = { path = "../libcore" }
-compiler_builtins = "0.1.0"
diff --git a/src/librustc_lsan/build.rs b/src/librustc_lsan/build.rs
deleted file mode 100644 (file)
index 6201bc9..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-use build_helper::sanitizer_lib_boilerplate;
-use std::env;
-
-use cmake::Config;
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
-    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
-        return;
-    }
-    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
-        build_helper::restore_library_path();
-
-        let (native, target) = match sanitizer_lib_boilerplate("lsan") {
-            Ok(native) => native,
-            _ => return,
-        };
-
-        Config::new(&native.src_dir)
-            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
-            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
-            .define("COMPILER_RT_BUILD_XRAY", "OFF")
-            .define("LLVM_CONFIG_PATH", llvm_config)
-            .out_dir(&native.out_dir)
-            .build_target(&target)
-            .build();
-    }
-    println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
-}
diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs
deleted file mode 100644 (file)
index bdbc154..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#![sanitizer_runtime]
-#![feature(nll)]
-#![feature(sanitizer_runtime)]
-#![feature(staged_api)]
-#![no_std]
-#![unstable(
-    feature = "sanitizer_runtime_lib",
-    reason = "internal implementation detail of sanitizers",
-    issue = "none"
-)]
index d998e82d4890b03dc5acc6a1a9f2abfb46b3c651..48767c377a94c7d40df21dad8e792bd31385504d 100644 (file)
@@ -16,8 +16,8 @@ memmap = "0.7"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_target = { path = "../librustc_target" }
 rustc_index = { path = "../librustc_index" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
index cfd7b76a22279d16f08772ba2a67eed48d166d16..181f872154c5107e55776b767d5c7a358bf23713 100644 (file)
@@ -6,32 +6,29 @@
 use rustc::hir::map::Definitions;
 use rustc::middle::cstore::DepKind;
 use rustc::middle::cstore::{CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn};
-use rustc::session::config::{self, Sanitizer};
+use rustc::session::config;
 use rustc::session::search_paths::PathKind;
 use rustc::session::{CrateDisambiguator, Session};
 use rustc::ty::TyCtxt;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
-use rustc_hir::def_id::CrateNum;
-use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_index::vec::IndexVec;
-use rustc_target::spec::{PanicStrategy, TargetTriple};
-
-use std::path::Path;
-use std::{cmp, fs};
-
-use log::{debug, info, log_enabled};
-use proc_macro::bridge::client::ProcMacro;
+use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_expand::base::SyntaxExtension;
+use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_index::vec::IndexVec;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::{PanicStrategy, TargetTriple};
 use syntax::ast;
 use syntax::attr;
 use syntax::expand::allocator::{global_allocator_spans, AllocatorKind};
-use syntax::span_fatal;
 
-use rustc_error_codes::*;
+use log::{debug, info, log_enabled};
+use proc_macro::bridge::client::ProcMacro;
+use std::path::Path;
+use std::{cmp, fs};
 
 #[derive(Clone)]
 pub struct CStore {
@@ -261,7 +258,7 @@ fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
         if self.local_crate_name == root.name()
             && self.sess.local_crate_disambiguator() == root.disambiguator()
         {
-            span_fatal!(
+            struct_span_err!(
                 self.sess,
                 span,
                 E0519,
@@ -271,6 +268,7 @@ fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
                          will result in symbol conflicts between the two.",
                 root.name()
             )
+            .emit()
         }
 
         // Check for conflicts with any crate loaded so far
@@ -280,7 +278,7 @@ fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
                other.hash() != root.hash()
             {
                 // but different SVH
-                span_fatal!(
+                struct_span_err!(
                     self.sess,
                     span,
                     E0523,
@@ -289,6 +287,7 @@ fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
                          will result in symbol conflicts between the two.",
                     root.name()
                 )
+                .emit();
             }
         });
     }
@@ -672,108 +671,6 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
     }
 
-    fn inject_sanitizer_runtime(&mut self) {
-        if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer {
-            // Sanitizers can only be used on some tested platforms with
-            // executables linked to `std`
-            const ASAN_SUPPORTED_TARGETS: &[&str] =
-                &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
-            const TSAN_SUPPORTED_TARGETS: &[&str] =
-                &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
-            const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
-            const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
-
-            let supported_targets = match *sanitizer {
-                Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
-                Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
-                Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
-                Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
-            };
-            if !supported_targets.contains(&&*self.sess.opts.target_triple.triple()) {
-                self.sess.err(&format!(
-                    "{:?}Sanitizer only works with the `{}` target",
-                    sanitizer,
-                    supported_targets.join("` or `")
-                ));
-                return;
-            }
-
-            // firstyear 2017 - during testing I was unable to access an OSX machine
-            // to make this work on different crate types. As a result, today I have
-            // only been able to test and support linux as a target.
-            if self.sess.opts.target_triple.triple() == "x86_64-unknown-linux-gnu" {
-                if !self.sess.crate_types.borrow().iter().all(|ct| {
-                    match *ct {
-                        // Link the runtime
-                        config::CrateType::Executable => true,
-                        // This crate will be compiled with the required
-                        // instrumentation pass
-                        config::CrateType::Staticlib
-                        | config::CrateType::Rlib
-                        | config::CrateType::Dylib
-                        | config::CrateType::Cdylib => false,
-                        _ => {
-                            self.sess.err(&format!(
-                                "Only executables, staticlibs, \
-                                cdylibs, dylibs and rlibs can be compiled with \
-                                `-Z sanitizer`"
-                            ));
-                            false
-                        }
-                    }
-                }) {
-                    return;
-                }
-            } else {
-                if !self.sess.crate_types.borrow().iter().all(|ct| {
-                    match *ct {
-                        // Link the runtime
-                        config::CrateType::Executable => true,
-                        // This crate will be compiled with the required
-                        // instrumentation pass
-                        config::CrateType::Rlib => false,
-                        _ => {
-                            self.sess.err(&format!(
-                                "Only executables and rlibs can be \
-                                                    compiled with `-Z sanitizer`"
-                            ));
-                            false
-                        }
-                    }
-                }) {
-                    return;
-                }
-            }
-
-            let mut uses_std = false;
-            self.cstore.iter_crate_data(|_, data| {
-                if data.name() == sym::std {
-                    uses_std = true;
-                }
-            });
-
-            if uses_std {
-                let name = Symbol::intern(match sanitizer {
-                    Sanitizer::Address => "rustc_asan",
-                    Sanitizer::Leak => "rustc_lsan",
-                    Sanitizer::Memory => "rustc_msan",
-                    Sanitizer::Thread => "rustc_tsan",
-                });
-                info!("loading sanitizer: {}", name);
-
-                let cnum = self.resolve_crate(name, DUMMY_SP, DepKind::Explicit, None);
-                let data = self.cstore.get_crate_data(cnum);
-
-                // Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
-                if !data.is_sanitizer_runtime() {
-                    self.sess.err(&format!("the crate `{}` is not a sanitizer runtime", name));
-                }
-            } else {
-                self.sess.err("Must link std to be compiled with `-Z sanitizer`");
-            }
-        }
-    }
-
     fn inject_profiler_runtime(&mut self) {
         if self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled() {
             info!("loading profiler");
@@ -925,7 +822,6 @@ fn inject_dependency_if(
     }
 
     pub fn postprocess(&mut self, krate: &ast::Crate) {
-        self.inject_sanitizer_runtime();
         self.inject_profiler_runtime();
         self.inject_allocator_crate(krate);
         self.inject_panic_runtime(krate);
index 59e769cabb7d47a837870eb101593b58ff9c467e..4745ad02a3aa4adcb10b0db6f3a8d7362e815a93 100644 (file)
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
-
-use errors::DiagnosticBuilder;
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
-use syntax::struct_span_err;
-use syntax::{span_err, span_fatal};
 
 use std::cmp;
 use std::fmt;
@@ -1038,28 +1035,28 @@ pub fn find_plugin_registrar(
     };
 
     if target_only {
-        // Need to abort before syntax expansion.
         let message = format!(
-            "plugin `{}` is not available for triple `{}` \
-                                (only found {})",
+            "plugin `{}` is not available for triple `{}` (only found {})",
             name,
             config::host_triple(),
             sess.opts.target_triple
         );
-        span_fatal!(sess, span, E0456, "{}", &message);
+        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 => {
-            span_err!(
+            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
index c524d2074f523a49b2e14f3e6d875663bb08849e..9426d5e26f5e545bdce78adecafdf0d8e67156f8 100644 (file)
@@ -1,17 +1,16 @@
 use rustc::middle::cstore::{self, NativeLibrary};
+use rustc::session::parse::feature_err;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_target::spec::abi::Abi;
 use syntax::attr;
-use syntax::feature_gate::feature_err;
-use syntax::{span_err, struct_span_err};
-
-use rustc_error_codes::*;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
     let mut collector = Collector { tcx, libs: Vec::new() };
@@ -159,7 +158,7 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
         if lib.kind == cstore::NativeFramework && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
-                Some(span) => span_err!(self.tcx.sess, span, E0455, "{}", msg),
+                Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(),
                 None => self.tcx.sess.err(msg),
             }
         }
index 77d143643b59e4277dd50b56967a28d66a714cfe..eb3dcfa72278ec7bee30db726fb0b8826c38930b 100644 (file)
@@ -16,8 +16,8 @@
 use rustc::session::Session;
 use rustc::ty::codec::TyDecoder;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::util::captures::Captures;
 use rustc::util::common::record_time;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
@@ -1587,10 +1587,6 @@ fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex {
         self.root.panic_runtime
     }
 
-    crate fn is_sanitizer_runtime(&self) -> bool {
-        self.root.sanitizer_runtime
-    }
-
     crate fn is_profiler_runtime(&self) -> bool {
         self.root.profiler_runtime
     }
index ba3c4e4aff443860a24a8d26c62cf9b44e6cdae1..fb7e5541e266eed383eb02a6661b14689d467f40 100644 (file)
@@ -161,7 +161,6 @@ fn into_args(self) -> (DefId, DefId) {
     is_compiler_builtins => { cdata.root.compiler_builtins }
     has_global_allocator => { cdata.root.has_global_allocator }
     has_panic_handler => { cdata.root.has_panic_handler }
-    is_sanitizer_runtime => { cdata.root.sanitizer_runtime }
     is_profiler_runtime => { cdata.root.profiler_runtime }
     panic_strategy => { cdata.root.panic_strategy }
     extern_crate => {
@@ -478,6 +477,14 @@ pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssocItem {
     pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
         self.get_crate_data(cnum).source.clone()
     }
+
+    pub fn get_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
+        self.get_crate_data(def_id.krate).get_span(def_id.index, sess)
+    }
+
+    pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
+        self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes
+    }
 }
 
 impl CrateStore for CStore {
@@ -485,10 +492,6 @@ fn as_any(&self) -> &dyn Any {
         self
     }
 
-    fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics {
-        self.get_crate_data(def.krate).get_generics(def.index, sess)
-    }
-
     fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol {
         self.get_crate_data(cnum).root.name
     }
index 92bfc51d9d5f0d7c88aef47a0d99ec89a5ab5005..7f8791d0c34dc467811e0045782d139c0b3f1bdd 100644 (file)
@@ -2,6 +2,7 @@
 use crate::rmeta::*;
 
 use rustc::hir::map::definitions::DefPathTable;
+use rustc::hir::map::Map;
 use rustc::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLibrary};
 use rustc::middle::dependency_format::Linkage;
 use rustc::middle::exported_symbols::{metadata_symbol_name, ExportedSymbol, SymbolExportLevel};
@@ -35,9 +36,8 @@
 use syntax::attr;
 use syntax::expand::is_proc_macro_attr;
 
-use rustc::hir::intravisit;
-use rustc::hir::intravisit::{NestedVisitorMap, Visitor};
 use rustc_hir as hir;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 
 struct EncodeContext<'tcx> {
@@ -514,7 +514,6 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
             no_builtins: attr::contains_name(&attrs, sym::no_builtins),
             panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
             profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
-            sanitizer_runtime: attr::contains_name(&attrs, sym::sanitizer_runtime),
             symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version,
 
             crate_deps,
@@ -1520,7 +1519,9 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
 
 // FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
 impl Visitor<'tcx> for EncodeContext<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
index 6309f1c260e1c5bc5a9deeb3e7f586658915efb2..426ea62b8cd4c6625f1038f9d8a702d36f6a34f0 100644 (file)
@@ -209,7 +209,6 @@ macro_rules! Lazy {
     no_builtins: bool,
     panic_runtime: bool,
     profiler_runtime: bool,
-    sanitizer_runtime: bool,
     symbol_mangling_version: SymbolManglingVersion,
 }
 
index 9b6908dbbe78906ab2f043fd63ce1c953942a873..f9b61b9e2c9d8dfd75f7f9ad0444e2b97adc2410 100644 (file)
@@ -10,7 +10,6 @@ path = "lib.rs"
 doctest = false
 
 [dependencies]
-arena = { path = "../libarena" }
 either = "1.5.0"
 dot = { path = "../libgraphviz", package = "graphviz" }
 itertools = "0.8"
index b66b2e4b1f7f548cd98b06730229207c01df6e6e..f2a44986cc4d4edccd167c26899abfb557130883 100644 (file)
@@ -208,9 +208,7 @@ fn visit_assign(
 
             self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);
 
-            if let mir::PlaceBase::Local(local) = borrowed_place.base {
-                self.local_map.entry(local).or_default().insert(idx);
-            }
+            self.local_map.entry(borrowed_place.local).or_default().insert(idx);
         }
 
         self.super_assign(assigned_place, rvalue, location)
index 97de201faba0187a9b4bf069b757ea7a0eba8f89..0f6a360c7933b3f5d525272717d9ec5d54492bbb 100644 (file)
@@ -2,8 +2,8 @@
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, PlaceRef, ProjectionElem,
-    Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
+    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue,
+    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::SubstsRef;
@@ -16,7 +16,6 @@
 
 pub(super) fn generate_constraints<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     liveness_constraints: &mut LivenessValues<RegionVid>,
     all_facts: &mut Option<AllFacts>,
     location_table: &LocationTable,
@@ -30,7 +29,6 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
         location_table,
         all_facts,
         body,
-        param_env,
     };
 
     for (bb, data) in body.basic_blocks().iter_enumerated() {
@@ -41,7 +39,6 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
 /// 'cg = the duration of the constraint generation process itself.
 struct ConstraintGeneration<'cg, 'cx, 'tcx> {
     infcx: &'cg InferCtxt<'cx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     all_facts: &'cg mut Option<AllFacts>,
     location_table: &'cg LocationTable,
     liveness_constraints: &'cg mut LivenessValues<RegionVid>,
@@ -191,11 +188,8 @@ fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Loc
             //   of the borrows are killed: the ones whose `borrowed_place`
             //   conflicts with the `place`.
             match place.as_ref() {
-                PlaceRef { base: &PlaceBase::Local(local), projection: &[] }
-                | PlaceRef {
-                    base: &PlaceBase::Local(local),
-                    projection: &[ProjectionElem::Deref],
-                } => {
+                PlaceRef { local, projection: &[] }
+                | PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
                     debug!(
                         "Recording `killed` facts for borrows of local={:?} at location={:?}",
                         local, location
@@ -205,16 +199,12 @@ fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Loc
                         all_facts,
                         self.borrow_set,
                         self.location_table,
-                        &local,
+                        local,
                         location,
                     );
                 }
 
-                PlaceRef { base: &PlaceBase::Static(_), .. } => {
-                    // Ignore kills of static or static mut variables.
-                }
-
-                PlaceRef { base: &PlaceBase::Local(local), projection: &[.., _] } => {
+                PlaceRef { local, projection: &[.., _] } => {
                     // Kill conflicting borrows of the innermost local.
                     debug!(
                         "Recording `killed` facts for borrows of \
@@ -222,11 +212,10 @@ fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Loc
                         local, location
                     );
 
-                    if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
+                    if let Some(borrow_indices) = self.borrow_set.local_map.get(local) {
                         for &borrow_index in borrow_indices {
                             let places_conflict = places_conflict::places_conflict(
                                 self.infcx.tcx,
-                                self.param_env,
                                 self.body,
                                 &self.borrow_set.borrows[borrow_index].borrowed_place,
                                 place,
index 7e251560a6c512923de340eca2887114c676a391..08333ae423da727a3bbce26beec5abf39ed705ea 100644 (file)
@@ -1,7 +1,7 @@
 use rustc::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
-    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceBase,
-    PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
+    ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
 };
 use rustc::traits::error_reporting::suggest_constraining_type_param;
 use rustc::ty::{self, Ty};
@@ -186,7 +186,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
             }
 
             let ty =
-                Place::ty_from(used_place.base, used_place.projection, *self.body, self.infcx.tcx)
+                Place::ty_from(used_place.local, used_place.projection, *self.body, self.infcx.tcx)
                     .ty;
             let needs_note = match ty.kind {
                 ty::Closure(id, _) => {
@@ -597,15 +597,15 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
                 // field access to a union. If we find that, then we will keep the place of the
                 // union being accessed and the field that was being accessed so we can check the
                 // second borrowed place for the same union and a access to a different field.
-                let Place { base, projection } = first_borrowed_place;
+                let Place { local, projection } = first_borrowed_place;
 
                 let mut cursor = projection.as_ref();
                 while let [proj_base @ .., elem] = cursor {
                     cursor = proj_base;
 
                     match elem {
-                        ProjectionElem::Field(field, _) if union_ty(base, proj_base).is_some() => {
-                            return Some((PlaceRef { base: base, projection: proj_base }, field));
+                        ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => {
+                            return Some((PlaceRef { local, projection: proj_base }, field));
                         }
                         _ => {}
                     }
@@ -615,21 +615,21 @@ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
             .and_then(|(target_base, target_field)| {
                 // With the place of a union and a field access into it, we traverse the second
                 // borrowed place and look for a access to a different field of the same union.
-                let Place { base, projection } = second_borrowed_place;
+                let Place { local, projection } = second_borrowed_place;
 
                 let mut cursor = projection.as_ref();
                 while let [proj_base @ .., elem] = cursor {
                     cursor = proj_base;
 
                     if let ProjectionElem::Field(field, _) = elem {
-                        if let Some(union_ty) = union_ty(base, proj_base) {
+                        if let Some(union_ty) = union_ty(local, proj_base) {
                             if field != target_field
-                                && base == target_base.base
+                                && local == target_base.local
                                 && proj_base == target_base.projection
                             {
                                 // FIXME when we avoid clone reuse describe_place closure
                                 let describe_base_place = self
-                                    .describe_place(PlaceRef { base: base, projection: proj_base })
+                                    .describe_place(PlaceRef { local, projection: proj_base })
                                     .unwrap_or_else(|| "_".to_owned());
 
                                 return Some((
@@ -686,15 +686,12 @@ pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
         let borrow_span = borrow_spans.var_or_use();
 
         assert!(root_place.projection.is_empty());
-        let proper_span = match root_place.base {
-            PlaceBase::Local(local) => self.body.local_decls[*local].source_info.span,
-            _ => drop_span,
-        };
+        let proper_span = self.body.local_decls[*root_place.local].source_info.span;
 
         let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
 
         if self.access_place_error_reported.contains(&(
-            Place { base: root_place.base.clone(), projection: root_place_projection },
+            Place { local: root_place.local.clone(), projection: root_place_projection },
             borrow_span,
         )) {
             debug!(
@@ -705,18 +702,17 @@ pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
         }
 
         self.access_place_error_reported.insert((
-            Place { base: root_place.base.clone(), projection: root_place_projection },
+            Place { local: root_place.local.clone(), projection: root_place_projection },
             borrow_span,
         ));
 
-        if let PlaceBase::Local(local) = borrow.borrowed_place.base {
-            if self.body.local_decls[local].is_ref_to_thread_local() {
-                let err = self
-                    .report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
-                err.buffer(&mut self.errors_buffer);
-                return;
-            }
-        };
+        let borrowed_local = borrow.borrowed_place.local;
+        if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
+            let err =
+                self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
+            err.buffer(&mut self.errors_buffer);
+            return;
+        }
 
         if let StorageDeadOrDrop::Destructor(dropped_ty) =
             self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
@@ -1142,12 +1138,7 @@ fn try_report_cannot_return_reference_to_local(
         } else {
             let root_place =
                 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
-            let local =
-                if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = root_place {
-                    local
-                } else {
-                    bug!("try_report_cannot_return_reference_to_local: not a local")
-                };
+            let local = root_place.local;
             match self.body.local_kind(*local) {
                 LocalKind::ReturnPointer | LocalKind::Temp => {
                     ("temporary value".to_string(), "temporary value created here".to_string())
@@ -1514,7 +1505,7 @@ fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOr
             [proj_base @ .., elem] => {
                 // FIXME(spastorino) make this iterate
                 let base_access = self.classify_drop_access_kind(PlaceRef {
-                    base: place.base,
+                    local: place.local,
                     projection: proj_base,
                 });
                 match elem {
@@ -1522,7 +1513,9 @@ fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOr
                         StorageDeadOrDrop::LocalStorageDead
                         | StorageDeadOrDrop::BoxedStorageDead => {
                             assert!(
-                                Place::ty_from(&place.base, proj_base, *self.body, tcx).ty.is_box(),
+                                Place::ty_from(&place.local, proj_base, *self.body, tcx)
+                                    .ty
+                                    .is_box(),
                                 "Drop of value behind a reference or raw pointer"
                             );
                             StorageDeadOrDrop::BoxedStorageDead
@@ -1530,7 +1523,7 @@ fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOr
                         StorageDeadOrDrop::Destructor(_) => base_access,
                     },
                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = Place::ty_from(&place.base, proj_base, *self.body, tcx).ty;
+                        let base_ty = Place::ty_from(&place.local, proj_base, *self.body, tcx).ty;
                         match base_ty.kind {
                             ty::Adt(def, _) if def.has_dtor(tcx) => {
                                 // Report the outermost adt with a destructor
index c8a59331f31af46e24323ba86466f9a3a009f08c..3f3bdb9d36c76352d429503a78f7677a41f3f92b 100644 (file)
@@ -2,8 +2,7 @@
 
 use rustc::mir::{
     AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
-    PlaceBase, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Static, StaticKind,
-    Terminator, TerminatorKind,
+    PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc::ty::layout::VariantIdx;
 use rustc::ty::print::Print;
@@ -169,42 +168,30 @@ fn append_place_to_string(
         including_downcast: &IncludingDowncast,
     ) -> Result<(), ()> {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 self.append_local_to_string(*local, buf)?;
             }
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }),
-                projection: [],
-            } => {
-                buf.push_str("promoted");
-            }
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }),
-                projection: [],
-            } => {
-                buf.push_str(&self.infcx.tcx.item_name(*def_id).to_string());
-            }
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_for_guard() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_for_guard() =>
             {
                 self.append_place_to_string(
-                    PlaceRef { base: &PlaceBase::Local(local), projection: &[] },
+                    PlaceRef { local: local, projection: &[] },
                     buf,
                     autoderef,
                     &including_downcast,
                 )?;
             }
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_to_static() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_to_static() =>
             {
-                let local_info = &self.body.local_decls[local].local_info;
+                let local_info = &self.body.local_decls[*local].local_info;
                 if let LocalInfo::StaticRef { def_id, .. } = *local_info {
                     buf.push_str(&self.infcx.tcx.item_name(def_id).as_str());
                 } else {
                     unreachable!();
                 }
             }
-            PlaceRef { base, projection: [proj_base @ .., elem] } => {
+            PlaceRef { local, projection: [proj_base @ .., elem] } => {
                 match elem {
                     ProjectionElem::Deref => {
                         let upvar_field_projection = self.is_upvar_field_projection(place);
@@ -220,29 +207,25 @@ fn append_place_to_string(
                             if autoderef {
                                 // FIXME turn this recursion into iteration
                                 self.append_place_to_string(
-                                    PlaceRef { base, projection: proj_base },
+                                    PlaceRef { local, projection: proj_base },
                                     buf,
                                     autoderef,
                                     &including_downcast,
                                 )?;
                             } else {
-                                match (proj_base, base) {
-                                    _ => {
-                                        buf.push_str(&"*");
-                                        self.append_place_to_string(
-                                            PlaceRef { base, projection: proj_base },
-                                            buf,
-                                            autoderef,
-                                            &including_downcast,
-                                        )?;
-                                    }
-                                }
+                                buf.push_str(&"*");
+                                self.append_place_to_string(
+                                    PlaceRef { local, projection: proj_base },
+                                    buf,
+                                    autoderef,
+                                    &including_downcast,
+                                )?;
                             }
                         }
                     }
                     ProjectionElem::Downcast(..) => {
                         self.append_place_to_string(
-                            PlaceRef { base, projection: proj_base },
+                            PlaceRef { local, projection: proj_base },
                             buf,
                             autoderef,
                             &including_downcast,
@@ -261,9 +244,9 @@ fn append_place_to_string(
                             buf.push_str(&name);
                         } else {
                             let field_name = self
-                                .describe_field(PlaceRef { base, projection: proj_base }, *field);
+                                .describe_field(PlaceRef { local, projection: proj_base }, *field);
                             self.append_place_to_string(
-                                PlaceRef { base, projection: proj_base },
+                                PlaceRef { local, projection: proj_base },
                                 buf,
                                 autoderef,
                                 &including_downcast,
@@ -275,7 +258,7 @@ fn append_place_to_string(
                         autoderef = true;
 
                         self.append_place_to_string(
-                            PlaceRef { base, projection: proj_base },
+                            PlaceRef { local, projection: proj_base },
                             buf,
                             autoderef,
                             &including_downcast,
@@ -292,7 +275,7 @@ fn append_place_to_string(
                         // then use another while the borrow is held, don't output indices details
                         // to avoid confusing the end-user
                         self.append_place_to_string(
-                            PlaceRef { base, projection: proj_base },
+                            PlaceRef { local, projection: proj_base },
                             buf,
                             autoderef,
                             &including_downcast,
@@ -323,20 +306,18 @@ fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), (
     fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String {
         // FIXME Place2 Make this work iteratively
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 let local = &self.body.local_decls[*local];
                 self.describe_field_from_ty(&local.ty, field, None)
             }
-            PlaceRef { base: PlaceBase::Static(static_), projection: [] } => {
-                self.describe_field_from_ty(&static_.ty, field, None)
-            }
-            PlaceRef { base, projection: [proj_base @ .., elem] } => match elem {
+            PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
                 ProjectionElem::Deref => {
-                    self.describe_field(PlaceRef { base, projection: proj_base }, field)
+                    self.describe_field(PlaceRef { local, projection: proj_base }, field)
                 }
                 ProjectionElem::Downcast(_, variant_index) => {
                     let base_ty =
-                        Place::ty_from(place.base, place.projection, *self.body, self.infcx.tcx).ty;
+                        Place::ty_from(place.local, place.projection, *self.body, self.infcx.tcx)
+                            .ty;
                     self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
                 }
                 ProjectionElem::Field(_, field_type) => {
@@ -345,7 +326,7 @@ fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String {
                 ProjectionElem::Index(..)
                 | ProjectionElem::ConstantIndex { .. }
                 | ProjectionElem::Subslice { .. } => {
-                    self.describe_field(PlaceRef { base, projection: proj_base }, field)
+                    self.describe_field(PlaceRef { local, projection: proj_base }, field)
                 }
             },
         }
@@ -466,7 +447,7 @@ pub(super) fn borrowed_content_source(
 
         // If we didn't find an overloaded deref or index, then assume it's a
         // built in deref and check the type of the base.
-        let base_ty = Place::ty_from(deref_base.base, deref_base.projection, *self.body, tcx).ty;
+        let base_ty = Place::ty_from(deref_base.local, deref_base.projection, *self.body, tcx).ty;
         if base_ty.is_unsafe_ptr() {
             BorrowedContentSource::DerefRawPointer
         } else if base_ty.is_mutable_ptr() {
index 3f4204bc12f6adec3021d2eb19f392b93a2af568..eb6db7c145c3cde6f10425a8a85a49da3602b884 100644 (file)
@@ -243,9 +243,6 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
             );
             (
                 match kind {
-                    IllegalMoveOriginKind::Static => {
-                        unreachable!();
-                    }
                     IllegalMoveOriginKind::BorrowedContent { target_place } => self
                         .report_cannot_move_from_borrowed_content(
                             original_path,
@@ -276,7 +273,8 @@ fn report_cannot_move_from_static(
         let description = if place.projection.len() == 1 {
             format!("static item `{}`", self.describe_place(place.as_ref()).unwrap())
         } else {
-            let base_static = PlaceRef { base: &place.base, projection: &[ProjectionElem::Deref] };
+            let base_static =
+                PlaceRef { local: &place.local, projection: &[ProjectionElem::Deref] };
 
             format!(
                 "`{:?}` as `{:?}` is a static item",
@@ -305,12 +303,12 @@ fn report_cannot_move_from_borrowed_content(
 
         let deref_base = match deref_target_place.projection.as_ref() {
             &[ref proj_base @ .., ProjectionElem::Deref] => {
-                PlaceRef { base: &deref_target_place.base, projection: &proj_base }
+                PlaceRef { local: &deref_target_place.local, projection: &proj_base }
             }
             _ => bug!("deref_target_place is not a deref projection"),
         };
 
-        if let PlaceRef { base: PlaceBase::Local(local), projection: [] } = deref_base {
+        if let PlaceRef { local, projection: [] } = deref_base {
             let decl = &self.body.local_decls[*local];
             if decl.is_ref_for_guard() {
                 let mut err = self.cannot_move_out_of(
index 595acec2f74d7e8f8036400fcc5a8305e4177257..ae468e83ae253f790d97638f9217ca2f6dbcd0af 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache};
-use rustc::mir::{Mutability, Place, PlaceBase, PlaceRef, ProjectionElem};
+use rustc::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::Node;
@@ -42,7 +42,7 @@ pub(crate) fn report_mutability_error(
         debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
 
         match the_place_err {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 item_msg = format!("`{}`", access_place_desc.unwrap());
                 if access_place.as_local().is_some() {
                     reason = ", as it is not declared as mutable".to_string();
@@ -53,11 +53,11 @@ pub(crate) fn report_mutability_error(
             }
 
             PlaceRef {
-                base: _,
+                local,
                 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(&the_place_err.base, proj_base, *self.body, self.infcx.tcx).ty
+                    Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty
                 ));
 
                 item_msg = format!("`{}`", access_place_desc.unwrap());
@@ -69,21 +69,21 @@ pub(crate) fn report_mutability_error(
                 }
             }
 
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_for_guard() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_for_guard() =>
             {
                 item_msg = format!("`{}`", access_place_desc.unwrap());
                 reason = ", as it is immutable for the pattern guard".to_string();
             }
-            PlaceRef { base: &PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
-                if self.body.local_decls[local].is_ref_to_static() =>
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if self.body.local_decls[*local].is_ref_to_static() =>
             {
                 if access_place.projection.len() == 1 {
                     item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
                     reason = String::new();
                 } else {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
-                    let local_info = &self.body.local_decls[local].local_info;
+                    let local_info = &self.body.local_decls[*local].local_info;
                     if let LocalInfo::StaticRef { def_id, .. } = *local_info {
                         let static_name = &self.infcx.tcx.item_name(def_id);
                         reason = format!(", as `{}` is an immutable static item", static_name);
@@ -92,8 +92,8 @@ pub(crate) fn report_mutability_error(
                     }
                 }
             }
-            PlaceRef { base: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
-                if the_place_err.base == &PlaceBase::Local(Local::new(1))
+            PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
+                if *the_place_err.local == Local::new(1)
                     && proj_base.is_empty()
                     && !self.upvars.is_empty()
                 {
@@ -101,7 +101,7 @@ pub(crate) fn report_mutability_error(
                     debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
                     debug_assert!(is_closure_or_generator(
                         Place::ty_from(
-                            the_place_err.base,
+                            the_place_err.local,
                             the_place_err.projection,
                             *self.body,
                             self.infcx.tcx
@@ -116,7 +116,7 @@ pub(crate) fn report_mutability_error(
                     }
                 } else {
                     let source = self.borrowed_content_source(PlaceRef {
-                        base: the_place_err.base,
+                        local: the_place_err.local,
                         projection: proj_base,
                     });
                     let pointer_type = source.describe_for_immutable_place();
@@ -136,11 +136,10 @@ pub(crate) fn report_mutability_error(
                 }
             }
 
-            PlaceRef { base: PlaceBase::Static(_), .. }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::Index(_)] }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::ConstantIndex { .. }] }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::Subslice { .. }] }
-            | PlaceRef { base: _, projection: [.., ProjectionElem::Downcast(..)] } => {
+            PlaceRef { local: _, projection: [.., ProjectionElem::Index(_)] }
+            | PlaceRef { local: _, projection: [.., ProjectionElem::ConstantIndex { .. }] }
+            | PlaceRef { local: _, projection: [.., ProjectionElem::Subslice { .. }] }
+            | PlaceRef { local: _, projection: [.., ProjectionElem::Downcast(..)] } => {
                 bug!("Unexpected immutable place.")
             }
         }
@@ -188,7 +187,7 @@ pub(crate) fn report_mutability_error(
             // struct we've got a field access of (it must be a reference since there's a deref
             // after the field access).
             PlaceRef {
-                base,
+                local,
                 projection:
                     [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref],
             } => {
@@ -196,7 +195,7 @@ pub(crate) fn report_mutability_error(
 
                 if let Some((span, message)) = annotate_struct_field(
                     self.infcx.tcx,
-                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty,
+                    Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty,
                     field,
                 ) {
                     err.span_suggestion(
@@ -209,7 +208,7 @@ pub(crate) fn report_mutability_error(
             }
 
             // Suggest removing a `&mut` from the use of a mutable reference.
-            PlaceRef { base: PlaceBase::Local(local), projection: [] }
+            PlaceRef { local, projection: [] }
                 if {
                     self.body
                         .local_decls
@@ -247,7 +246,7 @@ pub(crate) fn report_mutability_error(
 
             // We want to suggest users use `let mut` for local (user
             // variable) mutations...
-            PlaceRef { base: PlaceBase::Local(local), projection: [] }
+            PlaceRef { local, projection: [] }
                 if self.body.local_decls[*local].can_be_made_mutable() =>
             {
                 // ... but it doesn't make sense to suggest it on
@@ -268,11 +267,11 @@ pub(crate) fn report_mutability_error(
 
             // Also suggest adding mut for upvars
             PlaceRef {
-                base,
+                local,
                 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
             } => {
                 debug_assert!(is_closure_or_generator(
-                    Place::ty_from(base, proj_base, *self.body, self.infcx.tcx).ty
+                    Place::ty_from(local, proj_base, *self.body, self.infcx.tcx).ty
                 ));
 
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -299,7 +298,7 @@ pub(crate) fn report_mutability_error(
             // complete hack to approximate old AST-borrowck
             // diagnostic: if the span starts with a mutable borrow of
             // a local variable, then just suggest the user remove it.
-            PlaceRef { base: PlaceBase::Local(_), projection: [] }
+            PlaceRef { local: _, projection: [] }
                 if {
                     if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
                         snippet.starts_with("&mut ")
@@ -312,7 +311,7 @@ pub(crate) fn report_mutability_error(
                 err.span_label(span, "try removing `&mut` here");
             }
 
-            PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[*local].is_ref_for_guard() =>
             {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
@@ -326,7 +325,7 @@ pub(crate) fn report_mutability_error(
             //
             // FIXME: can this case be generalized to work for an
             // arbitrary base for the projection?
-            PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] }
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
                 if self.body.local_decls[*local].is_user_variable() =>
             {
                 let local_decl = &self.body.local_decls[*local];
@@ -409,10 +408,10 @@ pub(crate) fn report_mutability_error(
             }
 
             PlaceRef {
-                base,
+                local,
                 projection: [ProjectionElem::Deref],
                 // FIXME document what is this 1 magic number about
-            } if *base == PlaceBase::Local(Local::new(1)) && !self.upvars.is_empty() => {
+            } if *local == Local::new(1) && !self.upvars.is_empty() => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
                 err.span_help(
                     self.body.span,
@@ -420,7 +419,7 @@ pub(crate) fn report_mutability_error(
                 );
             }
 
-            PlaceRef { base: _, projection: [.., ProjectionElem::Deref] } => {
+            PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
                 match opt_source {
index 9a301a6ad32a81a36a9d33a28519bbba38a837b3..dc63fa80275e1994d242d35b121bc562092f9074 100644 (file)
@@ -6,13 +6,12 @@
 };
 use rustc::mir::{Body, ConstraintCategory, Location};
 use rustc::ty::{self, RegionVid, Ty};
-use rustc_errors::DiagnosticBuilder;
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 use std::collections::VecDeque;
-use syntax::errors::Applicability;
 
 use crate::util::borrowck_errors;
 
index f9ffa2138ba40ae50d5a1b028cc3ad478fc3f4c1..bb56c11872a29039e086838627db5c0bab629ba5 100644 (file)
@@ -3,7 +3,7 @@
 use rustc::mir::{BasicBlock, Body, Location, Place, ReadOnlyBodyAndCache, Rvalue};
 use rustc::mir::{BorrowKind, Mutability, Operand};
 use rustc::mir::{Statement, StatementKind};
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 use rustc_data_structures::graph::dominators::Dominators;
 
 use crate::dataflow::indexes::BorrowIndex;
@@ -16,7 +16,6 @@
 
 pub(super) fn generate_invalidates<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     all_facts: &mut Option<AllFacts>,
     location_table: &LocationTable,
     body: ReadOnlyBodyAndCache<'_, 'tcx>,
@@ -33,7 +32,6 @@ pub(super) fn generate_invalidates<'tcx>(
         let mut ig = InvalidationGenerator {
             all_facts,
             borrow_set,
-            param_env,
             tcx,
             location_table,
             body: &body,
@@ -45,7 +43,6 @@ pub(super) fn generate_invalidates<'tcx>(
 
 struct InvalidationGenerator<'cx, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     all_facts: &'cx mut AllFacts,
     location_table: &'cx LocationTable,
     body: &'cx Body<'tcx>,
@@ -337,13 +334,11 @@ fn check_access_for_conflict(
         );
         let tcx = self.tcx;
         let body = self.body;
-        let param_env = self.param_env;
         let borrow_set = self.borrow_set.clone();
         let indices = self.borrow_set.borrows.indices();
         each_borrow_involving_path(
             self,
             tcx,
-            param_env,
             body,
             location,
             (sd, place),
index fff6f036da08239b3b322e1a5cea72a2ff2ecc75..7b0a103fd00383effcbd24cc91092986002362c7 100644 (file)
@@ -5,7 +5,7 @@
 use rustc::lint::builtin::UNUSED_MUT;
 use rustc::mir::{
     read_only, Body, BodyAndCache, ClearCrossCrate, Local, Location, Mutability, Operand, Place,
-    PlaceBase, PlaceElem, PlaceRef, ReadOnlyBodyAndCache, Static, StaticKind,
+    PlaceElem, PlaceRef, ReadOnlyBodyAndCache,
 };
 use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@@ -239,7 +239,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         def_id,
         &attributes,
         &dead_unwinds,
-        Borrows::new(tcx, &body, param_env, regioncx.clone(), &borrow_set),
+        Borrows::new(tcx, &body, regioncx.clone(), &borrow_set),
         |rs, i| DebugFormatted::new(&rs.location(i)),
     ));
     let flow_uninits = FlowAtLocation::new(do_dataflow(
@@ -275,7 +275,6 @@ fn do_mir_borrowck<'a, 'tcx>(
         infcx,
         body,
         mir_def_id: def_id,
-        param_env,
         move_data: &mdpe.move_data,
         location_table,
         movable_generator,
@@ -418,7 +417,6 @@ fn do_mir_borrowck<'a, 'tcx>(
     crate infcx: &'cx InferCtxt<'cx, 'tcx>,
     body: ReadOnlyBodyAndCache<'cx, 'tcx>,
     mir_def_id: DefId,
-    param_env: ty::ParamEnv<'tcx>,
     move_data: &'cx MoveData<'tcx>,
 
     /// Map from MIR `Location` to `LocationIndex`; created
@@ -817,7 +815,7 @@ enum InitializationRequiringAction {
 }
 
 struct RootPlace<'d, 'tcx> {
-    place_base: &'d PlaceBase<'tcx>,
+    place_local: &'d Local,
     place_projection: &'d [PlaceElem<'tcx>],
     is_local_mutation_allowed: LocalMutationIsAllowed,
 }
@@ -926,13 +924,11 @@ fn check_access_for_conflict(
         let tcx = self.infcx.tcx;
         let body = self.body;
         let body: &Body<'_> = &body;
-        let param_env = self.param_env;
         let location_table = self.location_table.start_index(location);
         let borrow_set = self.borrow_set.clone();
         each_borrow_involving_path(
             self,
             tcx,
-            param_env,
             body,
             location,
             (sd, place_span.0),
@@ -1255,8 +1251,8 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
                 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
                     this.used_mut_upvars.push(field);
                 }
-            } else if let PlaceBase::Local(local) = place.base {
-                this.used_mut.insert(local);
+            } else {
+                this.used_mut.insert(place.local);
             }
         };
 
@@ -1380,7 +1376,7 @@ fn check_for_invalidation_at_exit(
         debug!("check_for_invalidation_at_exit({:?})", borrow);
         let place = &borrow.borrowed_place;
         let deref = [ProjectionElem::Deref];
-        let mut root_place = PlaceRef { base: &place.base, projection: &[] };
+        let mut root_place = PlaceRef { local: &place.local, projection: &[] };
 
         // FIXME(nll-rfc#40): do more precise destructor tracking here. For now
         // we just know that all locals are dropped at function exit (otherwise
@@ -1388,20 +1384,16 @@ fn check_for_invalidation_at_exit(
         //
         // FIXME: allow thread-locals to borrow other thread locals?
 
-        let (might_be_alive, will_be_dropped) = match root_place.base {
-            PlaceBase::Static(_) => (true, false),
-            PlaceBase::Local(local) => {
-                if self.body.local_decls[*local].is_ref_to_thread_local() {
-                    // Thread-locals might be dropped after the function exits
-                    // We have to dereference the outer reference because
-                    // borrows don't conflict behind shared references.
-                    root_place.projection = &deref;
-                    (true, true)
-                } else {
-                    (false, self.locals_are_invalidated_at_exit)
-                }
-            }
-        };
+        let (might_be_alive, will_be_dropped) =
+            if self.body.local_decls[*root_place.local].is_ref_to_thread_local() {
+                // Thread-locals might be dropped after the function exits
+                // We have to dereference the outer reference because
+                // borrows don't conflict behind shared references.
+                root_place.projection = &deref;
+                (true, true)
+            } else {
+                (false, self.locals_are_invalidated_at_exit)
+            };
 
         if !will_be_dropped {
             debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
@@ -1412,7 +1404,6 @@ fn check_for_invalidation_at_exit(
 
         if places_conflict::borrow_conflicts_with_place(
             self.infcx.tcx,
-            self.param_env,
             &self.body,
             place,
             borrow.kind,
@@ -1654,26 +1645,20 @@ fn check_if_full_path_is_moved(
         // This code covers scenarios 1, 2, and 3.
 
         debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
-        match self.move_path_closest_to(place_span.0) {
-            Ok((prefix, mpi)) => {
-                if maybe_uninits.contains(mpi) {
-                    self.report_use_of_moved_or_uninitialized(
-                        location,
-                        desired_action,
-                        (prefix, place_span.0, place_span.1),
-                        mpi,
-                    );
-                }
-            }
-            Err(NoMovePathFound::ReachedStatic) => {
-                // Okay: we do not build MoveData for static variables
-            } // Only query longest prefix with a MovePath, not further
-              // ancestors; dataflow recurs on children when parents
-              // move (to support partial (re)inits).
-              //
-              // (I.e., querying parents breaks scenario 7; but may want
-              // to do such a query based on partial-init feature-gate.)
-        }
+        let (prefix, mpi) = self.move_path_closest_to(place_span.0);
+        if maybe_uninits.contains(mpi) {
+            self.report_use_of_moved_or_uninitialized(
+                location,
+                desired_action,
+                (prefix, place_span.0, place_span.1),
+                mpi,
+            );
+        } // Only query longest prefix with a MovePath, not further
+        // ancestors; dataflow recurs on children when parents
+        // move (to support partial (re)inits).
+        //
+        // (I.e., querying parents breaks scenario 7; but may want
+        // to do such a query based on partial-init feature-gate.)
     }
 
     /// Subslices correspond to multiple move paths, so we iterate through the
@@ -1746,9 +1731,9 @@ fn check_if_path_or_subpath_is_moved(
             place_span.0.projection
         {
             let place_ty =
-                Place::ty_from(place_span.0.base, base_proj, self.body(), self.infcx.tcx);
+                Place::ty_from(place_span.0.local, base_proj, self.body(), self.infcx.tcx);
             if let ty::Array(..) = place_ty.ty.kind {
-                let array_place = PlaceRef { base: place_span.0.base, projection: base_proj };
+                let array_place = PlaceRef { local: place_span.0.local, projection: base_proj };
                 self.check_if_subslice_element_is_moved(
                     location,
                     desired_action,
@@ -1797,12 +1782,12 @@ fn check_if_path_or_subpath_is_moved(
     fn move_path_closest_to(
         &mut self,
         place: PlaceRef<'_, 'tcx>,
-    ) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> {
+    ) -> (PlaceRef<'cx, 'tcx>, MovePathIndex) {
         match self.move_data.rev_lookup.find(place) {
             LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
-                Ok((self.move_data.move_paths[mpi].place.as_ref(), mpi))
+                (self.move_data.move_paths[mpi].place.as_ref(), mpi)
             }
-            LookupResult::Parent(None) => Err(NoMovePathFound::ReachedStatic),
+            LookupResult::Parent(None) => panic!("should have move path for every Local"),
         }
     }
 
@@ -1845,7 +1830,7 @@ fn check_if_assigned_path_is_moved(
                     self.check_if_full_path_is_moved(
                         location, InitializationRequiringAction::Use,
                         (PlaceRef {
-                            base: &place.base,
+                            local: &place.local,
                             projection: proj_base,
                         }, span), flow_state);
                     // (base initialized; no need to
@@ -1863,13 +1848,13 @@ fn check_if_assigned_path_is_moved(
                     // assigning to `P.f` requires `P` itself
                     // be already initialized
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&place.base, proj_base, self.body(), tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, self.body(), tcx).ty;
                     match base_ty.kind {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
                                 location, InitializationRequiringAction::Assignment,
                                 (PlaceRef {
-                                    base: &place.base,
+                                    local: &place.local,
                                     projection: proj_base,
                                 }, span), flow_state);
 
@@ -1882,21 +1867,14 @@ fn check_if_assigned_path_is_moved(
                         // is allowed, remove this match arm.
                         ty::Adt(..) | ty::Tuple(..) => {
                             check_parent_of_field(self, location, PlaceRef {
-                                base: &place.base,
+                                local: &place.local,
                                 projection: proj_base,
                             }, span, flow_state);
 
-                            if let PlaceBase::Local(local) = place.base {
-                                // rust-lang/rust#21232,
-                                // #54499, #54986: during
-                                // period where we reject
-                                // partial initialization, do
-                                // not complain about
-                                // unnecessary `mut` on an
-                                // attempt to do a partial
-                                // initialization.
-                                self.used_mut.insert(local);
-                            }
+                            // rust-lang/rust#21232, #54499, #54986: during period where we reject
+                            // partial initialization, do not complain about unnecessary `mut` on
+                            // an attempt to do a partial initialization.
+                            self.used_mut.insert(place.local);
                         }
 
                         _ => {}
@@ -1974,7 +1952,7 @@ fn check_parent_of_field<'cx, 'tcx>(
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
                 if let ty::Adt(def, _) =
-                    Place::ty_from(base.base, base.projection, this.body(), tcx).ty.kind
+                    Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind
                 {
                     if def.is_union() {
                         if this.move_data.path_map[mpi].iter().any(|moi| {
@@ -2093,11 +2071,8 @@ fn check_access_permissions(
         // partial initialization, do not complain about mutability
         // errors except for actual mutation (as opposed to an attempt
         // to do a partial initialization).
-        let previously_initialized = if let PlaceBase::Local(local) = place.base {
-            self.is_local_ever_initialized(local, flow_state).is_some()
-        } else {
-            true
-        };
+        let previously_initialized =
+            self.is_local_ever_initialized(place.local, flow_state).is_some();
 
         // at this point, we have set up the error reporting state.
         if previously_initialized {
@@ -2126,11 +2101,7 @@ fn is_local_ever_initialized(
     /// Adds the place into the used mutable variables set
     fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) {
         match root_place {
-            RootPlace {
-                place_base: PlaceBase::Local(local),
-                place_projection: [],
-                is_local_mutation_allowed,
-            } => {
+            RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
                 // If the local may have been initialized, and it is now currently being
                 // mutated, then it is justified to be annotated with the `mut`
                 // keyword, since the mutation may be a possible reassignment.
@@ -2141,27 +2112,22 @@ fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flo
                 }
             }
             RootPlace {
-                place_base: _,
+                place_local: _,
                 place_projection: _,
                 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
             } => {}
             RootPlace {
-                place_base,
+                place_local,
                 place_projection: place_projection @ [.., _],
                 is_local_mutation_allowed: _,
             } => {
                 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
-                    base: &place_base,
-                    projection: &place_projection,
+                    local: place_local,
+                    projection: place_projection,
                 }) {
                     self.used_mut_upvars.push(field);
                 }
             }
-            RootPlace {
-                place_base: PlaceBase::Static(..),
-                place_projection: [],
-                is_local_mutation_allowed: _,
-            } => {}
         }
     }
 
@@ -2173,58 +2139,34 @@ fn is_mutable<'d>(
         is_local_mutation_allowed: LocalMutationIsAllowed,
     ) -> Result<RootPlace<'d, 'tcx>, PlaceRef<'d, 'tcx>> {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
+            PlaceRef { local, projection: [] } => {
                 let local = &self.body.local_decls[*local];
                 match local.mutability {
                     Mutability::Not => match is_local_mutation_allowed {
                         LocalMutationIsAllowed::Yes => Ok(RootPlace {
-                            place_base: place.base,
+                            place_local: place.local,
                             place_projection: place.projection,
                             is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
                         }),
                         LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
-                            place_base: place.base,
+                            place_local: place.local,
                             place_projection: place.projection,
                             is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
                         }),
                         LocalMutationIsAllowed::No => Err(place),
                     },
                     Mutability::Mut => Ok(RootPlace {
-                        place_base: place.base,
+                        place_local: place.local,
                         place_projection: place.projection,
                         is_local_mutation_allowed,
                     }),
                 }
             }
-            // The rules for promotion are made by `qualify_consts`, there wouldn't even be a
-            // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }),
-                projection: [],
-            } => Ok(RootPlace {
-                place_base: place.base,
-                place_projection: place.projection,
-                is_local_mutation_allowed,
-            }),
-            PlaceRef {
-                base: PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }),
-                projection: [],
-            } => {
-                if !self.infcx.tcx.is_mutable_static(*def_id) {
-                    Err(place)
-                } else {
-                    Ok(RootPlace {
-                        place_base: place.base,
-                        place_projection: place.projection,
-                        is_local_mutation_allowed,
-                    })
-                }
-            }
-            PlaceRef { base: _, projection: [proj_base @ .., elem] } => {
+            PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
                 match elem {
                     ProjectionElem::Deref => {
                         let base_ty =
-                            Place::ty_from(place.base, proj_base, self.body(), self.infcx.tcx).ty;
+                            Place::ty_from(place.local, proj_base, self.body(), self.infcx.tcx).ty;
 
                         // Check the kind of deref to decide
                         match base_ty.kind {
@@ -2243,7 +2185,7 @@ fn is_mutable<'d>(
                                         };
 
                                         self.is_mutable(
-                                            PlaceRef { base: place.base, projection: proj_base },
+                                            PlaceRef { local: place.local, projection: proj_base },
                                             mode,
                                         )
                                     }
@@ -2256,7 +2198,7 @@ fn is_mutable<'d>(
                                     // `*mut` raw pointers are always mutable, regardless of
                                     // context. The users have to check by themselves.
                                     hir::Mutability::Mut => Ok(RootPlace {
-                                        place_base: place.base,
+                                        place_local: place.local,
                                         place_projection: place.projection,
                                         is_local_mutation_allowed,
                                     }),
@@ -2264,7 +2206,7 @@ fn is_mutable<'d>(
                             }
                             // `Box<T>` owns its content, so mutable if its location is mutable
                             _ if base_ty.is_box() => self.is_mutable(
-                                PlaceRef { base: place.base, projection: proj_base },
+                                PlaceRef { local: place.local, projection: proj_base },
                                 is_local_mutation_allowed,
                             ),
                             // Deref should only be for reference, pointers or boxes
@@ -2320,11 +2262,11 @@ fn is_mutable<'d>(
                                     // }
                                     // ```
                                     let _ = self.is_mutable(
-                                        PlaceRef { base: place.base, projection: proj_base },
+                                        PlaceRef { local: place.local, projection: proj_base },
                                         is_local_mutation_allowed,
                                     )?;
                                     Ok(RootPlace {
-                                        place_base: place.base,
+                                        place_local: place.local,
                                         place_projection: place.projection,
                                         is_local_mutation_allowed,
                                     })
@@ -2332,7 +2274,7 @@ fn is_mutable<'d>(
                             }
                         } else {
                             self.is_mutable(
-                                PlaceRef { base: place.base, projection: proj_base },
+                                PlaceRef { local: place.local, projection: proj_base },
                                 is_local_mutation_allowed,
                             )
                         }
@@ -2358,7 +2300,7 @@ pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Optio
         match place_projection {
             [base @ .., ProjectionElem::Field(field, _ty)] => {
                 let tcx = self.infcx.tcx;
-                let base_ty = Place::ty_from(place_ref.base, base, self.body(), tcx).ty;
+                let base_ty = Place::ty_from(place_ref.local, base, self.body(), tcx).ty;
 
                 if (base_ty.is_closure() || base_ty.is_generator())
                     && (!by_ref || self.upvars[field.index()].by_ref)
@@ -2374,11 +2316,6 @@ pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Optio
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum NoMovePathFound {
-    ReachedStatic,
-}
-
 /// The degree of overlap between 2 places for borrow-checking.
 enum Overlap {
     /// The places might partially overlap - in this case, we give
index a4c2299b3eaacccef1d092c5192809efea3696bd..151a2c4c19a7dccee35547793c3c7808c1a6de62 100644 (file)
@@ -231,7 +231,6 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
 
     constraint_generation::generate_constraints(
         infcx,
-        param_env,
         &mut liveness_constraints,
         &mut all_facts,
         location_table,
@@ -253,14 +252,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     );
 
     // Generate various additional constraints.
-    invalidation::generate_invalidates(
-        infcx.tcx,
-        param_env,
-        &mut all_facts,
-        location_table,
-        body,
-        borrow_set,
-    );
+    invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set);
 
     // Dump facts if requested.
     let polonius_output = all_facts.and_then(|all_facts| {
index 23b4799643a6cfb6282b167ee692cb3c6425c6ab..deec6f386ffb3d9175795b83a3f37ec5c9265161 100644 (file)
@@ -3,8 +3,8 @@
 use crate::borrow_check::AccessDepth;
 use crate::dataflow::indexes::BorrowIndex;
 use rustc::mir::BorrowKind;
-use rustc::mir::{BasicBlock, Body, Location, Place, PlaceBase};
-use rustc::ty::{self, TyCtxt};
+use rustc::mir::{BasicBlock, Body, Location, Place};
+use rustc::ty::TyCtxt;
 use rustc_data_structures::graph::dominators::Dominators;
 
 /// Returns `true` if the borrow represented by `kind` is
@@ -25,7 +25,6 @@ pub(super) enum Control {
 pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
     s: &mut S,
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     _location: Location,
     access_place: (AccessDepth, &Place<'tcx>),
@@ -48,7 +47,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
 
         if places_conflict::borrow_conflicts_with_place(
             tcx,
-            param_env,
             body,
             &borrowed.borrowed_place,
             borrowed.kind,
@@ -133,11 +131,7 @@ pub(super) fn is_active<'tcx>(
 /// Determines if a given borrow is borrowing local data
 /// This is called for all Yield expressions on movable generators
 pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
-    match place.base {
-        PlaceBase::Static(_) => false,
-
-        // Reborrow of already borrowed data is ignored
-        // Any errors will be caught on the initial borrow
-        PlaceBase::Local(_) => !place.is_indirect(),
-    }
+    // Reborrow of already borrowed data is ignored
+    // Any errors will be caught on the initial borrow
+    !place.is_indirect()
 }
index 91ab314e2b910ad92df9bb25e47f56ac230d6f89..ac02da2661586d57c38ec867003b3956259a0ee3 100644 (file)
@@ -1,6 +1,6 @@
 use crate::borrow_check::borrow_set::LocalsStateAtExit;
 use rustc::mir::ProjectionElem;
-use rustc::mir::{Body, Mutability, Place, PlaceBase};
+use rustc::mir::{Body, Mutability, Place};
 use rustc::ty::{self, TyCtxt};
 use rustc_hir as hir;
 
@@ -25,41 +25,35 @@ fn ignore_borrow(
         body: &Body<'tcx>,
         locals_state_at_exit: &LocalsStateAtExit,
     ) -> bool {
-        let local = match self.base {
-            // If a local variable is immutable, then we only need to track borrows to guard
-            // against two kinds of errors:
-            // * The variable being dropped while still borrowed (e.g., because the fn returns
-            //   a reference to a local variable)
-            // * The variable being moved while still borrowed
-            //
-            // In particular, the variable cannot be mutated -- the "access checks" will fail --
-            // so we don't have to worry about mutation while borrowed.
-            PlaceBase::Local(local) => match locals_state_at_exit {
-                LocalsStateAtExit::AllAreInvalidated => local,
-                LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
-                    let ignore = !has_storage_dead_or_moved.contains(local)
-                        && body.local_decls[local].mutability == Mutability::Not;
-                    debug!("ignore_borrow: local {:?} => {:?}", local, ignore);
-                    if ignore {
-                        return true;
-                    } else {
-                        local
-                    }
-                }
-            },
-            PlaceBase::Static(_) => return true,
-        };
+        // If a local variable is immutable, then we only need to track borrows to guard
+        // against two kinds of errors:
+        // * The variable being dropped while still borrowed (e.g., because the fn returns
+        //   a reference to a local variable)
+        // * The variable being moved while still borrowed
+        //
+        // In particular, the variable cannot be mutated -- the "access checks" will fail --
+        // so we don't have to worry about mutation while borrowed.
+        if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } =
+            locals_state_at_exit
+        {
+            let ignore = !has_storage_dead_or_moved.contains(self.local)
+                && body.local_decls[self.local].mutability == Mutability::Not;
+            debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore);
+            if ignore {
+                return true;
+            }
+        }
 
         for (i, elem) in self.projection.iter().enumerate() {
             let proj_base = &self.projection[..i];
 
             if *elem == ProjectionElem::Deref {
-                let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
+                let ty = Place::ty_from(&self.local, proj_base, body, tcx).ty;
                 match ty.kind {
                     ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
                         // For references to thread-local statics, we do need
                         // to track the borrow.
-                        if body.local_decls[local].is_ref_to_thread_local() {
+                        if body.local_decls[self.local].is_ref_to_thread_local() {
                             continue;
                         }
                         return true;
index 64103719fe925722b3497bb3d0d4d1356a5c1acd..b95d1af11ad1d1c6fe64c250c83d3c773a79315b 100644 (file)
@@ -1,9 +1,7 @@
 use crate::borrow_check::ArtificialField;
 use crate::borrow_check::Overlap;
 use crate::borrow_check::{AccessDepth, Deep, Shallow};
-use rustc::mir::{
-    Body, BorrowKind, Place, PlaceBase, PlaceElem, PlaceRef, ProjectionElem, StaticKind,
-};
+use rustc::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
 use rustc::ty::{self, TyCtxt};
 use rustc_hir as hir;
 use std::cmp::max;
@@ -25,7 +23,6 @@
 /// dataflow).
 crate fn places_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     borrow_place: &Place<'tcx>,
     access_place: &Place<'tcx>,
@@ -33,7 +30,6 @@
 ) -> bool {
     borrow_conflicts_with_place(
         tcx,
-        param_env,
         body,
         borrow_place,
         BorrowKind::Mut { allow_two_phase_borrow: true },
@@ -49,7 +45,6 @@
 /// order to make the conservative choice and preserve soundness.
 pub(super) fn borrow_conflicts_with_place<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     borrow_place: &Place<'tcx>,
     borrow_kind: BorrowKind,
@@ -70,21 +65,11 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
         }
     }
 
-    place_components_conflict(
-        tcx,
-        param_env,
-        body,
-        borrow_place,
-        borrow_kind,
-        access_place,
-        access,
-        bias,
-    )
+    place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias)
 }
 
 fn place_components_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     borrow_place: &Place<'tcx>,
     borrow_kind: BorrowKind,
@@ -134,10 +119,10 @@ fn place_components_conflict<'tcx>(
     //    and either equal or disjoint.
     //  - If we did run out of access, the borrow can access a part of it.
 
-    let borrow_base = &borrow_place.base;
-    let access_base = access_place.base;
+    let borrow_local = &borrow_place.local;
+    let access_local = access_place.local;
 
-    match place_base_conflict(tcx, param_env, borrow_base, access_base) {
+    match place_base_conflict(borrow_local, access_local) {
         Overlap::Arbitrary => {
             bug!("Two base can't return Arbitrary");
         }
@@ -176,7 +161,7 @@ fn place_components_conflict<'tcx>(
         match place_projection_conflict(
             tcx,
             body,
-            borrow_base,
+            borrow_local,
             borrow_proj_base,
             borrow_c,
             access_c,
@@ -223,7 +208,7 @@ fn place_components_conflict<'tcx>(
             // access cares about.
 
             let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
-            let base_ty = Place::ty_from(borrow_base, proj_base, body, tcx).ty;
+            let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty;
 
             match (elem, &base_ty.kind, access) {
                 (_, _, Shallow(Some(ArtificialField::ArrayLength)))
@@ -308,68 +293,15 @@ fn place_components_conflict<'tcx>(
 // Given that the bases of `elem1` and `elem2` are always either equal
 // or disjoint (and have the same type!), return the overlap situation
 // between `elem1` and `elem2`.
-fn place_base_conflict<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    elem1: &PlaceBase<'tcx>,
-    elem2: &PlaceBase<'tcx>,
-) -> Overlap {
-    match (elem1, elem2) {
-        (PlaceBase::Local(l1), PlaceBase::Local(l2)) => {
-            if l1 == l2 {
-                // the same local - base case, equal
-                debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
-                Overlap::EqualOrDisjoint
-            } else {
-                // different locals - base case, disjoint
-                debug!("place_element_conflict: DISJOINT-LOCAL");
-                Overlap::Disjoint
-            }
-        }
-        (PlaceBase::Static(s1), PlaceBase::Static(s2)) => {
-            match (&s1.kind, &s2.kind) {
-                (StaticKind::Static, StaticKind::Static) => {
-                    if s1.def_id != s2.def_id {
-                        debug!("place_element_conflict: DISJOINT-STATIC");
-                        Overlap::Disjoint
-                    } else if tcx.is_mutable_static(s1.def_id) {
-                        // We ignore mutable statics - they can only be unsafe code.
-                        debug!("place_element_conflict: IGNORE-STATIC-MUT");
-                        Overlap::Disjoint
-                    } else {
-                        debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
-                        Overlap::EqualOrDisjoint
-                    }
-                }
-                (StaticKind::Promoted(promoted_1, _), StaticKind::Promoted(promoted_2, _)) => {
-                    if promoted_1 == promoted_2 {
-                        if let ty::Array(_, len) = s1.ty.kind {
-                            if let Some(0) = len.try_eval_usize(tcx, param_env) {
-                                // Ignore conflicts with promoted [T; 0].
-                                debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
-                                return Overlap::Disjoint;
-                            }
-                        }
-                        // the same promoted - base case, equal
-                        debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
-                        Overlap::EqualOrDisjoint
-                    } else {
-                        // different promoteds - base case, disjoint
-                        debug!("place_element_conflict: DISJOINT-PROMOTED");
-                        Overlap::Disjoint
-                    }
-                }
-                (_, _) => {
-                    debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED");
-                    Overlap::Disjoint
-                }
-            }
-        }
-        (PlaceBase::Local(_), PlaceBase::Static(_))
-        | (PlaceBase::Static(_), PlaceBase::Local(_)) => {
-            debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
-            Overlap::Disjoint
-        }
+fn place_base_conflict(l1: &Local, l2: &Local) -> Overlap {
+    if l1 == l2 {
+        // the same local - base case, equal
+        debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
+        Overlap::EqualOrDisjoint
+    } else {
+        // different locals - base case, disjoint
+        debug!("place_element_conflict: DISJOINT-LOCAL");
+        Overlap::Disjoint
     }
 }
 
@@ -379,7 +311,7 @@ fn place_base_conflict<'tcx>(
 fn place_projection_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    pi1_base: &PlaceBase<'tcx>,
+    pi1_local: &Local,
     pi1_proj_base: &[PlaceElem<'tcx>],
     pi1_elem: &PlaceElem<'tcx>,
     pi2_elem: &PlaceElem<'tcx>,
@@ -397,7 +329,7 @@ fn place_projection_conflict<'tcx>(
                 debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
                 Overlap::EqualOrDisjoint
             } else {
-                let ty = Place::ty_from(pi1_base, pi1_proj_base, body, tcx).ty;
+                let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
                 match ty.kind {
                     ty::Adt(def, _) if def.is_union() => {
                         // Different fields of a union, we are basically stuck.
index 1e88f696f2315ad34a2ab25dd20ffc3632c81cc2..31bee460fa0113f4a9be55e61c87062f0f4c0aad 100644 (file)
@@ -9,7 +9,7 @@
 
 use super::MirBorrowckCtxt;
 
-use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
+use rustc::mir::{Place, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
 use rustc::ty::{self, TyCtxt};
 use rustc_hir as hir;
 
@@ -19,7 +19,7 @@ pub trait IsPrefixOf<'cx, 'tcx> {
 
 impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
     fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
-        self.base == other.base
+        self.local == other.local
             && self.projection.len() <= other.projection.len()
             && self.projection == &other.projection[..self.projection.len()]
     }
@@ -69,39 +69,23 @@ fn next(&mut self) -> Option<Self::Item> {
 
         'cursor: loop {
             match &cursor {
-                PlaceRef {
-                    base: PlaceBase::Local(_),
-                    projection: [],
-                }
-                | // search yielded this leaf
-                PlaceRef {
-                    base: PlaceBase::Static(_),
-                    projection: [],
-                } => {
+                PlaceRef { local: _, projection: [] } => {
                     self.next = None;
                     return Some(cursor);
                 }
-                PlaceRef {
-                    base: _,
-                    projection: [proj_base @ .., elem],
-                } => {
+                PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
                     match elem {
                         ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
                             // FIXME: add union handling
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
-                        ProjectionElem::Downcast(..) |
-                        ProjectionElem::Subslice { .. } |
-                        ProjectionElem::ConstantIndex { .. } |
-                        ProjectionElem::Index(_) => {
-                            cursor = PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            };
+                        ProjectionElem::Downcast(..)
+                        | ProjectionElem::Subslice { .. }
+                        | ProjectionElem::ConstantIndex { .. }
+                        | ProjectionElem::Index(_) => {
+                            cursor = PlaceRef { local: cursor.local, projection: proj_base };
                             continue 'cursor;
                         }
                         ProjectionElem::Deref => {
@@ -122,10 +106,8 @@ fn next(&mut self) -> Option<Self::Item> {
                         PrefixSet::All => {
                             // All prefixes: just blindly enqueue the base
                             // of the projection.
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
                         PrefixSet::Supporting => {
@@ -138,37 +120,24 @@ fn next(&mut self) -> Option<Self::Item> {
                     // derefs, except we stop at the deref of a shared
                     // reference.
 
-                    let ty = Place::ty_from(cursor.base, proj_base, *self.body, self.tcx).ty;
+                    let ty = Place::ty_from(cursor.local, proj_base, *self.body, self.tcx).ty;
                     match ty.kind {
-                        ty::RawPtr(_) |
-                        ty::Ref(
-                            _, /*rgn*/
-                            _, /*ty*/
-                            hir::Mutability::Not
-                            ) => {
+                        ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
                             // don't continue traversing over derefs of raw pointers or shared
                             // borrows.
                             self.next = None;
                             return Some(cursor);
                         }
 
-                        ty::Ref(
-                            _, /*rgn*/
-                            _, /*ty*/
-                            hir::Mutability::Mut,
-                            ) => {
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                        ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
 
                         ty::Adt(..) if ty.is_box() => {
-                            self.next = Some(PlaceRef {
-                                base: cursor.base,
-                                projection: proj_base,
-                            });
+                            self.next =
+                                Some(PlaceRef { local: cursor.local, projection: proj_base });
                             return Some(cursor);
                         }
 
index 0e4801b88d87e966fc880d6889444dc1529ef9b5..f0dc94f417c1e23e60002c20a95b050c5ae8ef98 100644 (file)
@@ -1,10 +1,10 @@
 use rustc::infer::canonical::QueryRegionConstraints;
-use rustc::infer::outlives::free_region_map::FreeRegionRelations;
 use rustc::infer::region_constraints::GenericKind;
 use rustc::infer::InferCtxt;
 use rustc::mir::ConstraintCategory;
 use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
 use rustc::traits::query::type_op::{self, TypeOp};
+use rustc::ty::free_region_map::FreeRegionRelations;
 use rustc::ty::{self, RegionVid, Ty};
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 use rustc_span::DUMMY_SP;
index a963735905e69c763c067fd795cb4d60de4cec21..947bbef4379f5ab780af9363246c4d620b623af6 100644 (file)
@@ -28,6 +28,7 @@
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::{Idx, IndexVec};
@@ -309,17 +310,54 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
                 );
             }
         } else {
-            if let ty::ConstKind::Unevaluated(def_id, substs) = constant.literal.val {
-                if let Err(terr) = self.cx.fully_perform_op(
-                    location.to_locations(),
-                    ConstraintCategory::Boring,
-                    self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
-                        constant.literal.ty,
-                        def_id,
-                        UserSubsts { substs, user_self_ty: None },
-                    )),
-                ) {
-                    span_mirbug!(self, constant, "bad constant type {:?} ({:?})", constant, terr);
+            if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
+                if let Some(promoted) = promoted {
+                    let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
+                                     promoted: &ReadOnlyBodyAndCache<'_, 'tcx>,
+                                     ty,
+                                     san_ty| {
+                        if let Err(terr) = verifier.cx.eq_types(
+                            san_ty,
+                            ty,
+                            location.to_locations(),
+                            ConstraintCategory::Boring,
+                        ) {
+                            span_mirbug!(
+                                verifier,
+                                promoted,
+                                "bad promoted type ({:?}: {:?}): {:?}",
+                                ty,
+                                san_ty,
+                                terr
+                            );
+                        };
+                    };
+
+                    if !self.errors_reported {
+                        let promoted_body = self.promoted[promoted];
+                        self.sanitize_promoted(promoted_body, location);
+
+                        let promoted_ty = promoted_body.return_ty();
+                        check_err(self, &promoted_body, ty, promoted_ty);
+                    }
+                } else {
+                    if let Err(terr) = self.cx.fully_perform_op(
+                        location.to_locations(),
+                        ConstraintCategory::Boring,
+                        self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+                            constant.literal.ty,
+                            def_id,
+                            UserSubsts { substs, user_self_ty: None },
+                        )),
+                    ) {
+                        span_mirbug!(
+                            self,
+                            constant,
+                            "bad constant type {:?} ({:?})",
+                            constant,
+                            terr
+                        );
+                    }
                 }
             }
             if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {
@@ -427,83 +465,32 @@ fn sanitize_place(
     ) -> PlaceTy<'tcx> {
         debug!("sanitize_place: {:?}", place);
 
-        let mut place_ty = match &place.base {
-            PlaceBase::Local(index) => PlaceTy::from_ty(self.body.local_decls[*index].ty),
-            PlaceBase::Static(box Static { kind, ty, def_id }) => {
-                let san_ty = self.sanitize_type(place, ty);
-                let check_err =
-                    |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, place: &Place<'tcx>, ty, san_ty| {
-                        if let Err(terr) = verifier.cx.eq_types(
-                            san_ty,
-                            ty,
-                            location.to_locations(),
-                            ConstraintCategory::Boring,
-                        ) {
-                            span_mirbug!(
-                                verifier,
-                                place,
-                                "bad promoted type ({:?}: {:?}): {:?}",
-                                ty,
-                                san_ty,
-                                terr
-                            );
-                        };
-                    };
-                match kind {
-                    StaticKind::Promoted(promoted, _) => {
-                        if !self.errors_reported {
-                            let promoted_body_cache = self.promoted[*promoted];
-                            self.sanitize_promoted(promoted_body_cache, location);
-
-                            let promoted_ty = promoted_body_cache.return_ty();
-                            check_err(self, place, promoted_ty, san_ty);
-                        }
-                    }
-                    StaticKind::Static => {
-                        let ty = self.tcx().type_of(*def_id);
-                        let ty = self.cx.normalize(ty, location);
-
-                        check_err(self, place, ty, san_ty);
-                    }
-                }
-                PlaceTy::from_ty(san_ty)
-            }
-        };
+        let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
 
         if place.projection.is_empty() {
             if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
-                let is_promoted = match place.as_ref() {
-                    PlaceRef {
-                        base: &PlaceBase::Static(box Static { kind: StaticKind::Promoted(..), .. }),
-                        projection: &[],
-                    } => true,
-                    _ => false,
+                let tcx = self.tcx();
+                let trait_ref = ty::TraitRef {
+                    def_id: tcx.lang_items().copy_trait().unwrap(),
+                    substs: tcx.mk_substs_trait(place_ty.ty, &[]),
                 };
 
-                if !is_promoted {
-                    let tcx = self.tcx();
-                    let trait_ref = ty::TraitRef {
-                        def_id: tcx.lang_items().copy_trait().unwrap(),
-                        substs: tcx.mk_substs_trait(place_ty.ty, &[]),
-                    };
-
-                    // To have a `Copy` operand, the type `T` of the
-                    // value must be `Copy`. Note that we prove that `T: Copy`,
-                    // rather than using the `is_copy_modulo_regions`
-                    // test. This is important because
-                    // `is_copy_modulo_regions` ignores the resulting region
-                    // obligations and assumes they pass. This can result in
-                    // bounds from `Copy` impls being unsoundly ignored (e.g.,
-                    // #29149). Note that we decide to use `Copy` before knowing
-                    // whether the bounds fully apply: in effect, the rule is
-                    // that if a value of some type could implement `Copy`, then
-                    // it must.
-                    self.cx.prove_trait_ref(
-                        trait_ref,
-                        location.to_locations(),
-                        ConstraintCategory::CopyBound,
-                    );
-                }
+                // To have a `Copy` operand, the type `T` of the
+                // value must be `Copy`. Note that we prove that `T: Copy`,
+                // rather than using the `is_copy_modulo_regions`
+                // test. This is important because
+                // `is_copy_modulo_regions` ignores the resulting region
+                // obligations and assumes they pass. This can result in
+                // bounds from `Copy` impls being unsoundly ignored (e.g.,
+                // #29149). Note that we decide to use `Copy` before knowing
+                // whether the bounds fully apply: in effect, the rule is
+                // that if a value of some type could implement `Copy`, then
+                // it must.
+                self.cx.prove_trait_ref(
+                    trait_ref,
+                    location.to_locations(),
+                    ConstraintCategory::CopyBound,
+                );
             }
         }
 
@@ -2400,7 +2387,7 @@ fn add_reborrow_constraint(
             match elem {
                 ProjectionElem::Deref => {
                     let tcx = self.infcx.tcx;
-                    let base_ty = Place::ty_from(&borrowed_place.base, proj_base, body, tcx).ty;
+                    let base_ty = Place::ty_from(&borrowed_place.local, proj_base, body, tcx).ty;
 
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.kind {
index 608a2436bf3d3f69268fdf3b0e6031d291cdffa8..5e4eebb771f21d8a6cf5e26fac8cbeed481f9e49 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{Local, Location, Place, PlaceBase, Statement, StatementKind, TerminatorKind};
+use rustc::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind};
 
 use rustc_data_structures::fx::FxHashSet;
 
@@ -57,9 +57,7 @@ fn remove_never_initialized_mut_locals(&mut self, into: &Place<'_>) {
         // be those that were never initialized - we will consider those as being used as
         // they will either have been removed by unreachable code optimizations; or linted
         // as unused variables.
-        if let PlaceBase::Local(local) = into.base {
-            let _ = self.never_initialized_mut_locals.remove(&local);
-        }
+        self.never_initialized_mut_locals.remove(&into.local);
     }
 }
 
@@ -80,13 +78,11 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, _location: Loca
     fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) {
         match &statement.kind {
             StatementKind::Assign(box (into, _)) => {
-                if let PlaceBase::Local(local) = into.base {
-                    debug!(
-                        "visit_statement: statement={:?} local={:?} \
-                         never_initialized_mut_locals={:?}",
-                        statement, local, self.never_initialized_mut_locals
-                    );
-                }
+                debug!(
+                    "visit_statement: statement={:?} local={:?} \
+                    never_initialized_mut_locals={:?}",
+                    statement, into.local, self.never_initialized_mut_locals
+                );
                 self.remove_never_initialized_mut_locals(into);
             }
             _ => {}
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
deleted file mode 100644 (file)
index 2e133a0..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-use crate::build::matches::ArmHasGuard;
-use crate::build::ForGuard::OutsideGuard;
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::hair::*;
-use rustc::mir::*;
-use rustc_hir as hir;
-use rustc_span::Span;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub fn ast_block(
-        &mut self,
-        destination: &Place<'tcx>,
-        block: BasicBlock,
-        ast_block: &'tcx hir::Block<'tcx>,
-        source_info: SourceInfo,
-    ) -> BlockAnd<()> {
-        let Block {
-            region_scope,
-            opt_destruction_scope,
-            span,
-            stmts,
-            expr,
-            targeted_by_break,
-            safety_mode,
-        } = self.hir.mirror(ast_block);
-        self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
-            this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
-                if targeted_by_break {
-                    // This is a `break`-able block
-                    let exit_block = this.cfg.start_new_block();
-                    let block_exit =
-                        this.in_breakable_scope(None, exit_block, destination.clone(), |this| {
-                            this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
-                        });
-                    this.cfg.goto(unpack!(block_exit), source_info, exit_block);
-                    exit_block.unit()
-                } else {
-                    this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
-                }
-            })
-        })
-    }
-
-    fn ast_block_stmts(
-        &mut self,
-        destination: &Place<'tcx>,
-        mut block: BasicBlock,
-        span: Span,
-        stmts: Vec<StmtRef<'tcx>>,
-        expr: Option<ExprRef<'tcx>>,
-        safety_mode: BlockSafety,
-    ) -> BlockAnd<()> {
-        let this = self;
-
-        // This convoluted structure is to avoid using recursion as we walk down a list
-        // of statements. Basically, the structure we get back is something like:
-        //
-        //    let x = <init> in {
-        //       expr1;
-        //       let y = <init> in {
-        //           expr2;
-        //           expr3;
-        //           ...
-        //       }
-        //    }
-        //
-        // The let bindings are valid till the end of block so all we have to do is to pop all
-        // the let-scopes at the end.
-        //
-        // First we build all the statements in the block.
-        let mut let_scope_stack = Vec::with_capacity(8);
-        let outer_source_scope = this.source_scope;
-        let outer_push_unsafe_count = this.push_unsafe_count;
-        let outer_unpushed_unsafe = this.unpushed_unsafe;
-        this.update_source_scope_for_safety_mode(span, safety_mode);
-
-        let source_info = this.source_info(span);
-        for stmt in stmts {
-            let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
-            match kind {
-                StmtKind::Expr { scope, expr } => {
-                    this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
-                    unpack!(
-                        block = this.in_opt_scope(
-                            opt_destruction_scope.map(|de| (de, source_info)),
-                            |this| {
-                                let si = (scope, source_info);
-                                this.in_scope(si, LintLevel::Inherited, |this| {
-                                    let expr = this.hir.mirror(expr);
-                                    this.stmt_expr(block, expr, Some(scope))
-                                })
-                            }
-                        )
-                    );
-                }
-                StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => {
-                    let ignores_expr_result =
-                        if let PatKind::Wild = *pattern.kind { true } else { false };
-                    this.block_context.push(BlockFrame::Statement { ignores_expr_result });
-
-                    // Enter the remainder scope, i.e., the bindings' destruction scope.
-                    this.push_scope((remainder_scope, source_info));
-                    let_scope_stack.push(remainder_scope);
-
-                    // Declare the bindings, which may create a source scope.
-                    let remainder_span =
-                        remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree);
-
-                    let visibility_scope =
-                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
-
-                    // Evaluate the initializer, if present.
-                    if let Some(init) = initializer {
-                        let initializer_span = init.span();
-
-                        unpack!(
-                            block = this.in_opt_scope(
-                                opt_destruction_scope.map(|de| (de, source_info)),
-                                |this| {
-                                    let scope = (init_scope, source_info);
-                                    this.in_scope(scope, lint_level, |this| {
-                                        this.declare_bindings(
-                                            visibility_scope,
-                                            remainder_span,
-                                            &pattern,
-                                            ArmHasGuard(false),
-                                            Some((None, initializer_span)),
-                                        );
-                                        this.expr_into_pattern(block, pattern, init)
-                                    })
-                                }
-                            )
-                        );
-                    } else {
-                        let scope = (init_scope, source_info);
-                        unpack!(this.in_scope(scope, lint_level, |this| {
-                            this.declare_bindings(
-                                visibility_scope,
-                                remainder_span,
-                                &pattern,
-                                ArmHasGuard(false),
-                                None,
-                            );
-                            block.unit()
-                        }));
-
-                        debug!("ast_block_stmts: pattern={:?}", pattern);
-                        this.visit_bindings(
-                            &pattern,
-                            UserTypeProjections::none(),
-                            &mut |this, _, _, _, node, span, _, _| {
-                                this.storage_live_binding(block, node, span, OutsideGuard);
-                                this.schedule_drop_for_binding(node, span, OutsideGuard);
-                            },
-                        )
-                    }
-
-                    // Enter the visibility scope, after evaluating the initializer.
-                    if let Some(source_scope) = visibility_scope {
-                        this.source_scope = source_scope;
-                    }
-                }
-            }
-
-            let popped = this.block_context.pop();
-            assert!(popped.map_or(false, |bf| bf.is_statement()));
-        }
-
-        // Then, the block may have an optional trailing expression which is a “return” value
-        // of the block, which is stored into `destination`.
-        let tcx = this.hir.tcx();
-        let destination_ty = destination.ty(&this.local_decls, tcx).ty;
-        if let Some(expr) = expr {
-            let tail_result_is_ignored =
-                destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
-            this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored });
-
-            unpack!(block = this.into(destination, block, expr));
-            let popped = this.block_context.pop();
-
-            assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
-        } else {
-            // If a block has no trailing expression, then it is given an implicit return type.
-            // This return type is usually `()`, unless the block is diverging, in which case the
-            // return type is `!`. For the unit type, we need to actually return the unit, but in
-            // the case of `!`, no return value is required, as the block will never return.
-            if destination_ty.is_unit() {
-                // We only want to assign an implicit `()` as the return value of the block if the
-                // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
-                this.cfg.push_assign_unit(block, source_info, destination);
-            }
-        }
-        // Finally, we pop all the let scopes before exiting out from the scope of block
-        // itself.
-        for scope in let_scope_stack.into_iter().rev() {
-            unpack!(block = this.pop_scope((scope, source_info), block));
-        }
-        // Restore the original source scope.
-        this.source_scope = outer_source_scope;
-        this.push_unsafe_count = outer_push_unsafe_count;
-        this.unpushed_unsafe = outer_unpushed_unsafe;
-        block.unit()
-    }
-
-    /// If we are changing the safety mode, create a new source scope
-    fn update_source_scope_for_safety_mode(&mut self, span: Span, safety_mode: BlockSafety) {
-        debug!("update_source_scope_for({:?}, {:?})", span, safety_mode);
-        let new_unsafety = match safety_mode {
-            BlockSafety::Safe => None,
-            BlockSafety::ExplicitUnsafe(hir_id) => {
-                assert_eq!(self.push_unsafe_count, 0);
-                match self.unpushed_unsafe {
-                    Safety::Safe => {}
-                    _ => return,
-                }
-                self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id);
-                Some(Safety::ExplicitUnsafe(hir_id))
-            }
-            BlockSafety::PushUnsafe => {
-                self.push_unsafe_count += 1;
-                Some(Safety::BuiltinUnsafe)
-            }
-            BlockSafety::PopUnsafe => {
-                self.push_unsafe_count = self
-                    .push_unsafe_count
-                    .checked_sub(1)
-                    .unwrap_or_else(|| span_bug!(span, "unsafe count underflow"));
-                if self.push_unsafe_count == 0 { Some(self.unpushed_unsafe) } else { None }
-            }
-        };
-
-        if let Some(unsafety) = new_unsafety {
-            self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(unsafety));
-        }
-    }
-}
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
deleted file mode 100644 (file)
index 553701c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-//! Routines for manipulating the control-flow graph.
-
-use crate::build::CFG;
-use rustc::mir::*;
-
-impl<'tcx> CFG<'tcx> {
-    pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
-        &self.basic_blocks[blk]
-    }
-
-    pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
-        &mut self.basic_blocks[blk]
-    }
-
-    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
-    // it as #[inline(never)] to keep rustc's stack use in check.
-    #[inline(never)]
-    pub fn start_new_block(&mut self) -> BasicBlock {
-        self.basic_blocks.push(BasicBlockData::new(None))
-    }
-
-    pub fn start_new_cleanup_block(&mut self) -> BasicBlock {
-        let bb = self.start_new_block();
-        self.block_data_mut(bb).is_cleanup = true;
-        bb
-    }
-
-    pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
-        debug!("push({:?}, {:?})", block, statement);
-        self.block_data_mut(block).statements.push(statement);
-    }
-
-    pub fn push_assign(
-        &mut self,
-        block: BasicBlock,
-        source_info: SourceInfo,
-        place: &Place<'tcx>,
-        rvalue: Rvalue<'tcx>,
-    ) {
-        self.push(
-            block,
-            Statement { source_info, kind: StatementKind::Assign(box (place.clone(), rvalue)) },
-        );
-    }
-
-    pub fn push_assign_constant(
-        &mut self,
-        block: BasicBlock,
-        source_info: SourceInfo,
-        temp: &Place<'tcx>,
-        constant: Constant<'tcx>,
-    ) {
-        self.push_assign(block, source_info, temp, Rvalue::Use(Operand::Constant(box constant)));
-    }
-
-    pub fn push_assign_unit(
-        &mut self,
-        block: BasicBlock,
-        source_info: SourceInfo,
-        place: &Place<'tcx>,
-    ) {
-        self.push_assign(
-            block,
-            source_info,
-            place,
-            Rvalue::Aggregate(box AggregateKind::Tuple, vec![]),
-        );
-    }
-
-    pub fn push_fake_read(
-        &mut self,
-        block: BasicBlock,
-        source_info: SourceInfo,
-        cause: FakeReadCause,
-        place: Place<'tcx>,
-    ) {
-        let kind = StatementKind::FakeRead(cause, box place);
-        let stmt = Statement { source_info, kind };
-        self.push(block, stmt);
-    }
-
-    pub fn terminate(
-        &mut self,
-        block: BasicBlock,
-        source_info: SourceInfo,
-        kind: TerminatorKind<'tcx>,
-    ) {
-        debug!("terminating block {:?} <- {:?}", block, kind);
-        debug_assert!(
-            self.block_data(block).terminator.is_none(),
-            "terminate: block {:?}={:?} already has a terminator set",
-            block,
-            self.block_data(block)
-        );
-        self.block_data_mut(block).terminator = Some(Terminator { source_info, kind });
-    }
-
-    /// In the `origin` block, push a `goto -> target` terminator.
-    pub fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) {
-        self.terminate(origin, source_info, TerminatorKind::Goto { target })
-    }
-}
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
deleted file mode 100644 (file)
index ceac2a0..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-//! See docs in build/expr/mod.rs
-
-use crate::build::Builder;
-use crate::hair::*;
-use rustc::mir::*;
-use rustc::ty::CanonicalUserTypeAnnotation;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Compile `expr`, yielding a compile-time constant. Assumes that
-    /// `expr` is a valid compile-time constant!
-    pub fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let expr = self.hir.mirror(expr);
-        self.expr_as_constant(expr)
-    }
-
-    fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
-        let this = self;
-        let Expr { ty, temp_lifetime: _, span, kind } = expr;
-        match kind {
-            ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value),
-            ExprKind::Literal { literal, user_ty } => {
-                let user_ty = user_ty.map(|user_ty| {
-                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                        span,
-                        user_ty,
-                        inferred_ty: ty,
-                    })
-                });
-                assert_eq!(literal.ty, ty);
-                Constant { span, user_ty, literal }
-            }
-            ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal },
-            _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
-        }
-    }
-}
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
deleted file mode 100644 (file)
index b969932..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-//! See docs in build/expr/mod.rs
-
-use crate::build::expr::category::Category;
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::hair::*;
-use rustc::middle::region;
-use rustc::mir::*;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Returns an operand suitable for use until the end of the current
-    /// scope expression.
-    ///
-    /// The operand returned from this function will *not be valid* after
-    /// an ExprKind::Scope is passed, so please do *not* return it from
-    /// functions to avoid bad miscompiles.
-    pub fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let local_scope = self.local_scope();
-        self.as_operand(block, local_scope, expr)
-    }
-
-    /// Compile `expr` into a value that can be used as an operand.
-    /// If `expr` is a place like `x`, this will introduce a
-    /// temporary `tmp = x`, so that we capture the value of `x` at
-    /// this time.
-    ///
-    /// The operand is known to be live until the end of `scope`.
-    pub fn as_operand<M>(
-        &mut self,
-        block: BasicBlock,
-        scope: Option<region::Scope>,
-        expr: M,
-    ) -> BlockAnd<Operand<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let expr = self.hir.mirror(expr);
-        self.expr_as_operand(block, scope, expr)
-    }
-
-    fn expr_as_operand(
-        &mut self,
-        mut block: BasicBlock,
-        scope: Option<region::Scope>,
-        expr: Expr<'tcx>,
-    ) -> BlockAnd<Operand<'tcx>> {
-        debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
-        let this = self;
-
-        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
-            let source_info = this.source_info(expr.span);
-            let region_scope = (region_scope, source_info);
-            return this
-                .in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value));
-        }
-
-        let category = Category::of(&expr.kind).unwrap();
-        debug!("expr_as_operand: category={:?} for={:?}", category, expr.kind);
-        match category {
-            Category::Constant => {
-                let constant = this.as_constant(expr);
-                block.and(Operand::Constant(box constant))
-            }
-            Category::Place | Category::Rvalue(..) => {
-                let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
-                block.and(Operand::Move(Place::from(operand)))
-            }
-        }
-    }
-}
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
deleted file mode 100644 (file)
index 29eac5e..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-//! See docs in build/expr/mod.rs
-
-use crate::build::expr::category::Category;
-use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::hair::*;
-use rustc::middle::region;
-use rustc::mir::interpret::PanicInfo::BoundsCheck;
-use rustc::mir::*;
-use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
-use rustc_span::Span;
-
-use rustc_index::vec::Idx;
-
-/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
-/// place by pushing more and more projections onto the end, and then convert the final set into a
-/// place using the `into_place` method.
-///
-/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
-/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
-#[derive(Clone)]
-struct PlaceBuilder<'tcx> {
-    base: PlaceBase<'tcx>,
-    projection: Vec<PlaceElem<'tcx>>,
-}
-
-impl PlaceBuilder<'tcx> {
-    fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
-        Place { base: self.base, projection: tcx.intern_place_elems(&self.projection) }
-    }
-
-    fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
-        self.project(PlaceElem::Field(f, ty))
-    }
-
-    fn deref(self) -> Self {
-        self.project(PlaceElem::Deref)
-    }
-
-    fn index(self, index: Local) -> Self {
-        self.project(PlaceElem::Index(index))
-    }
-
-    fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
-        self.projection.push(elem);
-        self
-    }
-}
-
-impl From<Local> for PlaceBuilder<'tcx> {
-    fn from(local: Local) -> Self {
-        Self { base: local.into(), projection: Vec::new() }
-    }
-}
-
-impl From<PlaceBase<'tcx>> for PlaceBuilder<'tcx> {
-    fn from(base: PlaceBase<'tcx>) -> Self {
-        Self { base, projection: Vec::new() }
-    }
-}
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Compile `expr`, yielding a place that we can move from etc.
-    ///
-    /// WARNING: Any user code might:
-    /// * Invalidate any slice bounds checks performed.
-    /// * Change the address that this `Place` refers to.
-    /// * Modify the memory that this place refers to.
-    /// * Invalidate the memory that this place refers to, this will be caught
-    ///   by borrow checking.
-    ///
-    /// Extra care is needed if any user code is allowed to run between calling
-    /// this method and using it, as is the case for `match` and index
-    /// expressions.
-    pub fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let place_builder = unpack!(block = self.as_place_builder(block, expr));
-        block.and(place_builder.into_place(self.hir.tcx()))
-    }
-
-    /// This is used when constructing a compound `Place`, so that we can avoid creating
-    /// intermediate `Place` values until we know the full set of projections.
-    fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let expr = self.hir.mirror(expr);
-        self.expr_as_place(block, expr, Mutability::Mut, None)
-    }
-
-    /// Compile `expr`, yielding a place that we can move from etc.
-    /// Mutability note: The caller of this method promises only to read from the resulting
-    /// place. The place itself may or may not be mutable:
-    /// * If this expr is a place expr like a.b, then we will return that place.
-    /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
-    pub fn as_read_only_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
-        block.and(place_builder.into_place(self.hir.tcx()))
-    }
-
-    /// This is used when constructing a compound `Place`, so that we can avoid creating
-    /// intermediate `Place` values until we know the full set of projections.
-    /// Mutability note: The caller of this method promises only to read from the resulting
-    /// place. The place itself may or may not be mutable:
-    /// * If this expr is a place expr like a.b, then we will return that place.
-    /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
-    fn as_read_only_place_builder<M>(
-        &mut self,
-        block: BasicBlock,
-        expr: M,
-    ) -> BlockAnd<PlaceBuilder<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let expr = self.hir.mirror(expr);
-        self.expr_as_place(block, expr, Mutability::Not, None)
-    }
-
-    fn expr_as_place(
-        &mut self,
-        mut block: BasicBlock,
-        expr: Expr<'tcx>,
-        mutability: Mutability,
-        fake_borrow_temps: Option<&mut Vec<Local>>,
-    ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
-
-        let this = self;
-        let expr_span = expr.span;
-        let source_info = this.source_info(expr_span);
-        match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
-                this.in_scope((region_scope, source_info), lint_level, |this| {
-                    let value = this.hir.mirror(value);
-                    this.expr_as_place(block, value, mutability, fake_borrow_temps)
-                })
-            }
-            ExprKind::Field { lhs, name } => {
-                let lhs = this.hir.mirror(lhs);
-                let place_builder =
-                    unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
-                block.and(place_builder.field(name, expr.ty))
-            }
-            ExprKind::Deref { arg } => {
-                let arg = this.hir.mirror(arg);
-                let place_builder =
-                    unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
-                block.and(place_builder.deref())
-            }
-            ExprKind::Index { lhs, index } => this.lower_index_expression(
-                block,
-                lhs,
-                index,
-                mutability,
-                fake_borrow_temps,
-                expr.temp_lifetime,
-                expr_span,
-                source_info,
-            ),
-            ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))),
-            ExprKind::VarRef { id } => {
-                let place_builder = if this.is_bound_var_in_guard(id) {
-                    let index = this.var_local_id(id, RefWithinGuard);
-                    PlaceBuilder::from(index).deref()
-                } else {
-                    let index = this.var_local_id(id, OutsideGuard);
-                    PlaceBuilder::from(index)
-                };
-                block.and(place_builder)
-            }
-
-            ExprKind::PlaceTypeAscription { source, user_ty } => {
-                let source = this.hir.mirror(source);
-                let place_builder = unpack!(
-                    block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
-                );
-                if let Some(user_ty) = user_ty {
-                    let annotation_index =
-                        this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                            span: source_info.span,
-                            user_ty,
-                            inferred_ty: expr.ty,
-                        });
-
-                    let place = place_builder.clone().into_place(this.hir.tcx());
-                    this.cfg.push(
-                        block,
-                        Statement {
-                            source_info,
-                            kind: StatementKind::AscribeUserType(
-                                box (
-                                    place,
-                                    UserTypeProjection { base: annotation_index, projs: vec![] },
-                                ),
-                                Variance::Invariant,
-                            ),
-                        },
-                    );
-                }
-                block.and(place_builder)
-            }
-            ExprKind::ValueTypeAscription { source, user_ty } => {
-                let source = this.hir.mirror(source);
-                let temp =
-                    unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
-                if let Some(user_ty) = user_ty {
-                    let annotation_index =
-                        this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                            span: source_info.span,
-                            user_ty,
-                            inferred_ty: expr.ty,
-                        });
-                    this.cfg.push(
-                        block,
-                        Statement {
-                            source_info,
-                            kind: StatementKind::AscribeUserType(
-                                box (
-                                    Place::from(temp.clone()),
-                                    UserTypeProjection { base: annotation_index, projs: vec![] },
-                                ),
-                                Variance::Invariant,
-                            ),
-                        },
-                    );
-                }
-                block.and(PlaceBuilder::from(temp))
-            }
-
-            ExprKind::Array { .. }
-            | ExprKind::Tuple { .. }
-            | ExprKind::Adt { .. }
-            | ExprKind::Closure { .. }
-            | ExprKind::Unary { .. }
-            | ExprKind::Binary { .. }
-            | ExprKind::LogicalOp { .. }
-            | ExprKind::Box { .. }
-            | ExprKind::Cast { .. }
-            | ExprKind::Use { .. }
-            | ExprKind::NeverToAny { .. }
-            | ExprKind::Pointer { .. }
-            | ExprKind::Repeat { .. }
-            | ExprKind::Borrow { .. }
-            | ExprKind::AddressOf { .. }
-            | ExprKind::Match { .. }
-            | ExprKind::Loop { .. }
-            | ExprKind::Block { .. }
-            | ExprKind::Assign { .. }
-            | ExprKind::AssignOp { .. }
-            | ExprKind::Break { .. }
-            | ExprKind::Continue { .. }
-            | ExprKind::Return { .. }
-            | ExprKind::Literal { .. }
-            | ExprKind::StaticRef { .. }
-            | ExprKind::InlineAsm { .. }
-            | ExprKind::Yield { .. }
-            | ExprKind::Call { .. } => {
-                // these are not places, so we need to make a temporary.
-                debug_assert!(match Category::of(&expr.kind) {
-                    Some(Category::Place) => false,
-                    _ => true,
-                });
-                let temp =
-                    unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
-                block.and(PlaceBuilder::from(temp))
-            }
-        }
-    }
-
-    /// Lower an index expression
-    ///
-    /// This has two complications;
-    ///
-    /// * We need to do a bounds check.
-    /// * We need to ensure that the bounds check can't be invalidated using an
-    ///   expression like `x[1][{x = y; 2}]`. We use fake borrows here to ensure
-    ///   that this is the case.
-    fn lower_index_expression(
-        &mut self,
-        mut block: BasicBlock,
-        base: ExprRef<'tcx>,
-        index: ExprRef<'tcx>,
-        mutability: Mutability,
-        fake_borrow_temps: Option<&mut Vec<Local>>,
-        temp_lifetime: Option<region::Scope>,
-        expr_span: Span,
-        source_info: SourceInfo,
-    ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        let lhs = self.hir.mirror(base);
-
-        let base_fake_borrow_temps = &mut Vec::new();
-        let is_outermost_index = fake_borrow_temps.is_none();
-        let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
-
-        let base_place =
-            unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),));
-
-        // Making this a *fresh* temporary means we do not have to worry about
-        // the index changing later: Nothing will ever change this temporary.
-        // The "retagging" transformation (for Stacked Borrows) relies on this.
-        let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,));
-
-        block = self.bounds_check(
-            block,
-            base_place.clone().into_place(self.hir.tcx()),
-            idx,
-            expr_span,
-            source_info,
-        );
-
-        if is_outermost_index {
-            self.read_fake_borrows(block, fake_borrow_temps, source_info)
-        } else {
-            self.add_fake_borrows_of_base(
-                &base_place,
-                block,
-                fake_borrow_temps,
-                expr_span,
-                source_info,
-            );
-        }
-
-        block.and(base_place.index(idx))
-    }
-
-    fn bounds_check(
-        &mut self,
-        block: BasicBlock,
-        slice: Place<'tcx>,
-        index: Local,
-        expr_span: Span,
-        source_info: SourceInfo,
-    ) -> BasicBlock {
-        let usize_ty = self.hir.usize_ty();
-        let bool_ty = self.hir.bool_ty();
-        // bounds check:
-        let len = self.temp(usize_ty, expr_span);
-        let lt = self.temp(bool_ty, expr_span);
-
-        // len = len(slice)
-        self.cfg.push_assign(block, source_info, &len, Rvalue::Len(slice));
-        // lt = idx < len
-        self.cfg.push_assign(
-            block,
-            source_info,
-            &lt,
-            Rvalue::BinaryOp(
-                BinOp::Lt,
-                Operand::Copy(Place::from(index)),
-                Operand::Copy(len.clone()),
-            ),
-        );
-        let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
-        // assert!(lt, "...")
-        self.assert(block, Operand::Move(lt), true, msg, expr_span)
-    }
-
-    fn add_fake_borrows_of_base(
-        &mut self,
-        base_place: &PlaceBuilder<'tcx>,
-        block: BasicBlock,
-        fake_borrow_temps: &mut Vec<Local>,
-        expr_span: Span,
-        source_info: SourceInfo,
-    ) {
-        let tcx = self.hir.tcx();
-        let place_ty =
-            Place::ty_from(&base_place.base, &base_place.projection, &self.local_decls, tcx);
-        if let ty::Slice(_) = place_ty.ty.kind {
-            // We need to create fake borrows to ensure that the bounds
-            // check that we just did stays valid. Since we can't assign to
-            // unsized values, we only need to ensure that none of the
-            // pointers in the base place are modified.
-            for (idx, elem) in base_place.projection.iter().enumerate().rev() {
-                match elem {
-                    ProjectionElem::Deref => {
-                        let fake_borrow_deref_ty = Place::ty_from(
-                            &base_place.base,
-                            &base_place.projection[..idx],
-                            &self.local_decls,
-                            tcx,
-                        )
-                        .ty;
-                        let fake_borrow_ty =
-                            tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
-                        let fake_borrow_temp =
-                            self.local_decls.push(LocalDecl::new_temp(fake_borrow_ty, expr_span));
-                        let projection = tcx.intern_place_elems(&base_place.projection[..idx]);
-                        self.cfg.push_assign(
-                            block,
-                            source_info,
-                            &fake_borrow_temp.into(),
-                            Rvalue::Ref(
-                                tcx.lifetimes.re_erased,
-                                BorrowKind::Shallow,
-                                Place { base: base_place.base.clone(), projection },
-                            ),
-                        );
-                        fake_borrow_temps.push(fake_borrow_temp);
-                    }
-                    ProjectionElem::Index(_) => {
-                        let index_ty = Place::ty_from(
-                            &base_place.base,
-                            &base_place.projection[..idx],
-                            &self.local_decls,
-                            tcx,
-                        );
-                        match index_ty.ty.kind {
-                            // The previous index expression has already
-                            // done any index expressions needed here.
-                            ty::Slice(_) => break,
-                            ty::Array(..) => (),
-                            _ => bug!("unexpected index base"),
-                        }
-                    }
-                    ProjectionElem::Field(..)
-                    | ProjectionElem::Downcast(..)
-                    | ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. } => (),
-                }
-            }
-        }
-    }
-
-    fn read_fake_borrows(
-        &mut self,
-        bb: BasicBlock,
-        fake_borrow_temps: &mut Vec<Local>,
-        source_info: SourceInfo,
-    ) {
-        // All indexes have been evaluated now, read all of the
-        // fake borrows so that they are live across those index
-        // expressions.
-        for temp in fake_borrow_temps {
-            self.cfg.push_fake_read(bb, source_info, FakeReadCause::ForIndex, Place::from(*temp));
-        }
-    }
-}
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
deleted file mode 100644 (file)
index 34b0cbf..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-//! See docs in `build/expr/mod.rs`.
-
-use rustc_index::vec::Idx;
-
-use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::hair::*;
-use rustc::middle::region;
-use rustc::mir::interpret::PanicInfo;
-use rustc::mir::*;
-use rustc::ty::{self, Ty, UpvarSubsts};
-use rustc_span::Span;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Returns an rvalue suitable for use until the end of the current
-    /// scope expression.
-    ///
-    /// The operand returned from this function will *not be valid* after
-    /// an ExprKind::Scope is passed, so please do *not* return it from
-    /// functions to avoid bad miscompiles.
-    pub fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let local_scope = self.local_scope();
-        self.as_rvalue(block, local_scope, expr)
-    }
-
-    /// Compile `expr`, yielding an rvalue.
-    fn as_rvalue<M>(
-        &mut self,
-        block: BasicBlock,
-        scope: Option<region::Scope>,
-        expr: M,
-    ) -> BlockAnd<Rvalue<'tcx>>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let expr = self.hir.mirror(expr);
-        self.expr_as_rvalue(block, scope, expr)
-    }
-
-    fn expr_as_rvalue(
-        &mut self,
-        mut block: BasicBlock,
-        scope: Option<region::Scope>,
-        expr: Expr<'tcx>,
-    ) -> BlockAnd<Rvalue<'tcx>> {
-        debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
-
-        let this = self;
-        let expr_span = expr.span;
-        let source_info = this.source_info(expr_span);
-
-        match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
-                let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
-            }
-            ExprKind::Repeat { value, count } => {
-                let value_operand = unpack!(block = this.as_operand(block, scope, value));
-                block.and(Rvalue::Repeat(value_operand, count))
-            }
-            ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, scope, lhs));
-                let rhs = unpack!(block = this.as_operand(block, scope, rhs));
-                this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
-            }
-            ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, scope, arg));
-                // Check for -MIN on signed integers
-                if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
-                    let bool_ty = this.hir.bool_ty();
-
-                    let minval = this.minval_literal(expr_span, expr.ty);
-                    let is_min = this.temp(bool_ty, expr_span);
-
-                    this.cfg.push_assign(
-                        block,
-                        source_info,
-                        &is_min,
-                        Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval),
-                    );
-
-                    block = this.assert(
-                        block,
-                        Operand::Move(is_min),
-                        false,
-                        PanicInfo::OverflowNeg,
-                        expr_span,
-                    );
-                }
-                block.and(Rvalue::UnaryOp(op, arg))
-            }
-            ExprKind::Box { value } => {
-                let value = this.hir.mirror(value);
-                // The `Box<T>` temporary created here is not a part of the HIR,
-                // and therefore is not considered during generator OIBIT
-                // determination. See the comment about `box` at `yield_in_scope`.
-                let result = this.local_decls.push(LocalDecl::new_internal(expr.ty, expr_span));
-                this.cfg.push(
-                    block,
-                    Statement { source_info, kind: StatementKind::StorageLive(result) },
-                );
-                if let Some(scope) = scope {
-                    // schedule a shallow free of that memory, lest we unwind:
-                    this.schedule_drop_storage_and_value(expr_span, scope, result);
-                }
-
-                // malloc some memory of suitable type (thus far, uninitialized):
-                let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
-                this.cfg.push_assign(block, source_info, &Place::from(result), box_);
-
-                // initialize the box contents:
-                unpack!(
-                    block = this.into(
-                        &this.hir.tcx().mk_place_deref(Place::from(result)),
-                        block,
-                        value
-                    )
-                );
-                block.and(Rvalue::Use(Operand::Move(Place::from(result))))
-            }
-            ExprKind::Cast { source } => {
-                let source = unpack!(block = this.as_operand(block, scope, source));
-                block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
-            }
-            ExprKind::Pointer { cast, source } => {
-                let source = unpack!(block = this.as_operand(block, scope, source));
-                block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
-            }
-            ExprKind::Array { fields } => {
-                // (*) We would (maybe) be closer to codegen if we
-                // handled this and other aggregate cases via
-                // `into()`, not `as_rvalue` -- in that case, instead
-                // of generating
-                //
-                //     let tmp1 = ...1;
-                //     let tmp2 = ...2;
-                //     dest = Rvalue::Aggregate(Foo, [tmp1, tmp2])
-                //
-                // we could just generate
-                //
-                //     dest.f = ...1;
-                //     dest.g = ...2;
-                //
-                // The problem is that then we would need to:
-                //
-                // (a) have a more complex mechanism for handling
-                //     partial cleanup;
-                // (b) distinguish the case where the type `Foo` has a
-                //     destructor, in which case creating an instance
-                //     as a whole "arms" the destructor, and you can't
-                //     write individual fields; and,
-                // (c) handle the case where the type Foo has no
-                //     fields. We don't want `let x: ();` to compile
-                //     to the same MIR as `let x = ();`.
-
-                // first process the set of fields
-                let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
-                let fields: Vec<_> = fields
-                    .into_iter()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
-                    .collect();
-
-                block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
-            }
-            ExprKind::Tuple { fields } => {
-                // see (*) above
-                // first process the set of fields
-                let fields: Vec<_> = fields
-                    .into_iter()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
-                    .collect();
-
-                block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
-            }
-            ExprKind::Closure { closure_id, substs, upvars, movability } => {
-                // see (*) above
-                let operands: Vec<_> = upvars
-                    .into_iter()
-                    .map(|upvar| {
-                        let upvar = this.hir.mirror(upvar);
-                        match Category::of(&upvar.kind) {
-                            // Use as_place to avoid creating a temporary when
-                            // moving a variable into a closure, so that
-                            // borrowck knows which variables to mark as being
-                            // used as mut. This is OK here because the upvar
-                            // expressions have no side effects and act on
-                            // disjoint places.
-                            // This occurs when capturing by copy/move, while
-                            // by reference captures use as_operand
-                            Some(Category::Place) => {
-                                let place = unpack!(block = this.as_place(block, upvar));
-                                this.consume_by_copy_or_move(place)
-                            }
-                            _ => {
-                                // Turn mutable borrow captures into unique
-                                // borrow captures when capturing an immutable
-                                // variable. This is sound because the mutation
-                                // that caused the capture will cause an error.
-                                match upvar.kind {
-                                    ExprKind::Borrow {
-                                        borrow_kind:
-                                            BorrowKind::Mut { allow_two_phase_borrow: false },
-                                        arg,
-                                    } => unpack!(
-                                        block = this.limit_capture_mutability(
-                                            upvar.span, upvar.ty, scope, block, arg,
-                                        )
-                                    ),
-                                    _ => unpack!(block = this.as_operand(block, scope, upvar)),
-                                }
-                            }
-                        }
-                    })
-                    .collect();
-                let result = match substs {
-                    UpvarSubsts::Generator(substs) => {
-                        // We implicitly set the discriminant to 0. See
-                        // librustc_mir/transform/deaggregator.rs for details.
-                        let movability = movability.unwrap();
-                        box AggregateKind::Generator(closure_id, substs, movability)
-                    }
-                    UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
-                };
-                block.and(Rvalue::Aggregate(result, operands))
-            }
-            ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
-                block = unpack!(this.stmt_expr(block, expr, None));
-                block.and(this.unit_rvalue())
-            }
-            ExprKind::Yield { value } => {
-                let value = unpack!(block = this.as_operand(block, scope, value));
-                let resume = this.cfg.start_new_block();
-                let cleanup = this.generator_drop_cleanup();
-                this.cfg.terminate(
-                    block,
-                    source_info,
-                    TerminatorKind::Yield { value: value, resume: resume, drop: cleanup },
-                );
-                resume.and(this.unit_rvalue())
-            }
-            ExprKind::Literal { .. }
-            | ExprKind::StaticRef { .. }
-            | ExprKind::Block { .. }
-            | ExprKind::Match { .. }
-            | ExprKind::NeverToAny { .. }
-            | ExprKind::Use { .. }
-            | ExprKind::Borrow { .. }
-            | ExprKind::AddressOf { .. }
-            | ExprKind::Adt { .. }
-            | ExprKind::Loop { .. }
-            | ExprKind::LogicalOp { .. }
-            | ExprKind::Call { .. }
-            | ExprKind::Field { .. }
-            | ExprKind::Deref { .. }
-            | ExprKind::Index { .. }
-            | ExprKind::VarRef { .. }
-            | ExprKind::SelfRef
-            | ExprKind::Break { .. }
-            | ExprKind::Continue { .. }
-            | ExprKind::Return { .. }
-            | ExprKind::InlineAsm { .. }
-            | ExprKind::PlaceTypeAscription { .. }
-            | ExprKind::ValueTypeAscription { .. } => {
-                // these do not have corresponding `Rvalue` variants,
-                // so make an operand and then return that
-                debug_assert!(match Category::of(&expr.kind) {
-                    Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
-                    _ => true,
-                });
-                let operand = unpack!(block = this.as_operand(block, scope, expr));
-                block.and(Rvalue::Use(operand))
-            }
-        }
-    }
-
-    pub fn build_binary_op(
-        &mut self,
-        mut block: BasicBlock,
-        op: BinOp,
-        span: Span,
-        ty: Ty<'tcx>,
-        lhs: Operand<'tcx>,
-        rhs: Operand<'tcx>,
-    ) -> BlockAnd<Rvalue<'tcx>> {
-        let source_info = self.source_info(span);
-        let bool_ty = self.hir.bool_ty();
-        if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
-            let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
-            let result_value = self.temp(result_tup, span);
-
-            self.cfg.push_assign(
-                block,
-                source_info,
-                &result_value,
-                Rvalue::CheckedBinaryOp(op, lhs, rhs),
-            );
-            let val_fld = Field::new(0);
-            let of_fld = Field::new(1);
-
-            let tcx = self.hir.tcx();
-            let val = tcx.mk_place_field(result_value.clone(), val_fld, ty);
-            let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
-
-            let err = PanicInfo::Overflow(op);
-
-            block = self.assert(block, Operand::Move(of), false, err, span);
-
-            block.and(Rvalue::Use(Operand::Move(val)))
-        } else {
-            if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
-                // Checking division and remainder is more complex, since we 1. always check
-                // and 2. there are two possible failure cases, divide-by-zero and overflow.
-
-                let zero_err = if op == BinOp::Div {
-                    PanicInfo::DivisionByZero
-                } else {
-                    PanicInfo::RemainderByZero
-                };
-                let overflow_err = PanicInfo::Overflow(op);
-
-                // Check for / 0
-                let is_zero = self.temp(bool_ty, span);
-                let zero = self.zero_literal(span, ty);
-                self.cfg.push_assign(
-                    block,
-                    source_info,
-                    &is_zero,
-                    Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero),
-                );
-
-                block = self.assert(block, Operand::Move(is_zero), false, zero_err, span);
-
-                // We only need to check for the overflow in one case:
-                // MIN / -1, and only for signed values.
-                if ty.is_signed() {
-                    let neg_1 = self.neg_1_literal(span, ty);
-                    let min = self.minval_literal(span, ty);
-
-                    let is_neg_1 = self.temp(bool_ty, span);
-                    let is_min = self.temp(bool_ty, span);
-                    let of = self.temp(bool_ty, span);
-
-                    // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
-
-                    self.cfg.push_assign(
-                        block,
-                        source_info,
-                        &is_neg_1,
-                        Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1),
-                    );
-                    self.cfg.push_assign(
-                        block,
-                        source_info,
-                        &is_min,
-                        Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min),
-                    );
-
-                    let is_neg_1 = Operand::Move(is_neg_1);
-                    let is_min = Operand::Move(is_min);
-                    self.cfg.push_assign(
-                        block,
-                        source_info,
-                        &of,
-                        Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min),
-                    );
-
-                    block = self.assert(block, Operand::Move(of), false, overflow_err, span);
-                }
-            }
-
-            block.and(Rvalue::BinaryOp(op, lhs, rhs))
-        }
-    }
-
-    fn limit_capture_mutability(
-        &mut self,
-        upvar_span: Span,
-        upvar_ty: Ty<'tcx>,
-        temp_lifetime: Option<region::Scope>,
-        mut block: BasicBlock,
-        arg: ExprRef<'tcx>,
-    ) -> BlockAnd<Operand<'tcx>> {
-        let this = self;
-
-        let source_info = this.source_info(upvar_span);
-        let temp = this.local_decls.push(LocalDecl::new_temp(upvar_ty, upvar_span));
-
-        this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
-
-        let arg_place = unpack!(block = this.as_place(block, arg));
-
-        let mutability = match arg_place.as_ref() {
-            PlaceRef { base: &PlaceBase::Local(local), projection: &[] } => {
-                this.local_decls[local].mutability
-            }
-            PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => {
-                debug_assert!(
-                    this.local_decls[local].is_ref_for_guard(),
-                    "Unexpected capture place",
-                );
-                this.local_decls[local].mutability
-            }
-            PlaceRef {
-                ref base,
-                projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
-            }
-            | PlaceRef {
-                ref base,
-                projection:
-                    &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref],
-            } => {
-                let place = PlaceRef { base, projection: proj_base };
-
-                // Not projected from the implicit `self` in a closure.
-                debug_assert!(
-                    match place.local_or_deref_local() {
-                        Some(local) => local == Local::new(1),
-                        None => false,
-                    },
-                    "Unexpected capture place"
-                );
-                // Not in a closure
-                debug_assert!(
-                    this.upvar_mutbls.len() > upvar_index.index(),
-                    "Unexpected capture place"
-                );
-                this.upvar_mutbls[upvar_index.index()]
-            }
-            _ => bug!("Unexpected capture place"),
-        };
-
-        let borrow_kind = match mutability {
-            Mutability::Not => BorrowKind::Unique,
-            Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
-        };
-
-        this.cfg.push_assign(
-            block,
-            source_info,
-            &Place::from(temp),
-            Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
-        );
-
-        // In constants, temp_lifetime is None. We should not need to drop
-        // anything because no values with a destructor can be created in
-        // a constant at this time, even if the type may need dropping.
-        if let Some(temp_lifetime) = temp_lifetime {
-            this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp);
-        }
-
-        block.and(Operand::Move(Place::from(temp)))
-    }
-
-    // Helper to get a `-1` value of the appropriate type
-    fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let param_ty = ty::ParamEnv::empty().and(ty);
-        let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
-        let n = (!0u128) >> (128 - bits);
-        let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
-
-        self.literal_operand(span, literal)
-    }
-
-    // Helper to get the minimum value of the appropriate type
-    fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        assert!(ty.is_signed());
-        let param_ty = ty::ParamEnv::empty().and(ty);
-        let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
-        let n = 1 << (bits - 1);
-        let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
-
-        self.literal_operand(span, literal)
-    }
-}
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
deleted file mode 100644 (file)
index 3f71104..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-//! See docs in build/expr/mod.rs
-
-use crate::build::scope::DropKind;
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::hair::*;
-use rustc::middle::region;
-use rustc::mir::*;
-use rustc_hir as hir;
-use rustc_span::symbol::sym;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Compile `expr` into a fresh temporary. This is used when building
-    /// up rvalues so as to freeze the value that will be consumed.
-    pub fn as_temp<M>(
-        &mut self,
-        block: BasicBlock,
-        temp_lifetime: Option<region::Scope>,
-        expr: M,
-        mutability: Mutability,
-    ) -> BlockAnd<Local>
-    where
-        M: Mirror<'tcx, Output = Expr<'tcx>>,
-    {
-        let expr = self.hir.mirror(expr);
-        self.expr_as_temp(block, temp_lifetime, expr, mutability)
-    }
-
-    fn expr_as_temp(
-        &mut self,
-        mut block: BasicBlock,
-        temp_lifetime: Option<region::Scope>,
-        expr: Expr<'tcx>,
-        mutability: Mutability,
-    ) -> BlockAnd<Local> {
-        debug!(
-            "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
-            block, temp_lifetime, expr, mutability
-        );
-        let this = self;
-
-        let expr_span = expr.span;
-        let source_info = this.source_info(expr_span);
-        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
-            return this.in_scope((region_scope, source_info), lint_level, |this| {
-                this.as_temp(block, temp_lifetime, value, mutability)
-            });
-        }
-
-        let expr_ty = expr.ty;
-        let temp = {
-            let mut local_decl = LocalDecl::new_temp(expr_ty, expr_span);
-            if mutability == Mutability::Not {
-                local_decl = local_decl.immutable();
-            }
-
-            debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
-            // Find out whether this temp is being created within the
-            // tail expression of a block whose result is ignored.
-            if let Some(tail_info) = this.block_context.currently_in_block_tail() {
-                local_decl = local_decl.block_tail(tail_info);
-            }
-            if let ExprKind::StaticRef { def_id, .. } = expr.kind {
-                let is_thread_local = this.hir.tcx().has_attr(def_id, sym::thread_local);
-                local_decl.local_info = LocalInfo::StaticRef { def_id, is_thread_local };
-            }
-            this.local_decls.push(local_decl)
-        };
-        let temp_place = &Place::from(temp);
-
-        match expr.kind {
-            // Don't bother with StorageLive and Dead for these temporaries,
-            // they are never assigned.
-            ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
-            ExprKind::Block { body: hir::Block { expr: None, targeted_by_break: false, .. } }
-                if expr_ty.is_never() =>
-            {
-                ()
-            }
-            _ => {
-                this.cfg
-                    .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
-
-                // In constants, `temp_lifetime` is `None` for temporaries that
-                // live for the `'static` lifetime. Thus we do not drop these
-                // temporaries and simply leak them.
-                // This is equivalent to what `let x = &foo();` does in
-                // functions. The temporary is lifted to their surrounding
-                // scope. In a function that means the temporary lives until
-                // just before the function returns. In constants that means it
-                // outlives the constant's initialization value computation.
-                // Anything outliving a constant must have the `'static`
-                // lifetime and live forever.
-                // Anything with a shorter lifetime (e.g the `&foo()` in
-                // `bar(&foo())` or anything within a block will keep the
-                // regular drops just like runtime code.
-                if let Some(temp_lifetime) = temp_lifetime {
-                    this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage);
-                }
-            }
-        }
-
-        unpack!(block = this.into(temp_place, block, expr));
-
-        if let Some(temp_lifetime) = temp_lifetime {
-            this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
-        }
-
-        block.and(temp)
-    }
-}
diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs
deleted file mode 100644 (file)
index b35616c..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-use crate::hair::*;
-
-#[derive(Debug, PartialEq)]
-pub enum Category {
-    // An assignable memory location like `x`, `x.f`, `foo()[3]`, that
-    // sort of thing. Something that could appear on the LHS of an `=`
-    // sign.
-    Place,
-
-    // A literal like `23` or `"foo"`. Does not include constant
-    // expressions like `3 + 5`.
-    Constant,
-
-    // Something that generates a new value at runtime, like `x + y`
-    // or `foo()`.
-    Rvalue(RvalueFunc),
-}
-
-// Rvalues fall into different "styles" that will determine which fn
-// is best suited to generate them.
-#[derive(Debug, PartialEq)]
-pub enum RvalueFunc {
-    // Best generated by `into`. This is generally exprs that
-    // cause branching, like `match`, but also includes calls.
-    Into,
-
-    // Best generated by `as_rvalue`. This is usually the case.
-    AsRvalue,
-}
-
-/// Determines the category for a given expression. Note that scope
-/// and paren expressions have no category.
-impl Category {
-    pub fn of(ek: &ExprKind<'_>) -> Option<Category> {
-        match *ek {
-            ExprKind::Scope { .. } => None,
-
-            ExprKind::Field { .. }
-            | ExprKind::Deref { .. }
-            | ExprKind::Index { .. }
-            | ExprKind::SelfRef
-            | ExprKind::VarRef { .. }
-            | ExprKind::PlaceTypeAscription { .. }
-            | ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
-
-            ExprKind::LogicalOp { .. }
-            | ExprKind::Match { .. }
-            | ExprKind::NeverToAny { .. }
-            | ExprKind::Use { .. }
-            | ExprKind::Adt { .. }
-            | ExprKind::Borrow { .. }
-            | ExprKind::AddressOf { .. }
-            | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
-
-            ExprKind::Array { .. }
-            | ExprKind::Tuple { .. }
-            | ExprKind::Closure { .. }
-            | ExprKind::Unary { .. }
-            | ExprKind::Binary { .. }
-            | ExprKind::Box { .. }
-            | ExprKind::Cast { .. }
-            | ExprKind::Pointer { .. }
-            | ExprKind::Repeat { .. }
-            | ExprKind::Assign { .. }
-            | ExprKind::AssignOp { .. }
-            | ExprKind::Yield { .. }
-            | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
-
-            ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => Some(Category::Constant),
-
-            ExprKind::Loop { .. }
-            | ExprKind::Block { .. }
-            | ExprKind::Break { .. }
-            | ExprKind::Continue { .. }
-            | ExprKind::Return { .. } =>
-            // FIXME(#27840) these probably want their own
-            // category, like "nonterminating"
-            {
-                Some(Category::Rvalue(RvalueFunc::Into))
-            }
-        }
-    }
-}
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
deleted file mode 100644 (file)
index 2cf2b21..0000000
+++ /dev/null
@@ -1,406 +0,0 @@
-//! See docs in build/expr/mod.rs
-
-use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::hair::*;
-use rustc::mir::*;
-use rustc::ty::{self, CanonicalUserTypeAnnotation};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
-use rustc_span::symbol::sym;
-
-use rustc_target::spec::abi::Abi;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Compile `expr`, storing the result into `destination`, which
-    /// is assumed to be uninitialized.
-    pub fn into_expr(
-        &mut self,
-        destination: &Place<'tcx>,
-        mut block: BasicBlock,
-        expr: Expr<'tcx>,
-    ) -> BlockAnd<()> {
-        debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
-
-        // since we frequently have to reference `self` from within a
-        // closure, where `self` would be shadowed, it's easier to
-        // just use the name `this` uniformly
-        let this = self;
-        let expr_span = expr.span;
-        let source_info = this.source_info(expr_span);
-
-        let expr_is_block_or_scope = match expr.kind {
-            ExprKind::Block { .. } => true,
-            ExprKind::Scope { .. } => true,
-            _ => false,
-        };
-
-        if !expr_is_block_or_scope {
-            this.block_context.push(BlockFrame::SubExpr);
-        }
-
-        let block_and = match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
-                let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, |this| this.into(destination, block, value))
-            }
-            ExprKind::Block { body: ast_block } => {
-                this.ast_block(destination, block, ast_block, source_info)
-            }
-            ExprKind::Match { scrutinee, arms } => {
-                this.match_expr(destination, expr_span, block, scrutinee, arms)
-            }
-            ExprKind::NeverToAny { source } => {
-                let source = this.hir.mirror(source);
-                let is_call = match source.kind {
-                    ExprKind::Call { .. } => true,
-                    _ => false,
-                };
-
-                // (#66975) Source could be a const of type `!`, so has to
-                // exist in the generated MIR.
-                unpack!(block = this.as_temp(block, this.local_scope(), source, Mutability::Mut,));
-
-                // This is an optimization. If the expression was a call then we already have an
-                // unreachable block. Don't bother to terminate it and create a new one.
-                if is_call {
-                    block.unit()
-                } else {
-                    this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
-                    let end_block = this.cfg.start_new_block();
-                    end_block.unit()
-                }
-            }
-            ExprKind::LogicalOp { op, lhs, rhs } => {
-                // And:
-                //
-                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
-                //        |                          | (false)
-                //        +----------false-----------+------------------> [false_block]
-                //
-                // Or:
-                //
-                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
-                //        | (true)                   | (false)
-                //  [true_block]               [false_block]
-
-                let (true_block, false_block, mut else_block, join_block) = (
-                    this.cfg.start_new_block(),
-                    this.cfg.start_new_block(),
-                    this.cfg.start_new_block(),
-                    this.cfg.start_new_block(),
-                );
-
-                let lhs = unpack!(block = this.as_local_operand(block, lhs));
-                let blocks = match op {
-                    LogicalOp::And => (else_block, false_block),
-                    LogicalOp::Or => (true_block, else_block),
-                };
-                let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
-                this.cfg.terminate(block, source_info, term);
-
-                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
-                let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
-                this.cfg.terminate(else_block, source_info, term);
-
-                this.cfg.push_assign_constant(
-                    true_block,
-                    source_info,
-                    destination,
-                    Constant { span: expr_span, user_ty: None, literal: this.hir.true_literal() },
-                );
-
-                this.cfg.push_assign_constant(
-                    false_block,
-                    source_info,
-                    destination,
-                    Constant { span: expr_span, user_ty: None, literal: this.hir.false_literal() },
-                );
-
-                // Link up both branches:
-                this.cfg.goto(true_block, source_info, join_block);
-                this.cfg.goto(false_block, source_info, join_block);
-                join_block.unit()
-            }
-            ExprKind::Loop { body } => {
-                // [block]
-                //    |
-                //   [loop_block] -> [body_block] -/eval. body/-> [body_block_end]
-                //    |        ^                                         |
-                // false link  |                                         |
-                //    |        +-----------------------------------------+
-                //    +-> [diverge_cleanup]
-                // The false link is required to make sure borrowck considers unwinds through the
-                // body, even when the exact code in the body cannot unwind
-
-                let loop_block = this.cfg.start_new_block();
-                let exit_block = this.cfg.start_new_block();
-
-                // Start the loop.
-                this.cfg.goto(block, source_info, loop_block);
-
-                this.in_breakable_scope(
-                    Some(loop_block),
-                    exit_block,
-                    destination.clone(),
-                    move |this| {
-                        // conduct the test, if necessary
-                        let body_block = this.cfg.start_new_block();
-                        let diverge_cleanup = this.diverge_cleanup();
-                        this.cfg.terminate(
-                            loop_block,
-                            source_info,
-                            TerminatorKind::FalseUnwind {
-                                real_target: body_block,
-                                unwind: Some(diverge_cleanup),
-                            },
-                        );
-
-                        // The “return” value of the loop body must always be an unit. We therefore
-                        // introduce a unit temporary as the destination for the loop body.
-                        let tmp = this.get_unit_temp();
-                        // Execute the body, branching back to the test.
-                        let body_block_end = unpack!(this.into(&tmp, body_block, body));
-                        this.cfg.goto(body_block_end, source_info, loop_block);
-                    },
-                );
-                exit_block.unit()
-            }
-            ExprKind::Call { ty, fun, args, from_hir_call } => {
-                let intrinsic = match ty.kind {
-                    ty::FnDef(def_id, _) => {
-                        let f = ty.fn_sig(this.hir.tcx());
-                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
-                            Some(this.hir.tcx().item_name(def_id))
-                        } else {
-                            None
-                        }
-                    }
-                    _ => None,
-                };
-                let fun = unpack!(block = this.as_local_operand(block, fun));
-                if let Some(sym::move_val_init) = intrinsic {
-                    // `move_val_init` has "magic" semantics - the second argument is
-                    // always evaluated "directly" into the first one.
-
-                    let mut args = args.into_iter();
-                    let ptr = args.next().expect("0 arguments to `move_val_init`");
-                    let val = args.next().expect("1 argument to `move_val_init`");
-                    assert!(args.next().is_none(), ">2 arguments to `move_val_init`");
-
-                    let ptr = this.hir.mirror(ptr);
-                    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 {
-                        mutability: Mutability::Mut,
-                        ty: ptr_ty,
-                        user_ty: UserTypeProjections::none(),
-                        source_info,
-                        internal: true,
-                        local_info: LocalInfo::Other,
-                        is_block_tail: None,
-                    });
-                    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)
-                } else {
-                    let args: Vec<_> = args
-                        .into_iter()
-                        .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
-                        .collect();
-
-                    let success = this.cfg.start_new_block();
-                    let cleanup = this.diverge_cleanup();
-
-                    this.record_operands_moved(&args);
-
-                    this.cfg.terminate(
-                        block,
-                        source_info,
-                        TerminatorKind::Call {
-                            func: fun,
-                            args,
-                            cleanup: Some(cleanup),
-                            // FIXME(varkor): replace this with an uninhabitedness-based check.
-                            // This requires getting access to the current module to call
-                            // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
-                            destination: if expr.ty.is_never() {
-                                None
-                            } else {
-                                Some((destination.clone(), success))
-                            },
-                            from_hir_call,
-                        },
-                    );
-                    success.unit()
-                }
-            }
-            ExprKind::Use { source } => this.into(destination, block, source),
-            ExprKind::Borrow { arg, borrow_kind } => {
-                // We don't do this in `as_rvalue` because we use `as_place`
-                // for borrow expressions, so we cannot create an `RValue` that
-                // remains valid across user code. `as_rvalue` is usually called
-                // by this method anyway, so this shouldn't cause too many
-                // unnecessary temporaries.
-                let arg_place = match borrow_kind {
-                    BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
-                    _ => unpack!(block = this.as_place(block, arg)),
-                };
-                let borrow =
-                    Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place);
-                this.cfg.push_assign(block, source_info, destination, borrow);
-                block.unit()
-            }
-            ExprKind::AddressOf { mutability, arg } => {
-                let place = match mutability {
-                    hir::Mutability::Not => this.as_read_only_place(block, arg),
-                    hir::Mutability::Mut => this.as_place(block, arg),
-                };
-                let address_of = Rvalue::AddressOf(mutability, unpack!(block = place));
-                this.cfg.push_assign(block, source_info, destination, address_of);
-                block.unit()
-            }
-            ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, base } => {
-                // See the notes for `ExprKind::Array` in `as_rvalue` and for
-                // `ExprKind::Borrow` above.
-                let is_union = adt_def.is_union();
-                let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
-
-                let scope = this.local_scope();
-
-                // first process the set of fields that were provided
-                // (evaluating them in order given by user)
-                let fields_map: FxHashMap<_, _> = fields
-                    .into_iter()
-                    .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
-                    .collect();
-
-                let field_names = this.hir.all_fields(adt_def, variant_index);
-
-                let fields =
-                    if let Some(FruInfo { base, field_types }) = base {
-                        let base = unpack!(block = this.as_place(block, base));
-
-                        // MIR does not natively support FRU, so for each
-                        // base-supplied field, generate an operand that
-                        // reads it from the base.
-                        field_names
-                            .into_iter()
-                            .zip(field_types.into_iter())
-                            .map(|(n, ty)| match fields_map.get(&n) {
-                                Some(v) => v.clone(),
-                                None => this.consume_by_copy_or_move(
-                                    this.hir.tcx().mk_place_field(base.clone(), n, ty),
-                                ),
-                            })
-                            .collect()
-                    } else {
-                        field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
-                    };
-
-                let inferred_ty = expr.ty;
-                let user_ty = user_ty.map(|ty| {
-                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
-                        span: source_info.span,
-                        user_ty: ty,
-                        inferred_ty,
-                    })
-                });
-                let adt = box AggregateKind::Adt(
-                    adt_def,
-                    variant_index,
-                    substs,
-                    user_ty,
-                    active_field_index,
-                );
-                this.cfg.push_assign(
-                    block,
-                    source_info,
-                    destination,
-                    Rvalue::Aggregate(adt, fields),
-                );
-                block.unit()
-            }
-
-            // These cases don't actually need a destination
-            ExprKind::Assign { .. }
-            | ExprKind::AssignOp { .. }
-            | ExprKind::Continue { .. }
-            | ExprKind::Break { .. }
-            | ExprKind::InlineAsm { .. }
-            | ExprKind::Return { .. } => {
-                unpack!(block = this.stmt_expr(block, expr, None));
-                this.cfg.push_assign_unit(block, source_info, destination);
-                block.unit()
-            }
-
-            // Avoid creating a temporary
-            ExprKind::VarRef { .. }
-            | ExprKind::SelfRef
-            | ExprKind::PlaceTypeAscription { .. }
-            | ExprKind::ValueTypeAscription { .. } => {
-                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
-
-                let place = unpack!(block = this.as_place(block, expr));
-                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
-                this.cfg.push_assign(block, source_info, destination, rvalue);
-                block.unit()
-            }
-            ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
-                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
-
-                // Create a "fake" temporary variable so that we check that the
-                // value is Sized. Usually, this is caught in type checking, but
-                // in the case of box expr there is no such check.
-                if !destination.projection.is_empty() {
-                    this.local_decls.push(LocalDecl::new_temp(expr.ty, expr.span));
-                }
-
-                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
-
-                let place = unpack!(block = this.as_place(block, expr));
-                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
-                this.cfg.push_assign(block, source_info, destination, rvalue);
-                block.unit()
-            }
-
-            // these are the cases that are more naturally handled by some other mode
-            ExprKind::Unary { .. }
-            | ExprKind::Binary { .. }
-            | ExprKind::Box { .. }
-            | ExprKind::Cast { .. }
-            | ExprKind::Pointer { .. }
-            | ExprKind::Repeat { .. }
-            | ExprKind::Array { .. }
-            | ExprKind::Tuple { .. }
-            | ExprKind::Closure { .. }
-            | ExprKind::Literal { .. }
-            | ExprKind::StaticRef { .. }
-            | ExprKind::Yield { .. } => {
-                debug_assert!(match Category::of(&expr.kind).unwrap() {
-                    // should be handled above
-                    Category::Rvalue(RvalueFunc::Into) => false,
-
-                    // must be handled above or else we get an
-                    // infinite loop in the builder; see
-                    // e.g., `ExprKind::VarRef` above
-                    Category::Place => false,
-
-                    _ => true,
-                });
-
-                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
-                this.cfg.push_assign(block, source_info, destination, rvalue);
-                block.unit()
-            }
-        };
-
-        if !expr_is_block_or_scope {
-            let popped = this.block_context.pop();
-            assert!(popped.is_some());
-        }
-
-        block_and
-    }
-}
diff --git a/src/librustc_mir/build/expr/mod.rs b/src/librustc_mir/build/expr/mod.rs
deleted file mode 100644 (file)
index ac8c7e7..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-//! Builds MIR from expressions. As a caller into this module, you
-//! have many options, but the first thing you have to decide is
-//! whether you are evaluating this expression for its *value*, its
-//! *location*, or as a *constant*.
-//!
-//! Typically, you want the value: e.g., if you are doing `expr_a +
-//! expr_b`, you want the values of those expressions. In that case,
-//! you want one of the following functions. Note that if the expr has
-//! a type that is not `Copy`, then using any of these functions will
-//! "move" the value out of its current home (if any).
-//!
-//! - `into` -- writes the value into a specific location, which
-//!   should be uninitialized
-//! - `as_operand` -- evaluates the value and yields an `Operand`,
-//!   suitable for use as an argument to an `Rvalue`
-//! - `as_temp` -- evaluates into a temporary; this is similar to `as_operand`
-//!   except it always returns a fresh place, even for constants
-//! - `as_rvalue` -- yields an `Rvalue`, suitable for use in an assignment;
-//!   as of this writing, never needed outside of the `expr` module itself
-//!
-//! Sometimes though want the expression's *location*. An example
-//! would be during a match statement, or the operand of the `&`
-//! operator. In that case, you want `as_place`. This will create a
-//! temporary if necessary.
-//!
-//! Finally, if it's a constant you seek, then call
-//! `as_constant`. This creates a `Constant<H>`, but naturally it can
-//! only be used on constant expressions and hence is needed only in
-//! very limited contexts.
-//!
-//! ### Implementation notes
-//!
-//! For any given kind of expression, there is generally one way that
-//! can be lowered most naturally. This is specified by the
-//! `Category::of` function in the `category` module. For example, a
-//! struct expression (or other expression that creates a new value)
-//! is typically easiest to write in terms of `as_rvalue` or `into`,
-//! whereas a reference to a field is easiest to write in terms of
-//! `as_place`. (The exception to this is scope and paren
-//! expressions, which have no category.)
-//!
-//! Therefore, the various functions above make use of one another in
-//! a descending fashion. For any given expression, you should pick
-//! the most suitable spot to implement it, and then just let the
-//! other fns cycle around. The handoff works like this:
-//!
-//! - `into(place)` -> fallback is to create a rvalue with `as_rvalue` and assign it to `place`
-//! - `as_rvalue` -> fallback is to create an Operand with `as_operand` and use `Rvalue::use`
-//! - `as_operand` -> either invokes `as_constant` or `as_temp`
-//! - `as_constant` -> (no fallback)
-//! - `as_temp` -> creates a temporary and either calls `as_place` or `into`
-//! - `as_place` -> for rvalues, falls back to `as_temp` and returns that
-//!
-//! As you can see, there is a cycle where `into` can (in theory) fallback to `as_temp`
-//! which can fallback to `into`. So if one of the `ExprKind` variants is not, in fact,
-//! implemented in the category where it is supposed to be, there will be a problem.
-//!
-//! Of those fallbacks, the most interesting one is `into`, because
-//! it discriminates based on the category of the expression. This is
-//! basically the point where the "by value" operations are bridged
-//! over to the "by reference" mode (`as_place`).
-
-mod as_constant;
-mod as_operand;
-mod as_place;
-mod as_rvalue;
-mod as_temp;
-mod category;
-mod into;
-mod stmt;
diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs
deleted file mode 100644 (file)
index ff70492..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-use crate::build::scope::BreakableTarget;
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::hair::*;
-use rustc::middle::region;
-use rustc::mir::*;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Builds a block of MIR statements to evaluate the HAIR `expr`.
-    /// If the original expression was an AST statement,
-    /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the
-    /// span of that statement (including its semicolon, if any).
-    /// The scope is used if a statement temporary must be dropped.
-    pub fn stmt_expr(
-        &mut self,
-        mut block: BasicBlock,
-        expr: Expr<'tcx>,
-        statement_scope: Option<region::Scope>,
-    ) -> BlockAnd<()> {
-        let this = self;
-        let expr_span = expr.span;
-        let source_info = this.source_info(expr.span);
-        // Handle a number of expressions that don't need a destination at all. This
-        // avoids needing a mountain of temporary `()` variables.
-        let expr2 = expr.clone();
-        match expr.kind {
-            ExprKind::Scope { region_scope, lint_level, value } => {
-                let value = this.hir.mirror(value);
-                this.in_scope((region_scope, source_info), lint_level, |this| {
-                    this.stmt_expr(block, value, statement_scope)
-                })
-            }
-            ExprKind::Assign { lhs, rhs } => {
-                let lhs = this.hir.mirror(lhs);
-                let rhs = this.hir.mirror(rhs);
-                let lhs_span = lhs.span;
-
-                // Note: we evaluate assignments right-to-left. This
-                // is better for borrowck interaction with overloaded
-                // operators like x[j] = x[i].
-
-                debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr2);
-                this.block_context.push(BlockFrame::SubExpr);
-
-                // Generate better code for things that don't need to be
-                // dropped.
-                if this.hir.needs_drop(lhs.ty) {
-                    let rhs = unpack!(block = this.as_local_operand(block, rhs));
-                    let lhs = unpack!(block = this.as_place(block, lhs));
-                    unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
-                } else {
-                    let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
-                    let lhs = unpack!(block = this.as_place(block, lhs));
-                    this.cfg.push_assign(block, source_info, &lhs, rhs);
-                }
-
-                this.block_context.pop();
-                block.unit()
-            }
-            ExprKind::AssignOp { op, lhs, rhs } => {
-                // FIXME(#28160) there is an interesting semantics
-                // question raised here -- should we "freeze" the
-                // value of the lhs here?  I'm inclined to think not,
-                // since it seems closer to the semantics of the
-                // overloaded version, which takes `&mut self`.  This
-                // only affects weird things like `x += {x += 1; x}`
-                // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
-
-                let lhs = this.hir.mirror(lhs);
-                let lhs_ty = lhs.ty;
-
-                debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2);
-                this.block_context.push(BlockFrame::SubExpr);
-
-                // As above, RTL.
-                let rhs = unpack!(block = this.as_local_operand(block, rhs));
-                let lhs = unpack!(block = this.as_place(block, lhs));
-
-                // we don't have to drop prior contents or anything
-                // because AssignOp is only legal for Copy types
-                // (overloaded ops should be desugared into a call).
-                let result = unpack!(
-                    block = this.build_binary_op(
-                        block,
-                        op,
-                        expr_span,
-                        lhs_ty,
-                        Operand::Copy(lhs.clone()),
-                        rhs
-                    )
-                );
-                this.cfg.push_assign(block, source_info, &lhs, result);
-
-                this.block_context.pop();
-                block.unit()
-            }
-            ExprKind::Continue { label } => {
-                this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
-            }
-            ExprKind::Break { label, value } => {
-                this.break_scope(block, value, BreakableTarget::Break(label), source_info)
-            }
-            ExprKind::Return { value } => {
-                this.break_scope(block, value, BreakableTarget::Return, source_info)
-            }
-            ExprKind::InlineAsm { asm, outputs, inputs } => {
-                debug!("stmt_expr InlineAsm block_context.push(SubExpr) : {:?}", expr2);
-                this.block_context.push(BlockFrame::SubExpr);
-                let outputs = outputs
-                    .into_iter()
-                    .map(|output| unpack!(block = this.as_place(block, output)))
-                    .collect::<Vec<_>>()
-                    .into_boxed_slice();
-                let inputs = inputs
-                    .into_iter()
-                    .map(|input| {
-                        (input.span(), unpack!(block = this.as_local_operand(block, input)))
-                    })
-                    .collect::<Vec<_>>()
-                    .into_boxed_slice();
-                this.cfg.push(
-                    block,
-                    Statement {
-                        source_info,
-                        kind: StatementKind::InlineAsm(box InlineAsm {
-                            asm: asm.clone(),
-                            outputs,
-                            inputs,
-                        }),
-                    },
-                );
-                this.block_context.pop();
-                block.unit()
-            }
-            _ => {
-                assert!(
-                    statement_scope.is_some(),
-                    "Should not be calling `stmt_expr` on a general expression \
-                     without a statement scope",
-                );
-
-                // Issue #54382: When creating temp for the value of
-                // expression like:
-                //
-                // `{ side_effects(); { let l = stuff(); the_value } }`
-                //
-                // it is usually better to focus on `the_value` rather
-                // than the entirety of block(s) surrounding it.
-                let adjusted_span = (|| {
-                    if let ExprKind::Block { body } = expr.kind {
-                        if let Some(tail_expr) = &body.expr {
-                            let mut expr = tail_expr;
-                            while let rustc_hir::ExprKind::Block(subblock, _label) = &expr.kind {
-                                if let Some(subtail_expr) = &subblock.expr {
-                                    expr = subtail_expr
-                                } else {
-                                    break;
-                                }
-                            }
-                            this.block_context
-                                .push(BlockFrame::TailExpr { tail_result_is_ignored: true });
-                            return Some(expr.span);
-                        }
-                    }
-                    None
-                })();
-
-                let temp =
-                    unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not));
-
-                if let Some(span) = adjusted_span {
-                    this.local_decls[temp].source_info.span = span;
-                    this.block_context.pop();
-                }
-
-                block.unit()
-            }
-        }
-    }
-}
diff --git a/src/librustc_mir/build/into.rs b/src/librustc_mir/build/into.rs
deleted file mode 100644 (file)
index 9c3ea5f..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-//! In general, there are a number of things for which it's convenient
-//! to just call `builder.into` and have it emit its result into a
-//! given location. This is basically for expressions or things that can be
-//! wrapped up as expressions (e.g., blocks). To make this ergonomic, we use this
-//! latter `EvalInto` trait.
-
-use crate::build::{BlockAnd, Builder};
-use crate::hair::*;
-use rustc::mir::*;
-
-pub(in crate::build) trait EvalInto<'tcx> {
-    fn eval_into(
-        self,
-        builder: &mut Builder<'_, 'tcx>,
-        destination: &Place<'tcx>,
-        block: BasicBlock,
-    ) -> BlockAnd<()>;
-}
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub fn into<E>(&mut self, destination: &Place<'tcx>, block: BasicBlock, expr: E) -> BlockAnd<()>
-    where
-        E: EvalInto<'tcx>,
-    {
-        expr.eval_into(self, destination, block)
-    }
-}
-
-impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
-    fn eval_into(
-        self,
-        builder: &mut Builder<'_, 'tcx>,
-        destination: &Place<'tcx>,
-        block: BasicBlock,
-    ) -> BlockAnd<()> {
-        let expr = builder.hir.mirror(self);
-        builder.into_expr(destination, block, expr)
-    }
-}
-
-impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
-    fn eval_into(
-        self,
-        builder: &mut Builder<'_, 'tcx>,
-        destination: &Place<'tcx>,
-        block: BasicBlock,
-    ) -> BlockAnd<()> {
-        builder.into_expr(destination, block, self)
-    }
-}
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
deleted file mode 100644 (file)
index 7eea90b..0000000
+++ /dev/null
@@ -1,1671 +0,0 @@
-//! Code related to match expressions. These are sufficiently complex to
-//! warrant their own module and submodules. :) This main module includes the
-//! high-level algorithm, the submodules contain the details.
-//!
-//! This also includes code for pattern bindings in `let` statements and
-//! function parameters.
-
-use crate::build::scope::DropKind;
-use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
-use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
-use crate::hair::{self, *};
-use rustc::middle::region;
-use rustc::mir::*;
-use rustc::ty::layout::VariantIdx;
-use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::HirId;
-use rustc_index::bit_set::BitSet;
-use rustc_span::Span;
-use smallvec::{smallvec, SmallVec};
-use syntax::ast::Name;
-
-// helper functions, broken out by category:
-mod simplify;
-mod test;
-mod util;
-
-use itertools::Itertools;
-use std::convert::TryFrom;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Generates MIR for a `match` expression.
-    ///
-    /// The MIR that we generate for a match looks like this.
-    ///
-    /// ```text
-    /// [ 0. Pre-match ]
-    ///        |
-    /// [ 1. Evaluate Scrutinee (expression being matched on) ]
-    /// [ (fake read of scrutinee) ]
-    ///        |
-    /// [ 2. Decision tree -- check discriminants ] <--------+
-    ///        |                                             |
-    ///        | (once a specific arm is chosen)             |
-    ///        |                                             |
-    /// [pre_binding_block]                           [otherwise_block]
-    ///        |                                             |
-    /// [ 3. Create "guard bindings" for arm ]               |
-    /// [ (create fake borrows) ]                            |
-    ///        |                                             |
-    /// [ 4. Execute guard code ]                            |
-    /// [ (read fake borrows) ] --(guard is false)-----------+
-    ///        |
-    ///        | (guard results in true)
-    ///        |
-    /// [ 5. Create real bindings and execute arm ]
-    ///        |
-    /// [ Exit match ]
-    /// ```
-    ///
-    /// All of the different arms have been stacked on top of each other to
-    /// simplify the diagram. For an arm with no guard the blocks marked 3 and
-    /// 4 and the fake borrows are omitted.
-    ///
-    /// We generate MIR in the following steps:
-    ///
-    /// 1. Evaluate the scrutinee and add the fake read of it ([Builder::lower_scrutinee]).
-    /// 2. Create the prebinding and otherwise blocks ([Builder::create_match_candidates]).
-    /// 3. Create the decision tree ([Builder::lower_match_tree]).
-    /// 4. Determine the fake borrows that are needed from the places that were
-    ///    matched against and create the required temporaries for them
-    ///    ([Builder::calculate_fake_borrows]).
-    /// 5. Create everything else: the guards and the arms ([Builder::lower_match_arms]).
-    ///
-    /// ## False edges
-    ///
-    /// We don't want to have the exact structure of the decision tree be
-    /// visible through borrow checking. False edges ensure that the CFG as
-    /// seen by borrow checking doesn't encode this. False edges are added:
-    ///
-    /// * From each prebinding block to the next prebinding block.
-    /// * From each otherwise block to the next prebinding block.
-    pub fn match_expr(
-        &mut self,
-        destination: &Place<'tcx>,
-        span: Span,
-        mut block: BasicBlock,
-        scrutinee: ExprRef<'tcx>,
-        arms: Vec<Arm<'tcx>>,
-    ) -> BlockAnd<()> {
-        let scrutinee_span = scrutinee.span();
-        let scrutinee_place =
-            unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
-
-        let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms);
-
-        let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
-        let candidates =
-            arm_candidates.iter_mut().flat_map(|(_, candidates)| candidates).collect::<Vec<_>>();
-
-        let fake_borrow_temps =
-            self.lower_match_tree(block, scrutinee_span, match_has_guard, candidates);
-
-        self.lower_match_arms(
-            &destination,
-            scrutinee_place,
-            scrutinee_span,
-            arm_candidates,
-            self.source_info(span),
-            fake_borrow_temps,
-        )
-    }
-
-    /// Evaluate the scrutinee and add the fake read of it.
-    fn lower_scrutinee(
-        &mut self,
-        mut block: BasicBlock,
-        scrutinee: ExprRef<'tcx>,
-        scrutinee_span: Span,
-    ) -> BlockAnd<Place<'tcx>> {
-        let scrutinee_place = unpack!(block = self.as_place(block, scrutinee));
-        // Matching on a `scrutinee_place` with an uninhabited type doesn't
-        // generate any memory reads by itself, and so if the place "expression"
-        // contains unsafe operations like raw pointer dereferences or union
-        // field projections, we wouldn't know to require an `unsafe` block
-        // around a `match` equivalent to `std::intrinsics::unreachable()`.
-        // See issue #47412 for this hole being discovered in the wild.
-        //
-        // HACK(eddyb) Work around the above issue by adding a dummy inspection
-        // of `scrutinee_place`, specifically by applying `ReadForMatch`.
-        //
-        // NOTE: ReadForMatch also checks that the scrutinee is initialized.
-        // This is currently needed to not allow matching on an uninitialized,
-        // uninhabited value. If we get never patterns, those will check that
-        // the place is initialized, and so this read would only be used to
-        // check safety.
-        let cause_matched_place = FakeReadCause::ForMatchedPlace;
-        let source_info = self.source_info(scrutinee_span);
-        self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place.clone());
-
-        block.and(scrutinee_place)
-    }
-
-    /// Create the initial `Candidate`s for a `match` expression.
-    fn create_match_candidates<'pat>(
-        &mut self,
-        scrutinee: &Place<'tcx>,
-        arms: &'pat [Arm<'tcx>],
-    ) -> Vec<(&'pat Arm<'tcx>, Vec<Candidate<'pat, 'tcx>>)> {
-        let candidate_count = arms.iter().map(|c| c.top_pats_hack().len()).sum::<usize>();
-        let pre_binding_blocks: Vec<_> =
-            (0..candidate_count).map(|_| self.cfg.start_new_block()).collect();
-
-        let mut candidate_pre_binding_blocks = pre_binding_blocks.iter();
-        let mut next_candidate_pre_binding_blocks = pre_binding_blocks.iter().skip(1);
-
-        // Assemble a list of candidates: there is one candidate per pattern,
-        // which means there may be more than one candidate *per arm*.
-        arms.iter()
-            .map(|arm| {
-                let arm_has_guard = arm.guard.is_some();
-                let arm_candidates: Vec<_> = arm
-                    .top_pats_hack()
-                    .iter()
-                    .zip(candidate_pre_binding_blocks.by_ref())
-                    .map(|(pattern, pre_binding_block)| Candidate {
-                        span: pattern.span,
-                        match_pairs: smallvec![MatchPair::new(scrutinee.clone(), pattern)],
-                        bindings: vec![],
-                        ascriptions: vec![],
-                        otherwise_block: if arm_has_guard {
-                            Some(self.cfg.start_new_block())
-                        } else {
-                            None
-                        },
-                        pre_binding_block: *pre_binding_block,
-                        next_candidate_pre_binding_block: next_candidate_pre_binding_blocks
-                            .next()
-                            .copied(),
-                    })
-                    .collect();
-                (arm, arm_candidates)
-            })
-            .collect()
-    }
-
-    /// Create the decision tree for the match expression, starting from `block`.
-    ///
-    /// Modifies `candidates` to store the bindings and type ascriptions for
-    /// that candidate.
-    ///
-    /// Returns the places that need fake borrows because we bind or test them.
-    fn lower_match_tree<'pat>(
-        &mut self,
-        block: BasicBlock,
-        scrutinee_span: Span,
-        match_has_guard: bool,
-        mut candidates: Vec<&mut Candidate<'pat, 'tcx>>,
-    ) -> Vec<(Place<'tcx>, Local)> {
-        // The set of places that we are creating fake borrows of. If there are
-        // no match guards then we don't need any fake borrows, so don't track
-        // them.
-        let mut fake_borrows = if match_has_guard { Some(FxHashSet::default()) } else { None };
-
-        // This will generate code to test scrutinee_place and
-        // branch to the appropriate arm block
-        self.match_candidates(
-            scrutinee_span,
-            &mut Some(block),
-            None,
-            &mut candidates,
-            &mut fake_borrows,
-        );
-
-        if let Some(ref borrows) = fake_borrows {
-            self.calculate_fake_borrows(borrows, scrutinee_span)
-        } else {
-            Vec::new()
-        }
-    }
-
-    /// Lower the bindings, guards and arm bodies of a `match` expression.
-    ///
-    /// The decision tree should have already been created
-    /// (by [Builder::lower_match_tree]).
-    ///
-    /// `outer_source_info` is the SourceInfo for the whole match.
-    fn lower_match_arms(
-        &mut self,
-        destination: &Place<'tcx>,
-        scrutinee_place: Place<'tcx>,
-        scrutinee_span: Span,
-        arm_candidates: Vec<(&'_ Arm<'tcx>, Vec<Candidate<'_, 'tcx>>)>,
-        outer_source_info: SourceInfo,
-        fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
-    ) -> BlockAnd<()> {
-        let match_scope = self.scopes.topmost();
-
-        let arm_end_blocks: Vec<_> = arm_candidates
-            .into_iter()
-            .map(|(arm, candidates)| {
-                debug!("lowering arm {:?}\ncanidates = {:?}", arm, candidates);
-
-                let arm_source_info = self.source_info(arm.span);
-                let arm_scope = (arm.scope, arm_source_info);
-                self.in_scope(arm_scope, arm.lint_level, |this| {
-                    let body = this.hir.mirror(arm.body.clone());
-                    let scope = this.declare_bindings(
-                        None,
-                        arm.span,
-                        &arm.top_pats_hack()[0],
-                        ArmHasGuard(arm.guard.is_some()),
-                        Some((Some(&scrutinee_place), scrutinee_span)),
-                    );
-
-                    let arm_block = this.bind_pattern(
-                        outer_source_info,
-                        candidates,
-                        arm.guard.as_ref().map(|g| (g, match_scope)),
-                        &fake_borrow_temps,
-                        scrutinee_span,
-                        arm.scope,
-                    );
-
-                    if let Some(source_scope) = scope {
-                        this.source_scope = source_scope;
-                    }
-
-                    this.into(destination, arm_block, body)
-                })
-            })
-            .collect();
-
-        // all the arm blocks will rejoin here
-        let end_block = self.cfg.start_new_block();
-
-        for arm_block in arm_end_blocks {
-            self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
-        }
-
-        self.source_scope = outer_source_info.scope;
-
-        end_block.unit()
-    }
-
-    /// Binds the variables and ascribes types for a given `match` arm.
-    ///
-    /// Also check if the guard matches, if it's provided.
-    fn bind_pattern(
-        &mut self,
-        outer_source_info: SourceInfo,
-        mut candidates: Vec<Candidate<'_, 'tcx>>,
-        guard: Option<(&Guard<'tcx>, region::Scope)>,
-        fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
-        scrutinee_span: Span,
-        arm_scope: region::Scope,
-    ) -> BasicBlock {
-        if candidates.len() == 1 {
-            // Avoid generating another `BasicBlock` when we only have one
-            // candidate.
-            self.bind_and_guard_matched_candidate(
-                candidates.pop().unwrap(),
-                guard,
-                fake_borrow_temps,
-                scrutinee_span,
-            )
-        } else {
-            let arm_block = self.cfg.start_new_block();
-            for candidate in candidates {
-                // Avoid scheduling drops multiple times.
-                self.clear_top_scope(arm_scope);
-                let binding_end = self.bind_and_guard_matched_candidate(
-                    candidate,
-                    guard,
-                    fake_borrow_temps,
-                    scrutinee_span,
-                );
-                self.cfg.goto(binding_end, outer_source_info, arm_block);
-            }
-            arm_block
-        }
-    }
-
-    pub(super) fn expr_into_pattern(
-        &mut self,
-        mut block: BasicBlock,
-        irrefutable_pat: Pat<'tcx>,
-        initializer: ExprRef<'tcx>,
-    ) -> BlockAnd<()> {
-        match *irrefutable_pat.kind {
-            // Optimize the case of `let x = ...` to write directly into `x`
-            PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
-                let place =
-                    self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
-                unpack!(block = self.into(&place, block, initializer));
-
-                // Inject a fake read, see comments on `FakeReadCause::ForLet`.
-                let source_info = self.source_info(irrefutable_pat.span);
-                self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place);
-
-                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
-                block.unit()
-            }
-
-            // Optimize the case of `let x: T = ...` to write directly
-            // into `x` and then require that `T == typeof(x)`.
-            //
-            // Weirdly, this is needed to prevent the
-            // `intrinsic-move-val.rs` test case from crashing. That
-            // test works with uninitialized values in a rather
-            // dubious way, so it may be that the test is kind of
-            // broken.
-            PatKind::AscribeUserType {
-                subpattern:
-                    Pat {
-                        kind:
-                            box PatKind::Binding {
-                                mode: BindingMode::ByValue,
-                                var,
-                                subpattern: None,
-                                ..
-                            },
-                        ..
-                    },
-                ascription:
-                    hair::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
-            } => {
-                let place =
-                    self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
-                unpack!(block = self.into(&place, block, initializer));
-
-                // Inject a fake read, see comments on `FakeReadCause::ForLet`.
-                let pattern_source_info = self.source_info(irrefutable_pat.span);
-                let cause_let = FakeReadCause::ForLet;
-                self.cfg.push_fake_read(block, pattern_source_info, cause_let, place.clone());
-
-                let ty_source_info = self.source_info(user_ty_span);
-                let user_ty = pat_ascription_ty.user_ty(
-                    &mut self.canonical_user_type_annotations,
-                    place.ty(&self.local_decls, self.hir.tcx()).ty,
-                    ty_source_info.span,
-                );
-                self.cfg.push(
-                    block,
-                    Statement {
-                        source_info: ty_source_info,
-                        kind: StatementKind::AscribeUserType(
-                            box (place, user_ty),
-                            // We always use invariant as the variance here. This is because the
-                            // variance field from the ascription refers to the variance to use
-                            // when applying the type to the value being matched, but this
-                            // ascription applies rather to the type of the binding. e.g., in this
-                            // example:
-                            //
-                            // ```
-                            // let x: T = <expr>
-                            // ```
-                            //
-                            // We are creating an ascription that defines the type of `x` to be
-                            // exactly `T` (i.e., with invariance). The variance field, in
-                            // contrast, is intended to be used to relate `T` to the type of
-                            // `<expr>`.
-                            ty::Variance::Invariant,
-                        ),
-                    },
-                );
-
-                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
-                block.unit()
-            }
-
-            _ => {
-                let place = unpack!(block = self.as_place(block, initializer));
-                self.place_into_pattern(block, irrefutable_pat, &place, true)
-            }
-        }
-    }
-
-    pub fn place_into_pattern(
-        &mut self,
-        block: BasicBlock,
-        irrefutable_pat: Pat<'tcx>,
-        initializer: &Place<'tcx>,
-        set_match_place: bool,
-    ) -> BlockAnd<()> {
-        // create a dummy candidate
-        let mut candidate = Candidate {
-            span: irrefutable_pat.span,
-            match_pairs: smallvec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
-            bindings: vec![],
-            ascriptions: vec![],
-
-            // since we don't call `match_candidates`, next fields are unused
-            otherwise_block: None,
-            pre_binding_block: block,
-            next_candidate_pre_binding_block: None,
-        };
-
-        // Simplify the candidate. Since the pattern is irrefutable, this should
-        // always convert all match-pairs into bindings.
-        self.simplify_candidate(&mut candidate);
-
-        if !candidate.match_pairs.is_empty() {
-            // ICE if no other errors have been emitted. This used to be a hard error that wouldn't
-            // be reached because `hair::pattern::check_match::check_match` wouldn't have let the
-            // compiler continue. In our tests this is only ever hit by
-            // `ui/consts/const-match-check.rs` with `--cfg eval1`, and that file already generates
-            // a different error before hand.
-            self.hir.tcx().sess.delay_span_bug(
-                candidate.match_pairs[0].pattern.span,
-                &format!(
-                    "match pairs {:?} remaining after simplifying irrefutable pattern",
-                    candidate.match_pairs,
-                ),
-            );
-        }
-
-        // for matches and function arguments, the place that is being matched
-        // can be set when creating the variables. But the place for
-        // let PATTERN = ... might not even exist until we do the assignment.
-        // so we set it here instead
-        if set_match_place {
-            for binding in &candidate.bindings {
-                let local = self.var_local_id(binding.var_id, OutsideGuard);
-
-                if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                    opt_match_place: Some((ref mut match_place, _)),
-                    ..
-                }))) = self.local_decls[local].local_info
-                {
-                    *match_place = Some(initializer.clone());
-                } else {
-                    bug!("Let binding to non-user variable.")
-                }
-            }
-        }
-
-        self.ascribe_types(block, &candidate.ascriptions);
-
-        // now apply the bindings, which will also declare the variables
-        self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
-
-        block.unit()
-    }
-
-    /// Declares the bindings of the given patterns and returns the visibility
-    /// scope for the bindings in these patterns, if such a scope had to be
-    /// created. NOTE: Declaring the bindings should always be done in their
-    /// drop scope.
-    pub fn declare_bindings(
-        &mut self,
-        mut visibility_scope: Option<SourceScope>,
-        scope_span: Span,
-        pattern: &Pat<'tcx>,
-        has_guard: ArmHasGuard,
-        opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
-    ) -> Option<SourceScope> {
-        debug!("declare_bindings: pattern={:?}", pattern);
-        self.visit_bindings(
-            &pattern,
-            UserTypeProjections::none(),
-            &mut |this, mutability, name, mode, var, span, ty, user_ty| {
-                if visibility_scope.is_none() {
-                    visibility_scope =
-                        Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
-                }
-                let source_info = SourceInfo { span, scope: this.source_scope };
-                let visibility_scope = visibility_scope.unwrap();
-                this.declare_binding(
-                    source_info,
-                    visibility_scope,
-                    mutability,
-                    name,
-                    mode,
-                    var,
-                    ty,
-                    user_ty,
-                    has_guard,
-                    opt_match_place.map(|(x, y)| (x.cloned(), y)),
-                    pattern.span,
-                );
-            },
-        );
-        visibility_scope
-    }
-
-    pub fn storage_live_binding(
-        &mut self,
-        block: BasicBlock,
-        var: HirId,
-        span: Span,
-        for_guard: ForGuard,
-    ) -> Place<'tcx> {
-        let local_id = self.var_local_id(var, for_guard);
-        let source_info = self.source_info(span);
-        self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
-        let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
-        self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
-        Place::from(local_id)
-    }
-
-    pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
-        let local_id = self.var_local_id(var, for_guard);
-        let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
-        self.schedule_drop(span, region_scope, local_id, DropKind::Value);
-    }
-
-    pub(super) fn visit_bindings(
-        &mut self,
-        pattern: &Pat<'tcx>,
-        pattern_user_ty: UserTypeProjections,
-        f: &mut impl FnMut(
-            &mut Self,
-            Mutability,
-            Name,
-            BindingMode,
-            HirId,
-            Span,
-            Ty<'tcx>,
-            UserTypeProjections,
-        ),
-    ) {
-        debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
-        match *pattern.kind {
-            PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, .. } => {
-                f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
-                if let Some(subpattern) = subpattern.as_ref() {
-                    self.visit_bindings(subpattern, pattern_user_ty, f);
-                }
-            }
-
-            PatKind::Array { ref prefix, ref slice, ref suffix }
-            | PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                let from = u32::try_from(prefix.len()).unwrap();
-                let to = u32::try_from(suffix.len()).unwrap();
-                for subpattern in prefix {
-                    self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
-                }
-                for subpattern in slice {
-                    self.visit_bindings(subpattern, pattern_user_ty.clone().subslice(from, to), f);
-                }
-                for subpattern in suffix {
-                    self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
-                }
-            }
-
-            PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {}
-
-            PatKind::Deref { ref subpattern } => {
-                self.visit_bindings(subpattern, pattern_user_ty.deref(), f);
-            }
-
-            PatKind::AscribeUserType {
-                ref subpattern,
-                ascription: hair::pattern::Ascription { ref user_ty, user_ty_span, variance: _ },
-            } => {
-                // This corresponds to something like
-                //
-                // ```
-                // let A::<'a>(_): A<'static> = ...;
-                // ```
-                //
-                // Note that the variance doesn't apply here, as we are tracking the effect
-                // of `user_ty` on any bindings contained with subpattern.
-                let annotation = CanonicalUserTypeAnnotation {
-                    span: user_ty_span,
-                    user_ty: user_ty.user_ty,
-                    inferred_ty: subpattern.ty,
-                };
-                let projection = UserTypeProjection {
-                    base: self.canonical_user_type_annotations.push(annotation),
-                    projs: Vec::new(),
-                };
-                let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
-                self.visit_bindings(subpattern, subpattern_user_ty, f)
-            }
-
-            PatKind::Leaf { ref subpatterns } => {
-                for subpattern in subpatterns {
-                    let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
-                    debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
-                    self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
-                }
-            }
-
-            PatKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => {
-                for subpattern in subpatterns {
-                    let subpattern_user_ty =
-                        pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field);
-                    self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
-                }
-            }
-            PatKind::Or { ref pats } => {
-                for pat in pats {
-                    self.visit_bindings(&pat, pattern_user_ty.clone(), f);
-                }
-            }
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct Candidate<'pat, 'tcx> {
-    // span of the original pattern that gave rise to this candidate
-    span: Span,
-
-    // all of these must be satisfied...
-    match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
-
-    // ...these bindings established...
-    bindings: Vec<Binding<'tcx>>,
-
-    // ...and these types asserted...
-    ascriptions: Vec<Ascription<'tcx>>,
-
-    // ...and the guard must be evaluated, if false branch to Block...
-    otherwise_block: Option<BasicBlock>,
-
-    // ...and the blocks for add false edges between candidates
-    pre_binding_block: BasicBlock,
-    next_candidate_pre_binding_block: Option<BasicBlock>,
-}
-
-#[derive(Clone, Debug)]
-struct Binding<'tcx> {
-    span: Span,
-    source: Place<'tcx>,
-    name: Name,
-    var_id: HirId,
-    var_ty: Ty<'tcx>,
-    mutability: Mutability,
-    binding_mode: BindingMode,
-}
-
-/// Indicates that the type of `source` must be a subtype of the
-/// user-given type `user_ty`; this is basically a no-op but can
-/// influence region inference.
-#[derive(Clone, Debug)]
-struct Ascription<'tcx> {
-    span: Span,
-    source: Place<'tcx>,
-    user_ty: PatTyProj<'tcx>,
-    variance: ty::Variance,
-}
-
-#[derive(Clone, Debug)]
-pub struct MatchPair<'pat, 'tcx> {
-    // this place...
-    place: Place<'tcx>,
-
-    // ... must match this pattern.
-    pattern: &'pat Pat<'tcx>,
-}
-
-#[derive(Clone, Debug, PartialEq)]
-enum TestKind<'tcx> {
-    /// Test the branches of enum.
-    Switch {
-        /// The enum being tested
-        adt_def: &'tcx ty::AdtDef,
-        /// The set of variants that we should create a branch for. We also
-        /// create an additional "otherwise" case.
-        variants: BitSet<VariantIdx>,
-    },
-
-    /// Test what value an `integer`, `bool` or `char` has.
-    SwitchInt {
-        /// The type of the value that we're testing.
-        switch_ty: Ty<'tcx>,
-        /// The (ordered) set of values that we test for.
-        ///
-        /// For integers and `char`s we create a branch to each of the values in
-        /// `options`, as well as an "otherwise" branch for all other values, even
-        /// in the (rare) case that options is exhaustive.
-        ///
-        /// For `bool` we always generate two edges, one for `true` and one for
-        /// `false`.
-        options: Vec<u128>,
-        /// Reverse map used to ensure that the values in `options` are unique.
-        indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
-    },
-
-    /// Test for equality with value, possibly after an unsizing coercion to
-    /// `ty`,
-    Eq {
-        value: &'tcx ty::Const<'tcx>,
-        // Integer types are handled by `SwitchInt`, and constants with ADT
-        // types are converted back into patterns, so this can only be `&str`,
-        // `&[T]`, `f32` or `f64`.
-        ty: Ty<'tcx>,
-    },
-
-    /// Test whether the value falls within an inclusive or exclusive range
-    Range(PatRange<'tcx>),
-
-    /// Test length of the slice is equal to len
-    Len { len: u64, op: BinOp },
-}
-
-#[derive(Debug)]
-pub struct Test<'tcx> {
-    span: Span,
-    kind: TestKind<'tcx>,
-}
-
-/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether
-/// a match arm has a guard expression attached to it.
-#[derive(Copy, Clone, Debug)]
-pub(crate) struct ArmHasGuard(pub bool);
-
-///////////////////////////////////////////////////////////////////////////
-// Main matching algorithm
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// The main match algorithm. It begins with a set of candidates
-    /// `candidates` and has the job of generating code to determine
-    /// which of these candidates, if any, is the correct one. The
-    /// candidates are sorted such that the first item in the list
-    /// has the highest priority. When a candidate is found to match
-    /// the value, we will generate a branch to the appropriate
-    /// prebinding block.
-    ///
-    /// If we find that *NONE* of the candidates apply, we branch to the
-    /// `otherwise_block`. In principle, this means that the input list was not
-    /// exhaustive, though at present we sometimes are not smart enough to
-    /// recognize all exhaustive inputs.
-    ///
-    /// It might be surprising that the input can be inexhaustive.
-    /// Indeed, initially, it is not, because all matches are
-    /// exhaustive in Rust. But during processing we sometimes divide
-    /// up the list of candidates and recurse with a non-exhaustive
-    /// list. This is important to keep the size of the generated code
-    /// under control. See `test_candidates` for more details.
-    ///
-    /// If `fake_borrows` is Some, then places which need fake borrows
-    /// will be added to it.
-    fn match_candidates<'pat>(
-        &mut self,
-        span: Span,
-        start_block: &mut Option<BasicBlock>,
-        otherwise_block: Option<BasicBlock>,
-        candidates: &mut [&mut Candidate<'pat, 'tcx>],
-        fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
-    ) {
-        debug!(
-            "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
-            span, candidates, start_block, otherwise_block,
-        );
-
-        // Start by simplifying candidates. Once this process is complete, all
-        // the match pairs which remain require some form of test, whether it
-        // be a switch or pattern comparison.
-        for candidate in &mut *candidates {
-            self.simplify_candidate(candidate);
-        }
-
-        // The candidates are sorted by priority. Check to see whether the
-        // higher priority candidates (and hence at the front of the slice)
-        // have satisfied all their match pairs.
-        let fully_matched = candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
-        debug!("match_candidates: {:?} candidates fully matched", fully_matched);
-        let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched);
-
-        let block: BasicBlock = if !matched_candidates.is_empty() {
-            let otherwise_block =
-                self.select_matched_candidates(matched_candidates, start_block, fake_borrows);
-
-            if let Some(last_otherwise_block) = otherwise_block {
-                last_otherwise_block
-            } else {
-                // Any remaining candidates are unreachable.
-                if unmatched_candidates.is_empty() {
-                    return;
-                }
-                self.cfg.start_new_block()
-            }
-        } else {
-            *start_block.get_or_insert_with(|| self.cfg.start_new_block())
-        };
-
-        // If there are no candidates that still need testing, we're
-        // done. Since all matches are exhaustive, execution should
-        // never reach this point.
-        if unmatched_candidates.is_empty() {
-            let source_info = self.source_info(span);
-            match otherwise_block {
-                Some(otherwise) => self.cfg.goto(block, source_info, otherwise),
-                None => self.cfg.terminate(block, source_info, TerminatorKind::Unreachable),
-            }
-            return;
-        }
-
-        // Test for the remaining candidates.
-        self.test_candidates(span, unmatched_candidates, block, otherwise_block, fake_borrows);
-    }
-
-    /// Link up matched candidates. For example, if we have something like
-    /// this:
-    ///
-    /// ...
-    /// Some(x) if cond => ...
-    /// Some(x) => ...
-    /// Some(x) if cond => ...
-    /// ...
-    ///
-    /// We generate real edges from:
-    /// * `start_block` to the `prebinding_block` of the first pattern,
-    /// * the otherwise block of the first pattern to the second pattern,
-    /// * the otherwise block of the third pattern to the a block with an
-    ///   Unreachable terminator.
-    ///
-    /// As well as that we add fake edges from the otherwise blocks to the
-    /// prebinding block of the next candidate in the original set of
-    /// candidates.
-    fn select_matched_candidates(
-        &mut self,
-        matched_candidates: &mut [&mut Candidate<'_, 'tcx>],
-        start_block: &mut Option<BasicBlock>,
-        fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
-    ) -> Option<BasicBlock> {
-        debug_assert!(
-            !matched_candidates.is_empty(),
-            "select_matched_candidates called with no candidates",
-        );
-
-        // Insert a borrows of prefixes of places that are bound and are
-        // behind a dereference projection.
-        //
-        // These borrows are taken to avoid situations like the following:
-        //
-        // match x[10] {
-        //     _ if { x = &[0]; false } => (),
-        //     y => (), // Out of bounds array access!
-        // }
-        //
-        // match *x {
-        //     // y is bound by reference in the guard and then by copy in the
-        //     // arm, so y is 2 in the arm!
-        //     y if { y == 1 && (x = &2) == () } => y,
-        //     _ => 3,
-        // }
-        if let Some(fake_borrows) = fake_borrows {
-            for Binding { source, .. } in
-                matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
-            {
-                if let Some(i) =
-                    source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref)
-                {
-                    let proj_base = &source.projection[..i];
-
-                    fake_borrows.insert(Place {
-                        base: source.base.clone(),
-                        projection: self.hir.tcx().intern_place_elems(proj_base),
-                    });
-                }
-            }
-        }
-
-        let fully_matched_with_guard = matched_candidates
-            .iter()
-            .position(|c| c.otherwise_block.is_none())
-            .unwrap_or(matched_candidates.len() - 1);
-
-        let (reachable_candidates, unreachable_candidates) =
-            matched_candidates.split_at_mut(fully_matched_with_guard + 1);
-
-        let first_candidate = &reachable_candidates[0];
-        let first_prebinding_block = first_candidate.pre_binding_block;
-
-        // `goto -> first_prebinding_block` from the `start_block` if there is one.
-        if let Some(start_block) = *start_block {
-            let source_info = self.source_info(first_candidate.span);
-            self.cfg.goto(start_block, source_info, first_prebinding_block);
-        } else {
-            *start_block = Some(first_prebinding_block);
-        }
-
-        for (first_candidate, second_candidate) in reachable_candidates.iter().tuple_windows() {
-            let source_info = self.source_info(first_candidate.span);
-            if let Some(otherwise_block) = first_candidate.otherwise_block {
-                self.false_edges(
-                    otherwise_block,
-                    second_candidate.pre_binding_block,
-                    first_candidate.next_candidate_pre_binding_block,
-                    source_info,
-                );
-            } else {
-                bug!("candidate other than the last has no guard");
-            }
-        }
-
-        debug!("match_candidates: add false edges for unreachable {:?}", unreachable_candidates);
-        for candidate in unreachable_candidates {
-            if let Some(otherwise) = candidate.otherwise_block {
-                let source_info = self.source_info(candidate.span);
-                let unreachable = self.cfg.start_new_block();
-                self.false_edges(
-                    otherwise,
-                    unreachable,
-                    candidate.next_candidate_pre_binding_block,
-                    source_info,
-                );
-                self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
-            }
-        }
-
-        let last_candidate = reachable_candidates.last().unwrap();
-        if let Some(otherwise) = last_candidate.otherwise_block {
-            let source_info = self.source_info(last_candidate.span);
-            let block = self.cfg.start_new_block();
-            self.false_edges(
-                otherwise,
-                block,
-                last_candidate.next_candidate_pre_binding_block,
-                source_info,
-            );
-            Some(block)
-        } else {
-            None
-        }
-    }
-
-    /// This is the most subtle part of the matching algorithm. At
-    /// this point, the input candidates have been fully simplified,
-    /// and so we know that all remaining match-pairs require some
-    /// sort of test. To decide what test to do, we take the highest
-    /// priority candidate (last one in the list) and extract the
-    /// first match-pair from the list. From this we decide what kind
-    /// of test is needed using `test`, defined in the `test` module.
-    ///
-    /// *Note:* taking the first match pair is somewhat arbitrary, and
-    /// we might do better here by choosing more carefully what to
-    /// test.
-    ///
-    /// For example, consider the following possible match-pairs:
-    ///
-    /// 1. `x @ Some(P)` -- we will do a `Switch` to decide what variant `x` has
-    /// 2. `x @ 22` -- we will do a `SwitchInt`
-    /// 3. `x @ 3..5` -- we will do a range test
-    /// 4. etc.
-    ///
-    /// Once we know what sort of test we are going to perform, this
-    /// Tests may also help us with other candidates. So we walk over
-    /// the candidates (from high to low priority) and check. This
-    /// gives us, for each outcome of the test, a transformed list of
-    /// candidates. For example, if we are testing the current
-    /// variant of `x.0`, and we have a candidate `{x.0 @ Some(v), x.1
-    /// @ 22}`, then we would have a resulting candidate of `{(x.0 as
-    /// Some).0 @ v, x.1 @ 22}`. Note that the first match-pair is now
-    /// simpler (and, in fact, irrefutable).
-    ///
-    /// But there may also be candidates that the test just doesn't
-    /// apply to. The classical example involves wildcards:
-    ///
-    /// ```
-    /// # let (x, y, z) = (true, true, true);
-    /// match (x, y, z) {
-    ///     (true, _, true) => true,    // (0)
-    ///     (_, true, _) => true,       // (1)
-    ///     (false, false, _) => false, // (2)
-    ///     (true, _, false) => false,  // (3)
-    /// }
-    /// ```
-    ///
-    /// In that case, after we test on `x`, there are 2 overlapping candidate
-    /// sets:
-    ///
-    /// - If the outcome is that `x` is true, candidates 0, 1, and 3
-    /// - If the outcome is that `x` is false, candidates 1 and 2
-    ///
-    /// Here, the traditional "decision tree" method would generate 2
-    /// separate code-paths for the 2 separate cases.
-    ///
-    /// In some cases, this duplication can create an exponential amount of
-    /// code. This is most easily seen by noticing that this method terminates
-    /// with precisely the reachable arms being reachable - but that problem
-    /// is trivially NP-complete:
-    ///
-    /// ```rust
-    ///     match (var0, var1, var2, var3, ..) {
-    ///         (true, _, _, false, true, ...) => false,
-    ///         (_, true, true, false, _, ...) => false,
-    ///         (false, _, false, false, _, ...) => false,
-    ///         ...
-    ///         _ => true
-    ///     }
-    /// ```
-    ///
-    /// Here the last arm is reachable only if there is an assignment to
-    /// the variables that does not match any of the literals. Therefore,
-    /// compilation would take an exponential amount of time in some cases.
-    ///
-    /// That kind of exponential worst-case might not occur in practice, but
-    /// our simplistic treatment of constants and guards would make it occur
-    /// in very common situations - for example #29740:
-    ///
-    /// ```rust
-    /// match x {
-    ///     "foo" if foo_guard => ...,
-    ///     "bar" if bar_guard => ...,
-    ///     "baz" if baz_guard => ...,
-    ///     ...
-    /// }
-    /// ```
-    ///
-    /// Here we first test the match-pair `x @ "foo"`, which is an `Eq` test.
-    ///
-    /// It might seem that we would end up with 2 disjoint candidate
-    /// sets, consisting of the first candidate or the other 3, but our
-    /// algorithm doesn't reason about "foo" being distinct from the other
-    /// constants; it considers the latter arms to potentially match after
-    /// both outcomes, which obviously leads to an exponential amount
-    /// of tests.
-    ///
-    /// To avoid these kinds of problems, our algorithm tries to ensure
-    /// the amount of generated tests is linear. When we do a k-way test,
-    /// we return an additional "unmatched" set alongside the obvious `k`
-    /// sets. When we encounter a candidate that would be present in more
-    /// than one of the sets, we put it and all candidates below it into the
-    /// "unmatched" set. This ensures these `k+1` sets are disjoint.
-    ///
-    /// After we perform our test, we branch into the appropriate candidate
-    /// set and recurse with `match_candidates`. These sub-matches are
-    /// obviously inexhaustive - as we discarded our otherwise set - so
-    /// we set their continuation to do `match_candidates` on the
-    /// "unmatched" set (which is again inexhaustive).
-    ///
-    /// If you apply this to the above test, you basically wind up
-    /// with an if-else-if chain, testing each candidate in turn,
-    /// which is precisely what we want.
-    ///
-    /// In addition to avoiding exponential-time blowups, this algorithm
-    /// also has nice property that each guard and arm is only generated
-    /// once.
-    fn test_candidates<'pat, 'b, 'c>(
-        &mut self,
-        span: Span,
-        mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
-        block: BasicBlock,
-        mut otherwise_block: Option<BasicBlock>,
-        fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
-    ) {
-        // extract the match-pair from the highest priority candidate
-        let match_pair = &candidates.first().unwrap().match_pairs[0];
-        let mut test = self.test(match_pair);
-        let match_place = match_pair.place.clone();
-
-        // most of the time, the test to perform is simply a function
-        // of the main candidate; but for a test like SwitchInt, we
-        // may want to add cases based on the candidates that are
-        // available
-        match test.kind {
-            TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
-                for candidate in candidates.iter() {
-                    if !self.add_cases_to_switch(
-                        &match_place,
-                        candidate,
-                        switch_ty,
-                        options,
-                        indices,
-                    ) {
-                        break;
-                    }
-                }
-            }
-            TestKind::Switch { adt_def: _, ref mut variants } => {
-                for candidate in candidates.iter() {
-                    if !self.add_variants_to_switch(&match_place, candidate, variants) {
-                        break;
-                    }
-                }
-            }
-            _ => {}
-        }
-
-        // Insert a Shallow borrow of any places that is switched on.
-        fake_borrows.as_mut().map(|fb| fb.insert(match_place.clone()));
-
-        // perform the test, branching to one of N blocks. For each of
-        // those N possible outcomes, create a (initially empty)
-        // vector of candidates. Those are the candidates that still
-        // apply if the test has that particular outcome.
-        debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
-        let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![];
-        target_candidates.resize_with(test.targets(), Default::default);
-
-        let total_candidate_count = candidates.len();
-
-        // Sort the candidates into the appropriate vector in
-        // `target_candidates`. Note that at some point we may
-        // encounter a candidate where the test is not relevant; at
-        // that point, we stop sorting.
-        while let Some(candidate) = candidates.first_mut() {
-            if let Some(idx) = self.sort_candidate(&match_place, &test, candidate) {
-                let (candidate, rest) = candidates.split_first_mut().unwrap();
-                target_candidates[idx].push(candidate);
-                candidates = rest;
-            } else {
-                break;
-            }
-        }
-        // at least the first candidate ought to be tested
-        assert!(total_candidate_count > candidates.len());
-        debug!("tested_candidates: {}", total_candidate_count - candidates.len());
-        debug!("untested_candidates: {}", candidates.len());
-
-        // HACK(matthewjasper) This is a closure so that we can let the test
-        // create its blocks before the rest of the match. This currently
-        // improves the speed of llvm when optimizing long string literal
-        // matches
-        let make_target_blocks = move |this: &mut Self| -> Vec<BasicBlock> {
-            // For each outcome of test, process the candidates that still
-            // apply. Collect a list of blocks where control flow will
-            // branch if one of the `target_candidate` sets is not
-            // exhaustive.
-            if !candidates.is_empty() {
-                let remainder_start = &mut None;
-                this.match_candidates(
-                    span,
-                    remainder_start,
-                    otherwise_block,
-                    candidates,
-                    fake_borrows,
-                );
-                otherwise_block = Some(remainder_start.unwrap());
-            };
-
-            target_candidates
-                .into_iter()
-                .map(|mut candidates| {
-                    if candidates.len() != 0 {
-                        let candidate_start = &mut None;
-                        this.match_candidates(
-                            span,
-                            candidate_start,
-                            otherwise_block,
-                            &mut *candidates,
-                            fake_borrows,
-                        );
-                        candidate_start.unwrap()
-                    } else {
-                        *otherwise_block.get_or_insert_with(|| {
-                            let unreachable = this.cfg.start_new_block();
-                            let source_info = this.source_info(span);
-                            this.cfg.terminate(
-                                unreachable,
-                                source_info,
-                                TerminatorKind::Unreachable,
-                            );
-                            unreachable
-                        })
-                    }
-                })
-                .collect()
-        };
-
-        self.perform_test(block, &match_place, &test, make_target_blocks);
-    }
-
-    /// Determine the fake borrows that are needed from a set of places that
-    /// have to be stable across match guards.
-    ///
-    /// Returns a list of places that need a fake borrow and the temporary
-    /// that's used to store the fake borrow.
-    ///
-    /// Match exhaustiveness checking is not able to handle the case where the
-    /// place being matched on is mutated in the guards. We add "fake borrows"
-    /// to the guards that prevent any mutation of the place being matched.
-    /// There are a some subtleties:
-    ///
-    /// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared
-    ///    reference, the borrow isn't even tracked. As such we have to add fake
-    ///    borrows of any prefixes of a place
-    /// 2. We don't want `match x { _ => (), }` to conflict with mutable
-    ///    borrows of `x`, so we only add fake borrows for places which are
-    ///    bound or tested by the match.
-    /// 3. We don't want the fake borrows to conflict with `ref mut` bindings,
-    ///    so we use a special BorrowKind for them.
-    /// 4. The fake borrows may be of places in inactive variants, so it would
-    ///    be UB to generate code for them. They therefore have to be removed
-    ///    by a MIR pass run after borrow checking.
-    fn calculate_fake_borrows<'b>(
-        &mut self,
-        fake_borrows: &'b FxHashSet<Place<'tcx>>,
-        temp_span: Span,
-    ) -> Vec<(Place<'tcx>, Local)> {
-        let tcx = self.hir.tcx();
-
-        debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
-
-        let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len());
-
-        // Insert a Shallow borrow of the prefixes of any fake borrows.
-        for place in fake_borrows {
-            let mut cursor = place.projection.as_ref();
-            while let [proj_base @ .., elem] = cursor {
-                cursor = proj_base;
-
-                if let ProjectionElem::Deref = elem {
-                    // Insert a shallow borrow after a deref. For other
-                    // projections the borrow of prefix_cursor will
-                    // conflict with any mutation of base.
-                    all_fake_borrows.push(PlaceRef { base: &place.base, projection: proj_base });
-                }
-            }
-
-            all_fake_borrows.push(place.as_ref());
-        }
-
-        // Deduplicate and ensure a deterministic order.
-        all_fake_borrows.sort();
-        all_fake_borrows.dedup();
-
-        debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
-
-        all_fake_borrows
-            .into_iter()
-            .map(|matched_place_ref| {
-                let matched_place = Place {
-                    base: matched_place_ref.base.clone(),
-                    projection: tcx.intern_place_elems(matched_place_ref.projection),
-                };
-                let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
-                let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
-                let fake_borrow_temp =
-                    self.local_decls.push(LocalDecl::new_temp(fake_borrow_ty, temp_span));
-
-                (matched_place, fake_borrow_temp)
-            })
-            .collect()
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Pat binding - used for `let` and function parameters as well.
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Initializes each of the bindings from the candidate by
-    /// moving/copying/ref'ing the source as appropriate. Tests the guard, if
-    /// any, and then branches to the arm. Returns the block for the case where
-    /// the guard fails.
-    ///
-    /// Note: we do not check earlier that if there is a guard,
-    /// there cannot be move bindings. We avoid a use-after-move by only
-    /// moving the binding once the guard has evaluated to true (see below).
-    fn bind_and_guard_matched_candidate<'pat>(
-        &mut self,
-        candidate: Candidate<'pat, 'tcx>,
-        guard: Option<(&Guard<'tcx>, region::Scope)>,
-        fake_borrows: &Vec<(Place<'tcx>, Local)>,
-        scrutinee_span: Span,
-    ) -> BasicBlock {
-        debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
-
-        debug_assert!(candidate.match_pairs.is_empty());
-
-        let candidate_source_info = self.source_info(candidate.span);
-
-        let mut block = candidate.pre_binding_block;
-
-        // If we are adding our own statements, then we need a fresh block.
-        let create_fresh_block = candidate.next_candidate_pre_binding_block.is_some()
-            || !candidate.bindings.is_empty()
-            || !candidate.ascriptions.is_empty()
-            || guard.is_some();
-
-        if create_fresh_block {
-            let fresh_block = self.cfg.start_new_block();
-            self.false_edges(
-                block,
-                fresh_block,
-                candidate.next_candidate_pre_binding_block,
-                candidate_source_info,
-            );
-            block = fresh_block;
-            self.ascribe_types(block, &candidate.ascriptions);
-        } else {
-            return block;
-        }
-
-        // rust-lang/rust#27282: The `autoref` business deserves some
-        // explanation here.
-        //
-        // The intent of the `autoref` flag is that when it is true,
-        // then any pattern bindings of type T will map to a `&T`
-        // within the context of the guard expression, but will
-        // continue to map to a `T` in the context of the arm body. To
-        // avoid surfacing this distinction in the user source code
-        // (which would be a severe change to the language and require
-        // far more revision to the compiler), when `autoref` is true,
-        // then any occurrence of the identifier in the guard
-        // expression will automatically get a deref op applied to it.
-        //
-        // So an input like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { foo if inspect(foo)
-        //     => feed(foo), ...  }
-        // ```
-        //
-        // will be treated as if it were really something like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
-        //     => { let tmp2 = place; feed(tmp2) }, ... }
-        //
-        // And an input like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { ref mut foo if inspect(foo)
-        //     => feed(foo), ...  }
-        // ```
-        //
-        // will be treated as if it were really something like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
-        //     => { let tmp2 = &mut place; feed(tmp2) }, ... }
-        // ```
-        //
-        // In short, any pattern binding will always look like *some*
-        // kind of `&T` within the guard at least in terms of how the
-        // MIR-borrowck views it, and this will ensure that guard
-        // expressions cannot mutate their the match inputs via such
-        // bindings. (It also ensures that guard expressions can at
-        // most *copy* values from such bindings; non-Copy things
-        // cannot be moved via pattern bindings in guard expressions.)
-        //
-        // ----
-        //
-        // Implementation notes (under assumption `autoref` is true).
-        //
-        // To encode the distinction above, we must inject the
-        // temporaries `tmp1` and `tmp2`.
-        //
-        // There are two cases of interest: binding by-value, and binding by-ref.
-        //
-        // 1. Binding by-value: Things are simple.
-        //
-        //    * Establishing `tmp1` creates a reference into the
-        //      matched place. This code is emitted by
-        //      bind_matched_candidate_for_guard.
-        //
-        //    * `tmp2` is only initialized "lazily", after we have
-        //      checked the guard. Thus, the code that can trigger
-        //      moves out of the candidate can only fire after the
-        //      guard evaluated to true. This initialization code is
-        //      emitted by bind_matched_candidate_for_arm.
-        //
-        // 2. Binding by-reference: Things are tricky.
-        //
-        //    * Here, the guard expression wants a `&&` or `&&mut`
-        //      into the original input. This means we need to borrow
-        //      the reference that we create for the arm.
-        //    * So we eagerly create the reference for the arm and then take a
-        //      reference to that.
-        if let Some((guard, region_scope)) = guard {
-            let tcx = self.hir.tcx();
-
-            self.bind_matched_candidate_for_guard(block, &candidate.bindings);
-            let guard_frame = GuardFrame {
-                locals: candidate
-                    .bindings
-                    .iter()
-                    .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode))
-                    .collect(),
-            };
-            debug!("entering guard building context: {:?}", guard_frame);
-            self.guard_context.push(guard_frame);
-
-            let re_erased = tcx.lifetimes.re_erased;
-            let scrutinee_source_info = self.source_info(scrutinee_span);
-            for (place, temp) in fake_borrows {
-                let borrow = Rvalue::Ref(re_erased, BorrowKind::Shallow, place.clone());
-                self.cfg.push_assign(block, scrutinee_source_info, &Place::from(*temp), borrow);
-            }
-
-            // the block to branch to if the guard fails; if there is no
-            // guard, this block is simply unreachable
-            let guard = match guard {
-                Guard::If(e) => self.hir.mirror(e.clone()),
-            };
-            let source_info = self.source_info(guard.span);
-            let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span));
-            let (post_guard_block, otherwise_post_guard_block) =
-                self.test_bool(block, guard, source_info);
-            let guard_frame = self.guard_context.pop().unwrap();
-            debug!("Exiting guard building context with locals: {:?}", guard_frame);
-
-            for &(_, temp) in fake_borrows {
-                let cause = FakeReadCause::ForMatchGuard;
-                self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
-            }
-
-            self.exit_scope(
-                source_info.span,
-                region_scope,
-                otherwise_post_guard_block,
-                candidate.otherwise_block.unwrap(),
-            );
-
-            // We want to ensure that the matched candidates are bound
-            // after we have confirmed this candidate *and* any
-            // associated guard; Binding them on `block` is too soon,
-            // because that would be before we've checked the result
-            // from the guard.
-            //
-            // But binding them on the arm is *too late*, because
-            // then all of the candidates for a single arm would be
-            // bound in the same place, that would cause a case like:
-            //
-            // ```rust
-            // match (30, 2) {
-            //     (mut x, 1) | (2, mut x) if { true } => { ... }
-            //     ...                                 // ^^^^^^^ (this is `arm_block`)
-            // }
-            // ```
-            //
-            // would yield a `arm_block` something like:
-            //
-            // ```
-            // StorageLive(_4);        // _4 is `x`
-            // _4 = &mut (_1.0: i32);  // this is handling `(mut x, 1)` case
-            // _4 = &mut (_1.1: i32);  // this is handling `(2, mut x)` case
-            // ```
-            //
-            // and that is clearly not correct.
-            let by_value_bindings = candidate.bindings.iter().filter(|binding| {
-                if let BindingMode::ByValue = binding.binding_mode { true } else { false }
-            });
-            // Read all of the by reference bindings to ensure that the
-            // place they refer to can't be modified by the guard.
-            for binding in by_value_bindings.clone() {
-                let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
-                let cause = FakeReadCause::ForGuardBinding;
-                self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id));
-            }
-            self.bind_matched_candidate_for_arm_body(post_guard_block, by_value_bindings);
-
-            post_guard_block
-        } else {
-            assert!(candidate.otherwise_block.is_none());
-            // (Here, it is not too early to bind the matched
-            // candidate on `block`, because there is no guard result
-            // that we have to inspect before we bind them.)
-            self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
-            block
-        }
-    }
-
-    /// Append `AscribeUserType` statements onto the end of `block`
-    /// for each ascription
-    fn ascribe_types(&mut self, block: BasicBlock, ascriptions: &[Ascription<'tcx>]) {
-        for ascription in ascriptions {
-            let source_info = self.source_info(ascription.span);
-
-            debug!(
-                "adding user ascription at span {:?} of place {:?} and {:?}",
-                source_info.span, ascription.source, ascription.user_ty,
-            );
-
-            let user_ty = ascription.user_ty.clone().user_ty(
-                &mut self.canonical_user_type_annotations,
-                ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
-                source_info.span,
-            );
-            self.cfg.push(
-                block,
-                Statement {
-                    source_info,
-                    kind: StatementKind::AscribeUserType(
-                        box (ascription.source.clone(), user_ty),
-                        ascription.variance,
-                    ),
-                },
-            );
-        }
-    }
-
-    fn bind_matched_candidate_for_guard(&mut self, block: BasicBlock, bindings: &[Binding<'tcx>]) {
-        debug!("bind_matched_candidate_for_guard(block={:?}, bindings={:?})", block, bindings);
-
-        // Assign each of the bindings. Since we are binding for a
-        // guard expression, this will never trigger moves out of the
-        // candidate.
-        let re_erased = self.hir.tcx().lifetimes.re_erased;
-        for binding in bindings {
-            let source_info = self.source_info(binding.span);
-
-            // For each pattern ident P of type T, `ref_for_guard` is
-            // a reference R: &T pointing to the location matched by
-            // the pattern, and every occurrence of P within a guard
-            // denotes *R.
-            let ref_for_guard =
-                self.storage_live_binding(block, binding.var_id, binding.span, RefWithinGuard);
-            match binding.binding_mode {
-                BindingMode::ByValue => {
-                    let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source.clone());
-                    self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
-                }
-                BindingMode::ByRef(borrow_kind) => {
-                    let value_for_arm = self.storage_live_binding(
-                        block,
-                        binding.var_id,
-                        binding.span,
-                        OutsideGuard,
-                    );
-
-                    let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source.clone());
-                    self.cfg.push_assign(block, source_info, &value_for_arm, rvalue);
-                    let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
-                    self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
-                }
-            }
-        }
-    }
-
-    fn bind_matched_candidate_for_arm_body<'b>(
-        &mut self,
-        block: BasicBlock,
-        bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
-    ) where
-        'tcx: 'b,
-    {
-        debug!("bind_matched_candidate_for_arm_body(block={:?})", block);
-
-        let re_erased = self.hir.tcx().lifetimes.re_erased;
-        // Assign each of the bindings. This may trigger moves out of the candidate.
-        for binding in bindings {
-            let source_info = self.source_info(binding.span);
-            let local =
-                self.storage_live_binding(block, binding.var_id, binding.span, OutsideGuard);
-            self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
-            let rvalue = match binding.binding_mode {
-                BindingMode::ByValue => {
-                    Rvalue::Use(self.consume_by_copy_or_move(binding.source.clone()))
-                }
-                BindingMode::ByRef(borrow_kind) => {
-                    Rvalue::Ref(re_erased, borrow_kind, binding.source.clone())
-                }
-            };
-            self.cfg.push_assign(block, source_info, &local, rvalue);
-        }
-    }
-
-    /// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where the bound
-    /// `var` has type `T` in the arm body) in a pattern maps to 2 locals. The
-    /// first local is a binding for occurrences of `var` in the guard, which
-    /// will have type `&T`. The second local is a binding for occurrences of
-    /// `var` in the arm body, which will have type `T`.
-    fn declare_binding(
-        &mut self,
-        source_info: SourceInfo,
-        visibility_scope: SourceScope,
-        mutability: Mutability,
-        name: Name,
-        mode: BindingMode,
-        var_id: HirId,
-        var_ty: Ty<'tcx>,
-        user_ty: UserTypeProjections,
-        has_guard: ArmHasGuard,
-        opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
-        pat_span: Span,
-    ) {
-        debug!(
-            "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
-             visibility_scope={:?}, source_info={:?})",
-            var_id, name, mode, var_ty, visibility_scope, source_info
-        );
-
-        let tcx = self.hir.tcx();
-        let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
-        let binding_mode = match mode {
-            BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
-            BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability.into()),
-        };
-        debug!("declare_binding: user_ty={:?}", user_ty);
-        let local = LocalDecl::<'tcx> {
-            mutability,
-            ty: var_ty,
-            user_ty,
-            source_info,
-            internal: false,
-            is_block_tail: None,
-            local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                binding_mode,
-                // hypothetically, `visit_bindings` could try to unzip
-                // an outermost hir::Ty as we descend, matching up
-                // idents in pat; but complex w/ unclear UI payoff.
-                // Instead, just abandon providing diagnostic info.
-                opt_ty_info: None,
-                opt_match_place,
-                pat_span,
-            }))),
-        };
-        let for_arm_body = self.local_decls.push(local);
-        self.var_debug_info.push(VarDebugInfo {
-            name,
-            source_info: debug_source_info,
-            place: for_arm_body.into(),
-        });
-        let locals = if has_guard.0 {
-            let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
-                // This variable isn't mutated but has a name, so has to be
-                // immutable to avoid the unused mut lint.
-                mutability: Mutability::Not,
-                ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty),
-                user_ty: UserTypeProjections::none(),
-                source_info,
-                internal: false,
-                is_block_tail: None,
-                local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)),
-            });
-            self.var_debug_info.push(VarDebugInfo {
-                name,
-                source_info: debug_source_info,
-                place: ref_for_guard.into(),
-            });
-            LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
-        } else {
-            LocalsForNode::One(for_arm_body)
-        };
-        debug!("declare_binding: vars={:?}", locals);
-        self.var_indices.insert(var_id, locals);
-    }
-}
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
deleted file mode 100644 (file)
index 9dbf898..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-//! Simplifying Candidates
-//!
-//! *Simplifying* a match pair `place @ pattern` means breaking it down
-//! into bindings or other, simpler match pairs. For example:
-//!
-//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
-//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
-//!
-//! The `simplify_candidate` routine just repeatedly applies these
-//! sort of simplifications until there is nothing left to
-//! simplify. Match pairs cannot be simplified if they require some
-//! sort of test: for example, testing which variant an enum is, or
-//! testing a value against a constant.
-
-use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
-use crate::build::Builder;
-use crate::hair::{self, *};
-use rustc::mir::interpret::truncate;
-use rustc::ty;
-use rustc::ty::layout::{Integer, IntegerExt, Size};
-use rustc_hir::RangeEnd;
-use syntax::attr::{SignedInt, UnsignedInt};
-
-use std::mem;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) {
-        // repeatedly simplify match pairs until fixed point is reached
-        loop {
-            let match_pairs = mem::take(&mut candidate.match_pairs);
-            let mut changed = false;
-            for match_pair in match_pairs {
-                match self.simplify_match_pair(match_pair, candidate) {
-                    Ok(()) => {
-                        changed = true;
-                    }
-                    Err(match_pair) => {
-                        candidate.match_pairs.push(match_pair);
-                    }
-                }
-            }
-            if !changed {
-                return; // if we were not able to simplify any, done.
-            }
-        }
-    }
-
-    /// Tries to simplify `match_pair`, returning `Ok(())` if
-    /// successful. If successful, new match pairs and bindings will
-    /// have been pushed into the candidate. If no simplification is
-    /// possible, `Err` is returned and no changes are made to
-    /// candidate.
-    fn simplify_match_pair<'pat>(
-        &mut self,
-        match_pair: MatchPair<'pat, 'tcx>,
-        candidate: &mut Candidate<'pat, 'tcx>,
-    ) -> Result<(), MatchPair<'pat, 'tcx>> {
-        let tcx = self.hir.tcx();
-        match *match_pair.pattern.kind {
-            PatKind::AscribeUserType {
-                ref subpattern,
-                ascription: hair::pattern::Ascription { variance, ref user_ty, user_ty_span },
-            } => {
-                // Apply the type ascription to the value at `match_pair.place`, which is the
-                // value being matched, taking the variance field into account.
-                candidate.ascriptions.push(Ascription {
-                    span: user_ty_span,
-                    user_ty: user_ty.clone(),
-                    source: match_pair.place.clone(),
-                    variance,
-                });
-
-                candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
-
-                Ok(())
-            }
-
-            PatKind::Wild => {
-                // nothing left to do
-                Ok(())
-            }
-
-            PatKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
-                candidate.bindings.push(Binding {
-                    name,
-                    mutability,
-                    span: match_pair.pattern.span,
-                    source: match_pair.place.clone(),
-                    var_id: var,
-                    var_ty: ty,
-                    binding_mode: mode,
-                });
-
-                if let Some(subpattern) = subpattern.as_ref() {
-                    // this is the `x @ P` case; have to keep matching against `P` now
-                    candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
-                }
-
-                Ok(())
-            }
-
-            PatKind::Constant { .. } => {
-                // FIXME normalize patterns when possible
-                Err(match_pair)
-            }
-
-            PatKind::Range(PatRange { lo, hi, end }) => {
-                let (range, bias) = match lo.ty.kind {
-                    ty::Char => {
-                        (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
-                    }
-                    ty::Int(ity) => {
-                        let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
-                        let max = truncate(u128::max_value(), size);
-                        let bias = 1u128 << (size.bits() - 1);
-                        (Some((0, max, size)), bias)
-                    }
-                    ty::Uint(uty) => {
-                        let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
-                        let max = truncate(u128::max_value(), size);
-                        (Some((0, max, size)), 0)
-                    }
-                    _ => (None, 0),
-                };
-                if let Some((min, max, sz)) = range {
-                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
-                        // We want to compare ranges numerically, but the order of the bitwise
-                        // representation of signed integers does not match their numeric order.
-                        // Thus, to correct the ordering, we need to shift the range of signed
-                        // integers to correct the comparison. This is achieved by XORing with a
-                        // bias (see pattern/_match.rs for another pertinent example of this
-                        // pattern).
-                        let (lo, hi) = (lo ^ bias, hi ^ bias);
-                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
-                            // Irrefutable pattern match.
-                            return Ok(());
-                        }
-                    }
-                }
-                Err(match_pair)
-            }
-
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
-                    // irrefutable
-                    self.prefix_slice_suffix(
-                        &mut candidate.match_pairs,
-                        &match_pair.place,
-                        prefix,
-                        slice.as_ref(),
-                        suffix,
-                    );
-                    Ok(())
-                } else {
-                    Err(match_pair)
-                }
-            }
-
-            PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
-                let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
-                    i == variant_index || {
-                        self.hir.tcx().features().exhaustive_patterns
-                            && !v
-                                .uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind())
-                                .is_empty()
-                    }
-                }) && (adt_def.did.is_local()
-                    || !adt_def.is_variant_list_non_exhaustive());
-                if irrefutable {
-                    let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
-                    candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
-                    Ok(())
-                } else {
-                    Err(match_pair)
-                }
-            }
-
-            PatKind::Array { ref prefix, ref slice, ref suffix } => {
-                self.prefix_slice_suffix(
-                    &mut candidate.match_pairs,
-                    &match_pair.place,
-                    prefix,
-                    slice.as_ref(),
-                    suffix,
-                );
-                Ok(())
-            }
-
-            PatKind::Leaf { ref subpatterns } => {
-                // tuple struct, match subpats (if any)
-                candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
-                Ok(())
-            }
-
-            PatKind::Deref { ref subpattern } => {
-                let place = tcx.mk_place_deref(match_pair.place);
-                candidate.match_pairs.push(MatchPair::new(place, subpattern));
-                Ok(())
-            }
-
-            PatKind::Or { .. } => Err(match_pair),
-        }
-    }
-}
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
deleted file mode 100644 (file)
index afdb744..0000000
+++ /dev/null
@@ -1,835 +0,0 @@
-// Testing candidates
-//
-// After candidates have been simplified, the only match pairs that
-// remain are those that require some sort of test. The functions here
-// identify what tests are needed, perform the tests, and then filter
-// the candidates based on the result.
-
-use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
-use crate::build::Builder;
-use crate::hair::pattern::compare_const_vals;
-use crate::hair::*;
-use rustc::mir::*;
-use rustc::ty::layout::VariantIdx;
-use rustc::ty::util::IntTypeExt;
-use rustc::ty::{self, adjustment::PointerCast, Ty};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::RangeEnd;
-use rustc_index::bit_set::BitSet;
-use rustc_span::symbol::sym;
-
-use std::cmp::Ordering;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Identifies what test is needed to decide if `match_pair` is applicable.
-    ///
-    /// It is a bug to call this with a simplifiable pattern.
-    pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
-        match *match_pair.pattern.kind {
-            PatKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
-                span: match_pair.pattern.span,
-                kind: TestKind::Switch {
-                    adt_def,
-                    variants: BitSet::new_empty(adt_def.variants.len()),
-                },
-            },
-
-            PatKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
-                // For integers, we use a `SwitchInt` match, which allows
-                // us to handle more cases.
-                Test {
-                    span: match_pair.pattern.span,
-                    kind: TestKind::SwitchInt {
-                        switch_ty: match_pair.pattern.ty,
-
-                        // these maps are empty to start; cases are
-                        // added below in add_cases_to_switch
-                        options: vec![],
-                        indices: Default::default(),
-                    },
-                }
-            }
-
-            PatKind::Constant { value } => Test {
-                span: match_pair.pattern.span,
-                kind: TestKind::Eq { value, ty: match_pair.pattern.ty.clone() },
-            },
-
-            PatKind::Range(range) => {
-                assert_eq!(range.lo.ty, match_pair.pattern.ty);
-                assert_eq!(range.hi.ty, match_pair.pattern.ty);
-                Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
-            }
-
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                let len = prefix.len() + suffix.len();
-                let op = if slice.is_some() { BinOp::Ge } else { BinOp::Eq };
-                Test {
-                    span: match_pair.pattern.span,
-                    kind: TestKind::Len { len: len as u64, op: op },
-                }
-            }
-
-            PatKind::Or { .. } => self
-                .hir
-                .tcx()
-                .sess
-                .span_fatal(match_pair.pattern.span, "or-patterns are not fully implemented yet"),
-
-            PatKind::AscribeUserType { .. }
-            | PatKind::Array { .. }
-            | PatKind::Wild
-            | PatKind::Binding { .. }
-            | PatKind::Leaf { .. }
-            | PatKind::Deref { .. } => self.error_simplifyable(match_pair),
-        }
-    }
-
-    pub fn add_cases_to_switch<'pat>(
-        &mut self,
-        test_place: &Place<'tcx>,
-        candidate: &Candidate<'pat, 'tcx>,
-        switch_ty: Ty<'tcx>,
-        options: &mut Vec<u128>,
-        indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>,
-    ) -> bool {
-        let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
-            Some(match_pair) => match_pair,
-            _ => {
-                return false;
-            }
-        };
-
-        match *match_pair.pattern.kind {
-            PatKind::Constant { value } => {
-                indices.entry(value).or_insert_with(|| {
-                    options.push(value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty));
-                    options.len() - 1
-                });
-                true
-            }
-            PatKind::Variant { .. } => {
-                panic!("you should have called add_variants_to_switch instead!");
-            }
-            PatKind::Range(range) => {
-                // Check that none of the switch values are in the range.
-                self.values_not_contained_in_range(range, indices).unwrap_or(false)
-            }
-            PatKind::Slice { .. }
-            | PatKind::Array { .. }
-            | PatKind::Wild
-            | PatKind::Or { .. }
-            | PatKind::Binding { .. }
-            | PatKind::AscribeUserType { .. }
-            | PatKind::Leaf { .. }
-            | PatKind::Deref { .. } => {
-                // don't know how to add these patterns to a switch
-                false
-            }
-        }
-    }
-
-    pub fn add_variants_to_switch<'pat>(
-        &mut self,
-        test_place: &Place<'tcx>,
-        candidate: &Candidate<'pat, 'tcx>,
-        variants: &mut BitSet<VariantIdx>,
-    ) -> bool {
-        let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
-            Some(match_pair) => match_pair,
-            _ => {
-                return false;
-            }
-        };
-
-        match *match_pair.pattern.kind {
-            PatKind::Variant { adt_def: _, variant_index, .. } => {
-                // We have a pattern testing for variant `variant_index`
-                // set the corresponding index to true
-                variants.insert(variant_index);
-                true
-            }
-            _ => {
-                // don't know how to add these patterns to a switch
-                false
-            }
-        }
-    }
-
-    pub fn perform_test(
-        &mut self,
-        block: BasicBlock,
-        place: &Place<'tcx>,
-        test: &Test<'tcx>,
-        make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
-    ) {
-        debug!(
-            "perform_test({:?}, {:?}: {:?}, {:?})",
-            block,
-            place,
-            place.ty(&self.local_decls, self.hir.tcx()),
-            test
-        );
-
-        let source_info = self.source_info(test.span);
-        match test.kind {
-            TestKind::Switch { adt_def, ref variants } => {
-                let target_blocks = make_target_blocks(self);
-                // Variants is a BitVec of indexes into adt_def.variants.
-                let num_enum_variants = adt_def.variants.len();
-                let used_variants = variants.count();
-                debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
-                let otherwise_block = *target_blocks.last().unwrap();
-                let mut targets = Vec::with_capacity(used_variants + 1);
-                let mut values = Vec::with_capacity(used_variants);
-                let tcx = self.hir.tcx();
-                for (idx, discr) in adt_def.discriminants(tcx) {
-                    if variants.contains(idx) {
-                        debug_assert_ne!(
-                            target_blocks[idx.index()],
-                            otherwise_block,
-                            "no canididates for tested discriminant: {:?}",
-                            discr,
-                        );
-                        values.push(discr.val);
-                        targets.push(target_blocks[idx.index()]);
-                    } else {
-                        debug_assert_eq!(
-                            target_blocks[idx.index()],
-                            otherwise_block,
-                            "found canididates for untested discriminant: {:?}",
-                            discr,
-                        );
-                    }
-                }
-                targets.push(otherwise_block);
-                debug!(
-                    "num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
-                    num_enum_variants, values, variants
-                );
-                let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
-                let discr = self.temp(discr_ty, test.span);
-                self.cfg.push_assign(
-                    block,
-                    source_info,
-                    &discr,
-                    Rvalue::Discriminant(place.clone()),
-                );
-                assert_eq!(values.len() + 1, targets.len());
-                self.cfg.terminate(
-                    block,
-                    source_info,
-                    TerminatorKind::SwitchInt {
-                        discr: Operand::Move(discr),
-                        switch_ty: discr_ty,
-                        values: From::from(values),
-                        targets,
-                    },
-                );
-            }
-
-            TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
-                let target_blocks = make_target_blocks(self);
-                let terminator = if switch_ty.kind == ty::Bool {
-                    assert!(options.len() > 0 && options.len() <= 2);
-                    if let [first_bb, second_bb] = *target_blocks {
-                        let (true_bb, false_bb) = match options[0] {
-                            1 => (first_bb, second_bb),
-                            0 => (second_bb, first_bb),
-                            v => span_bug!(test.span, "expected boolean value but got {:?}", v),
-                        };
-                        TerminatorKind::if_(
-                            self.hir.tcx(),
-                            Operand::Copy(place.clone()),
-                            true_bb,
-                            false_bb,
-                        )
-                    } else {
-                        bug!("`TestKind::SwitchInt` on `bool` should have two targets")
-                    }
-                } else {
-                    // The switch may be inexhaustive so we have a catch all block
-                    debug_assert_eq!(options.len() + 1, target_blocks.len());
-                    TerminatorKind::SwitchInt {
-                        discr: Operand::Copy(place.clone()),
-                        switch_ty,
-                        values: options.clone().into(),
-                        targets: target_blocks,
-                    }
-                };
-                self.cfg.terminate(block, source_info, terminator);
-            }
-
-            TestKind::Eq { value, ty } => {
-                if !ty.is_scalar() {
-                    // Use `PartialEq::eq` instead of `BinOp::Eq`
-                    // (the binop can only handle primitives)
-                    self.non_scalar_compare(
-                        block,
-                        make_target_blocks,
-                        source_info,
-                        value,
-                        place,
-                        ty,
-                    );
-                } else {
-                    if let [success, fail] = *make_target_blocks(self) {
-                        assert_eq!(value.ty, ty);
-                        let expect = self.literal_operand(test.span, value);
-                        let val = Operand::Copy(place.clone());
-                        self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
-                    } else {
-                        bug!("`TestKind::Eq` should have two target blocks");
-                    }
-                }
-            }
-
-            TestKind::Range(PatRange { ref lo, ref hi, ref end }) => {
-                let lower_bound_success = self.cfg.start_new_block();
-                let target_blocks = make_target_blocks(self);
-
-                // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
-                let lo = self.literal_operand(test.span, lo);
-                let hi = self.literal_operand(test.span, hi);
-                let val = Operand::Copy(place.clone());
-
-                if let [success, fail] = *target_blocks {
-                    self.compare(
-                        block,
-                        lower_bound_success,
-                        fail,
-                        source_info,
-                        BinOp::Le,
-                        lo,
-                        val.clone(),
-                    );
-                    let op = match *end {
-                        RangeEnd::Included => BinOp::Le,
-                        RangeEnd::Excluded => BinOp::Lt,
-                    };
-                    self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
-                } else {
-                    bug!("`TestKind::Range` should have two target blocks");
-                }
-            }
-
-            TestKind::Len { len, op } => {
-                let target_blocks = make_target_blocks(self);
-
-                let usize_ty = self.hir.usize_ty();
-                let actual = self.temp(usize_ty, test.span);
-
-                // actual = len(place)
-                self.cfg.push_assign(block, source_info, &actual, Rvalue::Len(place.clone()));
-
-                // expected = <N>
-                let expected = self.push_usize(block, source_info, len);
-
-                if let [true_bb, false_bb] = *target_blocks {
-                    // result = actual == expected OR result = actual < expected
-                    // branch based on result
-                    self.compare(
-                        block,
-                        true_bb,
-                        false_bb,
-                        source_info,
-                        op,
-                        Operand::Move(actual),
-                        Operand::Move(expected),
-                    );
-                } else {
-                    bug!("`TestKind::Len` should have two target blocks");
-                }
-            }
-        }
-    }
-
-    /// Compare using the provided built-in comparison operator
-    fn compare(
-        &mut self,
-        block: BasicBlock,
-        success_block: BasicBlock,
-        fail_block: BasicBlock,
-        source_info: SourceInfo,
-        op: BinOp,
-        left: Operand<'tcx>,
-        right: Operand<'tcx>,
-    ) {
-        let bool_ty = self.hir.bool_ty();
-        let result = self.temp(bool_ty, source_info.span);
-
-        // result = op(left, right)
-        self.cfg.push_assign(block, source_info, &result, Rvalue::BinaryOp(op, left, right));
-
-        // branch based on result
-        self.cfg.terminate(
-            block,
-            source_info,
-            TerminatorKind::if_(self.hir.tcx(), Operand::Move(result), success_block, fail_block),
-        );
-    }
-
-    /// Compare two `&T` values using `<T as std::compare::PartialEq>::eq`
-    fn non_scalar_compare(
-        &mut self,
-        block: BasicBlock,
-        make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
-        source_info: SourceInfo,
-        value: &'tcx ty::Const<'tcx>,
-        place: &Place<'tcx>,
-        mut ty: Ty<'tcx>,
-    ) {
-        use rustc::middle::lang_items::EqTraitLangItem;
-
-        let mut expect = self.literal_operand(source_info.span, value);
-        let mut val = Operand::Copy(place.clone());
-
-        // If we're using `b"..."` as a pattern, we need to insert an
-        // unsizing coercion, as the byte string has the type `&[u8; N]`.
-        //
-        // We want to do this even when the scrutinee is a reference to an
-        // array, so we can call `<[u8]>::eq` rather than having to find an
-        // `<[u8; N]>::eq`.
-        let unsize = |ty: Ty<'tcx>| match ty.kind {
-            ty::Ref(region, rty, _) => match rty.kind {
-                ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
-                _ => None,
-            },
-            _ => None,
-        };
-        let opt_ref_ty = unsize(ty);
-        let opt_ref_test_ty = unsize(value.ty);
-        match (opt_ref_ty, opt_ref_test_ty) {
-            // nothing to do, neither is an array
-            (None, None) => {}
-            (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
-                let tcx = self.hir.tcx();
-                // make both a slice
-                ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
-                if opt_ref_ty.is_some() {
-                    let temp = self.temp(ty, source_info.span);
-                    self.cfg.push_assign(
-                        block,
-                        source_info,
-                        &temp,
-                        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty),
-                    );
-                    val = Operand::Move(temp);
-                }
-                if opt_ref_test_ty.is_some() {
-                    let slice = self.temp(ty, source_info.span);
-                    self.cfg.push_assign(
-                        block,
-                        source_info,
-                        &slice,
-                        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), expect, ty),
-                    );
-                    expect = Operand::Move(slice);
-                }
-            }
-        }
-
-        let deref_ty = match ty.kind {
-            ty::Ref(_, deref_ty, _) => deref_ty,
-            _ => bug!("non_scalar_compare called on non-reference type: {}", ty),
-        };
-
-        let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem, None);
-        let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]);
-
-        let bool_ty = self.hir.bool_ty();
-        let eq_result = self.temp(bool_ty, source_info.span);
-        let eq_block = self.cfg.start_new_block();
-        let cleanup = self.diverge_cleanup();
-        self.cfg.terminate(
-            block,
-            source_info,
-            TerminatorKind::Call {
-                func: Operand::Constant(box Constant {
-                    span: source_info.span,
-
-                    // FIXME(#54571): This constant comes from user input (a
-                    // constant in a pattern).  Are there forms where users can add
-                    // type annotations here?  For example, an associated constant?
-                    // Need to experiment.
-                    user_ty: None,
-
-                    literal: method,
-                }),
-                args: vec![val, expect],
-                destination: Some((eq_result.clone(), eq_block)),
-                cleanup: Some(cleanup),
-                from_hir_call: false,
-            },
-        );
-
-        if let [success_block, fail_block] = *make_target_blocks(self) {
-            // check the result
-            self.cfg.terminate(
-                eq_block,
-                source_info,
-                TerminatorKind::if_(
-                    self.hir.tcx(),
-                    Operand::Move(eq_result),
-                    success_block,
-                    fail_block,
-                ),
-            );
-        } else {
-            bug!("`TestKind::Eq` should have two target blocks")
-        }
-    }
-
-    /// Given that we are performing `test` against `test_place`, this job
-    /// sorts out what the status of `candidate` will be after the test. See
-    /// `test_candidates` for the usage of this function. The returned index is
-    /// the index that this candidate should be placed in the
-    /// `target_candidates` vec. The candidate may be modified to update its
-    /// `match_pairs`.
-    ///
-    /// So, for example, if this candidate is `x @ Some(P0)` and the `Test` is
-    /// a variant test, then we would modify the candidate to be `(x as
-    /// Option).0 @ P0` and return the index corresponding to the variant
-    /// `Some`.
-    ///
-    /// However, in some cases, the test may just not be relevant to candidate.
-    /// For example, suppose we are testing whether `foo.x == 22`, but in one
-    /// match arm we have `Foo { x: _, ... }`... in that case, the test for
-    /// what value `x` has has no particular relevance to this candidate. In
-    /// such cases, this function just returns None without doing anything.
-    /// This is used by the overall `match_candidates` algorithm to structure
-    /// the match as a whole. See `match_candidates` for more details.
-    ///
-    /// FIXME(#29623). In some cases, we have some tricky choices to make.  for
-    /// example, if we are testing that `x == 22`, but the candidate is `x @
-    /// 13..55`, what should we do? In the event that the test is true, we know
-    /// that the candidate applies, but in the event of false, we don't know
-    /// that it *doesn't* apply. For now, we return false, indicate that the
-    /// test does not apply to this candidate, but it might be we can get
-    /// tighter match code if we do something a bit different.
-    pub fn sort_candidate<'pat>(
-        &mut self,
-        test_place: &Place<'tcx>,
-        test: &Test<'tcx>,
-        candidate: &mut Candidate<'pat, 'tcx>,
-    ) -> Option<usize> {
-        // Find the match_pair for this place (if any). At present,
-        // afaik, there can be at most one. (In the future, if we
-        // adopted a more general `@` operator, there might be more
-        // than one, but it'd be very unusual to have two sides that
-        // both require tests; you'd expect one side to be simplified
-        // away.)
-        let (match_pair_index, match_pair) =
-            candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
-
-        match (&test.kind, &*match_pair.pattern.kind) {
-            // If we are performing a variant switch, then this
-            // informs variant patterns, but nothing else.
-            (
-                &TestKind::Switch { adt_def: tested_adt_def, .. },
-                &PatKind::Variant { adt_def, variant_index, ref subpatterns, .. },
-            ) => {
-                assert_eq!(adt_def, tested_adt_def);
-                self.candidate_after_variant_switch(
-                    match_pair_index,
-                    adt_def,
-                    variant_index,
-                    subpatterns,
-                    candidate,
-                );
-                Some(variant_index.as_usize())
-            }
-
-            (&TestKind::Switch { .. }, _) => None,
-
-            // If we are performing a switch over integers, then this informs integer
-            // equality, but nothing else.
-            //
-            // FIXME(#29623) we could use PatKind::Range to rule
-            // things out here, in some cases.
-            (
-                &TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
-                &PatKind::Constant { ref value },
-            ) if is_switch_ty(match_pair.pattern.ty) => {
-                let index = indices[value];
-                self.candidate_without_match_pair(match_pair_index, candidate);
-                Some(index)
-            }
-
-            (
-                &TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
-                &PatKind::Range(range),
-            ) => {
-                let not_contained =
-                    self.values_not_contained_in_range(range, indices).unwrap_or(false);
-
-                if not_contained {
-                    // No switch values are contained in the pattern range,
-                    // so the pattern can be matched only if this test fails.
-                    let otherwise = options.len();
-                    Some(otherwise)
-                } else {
-                    None
-                }
-            }
-
-            (&TestKind::SwitchInt { .. }, _) => None,
-
-            (
-                &TestKind::Len { len: test_len, op: BinOp::Eq },
-                &PatKind::Slice { ref prefix, ref slice, ref suffix },
-            ) => {
-                let pat_len = (prefix.len() + suffix.len()) as u64;
-                match (test_len.cmp(&pat_len), slice) {
-                    (Ordering::Equal, &None) => {
-                        // on true, min_len = len = $actual_length,
-                        // on false, len != $actual_length
-                        self.candidate_after_slice_test(
-                            match_pair_index,
-                            candidate,
-                            prefix,
-                            slice.as_ref(),
-                            suffix,
-                        );
-                        Some(0)
-                    }
-                    (Ordering::Less, _) => {
-                        // test_len < pat_len. If $actual_len = test_len,
-                        // then $actual_len < pat_len and we don't have
-                        // enough elements.
-                        Some(1)
-                    }
-                    (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
-                        // This can match both if $actual_len = test_len >= pat_len,
-                        // and if $actual_len > test_len. We can't advance.
-                        None
-                    }
-                    (Ordering::Greater, &None) => {
-                        // test_len != pat_len, so if $actual_len = test_len, then
-                        // $actual_len != pat_len.
-                        Some(1)
-                    }
-                }
-            }
-
-            (
-                &TestKind::Len { len: test_len, op: BinOp::Ge },
-                &PatKind::Slice { ref prefix, ref slice, ref suffix },
-            ) => {
-                // the test is `$actual_len >= test_len`
-                let pat_len = (prefix.len() + suffix.len()) as u64;
-                match (test_len.cmp(&pat_len), slice) {
-                    (Ordering::Equal, &Some(_)) => {
-                        // $actual_len >= test_len = pat_len,
-                        // so we can match.
-                        self.candidate_after_slice_test(
-                            match_pair_index,
-                            candidate,
-                            prefix,
-                            slice.as_ref(),
-                            suffix,
-                        );
-                        Some(0)
-                    }
-                    (Ordering::Less, _) | (Ordering::Equal, &None) => {
-                        // test_len <= pat_len. If $actual_len < test_len,
-                        // then it is also < pat_len, so the test passing is
-                        // necessary (but insufficient).
-                        Some(0)
-                    }
-                    (Ordering::Greater, &None) => {
-                        // test_len > pat_len. If $actual_len >= test_len > pat_len,
-                        // then we know we won't have a match.
-                        Some(1)
-                    }
-                    (Ordering::Greater, &Some(_)) => {
-                        // test_len < pat_len, and is therefore less
-                        // strict. This can still go both ways.
-                        None
-                    }
-                }
-            }
-
-            (&TestKind::Range(test), &PatKind::Range(pat)) => {
-                if test == pat {
-                    self.candidate_without_match_pair(match_pair_index, candidate);
-                    return Some(0);
-                }
-
-                let no_overlap = (|| {
-                    use rustc_hir::RangeEnd::*;
-                    use std::cmp::Ordering::*;
-
-                    let tcx = self.hir.tcx();
-
-                    let test_ty = test.lo.ty;
-                    let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test_ty)?;
-                    let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test_ty)?;
-
-                    match (test.end, pat.end, lo, hi) {
-                        // pat < test
-                        (_, _, Greater, _) |
-                        (_, Excluded, Equal, _) |
-                        // pat > test
-                        (_, _, _, Less) |
-                        (Excluded, _, _, Equal) => Some(true),
-                        _ => Some(false),
-                    }
-                })();
-
-                if let Some(true) = no_overlap {
-                    // Testing range does not overlap with pattern range,
-                    // so the pattern can be matched only if this test fails.
-                    Some(1)
-                } else {
-                    None
-                }
-            }
-
-            (&TestKind::Range(range), &PatKind::Constant { value }) => {
-                if let Some(false) = self.const_range_contains(range, value) {
-                    // `value` is not contained in the testing range,
-                    // so `value` can be matched only if this test fails.
-                    Some(1)
-                } else {
-                    None
-                }
-            }
-
-            (&TestKind::Range { .. }, _) => None,
-
-            (&TestKind::Eq { .. }, _) | (&TestKind::Len { .. }, _) => {
-                // These are all binary tests.
-                //
-                // FIXME(#29623) we can be more clever here
-                let pattern_test = self.test(&match_pair);
-                if pattern_test.kind == test.kind {
-                    self.candidate_without_match_pair(match_pair_index, candidate);
-                    Some(0)
-                } else {
-                    None
-                }
-            }
-        }
-    }
-
-    fn candidate_without_match_pair(
-        &mut self,
-        match_pair_index: usize,
-        candidate: &mut Candidate<'_, 'tcx>,
-    ) {
-        candidate.match_pairs.remove(match_pair_index);
-    }
-
-    fn candidate_after_slice_test<'pat>(
-        &mut self,
-        match_pair_index: usize,
-        candidate: &mut Candidate<'pat, 'tcx>,
-        prefix: &'pat [Pat<'tcx>],
-        opt_slice: Option<&'pat Pat<'tcx>>,
-        suffix: &'pat [Pat<'tcx>],
-    ) {
-        let removed_place = candidate.match_pairs.remove(match_pair_index).place;
-        self.prefix_slice_suffix(
-            &mut candidate.match_pairs,
-            &removed_place,
-            prefix,
-            opt_slice,
-            suffix,
-        );
-    }
-
-    fn candidate_after_variant_switch<'pat>(
-        &mut self,
-        match_pair_index: usize,
-        adt_def: &'tcx ty::AdtDef,
-        variant_index: VariantIdx,
-        subpatterns: &'pat [FieldPat<'tcx>],
-        candidate: &mut Candidate<'pat, 'tcx>,
-    ) {
-        let match_pair = candidate.match_pairs.remove(match_pair_index);
-        let tcx = self.hir.tcx();
-
-        // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
-        // we want to create a set of derived match-patterns like
-        // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
-        let elem = ProjectionElem::Downcast(
-            Some(adt_def.variants[variant_index].ident.name),
-            variant_index,
-        );
-        let downcast_place = tcx.mk_place_elem(match_pair.place, elem); // `(x as Variant)`
-        let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
-            // e.g., `(x as Variant).0`
-            let place =
-                tcx.mk_place_field(downcast_place.clone(), subpattern.field, subpattern.pattern.ty);
-            // e.g., `(x as Variant).0 @ P1`
-            MatchPair::new(place, &subpattern.pattern)
-        });
-
-        candidate.match_pairs.extend(consequent_match_pairs);
-    }
-
-    fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
-        span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
-    }
-
-    fn const_range_contains(
-        &self,
-        range: PatRange<'tcx>,
-        value: &'tcx ty::Const<'tcx>,
-    ) -> Option<bool> {
-        use std::cmp::Ordering::*;
-
-        let tcx = self.hir.tcx();
-
-        let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.lo.ty)?;
-        let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.lo.ty)?;
-
-        match (b, range.end) {
-            (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
-            _ => Some(false),
-        }
-    }
-
-    fn values_not_contained_in_range(
-        &self,
-        range: PatRange<'tcx>,
-        indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
-    ) -> Option<bool> {
-        for &val in indices.keys() {
-            if self.const_range_contains(range, val)? {
-                return Some(false);
-            }
-        }
-
-        Some(true)
-    }
-}
-
-impl Test<'_> {
-    pub(super) fn targets(&self) -> usize {
-        match self.kind {
-            TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => 2,
-            TestKind::Switch { adt_def, .. } => {
-                // While the switch that we generate doesn't test for all
-                // variants, we have a target for each variant and the
-                // otherwise case, and we make sure that all of the cases not
-                // specified have the same block.
-                adt_def.variants.len() + 1
-            }
-            TestKind::SwitchInt { switch_ty, ref options, .. } => {
-                if switch_ty.is_bool() {
-                    // `bool` is special cased in `perform_test` to always
-                    // branch to two blocks.
-                    2
-                } else {
-                    options.len() + 1
-                }
-            }
-        }
-    }
-}
-
-fn is_switch_ty(ty: Ty<'_>) -> bool {
-    ty.is_integral() || ty.is_char() || ty.is_bool()
-}
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
deleted file mode 100644 (file)
index b6e643a..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-use crate::build::matches::MatchPair;
-use crate::build::Builder;
-use crate::hair::*;
-use rustc::mir::*;
-use rustc::ty;
-use smallvec::SmallVec;
-use std::convert::TryInto;
-use std::u32;
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    pub fn field_match_pairs<'pat>(
-        &mut self,
-        place: Place<'tcx>,
-        subpatterns: &'pat [FieldPat<'tcx>],
-    ) -> Vec<MatchPair<'pat, 'tcx>> {
-        subpatterns
-            .iter()
-            .map(|fieldpat| {
-                let place = self.hir.tcx().mk_place_field(
-                    place.clone(),
-                    fieldpat.field,
-                    fieldpat.pattern.ty,
-                );
-                MatchPair::new(place, &fieldpat.pattern)
-            })
-            .collect()
-    }
-
-    pub fn prefix_slice_suffix<'pat>(
-        &mut self,
-        match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
-        place: &Place<'tcx>,
-        prefix: &'pat [Pat<'tcx>],
-        opt_slice: Option<&'pat Pat<'tcx>>,
-        suffix: &'pat [Pat<'tcx>],
-    ) {
-        let tcx = self.hir.tcx();
-        let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind {
-            ty::Array(_, length) => {
-                (length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), true)
-            }
-            _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
-        };
-
-        match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
-            let elem =
-                ProjectionElem::ConstantIndex { offset: idx as u32, min_length, from_end: false };
-            let place = tcx.mk_place_elem(place.clone(), elem);
-            MatchPair::new(place, subpattern)
-        }));
-
-        if let Some(subslice_pat) = opt_slice {
-            let suffix_len = suffix.len() as u32;
-            let subslice = tcx.mk_place_elem(
-                place.clone(),
-                ProjectionElem::Subslice {
-                    from: prefix.len() as u32,
-                    to: if exact_size { min_length - suffix_len } else { suffix_len },
-                    from_end: !exact_size,
-                },
-            );
-            match_pairs.push(MatchPair::new(subslice, subslice_pat));
-        }
-
-        match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
-            let end_offset = (idx + 1) as u32;
-            let elem = ProjectionElem::ConstantIndex {
-                offset: if exact_size { min_length - end_offset } else { end_offset },
-                min_length,
-                from_end: !exact_size,
-            };
-            let place = tcx.mk_place_elem(place.clone(), elem);
-            MatchPair::new(place, subpattern)
-        }));
-    }
-
-    /// Creates a false edge to `imaginary_target` and a real edge to
-    /// real_target. If `imaginary_target` is none, or is the same as the real
-    /// target, a Goto is generated instead to simplify the generated MIR.
-    pub fn false_edges(
-        &mut self,
-        from_block: BasicBlock,
-        real_target: BasicBlock,
-        imaginary_target: Option<BasicBlock>,
-        source_info: SourceInfo,
-    ) {
-        match imaginary_target {
-            Some(target) if target != real_target => {
-                self.cfg.terminate(
-                    from_block,
-                    source_info,
-                    TerminatorKind::FalseEdges { real_target, imaginary_target: target },
-                );
-            }
-            _ => self.cfg.goto(from_block, source_info, real_target),
-        }
-    }
-}
-
-impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
-    pub fn new(place: Place<'tcx>, pattern: &'pat Pat<'tcx>) -> MatchPair<'pat, 'tcx> {
-        MatchPair { place, pattern }
-    }
-}
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
deleted file mode 100644 (file)
index 7c358fe..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-//! Miscellaneous builder routines that are not specific to building any particular
-//! kind of thing.
-
-use crate::build::Builder;
-
-use rustc::ty::{self, Ty};
-
-use rustc::mir::*;
-use rustc_span::{Span, DUMMY_SP};
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    /// Adds a new temporary value of type `ty` storing the result of
-    /// evaluating `expr`.
-    ///
-    /// N.B., **No cleanup is scheduled for this temporary.** You should
-    /// call `schedule_drop` once the temporary is initialized.
-    pub fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> {
-        let temp = self.local_decls.push(LocalDecl::new_temp(ty, span));
-        let place = Place::from(temp);
-        debug!("temp: created temp {:?} with type {:?}", place, self.local_decls[temp].ty);
-        place
-    }
-
-    /// Convenience function for creating a literal operand, one
-    /// without any user type annotation.
-    pub fn literal_operand(&mut self, span: Span, literal: &'tcx ty::Const<'tcx>) -> Operand<'tcx> {
-        let constant = box Constant { span, user_ty: None, literal };
-        Operand::Constant(constant)
-    }
-
-    pub fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
-        Rvalue::Aggregate(box AggregateKind::Tuple, vec![])
-    }
-
-    // Returns a zero literal operand for the appropriate type, works for
-    // bool, char and integers.
-    pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty));
-
-        self.literal_operand(span, literal)
-    }
-
-    pub fn push_usize(
-        &mut self,
-        block: BasicBlock,
-        source_info: SourceInfo,
-        value: u64,
-    ) -> Place<'tcx> {
-        let usize_ty = self.hir.usize_ty();
-        let temp = self.temp(usize_ty, source_info.span);
-        self.cfg.push_assign_constant(
-            block,
-            source_info,
-            &temp,
-            Constant {
-                span: source_info.span,
-                user_ty: None,
-                literal: self.hir.usize_literal(value),
-            },
-        );
-        temp
-    }
-
-    pub fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
-        let tcx = self.hir.tcx();
-        let ty = place.ty(&self.local_decls, tcx).ty;
-        if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) {
-            Operand::Move(place)
-        } else {
-            Operand::Copy(place)
-        }
-    }
-}
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
deleted file mode 100644 (file)
index d6d22db..0000000
+++ /dev/null
@@ -1,976 +0,0 @@
-use crate::build;
-use crate::build::scope::DropKind;
-use crate::hair::cx::Cx;
-use crate::hair::{BindingMode, LintLevel, PatKind};
-use crate::transform::MirSource;
-use crate::util as mir_util;
-use rustc::middle::lang_items;
-use rustc::middle::region;
-use rustc::mir::*;
-use rustc::ty::subst::Subst;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_hir::{GeneratorKind, HirIdMap, Node};
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_span::symbol::kw;
-use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
-use rustc_target::spec::PanicStrategy;
-use std::u32;
-use syntax::attr::{self, UnwindAttr};
-
-use super::lints;
-
-/// Construct the MIR for a given `DefId`.
-pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
-    let id = tcx.hir().as_local_hir_id(def_id).unwrap();
-
-    // Figure out what primary body this item has.
-    let (body_id, return_ty_span) = match tcx.hir().get(id) {
-        Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => {
-            (*body_id, decl.output.span())
-        }
-        Node::Item(hir::Item {
-            kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
-            ..
-        })
-        | Node::ImplItem(hir::ImplItem {
-            kind: hir::ImplItemKind::Method(hir::FnSig { decl, .. }, body_id),
-            ..
-        })
-        | Node::TraitItem(hir::TraitItem {
-            kind:
-                hir::TraitItemKind::Method(hir::FnSig { decl, .. }, hir::TraitMethod::Provided(body_id)),
-            ..
-        }) => (*body_id, decl.output.span()),
-        Node::Item(hir::Item { kind: hir::ItemKind::Static(ty, _, body_id), .. })
-        | Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, body_id), .. })
-        | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, body_id), .. })
-        | Node::TraitItem(hir::TraitItem {
-            kind: hir::TraitItemKind::Const(ty, Some(body_id)),
-            ..
-        }) => (*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),
-    };
-
-    tcx.infer_ctxt().enter(|infcx| {
-        let cx = Cx::new(&infcx, id);
-        let body = if cx.tables().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].clone();
-            let fn_def_id = tcx.hir().local_def_id(id);
-
-            let ty = tcx.type_of(fn_def_id);
-            let mut abi = fn_sig.abi;
-            let implicit_argument = match ty.kind {
-                ty::Closure(..) => {
-                    // HACK(eddyb) Avoid having RustCall on closures,
-                    // as it adds unnecessary (and wrong) auto-tupling.
-                    abi = Abi::Rust;
-                    Some(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);
-                    Some(ArgInfo(gen_ty, None, None, None))
-                }
-                _ => None,
-            };
-
-            let safety = match fn_sig.unsafety {
-                hir::Unsafety::Normal => Safety::Safe,
-                hir::Unsafety::Unsafe => Safety::FnUnsafe,
-            };
-
-            let body = tcx.hir().body(body_id);
-            let explicit_arguments = body.params.iter().enumerate().map(|(index, arg)| {
-                let owner_id = tcx.hir().body_owner(body_id);
-                let opt_ty_info;
-                let self_arg;
-                if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) {
-                    opt_ty_info = fn_decl.inputs.get(index).map(|ty| ty.span);
-                    self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() {
-                        match fn_decl.implicit_self {
-                            hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm),
-                            hir::ImplicitSelfKind::Mut => Some(ImplicitSelfKind::Mut),
-                            hir::ImplicitSelfKind::ImmRef => Some(ImplicitSelfKind::ImmRef),
-                            hir::ImplicitSelfKind::MutRef => Some(ImplicitSelfKind::MutRef),
-                            _ => None,
-                        }
-                    } else {
-                        None
-                    };
-                } else {
-                    opt_ty_info = None;
-                    self_arg = None;
-                }
-
-                // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
-                // (as it's created inside the body itself, not passed in from outside).
-                let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() {
-                    let va_list_did =
-                        tcx.require_lang_item(lang_items::VaListTypeLangItem, Some(arg.span));
-                    let region = tcx.mk_region(ty::ReScope(region::Scope {
-                        id: body.value.hir_id.local_id,
-                        data: region::ScopeData::CallSite,
-                    }));
-
-                    tcx.type_of(va_list_did).subst(tcx, &[region.into()])
-                } else {
-                    fn_sig.inputs()[index]
-                };
-
-                ArgInfo(ty, opt_ty_info, Some(&arg), self_arg)
-            });
-
-            let arguments = implicit_argument.into_iter().chain(explicit_arguments);
-
-            let (yield_ty, return_ty) = if body.generator_kind.is_some() {
-                let gen_sig = match ty.kind {
-                    ty::Generator(gen_def_id, gen_substs, ..) => {
-                        gen_substs.as_generator().sig(gen_def_id, tcx)
-                    }
-                    _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty),
-                };
-                (Some(gen_sig.yield_ty), gen_sig.return_ty)
-            } else {
-                (None, fn_sig.output())
-            };
-
-            let mut mir = build::construct_fn(
-                cx,
-                id,
-                arguments,
-                safety,
-                abi,
-                return_ty,
-                return_ty_span,
-                body,
-            );
-            mir.yield_ty = yield_ty;
-            mir
-        } else {
-            // Get the revealed type of this const. This is *not* the adjusted
-            // type of its body, which may be a subtype of this type. For
-            // example:
-            //
-            // fn foo(_: &()) {}
-            // static X: fn(&'static ()) = foo;
-            //
-            // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
-            // is not the same as the type of X. We need the type of the return
-            // place to be the type of the constant because NLL typeck will
-            // equate them.
-
-            let return_ty = cx.tables().node_type(id);
-
-            build::construct_const(cx, body_id, return_ty, return_ty_span)
-        };
-
-        mir_util::dump_mir(tcx, None, "mir_map", &0, MirSource::item(def_id), &body, |_, _| Ok(()));
-
-        lints::check(tcx, &body, def_id);
-
-        let mut body = BodyAndCache::new(body);
-        body.ensure_predecessors();
-        body
-    })
-}
-
-///////////////////////////////////////////////////////////////////////////
-// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
-
-fn liberated_closure_env_ty(
-    tcx: TyCtxt<'_>,
-    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_def_id, closure_substs) = match closure_ty.kind {
-        ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs),
-        _ => bug!("closure expr does not have closure type: {:?}", closure_ty),
-    };
-
-    let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap();
-    tcx.liberate_late_bound_regions(closure_def_id, &closure_env_ty)
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub enum BlockFrame {
-    /// Evaluation is currently within a statement.
-    ///
-    /// Examples include:
-    /// 1. `EXPR;`
-    /// 2. `let _ = EXPR;`
-    /// 3. `let x = EXPR;`
-    Statement {
-        /// If true, then statement discards result from evaluating
-        /// the expression (such as examples 1 and 2 above).
-        ignores_expr_result: bool,
-    },
-
-    /// Evaluation is currently within the tail expression of a block.
-    ///
-    /// Example: `{ STMT_1; STMT_2; EXPR }`
-    TailExpr {
-        /// If true, then the surrounding context of the block ignores
-        /// the result of evaluating the block's tail expression.
-        ///
-        /// Example: `let _ = { STMT_1; EXPR };`
-        tail_result_is_ignored: bool,
-    },
-
-    /// Generic mark meaning that the block occurred as a subexpression
-    /// where the result might be used.
-    ///
-    /// Examples: `foo(EXPR)`, `match EXPR { ... }`
-    SubExpr,
-}
-
-impl BlockFrame {
-    fn is_tail_expr(&self) -> bool {
-        match *self {
-            BlockFrame::TailExpr { .. } => true,
-
-            BlockFrame::Statement { .. } | BlockFrame::SubExpr => false,
-        }
-    }
-    fn is_statement(&self) -> bool {
-        match *self {
-            BlockFrame::Statement { .. } => true,
-
-            BlockFrame::TailExpr { .. } | BlockFrame::SubExpr => false,
-        }
-    }
-}
-
-#[derive(Debug)]
-struct BlockContext(Vec<BlockFrame>);
-
-struct Builder<'a, 'tcx> {
-    hir: Cx<'a, 'tcx>,
-    cfg: CFG<'tcx>,
-
-    fn_span: Span,
-    arg_count: usize,
-    generator_kind: Option<GeneratorKind>,
-
-    /// The current set of scopes, updated as we traverse;
-    /// see the `scope` module for more details.
-    scopes: scope::Scopes<'tcx>,
-
-    /// The block-context: each time we build the code within an hair::Block,
-    /// we push a frame here tracking whether we are building a statement or
-    /// if we are pushing the tail expression of the block. This is used to
-    /// embed information in generated temps about whether they were created
-    /// for a block tail expression or not.
-    ///
-    /// It would be great if we could fold this into `self.scopes`
-    /// somehow, but right now I think that is very tightly tied to
-    /// the code generation in ways that we cannot (or should not)
-    /// start just throwing new entries onto that vector in order to
-    /// distinguish the context of EXPR1 from the context of EXPR2 in
-    /// `{ STMTS; EXPR1 } + EXPR2`.
-    block_context: BlockContext,
-
-    /// The current unsafe block in scope, even if it is hidden by
-    /// a `PushUnsafeBlock`.
-    unpushed_unsafe: Safety,
-
-    /// The number of `push_unsafe_block` levels in scope.
-    push_unsafe_count: usize,
-
-    /// The vector of all scopes that we have created thus far;
-    /// we track this for debuginfo later.
-    source_scopes: IndexVec<SourceScope, SourceScopeData>,
-    source_scope: SourceScope,
-
-    /// The guard-context: each time we build the guard expression for
-    /// a match arm, we push onto this stack, and then pop when we
-    /// finish building it.
-    guard_context: Vec<GuardFrame>,
-
-    /// Maps `HirId`s of variable bindings to the `Local`s created for them.
-    /// (A match binding can have two locals; the 2nd is for the arm's guard.)
-    var_indices: HirIdMap<LocalsForNode>,
-    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
-    canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
-    upvar_mutbls: Vec<Mutability>,
-    unit_temp: Option<Place<'tcx>>,
-
-    var_debug_info: Vec<VarDebugInfo<'tcx>>,
-
-    /// Cached block with the `RESUME` terminator; this is created
-    /// when first set of cleanups are built.
-    cached_resume_block: Option<BasicBlock>,
-    /// Cached block with the `RETURN` terminator.
-    cached_return_block: Option<BasicBlock>,
-    /// Cached block with the `UNREACHABLE` terminator.
-    cached_unreachable_block: Option<BasicBlock>,
-}
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool {
-        self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
-    }
-
-    fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local {
-        self.var_indices[&id].local_id(for_guard)
-    }
-}
-
-impl BlockContext {
-    fn new() -> Self {
-        BlockContext(vec![])
-    }
-    fn push(&mut self, bf: BlockFrame) {
-        self.0.push(bf);
-    }
-    fn pop(&mut self) -> Option<BlockFrame> {
-        self.0.pop()
-    }
-
-    /// Traverses the frames on the `BlockContext`, searching for either
-    /// the first block-tail expression frame with no intervening
-    /// statement frame.
-    ///
-    /// Notably, this skips over `SubExpr` frames; this method is
-    /// meant to be used in the context of understanding the
-    /// relationship of a temp (created within some complicated
-    /// expression) with its containing expression, and whether the
-    /// value of that *containing expression* (not the temp!) is
-    /// ignored.
-    fn currently_in_block_tail(&self) -> Option<BlockTailInfo> {
-        for bf in self.0.iter().rev() {
-            match bf {
-                BlockFrame::SubExpr => continue,
-                BlockFrame::Statement { .. } => break,
-                &BlockFrame::TailExpr { tail_result_is_ignored } => {
-                    return Some(BlockTailInfo { tail_result_is_ignored });
-                }
-            }
-        }
-
-        return None;
-    }
-
-    /// Looks at the topmost frame on the BlockContext and reports
-    /// whether its one that would discard a block tail result.
-    ///
-    /// Unlike `currently_within_ignored_tail_expression`, this does
-    /// *not* skip over `SubExpr` frames: here, we want to know
-    /// whether the block result itself is discarded.
-    fn currently_ignores_tail_results(&self) -> bool {
-        match self.0.last() {
-            // no context: conservatively assume result is read
-            None => false,
-
-            // sub-expression: block result feeds into some computation
-            Some(BlockFrame::SubExpr) => false,
-
-            // otherwise: use accumulated is_ignored state.
-            Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored })
-            | Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored,
-        }
-    }
-}
-
-#[derive(Debug)]
-enum LocalsForNode {
-    /// In the usual case, a `HirId` for an identifier maps to at most
-    /// one `Local` declaration.
-    One(Local),
-
-    /// The exceptional case is identifiers in a match arm's pattern
-    /// that are referenced in a guard of that match arm. For these,
-    /// we have `2` Locals.
-    ///
-    /// * `for_arm_body` is the Local used in the arm body (which is
-    ///   just like the `One` case above),
-    ///
-    /// * `ref_for_guard` is the Local used in the arm's guard (which
-    ///   is a reference to a temp that is an alias of
-    ///   `for_arm_body`).
-    ForGuard { ref_for_guard: Local, for_arm_body: Local },
-}
-
-#[derive(Debug)]
-struct GuardFrameLocal {
-    id: hir::HirId,
-}
-
-impl GuardFrameLocal {
-    fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self {
-        GuardFrameLocal { id: id }
-    }
-}
-
-#[derive(Debug)]
-struct GuardFrame {
-    /// These are the id's of names that are bound by patterns of the
-    /// arm of *this* guard.
-    ///
-    /// (Frames higher up the stack will have the id's bound in arms
-    /// further out, such as in a case like:
-    ///
-    /// match E1 {
-    ///      P1(id1) if (... (match E2 { P2(id2) if ... => B2 })) => B1,
-    /// }
-    ///
-    /// here, when building for FIXME.
-    locals: Vec<GuardFrameLocal>,
-}
-
-/// `ForGuard` indicates whether we are talking about:
-///   1. The variable for use outside of guard expressions, or
-///   2. The temp that holds reference to (1.), which is actually what the
-///      guard expressions see.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum ForGuard {
-    RefWithinGuard,
-    OutsideGuard,
-}
-
-impl LocalsForNode {
-    fn local_id(&self, for_guard: ForGuard) -> Local {
-        match (self, for_guard) {
-            (&LocalsForNode::One(local_id), ForGuard::OutsideGuard)
-            | (
-                &LocalsForNode::ForGuard { ref_for_guard: local_id, .. },
-                ForGuard::RefWithinGuard,
-            )
-            | (&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => {
-                local_id
-            }
-
-            (&LocalsForNode::One(_), ForGuard::RefWithinGuard) => {
-                bug!("anything with one local should never be within a guard.")
-            }
-        }
-    }
-}
-
-struct CFG<'tcx> {
-    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-}
-
-rustc_index::newtype_index! {
-    pub struct ScopeId { .. }
-}
-
-///////////////////////////////////////////////////////////////////////////
-/// The `BlockAnd` "monad" packages up the new basic block along with a
-/// produced value (sometimes just unit, of course). The `unpack!`
-/// macro (and methods below) makes working with `BlockAnd` much more
-/// convenient.
-
-#[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
-struct BlockAnd<T>(BasicBlock, T);
-
-trait BlockAndExtension {
-    fn and<T>(self, v: T) -> BlockAnd<T>;
-    fn unit(self) -> BlockAnd<()>;
-}
-
-impl BlockAndExtension for BasicBlock {
-    fn and<T>(self, v: T) -> BlockAnd<T> {
-        BlockAnd(self, v)
-    }
-
-    fn unit(self) -> BlockAnd<()> {
-        BlockAnd(self, ())
-    }
-}
-
-/// Update a block pointer and return the value.
-/// Use it like `let x = unpack!(block = self.foo(block, foo))`.
-macro_rules! unpack {
-    ($x:ident = $c:expr) => {{
-        let BlockAnd(b, v) = $c;
-        $x = b;
-        v
-    }};
-
-    ($c:expr) => {{
-        let BlockAnd(b, ()) = $c;
-        b
-    }};
-}
-
-fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, _abi: Abi) -> bool {
-    // Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
-    let attrs = &tcx.get_attrs(fn_def_id);
-    let unwind_attr = attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs);
-
-    // We never unwind, so it's not relevant to stop an unwind.
-    if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
-        return false;
-    }
-
-    // We cannot add landing pads, so don't add one.
-    if tcx.sess.no_landing_pads() {
-        return false;
-    }
-
-    // This is a special case: some functions have a C abi but are meant to
-    // unwind anyway. Don't stop them.
-    match unwind_attr {
-        None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)`
-        Some(UnwindAttr::Allowed) => false,
-        Some(UnwindAttr::Aborts) => true,
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-/// the main entry point for building MIR for a function
-
-struct ArgInfo<'tcx>(
-    Ty<'tcx>,
-    Option<Span>,
-    Option<&'tcx hir::Param<'tcx>>,
-    Option<ImplicitSelfKind>,
-);
-
-fn construct_fn<'a, 'tcx, A>(
-    hir: Cx<'a, 'tcx>,
-    fn_id: hir::HirId,
-    arguments: A,
-    safety: Safety,
-    abi: Abi,
-    return_ty: Ty<'tcx>,
-    return_ty_span: Span,
-    body: &'tcx hir::Body<'tcx>,
-) -> Body<'tcx>
-where
-    A: Iterator<Item = ArgInfo<'tcx>>,
-{
-    let arguments: Vec<_> = arguments.collect();
-
-    let tcx = hir.tcx();
-    let tcx_hir = tcx.hir();
-    let span = tcx_hir.span(fn_id);
-
-    let fn_def_id = tcx_hir.local_def_id(fn_id);
-
-    let mut builder = Builder::new(
-        hir,
-        span,
-        arguments.len(),
-        safety,
-        return_ty,
-        return_ty_span,
-        body.generator_kind,
-    );
-
-    let call_site_scope =
-        region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite };
-    let arg_scope =
-        region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Arguments };
-    let mut block = START_BLOCK;
-    let source_info = builder.source_info(span);
-    let call_site_s = (call_site_scope, source_info);
-    unpack!(
-        block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
-            if should_abort_on_panic(tcx, fn_def_id, abi) {
-                builder.schedule_abort();
-            }
-
-            let arg_scope_s = (arg_scope, source_info);
-            // `return_block` is called when we evaluate a `return` expression, so
-            // we just use `START_BLOCK` here.
-            unpack!(
-                block = builder.in_breakable_scope(
-                    None,
-                    START_BLOCK,
-                    Place::return_place(),
-                    |builder| {
-                        builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
-                            builder.args_and_body(
-                                block,
-                                fn_def_id,
-                                &arguments,
-                                arg_scope,
-                                &body.value,
-                            )
-                        })
-                    },
-                )
-            );
-            // Attribute epilogue to function's closing brace
-            let fn_end = span.shrink_to_hi();
-            let source_info = builder.source_info(fn_end);
-            let return_block = builder.return_block();
-            builder.cfg.goto(block, source_info, return_block);
-            builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
-            // Attribute any unreachable codepaths to the function's closing brace
-            if let Some(unreachable_block) = builder.cached_unreachable_block {
-                builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable);
-            }
-            return_block.unit()
-        })
-    );
-    assert_eq!(block, builder.return_block());
-
-    let mut spread_arg = None;
-    if abi == Abi::RustCall {
-        // RustCall pseudo-ABI untuples the last argument.
-        spread_arg = Some(Local::new(arguments.len()));
-    }
-    debug!("fn_id {:?} has attrs {:?}", fn_def_id, tcx.get_attrs(fn_def_id));
-
-    let mut body = builder.finish();
-    body.spread_arg = spread_arg;
-    body
-}
-
-fn construct_const<'a, 'tcx>(
-    hir: Cx<'a, 'tcx>,
-    body_id: hir::BodyId,
-    const_ty: Ty<'tcx>,
-    const_ty_span: Span,
-) -> Body<'tcx> {
-    let tcx = hir.tcx();
-    let owner_id = tcx.hir().body_owner(body_id);
-    let span = tcx.hir().span(owner_id);
-    let mut builder = Builder::new(hir, span, 0, Safety::Safe, const_ty, const_ty_span, None);
-
-    let mut block = START_BLOCK;
-    let ast_expr = &tcx.hir().body(body_id).value;
-    let expr = builder.hir.mirror(ast_expr);
-    unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
-
-    let source_info = builder.source_info(span);
-    builder.cfg.terminate(block, source_info, TerminatorKind::Return);
-
-    // Constants can't `return` so a return block should not be created.
-    assert_eq!(builder.cached_return_block, None);
-
-    // Constants may be match expressions in which case an unreachable block may
-    // be created, so terminate it properly.
-    if let Some(unreachable_block) = builder.cached_unreachable_block {
-        builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable);
-    }
-
-    builder.finish()
-}
-
-fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> {
-    let owner_id = hir.tcx().hir().body_owner(body_id);
-    let span = hir.tcx().hir().span(owner_id);
-    let ty = hir.tcx().types.err;
-    let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, None);
-    let source_info = builder.source_info(span);
-    builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
-    builder.finish()
-}
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    fn new(
-        hir: Cx<'a, 'tcx>,
-        span: Span,
-        arg_count: usize,
-        safety: Safety,
-        return_ty: Ty<'tcx>,
-        return_span: Span,
-        generator_kind: Option<GeneratorKind>,
-    ) -> Builder<'a, 'tcx> {
-        let lint_level = LintLevel::Explicit(hir.root_lint_level);
-        let mut builder = Builder {
-            hir,
-            cfg: CFG { basic_blocks: IndexVec::new() },
-            fn_span: span,
-            arg_count,
-            generator_kind,
-            scopes: Default::default(),
-            block_context: BlockContext::new(),
-            source_scopes: IndexVec::new(),
-            source_scope: OUTERMOST_SOURCE_SCOPE,
-            guard_context: vec![],
-            push_unsafe_count: 0,
-            unpushed_unsafe: safety,
-            local_decls: IndexVec::from_elem_n(
-                LocalDecl::new_return_place(return_ty, return_span),
-                1,
-            ),
-            canonical_user_type_annotations: IndexVec::new(),
-            upvar_mutbls: vec![],
-            var_indices: Default::default(),
-            unit_temp: None,
-            var_debug_info: vec![],
-            cached_resume_block: None,
-            cached_return_block: None,
-            cached_unreachable_block: None,
-        };
-
-        assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
-        assert_eq!(
-            builder.new_source_scope(span, lint_level, Some(safety)),
-            OUTERMOST_SOURCE_SCOPE
-        );
-        builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
-
-        builder
-    }
-
-    fn finish(self) -> Body<'tcx> {
-        for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
-            if block.terminator.is_none() {
-                span_bug!(self.fn_span, "no terminator on block {:?}", index);
-            }
-        }
-
-        Body::new(
-            self.cfg.basic_blocks,
-            self.source_scopes,
-            self.local_decls,
-            self.canonical_user_type_annotations,
-            self.arg_count,
-            self.var_debug_info,
-            self.fn_span,
-            self.hir.control_flow_destroyed(),
-            self.generator_kind,
-        )
-    }
-
-    fn args_and_body(
-        &mut self,
-        mut block: BasicBlock,
-        fn_def_id: DefId,
-        arguments: &[ArgInfo<'tcx>],
-        argument_scope: region::Scope,
-        ast_body: &'tcx hir::Expr<'tcx>,
-    ) -> BlockAnd<()> {
-        // Allocate locals for the function arguments
-        for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
-            let source_info = SourceInfo {
-                scope: OUTERMOST_SOURCE_SCOPE,
-                span: arg_opt.map_or(self.fn_span, |arg| arg.pat.span),
-            };
-            let arg_local = self.local_decls.push(LocalDecl {
-                mutability: Mutability::Mut,
-                ty,
-                user_ty: UserTypeProjections::none(),
-                source_info,
-                internal: false,
-                local_info: LocalInfo::Other,
-                is_block_tail: None,
-            });
-
-            // If this is a simple binding pattern, give debuginfo a nice name.
-            if let Some(arg) = arg_opt {
-                if let Some(ident) = arg.pat.simple_ident() {
-                    self.var_debug_info.push(VarDebugInfo {
-                        name: ident.name,
-                        source_info,
-                        place: arg_local.into(),
-                    });
-                }
-            }
-        }
-
-        let tcx = self.hir.tcx();
-        let tcx_hir = tcx.hir();
-        let hir_tables = self.hir.tables();
-
-        // In analyze_closure() in upvar.rs we gathered a list of upvars used by a
-        // closure and we stored in a map called upvar_list in TypeckTables indexed
-        // 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.upvar_list.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;
-            if let ty::Ref(_, ty, _) = closure_ty.kind {
-                closure_env_projs.push(ProjectionElem::Deref);
-                closure_ty = ty;
-            }
-            let (def_id, upvar_substs) = match closure_ty.kind {
-                ty::Closure(def_id, substs) => (def_id, ty::UpvarSubsts::Closure(substs)),
-                ty::Generator(def_id, substs, _) => (def_id, ty::UpvarSubsts::Generator(substs)),
-                _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty),
-            };
-            let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
-            let upvars_with_tys = upvars.iter().zip(upvar_tys);
-            self.upvar_mutbls = upvars_with_tys
-                .enumerate()
-                .map(|(i, ((&var_id, &upvar_id), ty))| {
-                    let capture = hir_tables.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) {
-                                Some(ty::BindByValue(hir::Mutability::Mut)) => {
-                                    mutability = Mutability::Mut;
-                                }
-                                Some(_) => mutability = Mutability::Not,
-                                _ => {}
-                            }
-                        }
-                    }
-
-                    let mut projs = closure_env_projs.clone();
-                    projs.push(ProjectionElem::Field(Field::new(i), ty));
-                    match capture {
-                        ty::UpvarCapture::ByValue => {}
-                        ty::UpvarCapture::ByRef(..) => {
-                            projs.push(ProjectionElem::Deref);
-                        }
-                    };
-
-                    self.var_debug_info.push(VarDebugInfo {
-                        name,
-                        source_info: SourceInfo {
-                            scope: OUTERMOST_SOURCE_SCOPE,
-                            span: tcx_hir.span(var_id),
-                        },
-                        place: Place {
-                            base: closure_env_arg.into(),
-                            projection: tcx.intern_place_elems(&projs),
-                        },
-                    });
-
-                    mutability
-                })
-                .collect();
-        }
-
-        let mut scope = None;
-        // Bind the argument patterns
-        for (index, arg_info) in arguments.iter().enumerate() {
-            // Function arguments always get the first Local indices after the return place
-            let local = Local::new(index + 1);
-            let place = Place::from(local);
-            let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info;
-
-            // Make sure we drop (parts of) the argument even when not matched on.
-            self.schedule_drop(
-                arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span),
-                argument_scope,
-                local,
-                DropKind::Value,
-            );
-
-            if let Some(arg) = arg_opt {
-                let pattern = self.hir.pattern_from_hir(&arg.pat);
-                let original_source_scope = self.source_scope;
-                let span = pattern.span;
-                self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
-                match *pattern.kind {
-                    // Don't introduce extra copies for simple bindings
-                    PatKind::Binding {
-                        mutability,
-                        var,
-                        mode: BindingMode::ByValue,
-                        subpattern: None,
-                        ..
-                    } => {
-                        self.local_decls[local].mutability = mutability;
-                        self.local_decls[local].source_info.scope = self.source_scope;
-                        self.local_decls[local].local_info = if let Some(kind) = self_binding {
-                            LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))
-                        } else {
-                            let binding_mode = ty::BindingMode::BindByValue(mutability.into());
-                            LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
-                                VarBindingForm {
-                                    binding_mode,
-                                    opt_ty_info,
-                                    opt_match_place: Some((Some(place.clone()), span)),
-                                    pat_span: span,
-                                },
-                            )))
-                        };
-                        self.var_indices.insert(var, LocalsForNode::One(local));
-                    }
-                    _ => {
-                        scope = self.declare_bindings(
-                            scope,
-                            ast_body.span,
-                            &pattern,
-                            matches::ArmHasGuard(false),
-                            Some((Some(&place), span)),
-                        );
-                        unpack!(block = self.place_into_pattern(block, pattern, &place, false));
-                    }
-                }
-                self.source_scope = original_source_scope;
-            }
-        }
-
-        // Enter the argument pattern bindings source scope, if it exists.
-        if let Some(source_scope) = scope {
-            self.source_scope = source_scope;
-        }
-
-        let body = self.hir.mirror(ast_body);
-        self.into(&Place::return_place(), block, body)
-    }
-
-    fn set_correct_source_scope_for_arg(
-        &mut self,
-        arg_hir_id: hir::HirId,
-        original_source_scope: SourceScope,
-        pattern_span: Span,
-    ) {
-        let tcx = self.hir.tcx();
-        let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir.root_lint_level);
-        let parent_root = tcx.maybe_lint_level_root_bounded(
-            self.source_scopes[original_source_scope]
-                .local_data
-                .as_ref()
-                .assert_crate_local()
-                .lint_root,
-            self.hir.root_lint_level,
-        );
-        if current_root != parent_root {
-            self.source_scope =
-                self.new_source_scope(pattern_span, LintLevel::Explicit(current_root), None);
-        }
-    }
-
-    fn get_unit_temp(&mut self) -> Place<'tcx> {
-        match self.unit_temp {
-            Some(ref tmp) => tmp.clone(),
-            None => {
-                let ty = self.hir.unit_ty();
-                let fn_span = self.fn_span;
-                let tmp = self.temp(ty, fn_span);
-                self.unit_temp = Some(tmp.clone());
-                tmp
-            }
-        }
-    }
-
-    fn return_block(&mut self) -> BasicBlock {
-        match self.cached_return_block {
-            Some(rb) => rb,
-            None => {
-                let rb = self.cfg.start_new_block();
-                self.cached_return_block = Some(rb);
-                rb
-            }
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Builder methods are broken up into modules, depending on what kind
-// of thing is being lowered. Note that they use the `unpack` macro
-// above extensively.
-
-mod block;
-mod cfg;
-mod expr;
-mod into;
-mod matches;
-mod misc;
-mod scope;
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
deleted file mode 100644 (file)
index 0aa9773..0000000
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*!
-Managing the scope stack. The scopes are tied to lexical scopes, so as
-we descend the HAIR, we push a scope on the stack, build its
-contents, and then pop it off. Every scope is named by a
-`region::Scope`.
-
-### SEME Regions
-
-When pushing a new scope, we record the current point in the graph (a
-basic block); this marks the entry to the scope. We then generate more
-stuff in the control-flow graph. Whenever the scope is exited, either
-via a `break` or `return` or just by fallthrough, that marks an exit
-from the scope. Each lexical scope thus corresponds to a single-entry,
-multiple-exit (SEME) region in the control-flow graph.
-
-For now, we keep a mapping from each `region::Scope` to its
-corresponding SEME region for later reference (see caveat in next
-paragraph). This is because region scopes are tied to
-them. Eventually, when we shift to non-lexical lifetimes, there should
-be no need to remember this mapping.
-
-### Not so SEME Regions
-
-In the course of building matches, it sometimes happens that certain code
-(namely guards) gets executed multiple times. This means that the scope lexical
-scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
-mapping is from one scope to a vector of SEME regions.
-
-Also in matches, the scopes assigned to arms are not even SEME regions! Each
-arm has a single region with one entry for each pattern. We manually
-manipulate the scheduled drops in this scope to avoid dropping things multiple
-times, although drop elaboration would clean this up for value drops.
-
-### Drops
-
-The primary purpose for scopes is to insert drops: while building
-the contents, we also accumulate places that need to be dropped upon
-exit from each scope. This is done by calling `schedule_drop`. Once a
-drop is scheduled, whenever we branch out we will insert drops of all
-those places onto the outgoing edge. Note that we don't know the full
-set of scheduled drops up front, and so whenever we exit from the
-scope we only drop the values scheduled thus far. For example, consider
-the scope S corresponding to this loop:
-
-```
-# let cond = true;
-loop {
-    let x = ..;
-    if cond { break; }
-    let y = ..;
-}
-```
-
-When processing the `let x`, we will add one drop to the scope for
-`x`.  The break will then insert a drop for `x`. When we process `let
-y`, we will add another drop (in fact, to a subscope, but let's ignore
-that for now); any later drops would also drop `y`.
-
-### Early exit
-
-There are numerous "normal" ways to early exit a scope: `break`,
-`continue`, `return` (panics are handled separately). Whenever an
-early exit occurs, the method `exit_scope` is called. It is given the
-current point in execution where the early exit occurs, as well as the
-scope you want to branch to (note that all early exits from to some
-other enclosing scope). `exit_scope` will record this exit point and
-also add all drops.
-
-Panics are handled in a similar fashion, except that a panic always
-returns out to the `DIVERGE_BLOCK`. To trigger a panic, simply call
-`panic(p)` with the current point `p`. Or else you can call
-`diverge_cleanup`, which will produce a block that you can branch to
-which does the appropriate cleanup and then diverges. `panic(p)`
-simply calls `diverge_cleanup()` and adds an edge from `p` to the
-result.
-
-### Loop scopes
-
-In addition to the normal scope stack, we track a loop scope stack
-that contains only loops. It tracks where a `break` and `continue`
-should go to.
-
-*/
-
-use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
-use crate::hair::{Expr, ExprRef, LintLevel};
-use rustc::middle::region;
-use rustc::mir::*;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
-use rustc_hir::GeneratorKind;
-use rustc_span::{Span, DUMMY_SP};
-use std::collections::hash_map::Entry;
-use std::mem;
-
-#[derive(Debug)]
-struct Scope {
-    /// The source scope this scope was created in.
-    source_scope: SourceScope,
-
-    /// the region span of this scope within source code.
-    region_scope: region::Scope,
-
-    /// the span of that region_scope
-    region_scope_span: Span,
-
-    /// set of places to drop when exiting this scope. This starts
-    /// out empty but grows as variables are declared during the
-    /// building process. This is a stack, so we always drop from the
-    /// end of the vector (top of the stack) first.
-    drops: Vec<DropData>,
-
-    moved_locals: Vec<Local>,
-
-    /// The cache for drop chain on “normal” exit into a particular BasicBlock.
-    cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>,
-
-    /// The cache for drop chain on "generator drop" exit.
-    cached_generator_drop: Option<BasicBlock>,
-
-    /// The cache for drop chain on "unwind" exit.
-    cached_unwind: CachedBlock,
-}
-
-#[derive(Debug, Default)]
-pub struct Scopes<'tcx> {
-    scopes: Vec<Scope>,
-    /// The current set of breakable scopes. See module comment for more details.
-    breakable_scopes: Vec<BreakableScope<'tcx>>,
-}
-
-#[derive(Debug)]
-struct DropData {
-    /// span where drop obligation was incurred (typically where place was declared)
-    span: Span,
-
-    /// local to drop
-    local: Local,
-
-    /// Whether this is a value Drop or a StorageDead.
-    kind: DropKind,
-
-    /// The cached blocks for unwinds.
-    cached_block: CachedBlock,
-}
-
-#[derive(Debug, Default, Clone, Copy)]
-struct CachedBlock {
-    /// The cached block for the cleanups-on-diverge path. This block
-    /// contains code to run the current drop and all the preceding
-    /// drops (i.e., those having lower index in Drop’s Scope drop
-    /// array)
-    unwind: Option<BasicBlock>,
-
-    /// The cached block for unwinds during cleanups-on-generator-drop path
-    ///
-    /// This is split from the standard unwind path here to prevent drop
-    /// elaboration from creating drop flags that would have to be captured
-    /// by the generator. I'm not sure how important this optimization is,
-    /// but it is here.
-    generator_drop: Option<BasicBlock>,
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub(crate) enum DropKind {
-    Value,
-    Storage,
-}
-
-#[derive(Clone, Debug)]
-struct BreakableScope<'tcx> {
-    /// Region scope of the loop
-    region_scope: region::Scope,
-    /// Where the body of the loop begins. `None` if block
-    continue_block: Option<BasicBlock>,
-    /// Block to branch into when the loop or block terminates (either by being
-    /// `break`-en out from, or by having its condition to become false)
-    break_block: BasicBlock,
-    /// The destination of the loop/block expression itself (i.e., where to put
-    /// the result of a `break` expression)
-    break_destination: Place<'tcx>,
-}
-
-/// The target of an expression that breaks out of a scope
-#[derive(Clone, Copy, Debug)]
-pub enum BreakableTarget {
-    Continue(region::Scope),
-    Break(region::Scope),
-    Return,
-}
-
-impl CachedBlock {
-    fn invalidate(&mut self) {
-        *self = CachedBlock::default();
-    }
-
-    fn get(&self, generator_drop: bool) -> Option<BasicBlock> {
-        if generator_drop { self.generator_drop } else { self.unwind }
-    }
-
-    fn ref_mut(&mut self, generator_drop: bool) -> &mut Option<BasicBlock> {
-        if generator_drop { &mut self.generator_drop } else { &mut self.unwind }
-    }
-}
-
-impl Scope {
-    /// Invalidates all the cached blocks in the scope.
-    ///
-    /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
-    /// larger extent of code.
-    ///
-    /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`.
-    /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
-    /// top-of-scope (as opposed to dependent scopes).
-    fn invalidate_cache(
-        &mut self,
-        storage_only: bool,
-        generator_kind: Option<GeneratorKind>,
-        this_scope_only: bool,
-    ) {
-        // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
-        // with lots of `try!`?
-
-        // cached exits drop storage and refer to the top-of-scope
-        self.cached_exits.clear();
-
-        // the current generator drop and unwind refer to top-of-scope
-        self.cached_generator_drop = None;
-
-        let ignore_unwinds = storage_only && generator_kind.is_none();
-        if !ignore_unwinds {
-            self.cached_unwind.invalidate();
-        }
-
-        if !ignore_unwinds && !this_scope_only {
-            for drop_data in &mut self.drops {
-                drop_data.cached_block.invalidate();
-            }
-        }
-    }
-
-    /// Given a span and this scope's source scope, make a SourceInfo.
-    fn source_info(&self, span: Span) -> SourceInfo {
-        SourceInfo { span, scope: self.source_scope }
-    }
-
-    /// Whether there's anything to do for the cleanup path, that is,
-    /// when unwinding through this scope. This includes destructors,
-    /// but not StorageDead statements, which don't get emitted at all
-    /// for unwinding, for several reasons:
-    ///  * clang doesn't emit llvm.lifetime.end for C++ unwinding
-    ///  * LLVM's memory dependency analysis can't handle it atm
-    ///  * polluting the cleanup MIR with StorageDead creates
-    ///    landing pads even though there's no actual destructors
-    ///  * freeing up stack space has no effect during unwinding
-    /// Note that for generators we do emit StorageDeads, for the
-    /// use of optimizations in the MIR generator transform.
-    fn needs_cleanup(&self) -> bool {
-        self.drops.iter().any(|drop| match drop.kind {
-            DropKind::Value => true,
-            DropKind::Storage => false,
-        })
-    }
-}
-
-impl<'tcx> Scopes<'tcx> {
-    fn len(&self) -> usize {
-        self.scopes.len()
-    }
-
-    fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) {
-        debug!("push_scope({:?})", region_scope);
-        self.scopes.push(Scope {
-            source_scope: vis_scope,
-            region_scope: region_scope.0,
-            region_scope_span: region_scope.1.span,
-            drops: vec![],
-            moved_locals: vec![],
-            cached_generator_drop: None,
-            cached_exits: Default::default(),
-            cached_unwind: CachedBlock::default(),
-        });
-    }
-
-    fn pop_scope(
-        &mut self,
-        region_scope: (region::Scope, SourceInfo),
-    ) -> (Scope, Option<BasicBlock>) {
-        let scope = self.scopes.pop().unwrap();
-        assert_eq!(scope.region_scope, region_scope.0);
-        let unwind_to =
-            self.scopes.last().and_then(|next_scope| next_scope.cached_unwind.get(false));
-        (scope, unwind_to)
-    }
-
-    fn may_panic(&self, scope_count: usize) -> bool {
-        let len = self.len();
-        self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup())
-    }
-
-    /// Finds the breakable scope for a given label. This is used for
-    /// resolving `return`, `break` and `continue`.
-    fn find_breakable_scope(
-        &self,
-        span: Span,
-        target: BreakableTarget,
-    ) -> (BasicBlock, region::Scope, Option<Place<'tcx>>) {
-        let get_scope = |scope: region::Scope| {
-            // find the loop-scope by its `region::Scope`.
-            self.breakable_scopes
-                .iter()
-                .rfind(|breakable_scope| breakable_scope.region_scope == scope)
-                .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
-        };
-        match target {
-            BreakableTarget::Return => {
-                let scope = &self.breakable_scopes[0];
-                if scope.break_destination != Place::return_place() {
-                    span_bug!(span, "`return` in item with no return scope");
-                }
-                (scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
-            }
-            BreakableTarget::Break(scope) => {
-                let scope = get_scope(scope);
-                (scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
-            }
-            BreakableTarget::Continue(scope) => {
-                let scope = get_scope(scope);
-                let continue_block = scope
-                    .continue_block
-                    .unwrap_or_else(|| span_bug!(span, "missing `continue` block"));
-                (continue_block, scope.region_scope, None)
-            }
-        }
-    }
-
-    fn num_scopes_above(&self, region_scope: region::Scope, span: Span) -> usize {
-        let scope_count = self
-            .scopes
-            .iter()
-            .rev()
-            .position(|scope| scope.region_scope == region_scope)
-            .unwrap_or_else(|| span_bug!(span, "region_scope {:?} does not enclose", region_scope));
-        let len = self.len();
-        assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
-        scope_count
-    }
-
-    fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
-        self.scopes.iter_mut().rev()
-    }
-
-    fn top_scopes(&mut self, count: usize) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
-        let len = self.len();
-        self.scopes[len - count..].iter_mut()
-    }
-
-    /// Returns the topmost active scope, which is known to be alive until
-    /// the next scope expression.
-    pub(super) fn topmost(&self) -> region::Scope {
-        self.scopes.last().expect("topmost_scope: no scopes present").region_scope
-    }
-
-    fn source_info(&self, index: usize, span: Span) -> SourceInfo {
-        self.scopes[self.len() - index].source_info(span)
-    }
-}
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
-    // Adding and removing scopes
-    // ==========================
-    //  Start a breakable scope, which tracks where `continue`, `break` and
-    //  `return` should branch to.
-    pub fn in_breakable_scope<F, R>(
-        &mut self,
-        loop_block: Option<BasicBlock>,
-        break_block: BasicBlock,
-        break_destination: Place<'tcx>,
-        f: F,
-    ) -> R
-    where
-        F: FnOnce(&mut Builder<'a, 'tcx>) -> R,
-    {
-        let region_scope = self.scopes.topmost();
-        let scope = BreakableScope {
-            region_scope,
-            continue_block: loop_block,
-            break_block,
-            break_destination,
-        };
-        self.scopes.breakable_scopes.push(scope);
-        let res = f(self);
-        let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
-        assert!(breakable_scope.region_scope == region_scope);
-        res
-    }
-
-    pub fn in_opt_scope<F, R>(
-        &mut self,
-        opt_scope: Option<(region::Scope, SourceInfo)>,
-        f: F,
-    ) -> BlockAnd<R>
-    where
-        F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
-    {
-        debug!("in_opt_scope(opt_scope={:?})", opt_scope);
-        if let Some(region_scope) = opt_scope {
-            self.push_scope(region_scope);
-        }
-        let mut block;
-        let rv = unpack!(block = f(self));
-        if let Some(region_scope) = opt_scope {
-            unpack!(block = self.pop_scope(region_scope, block));
-        }
-        debug!("in_scope: exiting opt_scope={:?} block={:?}", opt_scope, block);
-        block.and(rv)
-    }
-
-    /// Convenience wrapper that pushes a scope and then executes `f`
-    /// to build its contents, popping the scope afterwards.
-    pub fn in_scope<F, R>(
-        &mut self,
-        region_scope: (region::Scope, SourceInfo),
-        lint_level: LintLevel,
-        f: F,
-    ) -> BlockAnd<R>
-    where
-        F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
-    {
-        debug!("in_scope(region_scope={:?})", region_scope);
-        let source_scope = self.source_scope;
-        let tcx = self.hir.tcx();
-        if let LintLevel::Explicit(current_hir_id) = lint_level {
-            // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
-            // to avoid adding Hir dependences on our parents.
-            // We estimate the true lint roots here to avoid creating a lot of source scopes.
-
-            let parent_root = tcx.maybe_lint_level_root_bounded(
-                self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root,
-                self.hir.root_lint_level,
-            );
-            let current_root =
-                tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir.root_lint_level);
-
-            if parent_root != current_root {
-                self.source_scope = self.new_source_scope(
-                    region_scope.1.span,
-                    LintLevel::Explicit(current_root),
-                    None,
-                );
-            }
-        }
-        self.push_scope(region_scope);
-        let mut block;
-        let rv = unpack!(block = f(self));
-        unpack!(block = self.pop_scope(region_scope, block));
-        self.source_scope = source_scope;
-        debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
-        block.and(rv)
-    }
-
-    /// Push a scope onto the stack. You can then build code in this
-    /// scope and call `pop_scope` afterwards. Note that these two
-    /// calls must be paired; using `in_scope` as a convenience
-    /// wrapper maybe preferable.
-    pub fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) {
-        self.scopes.push_scope(region_scope, self.source_scope);
-    }
-
-    /// Pops a scope, which should have region scope `region_scope`,
-    /// adding any drops onto the end of `block` that are needed.
-    /// This must match 1-to-1 with `push_scope`.
-    pub fn pop_scope(
-        &mut self,
-        region_scope: (region::Scope, SourceInfo),
-        mut block: BasicBlock,
-    ) -> BlockAnd<()> {
-        debug!("pop_scope({:?}, {:?})", region_scope, block);
-        // If we are emitting a `drop` statement, we need to have the cached
-        // diverge cleanup pads ready in case that drop panics.
-        if self.scopes.may_panic(1) {
-            self.diverge_cleanup();
-        }
-        let (scope, unwind_to) = self.scopes.pop_scope(region_scope);
-        let unwind_to = unwind_to.unwrap_or_else(|| self.resume_block());
-
-        unpack!(
-            block = build_scope_drops(
-                &mut self.cfg,
-                self.generator_kind,
-                &scope,
-                block,
-                unwind_to,
-                self.arg_count,
-                false, // not generator
-                false, // not unwind path
-            )
-        );
-
-        block.unit()
-    }
-
-    pub fn break_scope(
-        &mut self,
-        mut block: BasicBlock,
-        value: Option<ExprRef<'tcx>>,
-        scope: BreakableTarget,
-        source_info: SourceInfo,
-    ) -> BlockAnd<()> {
-        let (mut target_block, region_scope, destination) =
-            self.scopes.find_breakable_scope(source_info.span, scope);
-        if let BreakableTarget::Return = scope {
-            // We call this now, rather than when we start lowering the
-            // function so that the return block doesn't precede the entire
-            // rest of the CFG. Some passes and LLVM prefer blocks to be in
-            // approximately CFG order.
-            target_block = self.return_block();
-        }
-        if let Some(destination) = destination {
-            if let Some(value) = value {
-                debug!("stmt_expr Break val block_context.push(SubExpr)");
-                self.block_context.push(BlockFrame::SubExpr);
-                unpack!(block = self.into(&destination, block, value));
-                self.block_context.pop();
-            } else {
-                self.cfg.push_assign_unit(block, source_info, &destination)
-            }
-        } else {
-            assert!(value.is_none(), "`return` and `break` should have a destination");
-        }
-        self.exit_scope(source_info.span, region_scope, block, target_block);
-        self.cfg.start_new_block().unit()
-    }
-
-    /// Branch out of `block` to `target`, exiting all scopes up to
-    /// and including `region_scope`. This will insert whatever drops are
-    /// needed. See module comment for details.
-    pub fn exit_scope(
-        &mut self,
-        span: Span,
-        region_scope: region::Scope,
-        mut block: BasicBlock,
-        target: BasicBlock,
-    ) {
-        debug!(
-            "exit_scope(region_scope={:?}, block={:?}, target={:?})",
-            region_scope, block, target
-        );
-        let scope_count = self.scopes.num_scopes_above(region_scope, span);
-
-        // If we are emitting a `drop` statement, we need to have the cached
-        // diverge cleanup pads ready in case that drop panics.
-        let may_panic = self.scopes.may_panic(scope_count);
-        if may_panic {
-            self.diverge_cleanup();
-        }
-
-        let mut scopes = self.scopes.top_scopes(scope_count + 1).rev();
-        let mut scope = scopes.next().unwrap();
-        for next_scope in scopes {
-            if scope.drops.is_empty() {
-                scope = next_scope;
-                continue;
-            }
-            let source_info = scope.source_info(span);
-            block = match scope.cached_exits.entry((target, region_scope)) {
-                Entry::Occupied(e) => {
-                    self.cfg.goto(block, source_info, *e.get());
-                    return;
-                }
-                Entry::Vacant(v) => {
-                    let b = self.cfg.start_new_block();
-                    self.cfg.goto(block, source_info, b);
-                    v.insert(b);
-                    b
-                }
-            };
-
-            let unwind_to = next_scope.cached_unwind.get(false).unwrap_or_else(|| {
-                debug_assert!(!may_panic, "cached block not present?");
-                START_BLOCK
-            });
-
-            unpack!(
-                block = build_scope_drops(
-                    &mut self.cfg,
-                    self.generator_kind,
-                    scope,
-                    block,
-                    unwind_to,
-                    self.arg_count,
-                    false, // not generator
-                    false, // not unwind path
-                )
-            );
-
-            scope = next_scope;
-        }
-
-        self.cfg.goto(block, self.scopes.source_info(scope_count, span), target);
-    }
-
-    /// Creates a path that performs all required cleanup for dropping a generator.
-    ///
-    /// This path terminates in GeneratorDrop. Returns the start of the path.
-    /// None indicates there’s no cleanup to do at this point.
-    pub fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
-        // Fill in the cache for unwinds
-        self.diverge_cleanup_gen(true);
-
-        let src_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
-        let resume_block = self.resume_block();
-        let mut scopes = self.scopes.iter_mut().peekable();
-        let mut block = self.cfg.start_new_block();
-        let result = block;
-
-        while let Some(scope) = scopes.next() {
-            block = if let Some(b) = scope.cached_generator_drop {
-                self.cfg.goto(block, src_info, b);
-                return Some(result);
-            } else {
-                let b = self.cfg.start_new_block();
-                scope.cached_generator_drop = Some(b);
-                self.cfg.goto(block, src_info, b);
-                b
-            };
-
-            let unwind_to = scopes
-                .peek()
-                .as_ref()
-                .map(|scope| {
-                    scope
-                        .cached_unwind
-                        .get(true)
-                        .unwrap_or_else(|| span_bug!(src_info.span, "cached block not present?"))
-                })
-                .unwrap_or(resume_block);
-
-            unpack!(
-                block = build_scope_drops(
-                    &mut self.cfg,
-                    self.generator_kind,
-                    scope,
-                    block,
-                    unwind_to,
-                    self.arg_count,
-                    true, // is generator
-                    true, // is cached path
-                )
-            );
-        }
-
-        self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
-
-        Some(result)
-    }
-
-    /// Creates a new source scope, nested in the current one.
-    pub fn new_source_scope(
-        &mut self,
-        span: Span,
-        lint_level: LintLevel,
-        safety: Option<Safety>,
-    ) -> SourceScope {
-        let parent = self.source_scope;
-        debug!(
-            "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
-            span,
-            lint_level,
-            safety,
-            parent,
-            self.source_scopes.get(parent)
-        );
-        let scope_local_data = SourceScopeLocalData {
-            lint_root: if let LintLevel::Explicit(lint_root) = lint_level {
-                lint_root
-            } else {
-                self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root
-            },
-            safety: safety.unwrap_or_else(|| {
-                self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety
-            }),
-        };
-        self.source_scopes.push(SourceScopeData {
-            span,
-            parent_scope: Some(parent),
-            local_data: ClearCrossCrate::Set(scope_local_data),
-        })
-    }
-
-    /// Given a span and the current source scope, make a SourceInfo.
-    pub fn source_info(&self, span: Span) -> SourceInfo {
-        SourceInfo { span, scope: self.source_scope }
-    }
-
-    // Finding scopes
-    // ==============
-    /// Returns the scope that we should use as the lifetime of an
-    /// operand. Basically, an operand must live until it is consumed.
-    /// This is similar to, but not quite the same as, the temporary
-    /// scope (which can be larger or smaller).
-    ///
-    /// Consider:
-    ///
-    ///     let x = foo(bar(X, Y));
-    ///
-    /// We wish to pop the storage for X and Y after `bar()` is
-    /// called, not after the whole `let` is completed.
-    ///
-    /// As another example, if the second argument diverges:
-    ///
-    ///     foo(Box::new(2), panic!())
-    ///
-    /// We would allocate the box but then free it on the unwinding
-    /// path; we would also emit a free on the 'success' path from
-    /// panic, but that will turn out to be removed as dead-code.
-    ///
-    /// When building statics/constants, returns `None` since
-    /// intermediate values do not have to be dropped in that case.
-    pub fn local_scope(&self) -> Option<region::Scope> {
-        match self.hir.body_owner_kind {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) =>
-            // No need to free storage in this context.
-            {
-                None
-            }
-            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()),
-        }
-    }
-
-    // Schedule an abort block - this is used for some ABIs that cannot unwind
-    pub fn schedule_abort(&mut self) -> BasicBlock {
-        let source_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
-        let abortblk = self.cfg.start_new_cleanup_block();
-        self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort);
-        self.cached_resume_block = Some(abortblk);
-        abortblk
-    }
-
-    // Scheduling drops
-    // ================
-    pub fn schedule_drop_storage_and_value(
-        &mut self,
-        span: Span,
-        region_scope: region::Scope,
-        local: Local,
-    ) {
-        self.schedule_drop(span, region_scope, local, DropKind::Storage);
-        self.schedule_drop(span, region_scope, local, DropKind::Value);
-    }
-
-    /// Indicates that `place` should be dropped on exit from
-    /// `region_scope`.
-    ///
-    /// When called with `DropKind::Storage`, `place` should be a local
-    /// with an index higher than the current `self.arg_count`.
-    pub fn schedule_drop(
-        &mut self,
-        span: Span,
-        region_scope: region::Scope,
-        local: Local,
-        drop_kind: DropKind,
-    ) {
-        let needs_drop = match drop_kind {
-            DropKind::Value => {
-                if !self.hir.needs_drop(self.local_decls[local].ty) {
-                    return;
-                }
-                true
-            }
-            DropKind::Storage => {
-                if local.index() <= self.arg_count {
-                    span_bug!(
-                        span,
-                        "`schedule_drop` called with local {:?} and arg_count {}",
-                        local,
-                        self.arg_count,
-                    )
-                }
-                false
-            }
-        };
-
-        for scope in self.scopes.iter_mut() {
-            let this_scope = scope.region_scope == region_scope;
-            // When building drops, we try to cache chains of drops in such a way so these drops
-            // could be reused by the drops which would branch into the cached (already built)
-            // blocks.  This, however, means that whenever we add a drop into a scope which already
-            // had some blocks built (and thus, cached) for it, we must invalidate all caches which
-            // might branch into the scope which had a drop just added to it. This is necessary,
-            // because otherwise some other code might use the cache to branch into already built
-            // chain of drops, essentially ignoring the newly added drop.
-            //
-            // For example consider there’s two scopes with a drop in each. These are built and
-            // thus the caches are filled:
-            //
-            // +--------------------------------------------------------+
-            // | +---------------------------------+                    |
-            // | | +--------+     +-------------+  |  +---------------+ |
-            // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
-            // | | +--------+     +-------------+  |  +---------------+ |
-            // | +------------|outer_scope cache|--+                    |
-            // +------------------------------|middle_scope cache|------+
-            //
-            // Now, a new, inner-most scope is added along with a new drop into both inner-most and
-            // outer-most scopes:
-            //
-            // +------------------------------------------------------------+
-            // | +----------------------------------+                       |
-            // | | +--------+      +-------------+  |   +---------------+   | +-------------+
-            // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
-            // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
-            // | |             +-+ +-------------+  |                       |
-            // | +---|invalid outer_scope cache|----+                       |
-            // +----=----------------|invalid middle_scope cache|-----------+
-            //
-            // If, when adding `drop(new)` we do not invalidate the cached blocks for both
-            // outer_scope and middle_scope, then, when building drops for the inner (right-most)
-            // scope, the old, cached blocks, without `drop(new)` will get used, producing the
-            // wrong results.
-            //
-            // The cache and its invalidation for unwind branch is somewhat special. The cache is
-            // per-drop, rather than per scope, which has a several different implications. Adding
-            // a new drop into a scope will not invalidate cached blocks of the prior drops in the
-            // scope. That is true, because none of the already existing drops will have an edge
-            // into a block with the newly added drop.
-            //
-            // Note that this code iterates scopes from the inner-most to the outer-most,
-            // invalidating caches of each scope visited. This way bare minimum of the
-            // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
-            // cache of outer scope stays intact.
-            scope.invalidate_cache(!needs_drop, self.generator_kind, this_scope);
-            if this_scope {
-                let region_scope_span =
-                    region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree);
-                // Attribute scope exit drops to scope's closing brace.
-                let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span);
-
-                scope.drops.push(DropData {
-                    span: scope_end,
-                    local,
-                    kind: drop_kind,
-                    cached_block: CachedBlock::default(),
-                });
-                return;
-            }
-        }
-        span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
-    }
-
-    /// Indicates that the "local operand" stored in `local` is
-    /// *moved* at some point during execution (see `local_scope` for
-    /// more information about what a "local operand" is -- in short,
-    /// it's an intermediate operand created as part of preparing some
-    /// MIR instruction). We use this information to suppress
-    /// redundant drops on the non-unwind paths. This results in less
-    /// MIR, but also avoids spurious borrow check errors
-    /// (c.f. #64391).
-    ///
-    /// Example: when compiling the call to `foo` here:
-    ///
-    /// ```rust
-    /// foo(bar(), ...)
-    /// ```
-    ///
-    /// we would evaluate `bar()` to an operand `_X`. We would also
-    /// schedule `_X` to be dropped when the expression scope for
-    /// `foo(bar())` is exited. This is relevant, for example, if the
-    /// later arguments should unwind (it would ensure that `_X` gets
-    /// dropped). However, if no unwind occurs, then `_X` will be
-    /// unconditionally consumed by the `call`:
-    ///
-    /// ```
-    /// bb {
-    ///   ...
-    ///   _R = CALL(foo, _X, ...)
-    /// }
-    /// ```
-    ///
-    /// However, `_X` is still registered to be dropped, and so if we
-    /// do nothing else, we would generate a `DROP(_X)` that occurs
-    /// after the call. This will later be optimized out by the
-    /// drop-elaboation code, but in the meantime it can lead to
-    /// spurious borrow-check errors -- the problem, ironically, is
-    /// not the `DROP(_X)` itself, but the (spurious) unwind pathways
-    /// that it creates. See #64391 for an example.
-    pub fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
-        let scope = match self.local_scope() {
-            None => {
-                // if there is no local scope, operands won't be dropped anyway
-                return;
-            }
-
-            Some(local_scope) => self
-                .scopes
-                .iter_mut()
-                .find(|scope| scope.region_scope == local_scope)
-                .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)),
-        };
-
-        // look for moves of a local variable, like `MOVE(_X)`
-        let locals_moved = operands.iter().flat_map(|operand| match operand {
-            Operand::Copy(_) | Operand::Constant(_) => None,
-            Operand::Move(place) => place.as_local(),
-        });
-
-        for local in locals_moved {
-            // check if we have a Drop for this operand and -- if so
-            // -- add it to the list of moved operands. Note that this
-            // local might not have been an operand created for this
-            // call, it could come from other places too.
-            if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) {
-                scope.moved_locals.push(local);
-            }
-        }
-    }
-
-    // Other
-    // =====
-    /// Branch based on a boolean condition.
-    ///
-    /// This is a special case because the temporary for the condition needs to
-    /// be dropped on both the true and the false arm.
-    pub fn test_bool(
-        &mut self,
-        mut block: BasicBlock,
-        condition: Expr<'tcx>,
-        source_info: SourceInfo,
-    ) -> (BasicBlock, BasicBlock) {
-        let cond = unpack!(block = self.as_local_operand(block, condition));
-        let true_block = self.cfg.start_new_block();
-        let false_block = self.cfg.start_new_block();
-        let term = TerminatorKind::if_(self.hir.tcx(), cond.clone(), true_block, false_block);
-        self.cfg.terminate(block, source_info, term);
-
-        match cond {
-            // Don't try to drop a constant
-            Operand::Constant(_) => (),
-            // If constants and statics, we don't generate StorageLive for this
-            // temporary, so don't try to generate StorageDead for it either.
-            _ if self.local_scope().is_none() => (),
-            Operand::Copy(place) | Operand::Move(place) => {
-                if let Some(cond_temp) = place.as_local() {
-                    // Manually drop the condition on both branches.
-                    let top_scope = self.scopes.scopes.last_mut().unwrap();
-                    let top_drop_data = top_scope.drops.pop().unwrap();
-
-                    match top_drop_data.kind {
-                        DropKind::Value { .. } => {
-                            bug!("Drop scheduled on top of condition variable")
-                        }
-                        DropKind::Storage => {
-                            let source_info = top_scope.source_info(top_drop_data.span);
-                            let local = top_drop_data.local;
-                            assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
-                            self.cfg.push(
-                                true_block,
-                                Statement { source_info, kind: StatementKind::StorageDead(local) },
-                            );
-                            self.cfg.push(
-                                false_block,
-                                Statement { source_info, kind: StatementKind::StorageDead(local) },
-                            );
-                        }
-                    }
-
-                    top_scope.invalidate_cache(true, self.generator_kind, true);
-                } else {
-                    bug!("Expected as_local_operand to produce a temporary");
-                }
-            }
-        }
-
-        (true_block, false_block)
-    }
-
-    /// Creates a path that performs all required cleanup for unwinding.
-    ///
-    /// This path terminates in Resume. Returns the start of the path.
-    /// See module comment for more details.
-    pub fn diverge_cleanup(&mut self) -> BasicBlock {
-        self.diverge_cleanup_gen(false)
-    }
-
-    fn resume_block(&mut self) -> BasicBlock {
-        if let Some(target) = self.cached_resume_block {
-            target
-        } else {
-            let resumeblk = self.cfg.start_new_cleanup_block();
-            self.cfg.terminate(
-                resumeblk,
-                SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span: self.fn_span },
-                TerminatorKind::Resume,
-            );
-            self.cached_resume_block = Some(resumeblk);
-            resumeblk
-        }
-    }
-
-    fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
-        // Build up the drops in **reverse** order. The end result will
-        // look like:
-        //
-        //    scopes[n] -> scopes[n-1] -> ... -> scopes[0]
-        //
-        // However, we build this in **reverse order**. That is, we
-        // process scopes[0], then scopes[1], etc, pointing each one at
-        // the result generates from the one before. Along the way, we
-        // store caches. If everything is cached, we'll just walk right
-        // to left reading the cached results but never created anything.
-
-        // Find the last cached block
-        debug!("diverge_cleanup_gen(self.scopes = {:?})", self.scopes);
-        let cached_cleanup = self.scopes.iter_mut().enumerate().find_map(|(idx, ref scope)| {
-            let cached_block = scope.cached_unwind.get(generator_drop)?;
-            Some((cached_block, idx))
-        });
-        let (mut target, first_uncached) =
-            cached_cleanup.unwrap_or_else(|| (self.resume_block(), self.scopes.len()));
-
-        for scope in self.scopes.top_scopes(first_uncached) {
-            target = build_diverge_scope(
-                &mut self.cfg,
-                scope.region_scope_span,
-                scope,
-                target,
-                generator_drop,
-                self.generator_kind,
-            );
-        }
-
-        target
-    }
-
-    /// Utility function for *non*-scope code to build their own drops
-    pub fn build_drop_and_replace(
-        &mut self,
-        block: BasicBlock,
-        span: Span,
-        location: Place<'tcx>,
-        value: Operand<'tcx>,
-    ) -> BlockAnd<()> {
-        let source_info = self.source_info(span);
-        let next_target = self.cfg.start_new_block();
-        let diverge_target = self.diverge_cleanup();
-        self.cfg.terminate(
-            block,
-            source_info,
-            TerminatorKind::DropAndReplace {
-                location,
-                value,
-                target: next_target,
-                unwind: Some(diverge_target),
-            },
-        );
-        next_target.unit()
-    }
-
-    /// Creates an Assert terminator and return the success block.
-    /// If the boolean condition operand is not the expected value,
-    /// a runtime panic will be caused with the given message.
-    pub fn assert(
-        &mut self,
-        block: BasicBlock,
-        cond: Operand<'tcx>,
-        expected: bool,
-        msg: AssertMessage<'tcx>,
-        span: Span,
-    ) -> BasicBlock {
-        let source_info = self.source_info(span);
-
-        let success_block = self.cfg.start_new_block();
-        let cleanup = self.diverge_cleanup();
-
-        self.cfg.terminate(
-            block,
-            source_info,
-            TerminatorKind::Assert {
-                cond,
-                expected,
-                msg,
-                target: success_block,
-                cleanup: Some(cleanup),
-            },
-        );
-
-        success_block
-    }
-
-    // `match` arm scopes
-    // ==================
-    /// Unschedules any drops in the top scope.
-    ///
-    /// This is only needed for `match` arm scopes, because they have one
-    /// entrance per pattern, but only one exit.
-    pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) {
-        let top_scope = self.scopes.scopes.last_mut().unwrap();
-
-        assert_eq!(top_scope.region_scope, region_scope);
-
-        top_scope.drops.clear();
-        top_scope.invalidate_cache(false, self.generator_kind, true);
-    }
-}
-
-/// Builds drops for pop_scope and exit_scope.
-fn build_scope_drops<'tcx>(
-    cfg: &mut CFG<'tcx>,
-    generator_kind: Option<GeneratorKind>,
-    scope: &Scope,
-    mut block: BasicBlock,
-    last_unwind_to: BasicBlock,
-    arg_count: usize,
-    generator_drop: bool,
-    is_cached_path: bool,
-) -> BlockAnd<()> {
-    debug!("build_scope_drops({:?} -> {:?})", block, scope);
-
-    // Build up the drops in evaluation order. The end result will
-    // look like:
-    //
-    // [SDs, drops[n]] --..> [SDs, drop[1]] -> [SDs, drop[0]] -> [[SDs]]
-    //               |                    |                 |
-    //               :                    |                 |
-    //                                    V                 V
-    // [drop[n]] -...-> [drop[1]] ------> [drop[0]] ------> [last_unwind_to]
-    //
-    // The horizontal arrows represent the execution path when the drops return
-    // successfully. The downwards arrows represent the execution path when the
-    // drops panic (panicking while unwinding will abort, so there's no need for
-    // another set of arrows).
-    //
-    // For generators, we unwind from a drop on a local to its StorageDead
-    // statement. For other functions we don't worry about StorageDead. The
-    // drops for the unwind path should have already been generated by
-    // `diverge_cleanup_gen`.
-
-    for drop_idx in (0..scope.drops.len()).rev() {
-        let drop_data = &scope.drops[drop_idx];
-        let source_info = scope.source_info(drop_data.span);
-        let local = drop_data.local;
-
-        match drop_data.kind {
-            DropKind::Value => {
-                // If the operand has been moved, and we are not on an unwind
-                // path, then don't generate the drop. (We only take this into
-                // account for non-unwind paths so as not to disturb the
-                // caching mechanism.)
-                if !is_cached_path && scope.moved_locals.iter().any(|&o| o == local) {
-                    continue;
-                }
-
-                let unwind_to = get_unwind_to(scope, generator_kind, drop_idx, generator_drop)
-                    .unwrap_or(last_unwind_to);
-
-                let next = cfg.start_new_block();
-                cfg.terminate(
-                    block,
-                    source_info,
-                    TerminatorKind::Drop {
-                        location: local.into(),
-                        target: next,
-                        unwind: Some(unwind_to),
-                    },
-                );
-                block = next;
-            }
-            DropKind::Storage => {
-                // Only temps and vars need their storage dead.
-                assert!(local.index() > arg_count);
-                cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) });
-            }
-        }
-    }
-    block.unit()
-}
-
-fn get_unwind_to(
-    scope: &Scope,
-    generator_kind: Option<GeneratorKind>,
-    unwind_from: usize,
-    generator_drop: bool,
-) -> Option<BasicBlock> {
-    for drop_idx in (0..unwind_from).rev() {
-        let drop_data = &scope.drops[drop_idx];
-        match (generator_kind, &drop_data.kind) {
-            (Some(_), DropKind::Storage) => {
-                return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
-                    span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
-                }));
-            }
-            (None, DropKind::Value) => {
-                return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
-                    span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
-                }));
-            }
-            _ => (),
-        }
-    }
-    None
-}
-
-fn build_diverge_scope<'tcx>(
-    cfg: &mut CFG<'tcx>,
-    span: Span,
-    scope: &mut Scope,
-    mut target: BasicBlock,
-    generator_drop: bool,
-    generator_kind: Option<GeneratorKind>,
-) -> BasicBlock {
-    // Build up the drops in **reverse** order. The end result will
-    // look like:
-    //
-    //    [drops[n]] -...-> [drops[0]] -> [target]
-    //
-    // The code in this function reads from right to left. At each
-    // point, we check for cached blocks representing the
-    // remainder. If everything is cached, we'll just walk right to
-    // left reading the cached results but never create anything.
-
-    let source_scope = scope.source_scope;
-    let source_info = |span| SourceInfo { span, scope: source_scope };
-
-    // We keep track of StorageDead statements to prepend to our current block
-    // and store them here, in reverse order.
-    let mut storage_deads = vec![];
-
-    let mut target_built_by_us = false;
-
-    // Build up the drops. Here we iterate the vector in
-    // *forward* order, so that we generate drops[0] first (right to
-    // left in diagram above).
-    debug!("build_diverge_scope({:?})", scope.drops);
-    for (j, drop_data) in scope.drops.iter_mut().enumerate() {
-        debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data);
-        // Only full value drops are emitted in the diverging path,
-        // not StorageDead, except in the case of generators.
-        //
-        // Note: This may not actually be what we desire (are we
-        // "freeing" stack storage as we unwind, or merely observing a
-        // frozen stack)? In particular, the intent may have been to
-        // match the behavior of clang, but on inspection eddyb says
-        // this is not what clang does.
-        match drop_data.kind {
-            DropKind::Storage if generator_kind.is_some() => {
-                storage_deads.push(Statement {
-                    source_info: source_info(drop_data.span),
-                    kind: StatementKind::StorageDead(drop_data.local),
-                });
-                if !target_built_by_us {
-                    // We cannot add statements to an existing block, so we create a new
-                    // block for our StorageDead statements.
-                    let block = cfg.start_new_cleanup_block();
-                    let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope };
-                    cfg.goto(block, source_info, target);
-                    target = block;
-                    target_built_by_us = true;
-                }
-                *drop_data.cached_block.ref_mut(generator_drop) = Some(target);
-            }
-            DropKind::Storage => {}
-            DropKind::Value => {
-                let cached_block = drop_data.cached_block.ref_mut(generator_drop);
-                target = if let Some(cached_block) = *cached_block {
-                    storage_deads.clear();
-                    target_built_by_us = false;
-                    cached_block
-                } else {
-                    push_storage_deads(cfg, target, &mut storage_deads);
-                    let block = cfg.start_new_cleanup_block();
-                    cfg.terminate(
-                        block,
-                        source_info(drop_data.span),
-                        TerminatorKind::Drop {
-                            location: drop_data.local.into(),
-                            target,
-                            unwind: None,
-                        },
-                    );
-                    *cached_block = Some(block);
-                    target_built_by_us = true;
-                    block
-                };
-            }
-        };
-    }
-    push_storage_deads(cfg, target, &mut storage_deads);
-    *scope.cached_unwind.ref_mut(generator_drop) = Some(target);
-
-    assert!(storage_deads.is_empty());
-    debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
-
-    target
-}
-
-fn push_storage_deads(
-    cfg: &mut CFG<'tcx>,
-    target: BasicBlock,
-    storage_deads: &mut Vec<Statement<'tcx>>,
-) {
-    if storage_deads.is_empty() {
-        return;
-    }
-    let statements = &mut cfg.block_data_mut(target).statements;
-    storage_deads.reverse();
-    debug!(
-        "push_storage_deads({:?}), storage_deads={:?}, statements={:?}",
-        target, storage_deads, statements
-    );
-    storage_deads.append(statements);
-    mem::swap(statements, storage_deads);
-    assert!(storage_deads.is_empty());
-}
index ac04ae285884b39887bcff556075536f111928d6..aa7be3d80e1dcca997421f7fa3f723a2e7c239e9 100644 (file)
@@ -9,10 +9,12 @@
 
 mod error;
 mod eval_queries;
+mod fn_queries;
 mod machine;
 
 pub use error::*;
 pub use eval_queries::*;
+pub use fn_queries::*;
 pub use machine::*;
 
 /// Extracts a field of a (variant of a) const.
@@ -50,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
 
     let loc_ty = tcx.caller_location_ty();
     let loc_place = ecx.alloc_caller_location(file, line, col);
-    intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
+    intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
     let loc_const = ty::Const {
         ty: loc_ty,
         val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),
@@ -59,15 +61,32 @@ pub(crate) fn const_caller_location<'tcx>(
     tcx.mk_const(loc_const)
 }
 
-// this function uses `unwrap` copiously, because an already validated constant must have valid
-// fields and can thus never fail outside of compiler bugs
-pub(crate) fn const_variant_index<'tcx>(
+// this function uses `unwrap` copiously, because an already validated constant
+// must have valid fields and can thus never fail outside of compiler bugs
+pub(crate) fn destructure_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     val: &'tcx ty::Const<'tcx>,
-) -> VariantIdx {
-    trace!("const_variant_index: {:?}", val);
+) -> mir::DestructuredConst<'tcx> {
+    trace!("destructure_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
     let op = ecx.eval_const_to_op(val, None).unwrap();
-    ecx.read_discriminant(op).unwrap().1
+
+    let variant = ecx.read_discriminant(op).unwrap().1;
+
+    let field_count = match val.ty.kind {
+        ty::Array(_, len) => len.eval_usize(tcx, param_env),
+        ty::Adt(def, _) => def.variants[variant].fields.len() as u64,
+        ty::Tuple(substs) => substs.len() as u64,
+        _ => bug!("cannot destructure constant {:?}", val),
+    };
+
+    let down = ecx.operand_downcast(op, variant).unwrap();
+    let fields_iter = (0..field_count).map(|i| {
+        let field_op = ecx.operand_field(down, i).unwrap();
+        op_to_const(&ecx, field_op)
+    });
+    let fields = tcx.arena.alloc_from_iter(fields_iter);
+
+    mir::DestructuredConst { variant, fields }
 }
index dbeb75b60c2909d02f695b6095afd45c4f056d8a..d260a6808d120dc37929a59a53e7b1bf750627e0 100644 (file)
@@ -56,7 +56,12 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.run()?;
 
     // Intern the result
-    intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?;
+    intern_const_alloc_recursive(
+        ecx,
+        tcx.static_mutability(cid.instance.def_id()),
+        ret,
+        body.ignore_interior_mut_in_const_validation,
+    )?;
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret)
@@ -115,28 +120,31 @@ pub(super) fn op_to_const<'tcx>(
         // by-val is if we are in const_field, i.e., if this is (a field of) something that we
         // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
         // structs containing such.
-        op.try_as_mplace()
+        op.try_as_mplace(ecx)
     };
-    let val = match immediate {
-        Ok(mplace) => {
-            let ptr = mplace.ptr.assert_ptr();
+
+    let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr {
+        Scalar::Ptr(ptr) => {
             let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
             ConstValue::ByRef { alloc, offset: ptr.offset }
         }
+        Scalar::Raw { data, .. } => {
+            assert!(mplace.layout.is_zst());
+            assert_eq!(
+                data,
+                mplace.layout.align.abi.bytes().into(),
+                "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what
+                 value this integer address must have",
+            );
+            ConstValue::Scalar(Scalar::zst())
+        }
+    };
+    let val = match immediate {
+        Ok(mplace) => to_const_value(mplace),
         // see comment on `let try_as_immediate` above
         Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x {
             ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s),
-            ScalarMaybeUndef::Undef => {
-                // When coming out of "normal CTFE", we'll always have an `Indirect` operand as
-                // argument and we will not need this. The only way we can already have an
-                // `Immediate` is when we are called from `const_field`, and that `Immediate`
-                // comes from a constant so it can happen have `Undef`, because the indirect
-                // memory that was read had undefined bytes.
-                let mplace = op.assert_mem_place();
-                let ptr = mplace.ptr.assert_ptr();
-                let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
-                ConstValue::ByRef { alloc, offset: ptr.offset }
-            }
+            ScalarMaybeUndef::Undef => to_const_value(op.assert_mem_place(ecx)),
         },
         Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => {
             let (data, start) = match a.not_undef().unwrap() {
@@ -168,9 +176,14 @@ fn validate_and_turn_into_const<'tcx>(
     let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
     let val = (|| {
         let mplace = ecx.raw_const_to_mplace(constant)?;
-        let mut ref_tracking = RefTracking::new(mplace);
-        while let Some((mplace, path)) = ref_tracking.todo.pop() {
-            ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
+
+        // FIXME do not validate promoteds until a decision on
+        // https://github.com/rust-lang/rust/issues/67465 is made
+        if cid.promoted.is_none() {
+            let mut ref_tracking = RefTracking::new(mplace);
+            while let Some((mplace, path)) = ref_tracking.todo.pop() {
+                ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
+            }
         }
         // Now that we validated, turn this into a proper constant.
         // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
diff --git a/src/librustc_mir/const_eval/fn_queries.rs b/src/librustc_mir/const_eval/fn_queries.rs
new file mode 100644 (file)
index 0000000..2443e1e
--- /dev/null
@@ -0,0 +1,151 @@
+use rustc::hir::map::blocks::FnLikeNode;
+use rustc::ty::query::Providers;
+use rustc::ty::TyCtxt;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::Symbol;
+use rustc_target::spec::abi::Abi;
+use syntax::attr;
+
+/// Whether the `def_id` counts as const fn in your current crate, considering all active
+/// feature gates
+pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    tcx.is_const_fn_raw(def_id)
+        && match is_unstable_const_fn(tcx, def_id) {
+            Some(feature_name) => {
+                // has a `rustc_const_unstable` attribute, check whether the user enabled the
+                // corresponding feature gate.
+                tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
+            }
+            // functions without const stability are either stable user written
+            // const fn or the user is using feature gates and we thus don't
+            // care what they do
+            None => true,
+        }
+}
+
+/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
+pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
+    if tcx.is_const_fn_raw(def_id) {
+        let const_stab = tcx.lookup_const_stability(def_id)?;
+        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
+    } else {
+        None
+    }
+}
+
+/// Returns `true` if this function must conform to `min_const_fn`
+pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    // Bail out if the signature doesn't contain `const`
+    if !tcx.is_const_fn_raw(def_id) {
+        return false;
+    }
+
+    if tcx.features().staged_api {
+        // In order for a libstd function to be considered min_const_fn
+        // it needs to be stable and have no `rustc_const_unstable` attribute.
+        match tcx.lookup_const_stability(def_id) {
+            // `rustc_const_unstable` functions don't need to conform.
+            Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
+            None => {
+                if let Some(stab) = tcx.lookup_stability(def_id) {
+                    if stab.level.is_stable() {
+                        tcx.sess.span_err(
+                            tcx.def_span(def_id),
+                            "stable const functions must have either `rustc_const_stable` or \
+                             `rustc_const_unstable` attribute",
+                        );
+                        // While we errored above, because we don't know if we need to conform, we
+                        // err on the "safe" side and require min_const_fn.
+                        true
+                    } else {
+                        // Unstable functions need not conform to min_const_fn.
+                        false
+                    }
+                } else {
+                    // Internal functions are forced to conform to min_const_fn.
+                    // Annotate the internal function with a const stability attribute if
+                    // you need to use unstable features.
+                    // Note: this is an arbitrary choice that does not affect stability or const
+                    // safety or anything, it just changes whether we need to annotate some
+                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
+                    true
+                }
+            }
+            // Everything else needs to conform, because it would be callable from
+            // other `min_const_fn` functions.
+            _ => true,
+        }
+    } else {
+        // users enabling the `const_fn` feature gate can do what they want
+        !tcx.features().const_fn
+    }
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    /// Const evaluability whitelist is here to check evaluability at the
+    /// top level beforehand.
+    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
+        match tcx.fn_sig(def_id).abi() {
+            Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
+                Some(tcx.lookup_const_stability(def_id).is_some())
+            }
+            _ => None,
+        }
+    }
+
+    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
+    /// said intrinsic is on the whitelist for being const callable.
+    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        let hir_id = tcx
+            .hir()
+            .as_local_hir_id(def_id)
+            .expect("Non-local call to local provider is_const_fn");
+
+        let node = tcx.hir().get(hir_id);
+
+        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
+            whitelisted
+        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
+            fn_like.constness() == hir::Constness::Const
+        } else if let hir::Node::Ctor(_) = node {
+            true
+        } else {
+            false
+        }
+    }
+
+    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        is_const_fn(tcx, def_id)
+            && match tcx.lookup_const_stability(def_id) {
+                Some(stab) => {
+                    if cfg!(debug_assertions) && stab.promotable {
+                        let sig = tcx.fn_sig(def_id);
+                        assert_eq!(
+                            sig.unsafety(),
+                            hir::Unsafety::Normal,
+                            "don't mark const unsafe fns as promotable",
+                            // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
+                        );
+                    }
+                    stab.promotable
+                }
+                None => false,
+            }
+    }
+
+    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        is_const_fn(tcx, def_id)
+            && tcx
+                .lookup_const_stability(def_id)
+                .map(|stab| stab.allow_const_fn_ptr)
+                .unwrap_or(false)
+    }
+
+    *providers = Providers {
+        is_const_fn_raw,
+        is_promotable_const_fn,
+        const_fn_is_allowed_fn_ptr,
+        ..*providers
+    };
+}
index 65976908f597e4e436fbd76a170a96ac747d6064..63834d0ecda00215a26601e183d944a998541ae7 100644 (file)
@@ -86,10 +86,7 @@ struct BorrowedLocalsVisitor<'gk> {
 }
 
 fn find_local(place: &Place<'_>) -> Option<Local> {
-    match place.base {
-        PlaceBase::Local(local) if !place.is_indirect() => Some(local),
-        _ => None,
-    }
+    if !place.is_indirect() { Some(place.local) } else { None }
 }
 
 impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> {
index 8d51cb2391234749c76d1832ac7e078f690504f2..f94ee67f2bea7c72d2aab2138bd9d8ddea1b33a3 100644 (file)
@@ -1,6 +1,6 @@
-use rustc::mir::{self, Body, Location, Place, PlaceBase};
+use rustc::mir::{self, Body, Location, Place};
 use rustc::ty::RegionVid;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
@@ -30,7 +30,6 @@ pub struct BorrowIndex {
 pub struct Borrows<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
 
     borrow_set: Rc<BorrowSet<'tcx>>,
     borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
@@ -134,7 +133,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     crate fn new(
         tcx: TyCtxt<'tcx>,
         body: &'a Body<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
         nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
         borrow_set: &Rc<BorrowSet<'tcx>>,
     ) -> Self {
@@ -156,7 +154,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         Borrows {
             tcx,
             body,
-            param_env,
             borrow_set: borrow_set.clone(),
             borrows_out_of_scope_at_location,
             _nonlexical_regioncx: nonlexical_regioncx,
@@ -198,37 +195,34 @@ fn kill_loans_out_of_scope_at_location(
     fn kill_borrows_on_place(&self, trans: &mut GenKillSet<BorrowIndex>, place: &Place<'tcx>) {
         debug!("kill_borrows_on_place: place={:?}", place);
 
-        if let PlaceBase::Local(local) = place.base {
-            let other_borrows_of_local =
-                self.borrow_set.local_map.get(&local).into_iter().flat_map(|bs| bs.into_iter());
+        let other_borrows_of_local =
+            self.borrow_set.local_map.get(&place.local).into_iter().flat_map(|bs| bs.into_iter());
 
-            // If the borrowed place is a local with no projections, all other borrows of this
-            // local must conflict. This is purely an optimization so we don't have to call
-            // `places_conflict` for every borrow.
-            if place.projection.is_empty() {
-                if !self.body.local_decls[local].is_ref_to_static() {
-                    trans.kill_all(other_borrows_of_local);
-                }
-                return;
+        // If the borrowed place is a local with no projections, all other borrows of this
+        // local must conflict. This is purely an optimization so we don't have to call
+        // `places_conflict` for every borrow.
+        if place.projection.is_empty() {
+            if !self.body.local_decls[place.local].is_ref_to_static() {
+                trans.kill_all(other_borrows_of_local);
             }
-
-            // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
-            // pair of array indices are unequal, so that when `places_conflict` returns true, we
-            // will be assured that two places being compared definitely denotes the same sets of
-            // locations.
-            let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| {
-                places_conflict(
-                    self.tcx,
-                    self.param_env,
-                    self.body,
-                    &self.borrow_set.borrows[i].borrowed_place,
-                    place,
-                    PlaceConflictBias::NoOverlap,
-                )
-            });
-
-            trans.kill_all(definitely_conflicting_borrows);
+            return;
         }
+
+        // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
+        // pair of array indices are unequal, so that when `places_conflict` returns true, we
+        // will be assured that two places being compared definitely denotes the same sets of
+        // locations.
+        let definitely_conflicting_borrows = other_borrows_of_local.filter(|&&i| {
+            places_conflict(
+                self.tcx,
+                self.body,
+                &self.borrow_set.borrows[i].borrowed_place,
+                place,
+                PlaceConflictBias::NoOverlap,
+            )
+        });
+
+        trans.kill_all(definitely_conflicting_borrows);
     }
 }
 
index 38401b42b48a8a3019a06c39fa988a0477893956..85bf342c8a39a95da5efd20d1367a1656cd88247 100644 (file)
@@ -111,12 +111,8 @@ impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
         if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
             if self.borrow_allows_mutation(kind, borrowed_place) {
-                match borrowed_place.base {
-                    mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect() => {
-                        self.trans.gen(borrowed_local)
-                    }
-
-                    _ => (),
+                if !borrowed_place.is_indirect() {
+                    self.trans.gen(borrowed_place.local);
                 }
             }
         }
index 17f71e83cfd21c8d3f917b288cee817795c21d3f..6a48d1e98032c0d92426e1b7ae2d8e9b3e2c9144 100644 (file)
@@ -116,15 +116,11 @@ fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Locatio
             StatementKind::StorageDead(l) => sets.kill(l),
             StatementKind::Assign(box (ref place, _))
             | StatementKind::SetDiscriminant { box ref place, .. } => {
-                if let PlaceBase::Local(local) = place.base {
-                    sets.gen(local);
-                }
+                sets.gen(place.local);
             }
             StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => {
-                for p in &**outputs {
-                    if let PlaceBase::Local(local) = p.base {
-                        sets.gen(local);
-                    }
+                for place in &**outputs {
+                    sets.gen(place.local);
                 }
             }
             _ => (),
@@ -140,10 +136,8 @@ fn statement_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
     fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
         self.check_for_borrow(sets, loc);
 
-        if let TerminatorKind::Call {
-            destination: Some((Place { base: PlaceBase::Local(local), .. }, _)),
-            ..
-        } = self.body[loc.block].terminator().kind
+        if let TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } =
+            self.body[loc.block].terminator().kind
         {
             sets.gen(local);
         }
@@ -171,9 +165,7 @@ fn propagate_call_return(
         _dest_bb: mir::BasicBlock,
         dest_place: &mir::Place<'tcx>,
     ) {
-        if let PlaceBase::Local(local) = dest_place.base {
-            in_out.insert(local);
-        }
+        in_out.insert(dest_place.local);
     }
 }
 
index 01f6177a93ab43488dbdacda2de57652d25e2b0a..e29730f267c2c61493866554f7070e2d0070c9cc 100644 (file)
@@ -668,6 +668,26 @@ pub trait BottomValue {
     const BOTTOM_VALUE: bool;
 
     /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed.
+    ///
+    /// It is almost certainly wrong to override this, since it automatically applies
+    /// * `inout_set & in_set` if `BOTTOM_VALUE == true`
+    /// * `inout_set | in_set` if `BOTTOM_VALUE == false`
+    ///
+    /// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks.
+    /// For clarity, the above statement again from a different perspective:
+    /// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is
+    /// `!BOTTOM_VALUE`.
+    ///
+    /// There are situations where you want the opposite behaviour: propagate only if *all*
+    /// predecessor blocks's value is `!BOTTOM_VALUE`.
+    /// E.g. if you want to know whether a bit is *definitely* set at a specific location. This
+    /// means that all code paths leading to the location must have set the bit, instead of any
+    /// code path leading there.
+    ///
+    /// If you want this kind of "definitely set" analysis, you need to
+    /// 1. Invert `BOTTOM_VALUE`
+    /// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE`
+    /// 3. Override `join` to do the opposite from what it's doing now.
     #[inline]
     fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
         if Self::BOTTOM_VALUE == false {
@@ -685,7 +705,9 @@ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
 /// for each block individually. The entry set for all other basic blocks is
 /// initialized to `Self::BOTTOM_VALUE`. The dataflow analysis then
 /// iteratively modifies the various entry sets (but leaves the the transfer
-/// function unchanged).
+/// function unchanged). `BottomValue::join` is used to merge the bitsets from
+/// two blocks (e.g. when two blocks' terminator jumps to a single block, that
+/// target block's state is the merged state of both incoming blocks).
 pub trait BitDenotation<'tcx>: BottomValue {
     /// Specifies what index type is used to access the bitvector.
     type Idx: Idx;
index c05f7f8959dbfb0cd36d5d15e4ea767f03198c40..271bcce6ca53c3873c08dbb559b06854432032b3 100644 (file)
@@ -96,12 +96,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     /// Maybe we should have separate "borrowck" and "moveck" modes.
     fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
         debug!("lookup({:?})", place);
-        let mut base = match place.base {
-            PlaceBase::Local(local) => self.builder.data.rev_lookup.locals[local],
-            PlaceBase::Static(..) => {
-                return Err(MoveError::cannot_move_out_of(self.loc, Static));
-            }
-        };
+        let mut base = self.builder.data.rev_lookup.locals[place.local];
 
         // The move path index of the first union that we find. Once this is
         // some we stop creating child move paths, since moves from unions
@@ -114,7 +109,7 @@ fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveEr
             let proj_base = &place.projection[..i];
             let body = self.builder.body;
             let tcx = self.builder.tcx;
-            let place_ty = Place::ty_from(&place.base, proj_base, body, tcx).ty;
+            let place_ty = Place::ty_from(&place.local, proj_base, body, tcx).ty;
             match place_ty.kind {
                 ty::Ref(..) | ty::RawPtr(..) => {
                     let proj = &place.projection[..i + 1];
@@ -122,7 +117,7 @@ fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveEr
                         self.loc,
                         BorrowedContent {
                             target_place: Place {
-                                base: place.base.clone(),
+                                local: place.local,
                                 projection: tcx.intern_place_elems(proj),
                             },
                         },
@@ -163,7 +158,7 @@ fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveEr
 
             if union_path.is_none() {
                 base = self.add_move_path(base, elem, |tcx| Place {
-                    base: place.base.clone(),
+                    local: place.local.clone(),
                     projection: tcx.intern_place_elems(&place.projection[..i + 1]),
                 });
             }
@@ -436,7 +431,7 @@ fn gather_move(&mut self, place: &Place<'tcx>) {
             // `ConstIndex` patterns. This is done to ensure that all move paths
             // are disjoint, which is expected by drop elaboration.
             let base_place = Place {
-                base: place.base.clone(),
+                local: place.local.clone(),
                 projection: self.builder.tcx.intern_place_elems(base),
             };
             let base_path = match self.move_path_for(&base_place) {
@@ -497,10 +492,10 @@ fn gather_init(&mut self, place: PlaceRef<'cx, 'tcx>, kind: InitKind) {
         // of the union so it is marked as initialized again.
         if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
             if let ty::Adt(def, _) =
-                Place::ty_from(place.base, proj_base, self.builder.body, self.builder.tcx).ty.kind
+                Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx).ty.kind
             {
                 if def.is_union() {
-                    place = PlaceRef { base: place.base, projection: proj_base }
+                    place = PlaceRef { local: place.local, projection: proj_base }
                 }
             }
         }
index e5cddaf6c66f28839c752ff1a7936d5952dd948a..a46465ab4937646b5b744f1bc77f016275cc23fd 100644 (file)
@@ -246,10 +246,7 @@ impl MovePathLookup {
     // unknown place, but will rather return the nearest available
     // parent.
     pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult {
-        let mut result = match place.base {
-            PlaceBase::Local(local) => self.locals[*local],
-            PlaceBase::Static(..) => return LookupResult::Parent(None),
-        };
+        let mut result = self.locals[*place.local];
 
         for elem in place.projection.iter() {
             if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
@@ -281,9 +278,6 @@ pub struct IllegalMoveOrigin<'tcx> {
 
 #[derive(Debug)]
 pub(crate) enum IllegalMoveOriginKind<'tcx> {
-    /// Illegal move due to attempt to move from `static` variable.
-    Static,
-
     /// Illegal move due to attempt to move from behind a reference.
     BorrowedContent {
         /// The place the reference refers to: if erroneous code was trying to
diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs
deleted file mode 100644 (file)
index a4bedfa..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-use rustc::mir::interpret::{ConstValue, Scalar};
-use rustc::ty::{self, layout::Size, ParamEnv, Ty, TyCtxt};
-use rustc_span::symbol::Symbol;
-use syntax::ast;
-
-#[derive(PartialEq)]
-crate enum LitToConstError {
-    UnparseableFloat,
-    Reported,
-}
-
-crate fn lit_to_const<'tcx>(
-    lit: &'tcx ast::LitKind,
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-    neg: bool,
-) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
-    use syntax::ast::*;
-
-    let trunc = |n| {
-        let param_ty = ParamEnv::reveal_all().and(ty);
-        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
-        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
-        let result = truncate(n, width);
-        trace!("trunc result: {}", result);
-        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
-    };
-
-    use rustc::mir::interpret::*;
-    let lit = match *lit {
-        LitKind::Str(ref s, _) => {
-            let s = s.as_str();
-            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
-            let allocation = tcx.intern_const_alloc(allocation);
-            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
-        }
-        LitKind::ByteStr(ref data) => {
-            let id = tcx.allocate_bytes(data);
-            ConstValue::Scalar(Scalar::Ptr(id.into()))
-        }
-        LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))),
-        LitKind::Int(n, _) if neg => {
-            let n = n as i128;
-            let n = n.overflowing_neg().0;
-            trunc(n as u128)?
-        }
-        LitKind::Int(n, _) => trunc(n)?,
-        LitKind::Float(n, _) => {
-            let fty = match ty.kind {
-                ty::Float(fty) => fty,
-                _ => bug!(),
-            };
-            parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
-        }
-        LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
-        LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
-        LitKind::Err(_) => unreachable!(),
-    };
-    Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(lit), ty }))
-}
-
-fn parse_float<'tcx>(num: Symbol, fty: ast::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
-    let num = num.as_str();
-    use rustc_apfloat::ieee::{Double, Single};
-    let scalar = match fty {
-        ast::FloatTy::F32 => {
-            num.parse::<f32>().map_err(|_| ())?;
-            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
-                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
-            });
-            if neg {
-                f = -f;
-            }
-            Scalar::from_f32(f)
-        }
-        ast::FloatTy::F64 => {
-            num.parse::<f64>().map_err(|_| ())?;
-            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
-                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
-            });
-            if neg {
-                f = -f;
-            }
-            Scalar::from_f64(f)
-        }
-    };
-
-    Ok(ConstValue::Scalar(scalar))
-}
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
deleted file mode 100644 (file)
index 674c148..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-use crate::hair::cx::to_ref::ToRef;
-use crate::hair::cx::Cx;
-use crate::hair::{self, *};
-
-use rustc::middle::region;
-use rustc::ty;
-use rustc_hir as hir;
-
-use rustc_index::vec::Idx;
-
-impl<'tcx> Mirror<'tcx> for &'tcx hir::Block<'tcx> {
-    type Output = Block<'tcx>;
-
-    fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
-        // We have to eagerly lower the "spine" of the statements
-        // in order to get the lexical scoping correctly.
-        let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts);
-        let opt_destruction_scope =
-            cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id);
-        Block {
-            targeted_by_break: self.targeted_by_break,
-            region_scope: region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node },
-            opt_destruction_scope,
-            span: self.span,
-            stmts,
-            expr: self.expr.to_ref(),
-            safety_mode: match self.rules {
-                hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
-                hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(self.hir_id),
-                hir::BlockCheckMode::PushUnsafeBlock(..) => BlockSafety::PushUnsafe,
-                hir::BlockCheckMode::PopUnsafeBlock(..) => BlockSafety::PopUnsafe,
-            },
-        }
-    }
-}
-
-fn mirror_stmts<'a, 'tcx>(
-    cx: &mut Cx<'a, 'tcx>,
-    block_id: hir::ItemLocalId,
-    stmts: &'tcx [hir::Stmt<'tcx>],
-) -> Vec<StmtRef<'tcx>> {
-    let mut result = vec![];
-    for (index, stmt) in stmts.iter().enumerate() {
-        let hir_id = stmt.hir_id;
-        let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id);
-        match stmt.kind {
-            hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
-                result.push(StmtRef::Mirror(Box::new(Stmt {
-                    kind: StmtKind::Expr {
-                        scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node },
-                        expr: expr.to_ref(),
-                    },
-                    opt_destruction_scope: opt_dxn_ext,
-                })))
-            }
-            hir::StmtKind::Item(..) => {
-                // ignore for purposes of the MIR
-            }
-            hir::StmtKind::Local(ref local) => {
-                let remainder_scope = region::Scope {
-                    id: block_id,
-                    data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
-                };
-
-                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) {
-                        debug!("mirror_stmts: user_ty={:?}", user_ty);
-                        pattern = Pat {
-                            ty: pattern.ty,
-                            span: pattern.span,
-                            kind: Box::new(PatKind::AscribeUserType {
-                                ascription: hair::pattern::Ascription {
-                                    user_ty: PatTyProj::from_user_type(user_ty),
-                                    user_ty_span: ty.span,
-                                    variance: ty::Variance::Covariant,
-                                },
-                                subpattern: pattern,
-                            }),
-                        };
-                    }
-                }
-
-                result.push(StmtRef::Mirror(Box::new(Stmt {
-                    kind: StmtKind::Let {
-                        remainder_scope: remainder_scope,
-                        init_scope: region::Scope {
-                            id: hir_id.local_id,
-                            data: region::ScopeData::Node,
-                        },
-                        pattern,
-                        initializer: local.init.to_ref(),
-                        lint_level: LintLevel::Explicit(local.hir_id),
-                    },
-                    opt_destruction_scope: opt_dxn_ext,
-                })));
-            }
-        }
-    }
-    return result;
-}
-
-pub fn to_expr_ref<'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 temp_lifetime = cx.region_scope_tree.temporary_scope(block.hir_id.local_id);
-    let expr = Expr {
-        ty: block_ty,
-        temp_lifetime,
-        span: block.span,
-        kind: ExprKind::Block { body: block },
-    };
-    expr.to_ref()
-}
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
deleted file mode 100644 (file)
index 8fd8143..0000000
+++ /dev/null
@@ -1,1017 +0,0 @@
-use crate::hair::cx::block;
-use crate::hair::cx::to_ref::ToRef;
-use crate::hair::cx::Cx;
-use crate::hair::util::UserAnnotatedTyHelpers;
-use crate::hair::*;
-use rustc::mir::interpret::{ErrorHandled, Scalar};
-use rustc::mir::BorrowKind;
-use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast};
-use rustc::ty::subst::{InternalSubsts, SubstsRef};
-use rustc::ty::{self, AdtKind, Ty};
-use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::def_id::LocalDefId;
-use rustc_index::vec::Idx;
-use rustc_span::Span;
-
-impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr<'tcx> {
-    type Output = Expr<'tcx>;
-
-    fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
-        let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id);
-        let expr_scope = region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node };
-
-        debug!("Expr::make_mirror(): id={}, span={:?}", self.hir_id, self.span);
-
-        let mut expr = make_mirror_unadjusted(cx, self);
-
-        // Now apply adjustments, if any.
-        for adjustment in cx.tables().expr_adjustments(self) {
-            debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
-            expr = apply_adjustment(cx, self, expr, adjustment);
-        }
-
-        // Next, wrap this up in the expr's scope.
-        expr = Expr {
-            temp_lifetime,
-            ty: expr.ty,
-            span: self.span,
-            kind: ExprKind::Scope {
-                region_scope: expr_scope,
-                value: expr.to_ref(),
-                lint_level: LintLevel::Explicit(self.hir_id),
-            },
-        };
-
-        // Finally, create a destruction scope, if any.
-        if let Some(region_scope) = cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id)
-        {
-            expr = Expr {
-                temp_lifetime,
-                ty: expr.ty,
-                span: self.span,
-                kind: ExprKind::Scope {
-                    region_scope,
-                    value: expr.to_ref(),
-                    lint_level: LintLevel::Inherited,
-                },
-            };
-        }
-
-        // OK, all done!
-        expr
-    }
-}
-
-fn apply_adjustment<'a, 'tcx>(
-    cx: &mut Cx<'a, 'tcx>,
-    hir_expr: &'tcx hir::Expr<'tcx>,
-    mut expr: Expr<'tcx>,
-    adjustment: &Adjustment<'tcx>,
-) -> Expr<'tcx> {
-    let Expr { temp_lifetime, mut span, .. } = expr;
-
-    // Adjust the span from the block, to the last expression of the
-    // block. This is a better span when returning a mutable reference
-    // with too short a lifetime. The error message will use the span
-    // from the assignment to the return place, which should only point
-    // at the returned value, not the entire function body.
-    //
-    // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 {
-    //      x
-    //   // ^ error message points at this expression.
-    // }
-    let mut adjust_span = |expr: &mut Expr<'tcx>| {
-        if let ExprKind::Block { body } = expr.kind {
-            if let Some(ref last_expr) = body.expr {
-                span = last_expr.span;
-                expr.span = span;
-            }
-        }
-    };
-
-    let kind = match adjustment.kind {
-        Adjust::Pointer(PointerCast::Unsize) => {
-            adjust_span(&mut expr);
-            ExprKind::Pointer { cast: PointerCast::Unsize, source: expr.to_ref() }
-        }
-        Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: expr.to_ref() },
-        Adjust::NeverToAny => ExprKind::NeverToAny { source: expr.to_ref() },
-        Adjust::Deref(None) => {
-            adjust_span(&mut expr);
-            ExprKind::Deref { arg: expr.to_ref() }
-        }
-        Adjust::Deref(Some(deref)) => {
-            // We don't need to do call adjust_span here since
-            // deref coercions always start with a built-in deref.
-            let call = deref.method_call(cx.tcx(), expr.ty);
-
-            expr = Expr {
-                temp_lifetime,
-                ty: cx.tcx.mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }),
-                span,
-                kind: ExprKind::Borrow {
-                    borrow_kind: deref.mutbl.to_borrow_kind(),
-                    arg: expr.to_ref(),
-                },
-            };
-
-            overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
-        }
-        Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
-            ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
-        }
-        Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
-            ExprKind::AddressOf { mutability, arg: expr.to_ref() }
-        }
-    };
-
-    Expr { temp_lifetime, ty: adjustment.target, span, kind }
-}
-
-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 temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-
-    let kind = match expr.kind {
-        // Here comes the interesting stuff:
-        hir::ExprKind::MethodCall(_, method_span, ref args) => {
-            // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
-            let expr = method_callee(cx, expr, method_span, None);
-            let args = args.iter().map(|e| e.to_ref()).collect();
-            ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true }
-        }
-
-        hir::ExprKind::Call(ref fun, ref args) => {
-            if cx.tables().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
-                // callee-object as expr parameter.
-
-                // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
-
-                let method = method_callee(cx, expr, fun.span, None);
-
-                let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
-                let tupled_args = Expr {
-                    ty: cx.tcx.mk_tup(arg_tys),
-                    temp_lifetime,
-                    span: expr.span,
-                    kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
-                };
-
-                ExprKind::Call {
-                    ty: method.ty,
-                    fun: method.to_ref(),
-                    args: vec![fun.to_ref(), tupled_args.to_ref()],
-                    from_hir_call: true,
-                }
-            } else {
-                let adt_data =
-                    if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind {
-                        // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
-                        expr_ty.ty_adt_def().and_then(|adt_def| match path.res {
-                            Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
-                                Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
-                            }
-                            Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))),
-                            _ => None,
-                        })
-                    } else {
-                        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 user_ty =
-                        user_provided_types.get(fun.hir_id).map(|u_ty| *u_ty).map(|mut u_ty| {
-                            if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
-                                *did = adt_def.did;
-                            }
-                            u_ty
-                        });
-                    debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
-
-                    let field_refs = args
-                        .iter()
-                        .enumerate()
-                        .map(|(idx, e)| FieldExprRef { name: Field::new(idx), expr: e.to_ref() })
-                        .collect();
-                    ExprKind::Adt {
-                        adt_def,
-                        substs,
-                        variant_index: index,
-                        fields: field_refs,
-                        user_ty,
-                        base: None,
-                    }
-                } else {
-                    ExprKind::Call {
-                        ty: cx.tables().node_type(fun.hir_id),
-                        fun: fun.to_ref(),
-                        args: args.to_ref(),
-                        from_hir_call: true,
-                    }
-                }
-            }
-        }
-
-        hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => {
-            ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: arg.to_ref() }
-        }
-
-        hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
-            ExprKind::AddressOf { mutability, arg: arg.to_ref() }
-        }
-
-        hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk },
-
-        hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
-            ExprKind::Assign { lhs: lhs.to_ref(), rhs: rhs.to_ref() }
-        }
-
-        hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-            if cx.tables().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() }
-            }
-        }
-
-        hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
-            literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
-            user_ty: None,
-        },
-
-        hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
-            if cx.tables().is_method_call(expr) {
-                overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
-            } else {
-                // FIXME overflow
-                match (op.node, cx.constness) {
-                    // Destroy control flow if `#![feature(const_if_match)]` is not enabled.
-                    (hir::BinOpKind::And, hir::Constness::Const)
-                        if !cx.tcx.features().const_if_match =>
-                    {
-                        cx.control_flow_destroyed.push((op.span, "`&&` operator".into()));
-                        ExprKind::Binary { op: BinOp::BitAnd, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
-                    }
-                    (hir::BinOpKind::Or, hir::Constness::Const)
-                        if !cx.tcx.features().const_if_match =>
-                    {
-                        cx.control_flow_destroyed.push((op.span, "`||` operator".into()));
-                        ExprKind::Binary { op: BinOp::BitOr, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
-                    }
-
-                    (hir::BinOpKind::And, _) => ExprKind::LogicalOp {
-                        op: LogicalOp::And,
-                        lhs: lhs.to_ref(),
-                        rhs: rhs.to_ref(),
-                    },
-                    (hir::BinOpKind::Or, _) => ExprKind::LogicalOp {
-                        op: LogicalOp::Or,
-                        lhs: lhs.to_ref(),
-                        rhs: rhs.to_ref(),
-                    },
-
-                    _ => {
-                        let op = bin_op(op.node);
-                        ExprKind::Binary { op, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
-                    }
-                }
-            }
-        }
-
-        hir::ExprKind::Index(ref lhs, ref index) => {
-            if cx.tables().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() }
-            }
-        }
-
-        hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
-            if cx.tables().is_method_call(expr) {
-                overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()])
-            } else {
-                ExprKind::Deref { arg: arg.to_ref() }
-            }
-        }
-
-        hir::ExprKind::Unary(hir::UnOp::UnNot, ref arg) => {
-            if cx.tables().is_method_call(expr) {
-                overloaded_operator(cx, expr, vec![arg.to_ref()])
-            } else {
-                ExprKind::Unary { op: UnOp::Not, arg: arg.to_ref() }
-            }
-        }
-
-        hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => {
-            if cx.tables().is_method_call(expr) {
-                overloaded_operator(cx, expr, vec![arg.to_ref()])
-            } else {
-                if let hir::ExprKind::Lit(ref lit) = arg.kind {
-                    ExprKind::Literal {
-                        literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
-                        user_ty: None,
-                    }
-                } else {
-                    ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() }
-                }
-            }
-        }
-
-        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_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
-                    debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
-                    ExprKind::Adt {
-                        adt_def: adt,
-                        variant_index: VariantIdx::new(0),
-                        substs,
-                        user_ty,
-                        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(),
-                        }),
-                    }
-                }
-                AdtKind::Enum => {
-                    let res = cx.tables().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_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
-                            debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
-                            ExprKind::Adt {
-                                adt_def: adt,
-                                variant_index: index,
-                                substs,
-                                user_ty,
-                                fields: field_refs(cx, fields),
-                                base: None,
-                            }
-                        }
-                        _ => {
-                            span_bug!(expr.span, "unexpected res: {:?}", res);
-                        }
-                    }
-                }
-            },
-            _ => {
-                span_bug!(expr.span, "unexpected type for struct literal: {:?}", expr_ty);
-            }
-        },
-
-        hir::ExprKind::Closure(..) => {
-            let closure_ty = cx.tables().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) => {
-                    (def_id, UpvarSubsts::Generator(substs), Some(movability))
-                }
-                _ => {
-                    span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
-                }
-            };
-            let upvars = cx
-                .tcx
-                .upvars(def_id)
-                .iter()
-                .flat_map(|upvars| upvars.iter())
-                .zip(substs.upvar_tys(def_id, cx.tcx))
-                .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty))
-                .collect();
-            ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
-        }
-
-        hir::ExprKind::Path(ref qpath) => {
-            let res = cx.tables().qpath_res(qpath, expr.hir_id);
-            convert_path_expr(cx, expr, res)
-        }
-
-        hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
-            asm: &asm.inner,
-            outputs: asm.outputs_exprs.to_ref(),
-            inputs: asm.inputs_exprs.to_ref(),
-        },
-
-        // Now comes the rote stuff:
-        hir::ExprKind::Repeat(ref v, ref count) => {
-            let def_id = cx.tcx.hir().local_def_id(count.hir_id);
-            let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
-            let span = cx.tcx.def_span(def_id);
-            let count = match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, Some(span)) {
-                Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
-                Err(ErrorHandled::Reported) => 0,
-                Err(ErrorHandled::TooGeneric) => {
-                    let span = cx.tcx.def_span(def_id);
-                    cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters");
-                    0
-                }
-            };
-
-            ExprKind::Repeat { value: v.to_ref(), count }
-        }
-        hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.to_ref() },
-        hir::ExprKind::Break(dest, ref value) => match dest.target_id {
-            Ok(target_id) => ExprKind::Break {
-                label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
-                value: value.to_ref(),
-            },
-            Err(err) => bug!("invalid loop id for break: {}", err),
-        },
-        hir::ExprKind::Continue(dest) => match dest.target_id {
-            Ok(loop_id) => ExprKind::Continue {
-                label: region::Scope { id: loop_id.local_id, data: region::ScopeData::Node },
-            },
-            Err(err) => bug!("invalid loop id for continue: {}", err),
-        },
-        hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
-            scrutinee: discr.to_ref(),
-            arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
-        },
-        hir::ExprKind::Loop(ref body, _, _) => {
-            ExprKind::Loop { body: block::to_expr_ref(cx, body) }
-        }
-        hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
-            lhs: source.to_ref(),
-            name: Field::new(cx.tcx.field_index(expr.hir_id, cx.tables)),
-        },
-        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_ty = user_provided_types.get(cast_ty.hir_id);
-
-            debug!(
-                "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
-                expr, cast_ty.hir_id, user_ty,
-            );
-
-            // 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) {
-                // Convert the lexpr to a vexpr.
-                ExprKind::Use { source: source.to_ref() }
-            } else if cx.tables().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.
-                ExprKind::Pointer { source: source.to_ref(), cast: PointerCast::ArrayToPointer }
-            } else {
-                // check whether this is casting an enum variant discriminant
-                // to prevent cycles, we refer to the discriminant initializer
-                // which is always an integer and thus doesn't need to know the
-                // enum's layout (or its tag type) to compute it during const eval
-                // Example:
-                // enum Foo {
-                //     A,
-                //     B = A as isize + 4,
-                // }
-                // 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 {
-                            Res::Def(
-                                DefKind::Ctor(CtorOf::Variant, CtorKind::Const),
-                                variant_ctor_id,
-                            ) => {
-                                let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
-                                let (d, o) = adt_def.discriminant_def_for_variant(idx);
-                                use rustc::ty::util::IntTypeExt;
-                                let ty = adt_def.repr.discr_type();
-                                let ty = ty.to_ty(cx.tcx());
-                                Some((d, o, ty))
-                            }
-                            _ => None,
-                        },
-                    )
-                } else {
-                    None
-                };
-
-                let source = if let Some((did, offset, var_ty)) = var {
-                    let mk_const = |literal| {
-                        Expr {
-                            temp_lifetime,
-                            ty: var_ty,
-                            span: expr.span,
-                            kind: ExprKind::Literal { literal, user_ty: None },
-                        }
-                        .to_ref()
-                    };
-                    let offset = mk_const(ty::Const::from_bits(
-                        cx.tcx,
-                        offset as u128,
-                        cx.param_env.and(var_ty),
-                    ));
-                    match did {
-                        Some(did) => {
-                            // in case we are offsetting from a computed discriminant
-                            // and not the beginning of discriminants (which is always `0`)
-                            let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
-                            let lhs = mk_const(cx.tcx().mk_const(ty::Const {
-                                val: ty::ConstKind::Unevaluated(did, substs),
-                                ty: var_ty,
-                            }));
-                            let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
-                            Expr { temp_lifetime, ty: var_ty, span: expr.span, kind: bin }.to_ref()
-                        }
-                        None => offset,
-                    }
-                } else {
-                    source.to_ref()
-                };
-
-                ExprKind::Cast { source }
-            };
-
-            if let Some(user_ty) = user_ty {
-                // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
-                //       inefficient, revisit this when performance becomes an issue.
-                let cast_expr = Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: cast };
-                debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
-
-                ExprKind::ValueTypeAscription {
-                    source: cast_expr.to_ref(),
-                    user_ty: Some(*user_ty),
-                }
-            } else {
-                cast
-            }
-        }
-        hir::ExprKind::Type(ref source, ref ty) => {
-            let user_provided_types = cx.tables.user_provided_types();
-            let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty);
-            debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
-            if source.is_syntactic_place_expr() {
-                ExprKind::PlaceTypeAscription { source: source.to_ref(), user_ty }
-            } else {
-                ExprKind::ValueTypeAscription { source: source.to_ref(), user_ty }
-            }
-        }
-        hir::ExprKind::DropTemps(ref source) => ExprKind::Use { source: source.to_ref() },
-        hir::ExprKind::Box(ref value) => ExprKind::Box { value: value.to_ref() },
-        hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() },
-        hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
-
-        hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: v.to_ref() },
-        hir::ExprKind::Err => unreachable!(),
-    };
-
-    Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
-}
-
-fn user_substs_applied_to_res(
-    cx: &mut Cx<'a, 'tcx>,
-    hir_id: hir::HirId,
-    res: Res,
-) -> Option<ty::CanonicalUserType<'tcx>> {
-    debug!("user_substs_applied_to_res: res={:?}", res);
-    let user_provided_type = match res {
-        // A reference to something callable -- e.g., a fn, method, or
-        // a tuple-struct or tuple-variant. This has the type of a
-        // `Fn` but with the user-given substitutions.
-        Res::Def(DefKind::Fn, _)
-        | Res::Def(DefKind::Method, _)
-        | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
-        | Res::Def(DefKind::Const, _)
-        | Res::Def(DefKind::AssocConst, _) => {
-            cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty)
-        }
-
-        // A unit struct/variant which is used as a value (e.g.,
-        // `None`). This has the type of the enum/struct that defines
-        // this variant -- but with the substitutions given by the
-        // user.
-        Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
-            cx.user_substs_applied_to_ty_of_hir_id(hir_id)
-        }
-
-        // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
-        Res::SelfCtor(_) => cx.user_substs_applied_to_ty_of_hir_id(hir_id),
-
-        _ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
-    };
-    debug!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type);
-    user_provided_type
-}
-
-fn method_callee<'a, 'tcx>(
-    cx: &mut Cx<'a, 'tcx>,
-    expr: &hir::Expr<'_>,
-    span: Span,
-    overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-) -> Expr<'tcx> {
-    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-    let (def_id, substs, user_ty) = match overloaded_callee {
-        Some((def_id, substs)) => (def_id, substs, None),
-        None => {
-            let (kind, def_id) = cx
-                .tables()
-                .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)
-        }
-    };
-    let ty = cx.tcx().mk_fn_def(def_id, substs);
-    Expr {
-        temp_lifetime,
-        ty,
-        span,
-        kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx(), ty), user_ty },
-    }
-}
-
-trait ToBorrowKind {
-    fn to_borrow_kind(&self) -> BorrowKind;
-}
-
-impl ToBorrowKind for AutoBorrowMutability {
-    fn to_borrow_kind(&self) -> BorrowKind {
-        use rustc::ty::adjustment::AllowTwoPhase;
-        match *self {
-            AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut {
-                allow_two_phase_borrow: match allow_two_phase_borrow {
-                    AllowTwoPhase::Yes => true,
-                    AllowTwoPhase::No => false,
-                },
-            },
-            AutoBorrowMutability::Not => BorrowKind::Shared,
-        }
-    }
-}
-
-impl ToBorrowKind for hir::Mutability {
-    fn to_borrow_kind(&self) -> BorrowKind {
-        match *self {
-            hir::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
-            hir::Mutability::Not => BorrowKind::Shared,
-        }
-    }
-}
-
-fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> {
-    Arm {
-        pattern: cx.pattern_from_hir(&arm.pat),
-        guard: match arm.guard {
-            Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())),
-            _ => None,
-        },
-        body: arm.body.to_ref(),
-        lint_level: LintLevel::Explicit(arm.hir_id),
-        scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
-        span: arm.span,
-    }
-}
-
-fn convert_path_expr<'a, 'tcx>(
-    cx: &mut Cx<'a, 'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
-    res: Res,
-) -> ExprKind<'tcx> {
-    let substs = cx.tables().node_substs(expr.hir_id);
-    match res {
-        // A regular function, constructor function or a constant.
-        Res::Def(DefKind::Fn, _)
-        | Res::Def(DefKind::Method, _)
-        | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
-        | Res::SelfCtor(..) => {
-            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)),
-                user_ty,
-            }
-        }
-
-        Res::Def(DefKind::ConstParam, def_id) => {
-            let hir_id = cx.tcx.hir().as_local_hir_id(def_id).unwrap();
-            let item_id = cx.tcx.hir().get_parent_node(hir_id);
-            let item_def_id = cx.tcx.hir().local_def_id(item_id);
-            let generics = cx.tcx.generics_of(item_def_id);
-            let local_def_id = cx.tcx.hir().local_def_id(hir_id);
-            let index = generics.param_def_id_to_index[&local_def_id];
-            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) }),
-                user_ty: None,
-            }
-        }
-
-        Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
-            let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
-            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),
-                    ty: cx.tables().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_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
-            debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
-            let ty = cx.tables().node_type(expr.hir_id);
-            match ty.kind {
-                // A unit struct/variant which is used as a value.
-                // We return a completely different ExprKind here to account for this special case.
-                ty::Adt(adt_def, substs) => ExprKind::Adt {
-                    adt_def,
-                    variant_index: adt_def.variant_index_with_ctor_id(def_id),
-                    substs,
-                    user_ty: user_provided_type,
-                    fields: vec![],
-                    base: None,
-                },
-                _ => bug!("unexpected ty: {:?}", ty),
-            }
-        }
-
-        // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
-        // a constant reference (or constant raw pointer for `static mut`) in MIR
-        Res::Def(DefKind::Static, id) => {
-            let ty = cx.tcx.static_ptr_ty(id);
-            let ptr = cx.tcx.alloc_map.lock().create_static_alloc(id);
-            let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-            ExprKind::Deref {
-                arg: Expr {
-                    ty,
-                    temp_lifetime,
-                    span: expr.span,
-                    kind: ExprKind::StaticRef {
-                        literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty),
-                        def_id: id,
-                    },
-                }
-                .to_ref(),
-            }
-        }
-
-        Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id),
-
-        _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
-    }
-}
-
-fn convert_var(
-    cx: &mut Cx<'_, 'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
-    var_hir_id: hir::HirId,
-) -> ExprKind<'tcx> {
-    let upvar_index = cx
-        .tables()
-        .upvar_list
-        .get(&cx.body_owner)
-        .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
-
-    debug!(
-        "convert_var({:?}): upvar_index={:?}, body_owner={:?}",
-        var_hir_id, upvar_index, cx.body_owner
-    );
-
-    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-
-    match upvar_index {
-        None => ExprKind::VarRef { id: var_hir_id },
-
-        Some(upvar_index) => {
-            let closure_def_id = cx.body_owner;
-            let upvar_id = ty::UpvarId {
-                var_path: ty::UpvarPath { hir_id: var_hir_id },
-                closure_expr_id: LocalDefId::from_def_id(closure_def_id),
-            };
-            let var_ty = cx.tables().node_type(var_hir_id);
-
-            // FIXME free regions in closures are not right
-            let closure_ty = cx
-                .tables()
-                .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
-            // signature will be &self or &mut self and hence will
-            // have a bound region with number 0
-            let region = ty::ReFree(ty::FreeRegion {
-                scope: closure_def_id,
-                bound_region: ty::BoundRegion::BrAnon(0),
-            });
-            let region = cx.tcx.mk_region(region);
-
-            let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind {
-                match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() {
-                    ty::ClosureKind::Fn => {
-                        let ref_closure_ty = cx.tcx.mk_ref(
-                            region,
-                            ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Not },
-                        );
-                        Expr {
-                            ty: closure_ty,
-                            temp_lifetime,
-                            span: expr.span,
-                            kind: ExprKind::Deref {
-                                arg: Expr {
-                                    ty: ref_closure_ty,
-                                    temp_lifetime,
-                                    span: expr.span,
-                                    kind: ExprKind::SelfRef,
-                                }
-                                .to_ref(),
-                            },
-                        }
-                    }
-                    ty::ClosureKind::FnMut => {
-                        let ref_closure_ty = cx.tcx.mk_ref(
-                            region,
-                            ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Mut },
-                        );
-                        Expr {
-                            ty: closure_ty,
-                            temp_lifetime,
-                            span: expr.span,
-                            kind: ExprKind::Deref {
-                                arg: Expr {
-                                    ty: ref_closure_ty,
-                                    temp_lifetime,
-                                    span: expr.span,
-                                    kind: ExprKind::SelfRef,
-                                }
-                                .to_ref(),
-                            },
-                        }
-                    }
-                    ty::ClosureKind::FnOnce => Expr {
-                        ty: closure_ty,
-                        temp_lifetime,
-                        span: expr.span,
-                        kind: ExprKind::SelfRef,
-                    },
-                }
-            } else {
-                Expr { ty: closure_ty, temp_lifetime, span: expr.span, kind: ExprKind::SelfRef }
-            };
-
-            // at this point we have `self.n`, which loads up the upvar
-            let field_kind =
-                ExprKind::Field { lhs: self_expr.to_ref(), name: Field::new(upvar_index) };
-
-            // ...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) {
-                ty::UpvarCapture::ByValue => field_kind,
-                ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref {
-                    arg: Expr {
-                        temp_lifetime,
-                        ty: cx.tcx.mk_ref(
-                            borrow.region,
-                            ty::TypeAndMut { ty: var_ty, mutbl: borrow.kind.to_mutbl_lossy() },
-                        ),
-                        span: expr.span,
-                        kind: field_kind,
-                    }
-                    .to_ref(),
-                },
-            }
-        }
-    }
-}
-
-fn bin_op(op: hir::BinOpKind) -> BinOp {
-    match op {
-        hir::BinOpKind::Add => BinOp::Add,
-        hir::BinOpKind::Sub => BinOp::Sub,
-        hir::BinOpKind::Mul => BinOp::Mul,
-        hir::BinOpKind::Div => BinOp::Div,
-        hir::BinOpKind::Rem => BinOp::Rem,
-        hir::BinOpKind::BitXor => BinOp::BitXor,
-        hir::BinOpKind::BitAnd => BinOp::BitAnd,
-        hir::BinOpKind::BitOr => BinOp::BitOr,
-        hir::BinOpKind::Shl => BinOp::Shl,
-        hir::BinOpKind::Shr => BinOp::Shr,
-        hir::BinOpKind::Eq => BinOp::Eq,
-        hir::BinOpKind::Lt => BinOp::Lt,
-        hir::BinOpKind::Le => BinOp::Le,
-        hir::BinOpKind::Ne => BinOp::Ne,
-        hir::BinOpKind::Ge => BinOp::Ge,
-        hir::BinOpKind::Gt => BinOp::Gt,
-        _ => bug!("no equivalent for ast binop {:?}", op),
-    }
-}
-
-fn overloaded_operator<'a, 'tcx>(
-    cx: &mut Cx<'a, 'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
-    args: Vec<ExprRef<'tcx>>,
-) -> ExprKind<'tcx> {
-    let fun = method_callee(cx, expr, expr.span, None);
-    ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false }
-}
-
-fn overloaded_place<'a, 'tcx>(
-    cx: &mut Cx<'a, 'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
-    place_ty: Ty<'tcx>,
-    overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-    args: Vec<ExprRef<'tcx>>,
-) -> ExprKind<'tcx> {
-    // For an overloaded *x or x[y] expression of type T, the method
-    // call returns an &T and we must add the deref so that the types
-    // 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::Mirror(ref e) => e.ty,
-    };
-
-    // Reconstruct the output assuming it's a reference with the
-    // same region and mutability as the receiver. This holds for
-    // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
-    let (region, mutbl) = match recv_ty.kind {
-        ty::Ref(region, _, mutbl) => (region, mutbl),
-        _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"),
-    };
-    let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
-
-    // construct the complete expression `foo()` for the overloaded call,
-    // which will yield the &T type
-    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-    let fun = method_callee(cx, expr, expr.span, overloaded_callee);
-    let ref_expr = Expr {
-        temp_lifetime,
-        ty: ref_ty,
-        span: expr.span,
-        kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false },
-    };
-
-    // construct and return a deref wrapper `*foo()`
-    ExprKind::Deref { arg: ref_expr.to_ref() }
-}
-
-fn capture_upvar<'tcx>(
-    cx: &mut Cx<'_, 'tcx>,
-    closure_expr: &'tcx hir::Expr<'tcx>,
-    var_hir_id: hir::HirId,
-    upvar_ty: Ty<'tcx>,
-) -> ExprRef<'tcx> {
-    let upvar_id = ty::UpvarId {
-        var_path: ty::UpvarPath { hir_id: var_hir_id },
-        closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id).to_local(),
-    };
-    let upvar_capture = cx.tables().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 captured_var = Expr {
-        temp_lifetime,
-        ty: var_ty,
-        span: closure_expr.span,
-        kind: convert_var(cx, closure_expr, var_hir_id),
-    };
-    match upvar_capture {
-        ty::UpvarCapture::ByValue => captured_var.to_ref(),
-        ty::UpvarCapture::ByRef(upvar_borrow) => {
-            let borrow_kind = match upvar_borrow.kind {
-                ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
-                ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
-                ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
-            };
-            Expr {
-                temp_lifetime,
-                ty: upvar_ty,
-                span: closure_expr.span,
-                kind: ExprKind::Borrow { borrow_kind, arg: captured_var.to_ref() },
-            }
-            .to_ref()
-        }
-    }
-}
-
-/// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExprRef.
-fn field_refs<'a, 'tcx>(
-    cx: &mut Cx<'a, 'tcx>,
-    fields: &'tcx [hir::Field<'tcx>],
-) -> Vec<FieldExprRef<'tcx>> {
-    fields
-        .iter()
-        .map(|field| FieldExprRef {
-            name: Field::new(cx.tcx.field_index(field.hir_id, cx.tables)),
-            expr: field.expr.to_ref(),
-        })
-        .collect()
-}
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
deleted file mode 100644 (file)
index 2e5ab33..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-//! This module contains the fcuntaiontliy 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.
-
-use crate::hair::util::UserAnnotatedTyHelpers;
-use crate::hair::*;
-
-use crate::hair::constant::{lit_to_const, LitToConstError};
-use rustc::infer::InferCtxt;
-use rustc::middle::region;
-use rustc::ty::layout::VariantIdx;
-use rustc::ty::subst::Subst;
-use rustc::ty::subst::{GenericArg, InternalSubsts};
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_hir::Node;
-use rustc_index::vec::Idx;
-use rustc_span::symbol::{sym, Symbol};
-use syntax::ast;
-use syntax::attr;
-
-#[derive(Clone)]
-pub struct Cx<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    infcx: &'a InferCtxt<'a, 'tcx>,
-
-    pub root_lint_level: hir::HirId,
-    pub param_env: ty::ParamEnv<'tcx>,
-
-    /// Identity `InternalSubsts` for use with const-evaluation.
-    pub identity_substs: &'tcx InternalSubsts<'tcx>,
-
-    pub region_scope_tree: &'tcx region::ScopeTree,
-    pub tables: &'a ty::TypeckTables<'tcx>,
-
-    /// This is `Constness::Const` if we are compiling a `static`,
-    /// `const`, or the body of a `const fn`.
-    constness: hir::Constness,
-
-    /// The `DefId` of the owner of this body.
-    body_owner: DefId,
-
-    /// What kind of body is being compiled.
-    pub body_owner_kind: hir::BodyOwnerKind,
-
-    /// Whether this constant/function needs overflow checks.
-    check_overflow: bool,
-
-    /// See field with the same name on `mir::Body`.
-    control_flow_destroyed: Vec<(Span, String)>,
-}
-
-impl<'a, 'tcx> Cx<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, 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 body_owner_kind = tcx.hir().body_owner_kind(src_id);
-
-        let constness = match body_owner_kind {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
-            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
-        };
-
-        let attrs = tcx.hir().attrs(src_id);
-
-        // Some functions always have overflow checks enabled,
-        // however, they may not get codegen'd, depending on
-        // the settings for the crate they are codegened in.
-        let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
-
-        // Respect -C overflow-checks.
-        check_overflow |= tcx.sess.overflow_checks();
-
-        // Constants always need overflow checks.
-        check_overflow |= constness == hir::Constness::Const;
-
-        Cx {
-            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),
-            region_scope_tree: tcx.region_scope_tree(src_def_id),
-            tables,
-            constness,
-            body_owner: src_def_id,
-            body_owner_kind,
-            check_overflow,
-            control_flow_destroyed: Vec::new(),
-        }
-    }
-
-    pub fn control_flow_destroyed(self) -> Vec<(Span, String)> {
-        self.control_flow_destroyed
-    }
-}
-
-impl<'a, 'tcx> Cx<'a, 'tcx> {
-    /// Normalizes `ast` into the appropriate "mirror" type.
-    pub fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
-        ast.make_mirror(self)
-    }
-
-    pub fn usize_ty(&mut self) -> Ty<'tcx> {
-        self.tcx.types.usize
-    }
-
-    pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
-        ty::Const::from_usize(self.tcx, value)
-    }
-
-    pub fn bool_ty(&mut self) -> Ty<'tcx> {
-        self.tcx.types.bool
-    }
-
-    pub fn unit_ty(&mut self) -> Ty<'tcx> {
-        self.tcx.mk_unit()
-    }
-
-    pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
-        ty::Const::from_bool(self.tcx, true)
-    }
-
-    pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
-        ty::Const::from_bool(self.tcx, false)
-    }
-
-    pub fn const_eval_literal(
-        &mut self,
-        lit: &'tcx ast::LitKind,
-        ty: Ty<'tcx>,
-        sp: Span,
-        neg: bool,
-    ) -> &'tcx ty::Const<'tcx> {
-        trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
-
-        match lit_to_const(lit, self.tcx, ty, neg) {
-            Ok(c) => c,
-            Err(LitToConstError::UnparseableFloat) => {
-                // FIXME(#31407) this is only necessary because float parsing is buggy
-                self.tcx.sess.span_err(sp, "could not evaluate float literal (see issue #31407)");
-                // create a dummy value and continue compiling
-                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
-            }
-            Err(LitToConstError::Reported) => {
-                // create a dummy value and continue compiling
-                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
-            }
-        }
-    }
-
-    pub fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
-        let p = match self.tcx.hir().get(p.hir_id) {
-            Node::Pat(p) | Node::Binding(p) => p,
-            node => bug!("pattern became {:?}", node),
-        };
-        Pat::from_hir(self.tcx, self.param_env.and(self.identity_substs), self.tables(), p)
-    }
-
-    pub fn trait_method(
-        &mut self,
-        trait_def_id: DefId,
-        method_name: Symbol,
-        self_ty: Ty<'tcx>,
-        params: &[GenericArg<'tcx>],
-    ) -> &'tcx ty::Const<'tcx> {
-        let substs = self.tcx.mk_substs_trait(self_ty, params);
-        for item in self.tcx.associated_items(trait_def_id) {
-            if item.kind == ty::AssocKind::Method && item.ident.name == method_name {
-                let method_ty = self.tcx.type_of(item.def_id);
-                let method_ty = method_ty.subst(self.tcx, substs);
-                return ty::Const::zero_sized(self.tcx, method_ty);
-            }
-        }
-
-        bug!("found no method `{}` in `{:?}`", method_name, trait_def_id);
-    }
-
-    pub fn all_fields(&mut self, adt_def: &ty::AdtDef, variant_index: VariantIdx) -> Vec<Field> {
-        (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect()
-    }
-
-    pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(self.tcx, self.param_env)
-    }
-
-    pub fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    pub fn tables(&self) -> &'a ty::TypeckTables<'tcx> {
-        self.tables
-    }
-
-    pub fn check_overflow(&self) -> bool {
-        self.check_overflow
-    }
-
-    pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
-        self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
-    }
-}
-
-impl UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx()
-    }
-
-    fn tables(&self) -> &ty::TypeckTables<'tcx> {
-        self.tables()
-    }
-}
-
-mod block;
-mod expr;
-mod to_ref;
diff --git a/src/librustc_mir/hair/cx/to_ref.rs b/src/librustc_mir/hair/cx/to_ref.rs
deleted file mode 100644 (file)
index d6859e3..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-use crate::hair::*;
-
-use rustc_hir as hir;
-
-pub trait ToRef {
-    type Output;
-    fn to_ref(self) -> Self::Output;
-}
-
-impl<'tcx> ToRef for &'tcx hir::Expr<'tcx> {
-    type Output = ExprRef<'tcx>;
-
-    fn to_ref(self) -> ExprRef<'tcx> {
-        ExprRef::Hair(self)
-    }
-}
-
-impl<'tcx> ToRef for &'tcx &'tcx hir::Expr<'tcx> {
-    type Output = ExprRef<'tcx>;
-
-    fn to_ref(self) -> ExprRef<'tcx> {
-        ExprRef::Hair(&**self)
-    }
-}
-
-impl<'tcx> ToRef for Expr<'tcx> {
-    type Output = ExprRef<'tcx>;
-
-    fn to_ref(self) -> ExprRef<'tcx> {
-        ExprRef::Mirror(Box::new(self))
-    }
-}
-
-impl<'tcx, T, U> ToRef for &'tcx Option<T>
-where
-    &'tcx T: ToRef<Output = U>,
-{
-    type Output = Option<U>;
-
-    fn to_ref(self) -> Option<U> {
-        self.as_ref().map(|expr| expr.to_ref())
-    }
-}
-
-impl<'tcx, T, U> ToRef for &'tcx Vec<T>
-where
-    &'tcx T: ToRef<Output = U>,
-{
-    type Output = Vec<U>;
-
-    fn to_ref(self) -> Vec<U> {
-        self.iter().map(|expr| expr.to_ref()).collect()
-    }
-}
-
-impl<'tcx, T, U> ToRef for &'tcx [T]
-where
-    &'tcx T: ToRef<Output = U>,
-{
-    type Output = Vec<U>;
-
-    fn to_ref(self) -> Vec<U> {
-        self.iter().map(|expr| expr.to_ref()).collect()
-    }
-}
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
deleted file mode 100644 (file)
index cde91cc..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-//! The MIR is built from some high-level abstract IR
-//! (HAIR). This section defines the HAIR along with a trait for
-//! accessing it. The intention is to allow MIR construction to be
-//! unit-tested and separated from the Rust source and compiler data
-//! structures.
-
-use self::cx::Cx;
-use rustc::infer::canonical::Canonical;
-use rustc::middle::region;
-use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
-use rustc::ty::adjustment::PointerCast;
-use rustc::ty::layout::VariantIdx;
-use rustc::ty::subst::SubstsRef;
-use rustc::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_span::Span;
-
-mod constant;
-pub mod cx;
-
-pub mod pattern;
-pub(crate) use self::pattern::PatTyProj;
-pub use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange};
-
-mod util;
-
-#[derive(Copy, Clone, Debug)]
-pub enum LintLevel {
-    Inherited,
-    Explicit(hir::HirId),
-}
-
-#[derive(Clone, Debug)]
-pub struct Block<'tcx> {
-    pub targeted_by_break: bool,
-    pub region_scope: region::Scope,
-    pub opt_destruction_scope: Option<region::Scope>,
-    pub span: Span,
-    pub stmts: Vec<StmtRef<'tcx>>,
-    pub expr: Option<ExprRef<'tcx>>,
-    pub safety_mode: BlockSafety,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum BlockSafety {
-    Safe,
-    ExplicitUnsafe(hir::HirId),
-    PushUnsafe,
-    PopUnsafe,
-}
-
-#[derive(Clone, Debug)]
-pub enum StmtRef<'tcx> {
-    Mirror(Box<Stmt<'tcx>>),
-}
-
-#[derive(Clone, Debug)]
-pub struct Stmt<'tcx> {
-    pub kind: StmtKind<'tcx>,
-    pub opt_destruction_scope: Option<region::Scope>,
-}
-
-#[derive(Clone, Debug)]
-pub enum StmtKind<'tcx> {
-    Expr {
-        /// scope for this statement; may be used as lifetime of temporaries
-        scope: region::Scope,
-
-        /// expression being evaluated in this statement
-        expr: ExprRef<'tcx>,
-    },
-
-    Let {
-        /// scope for variables bound in this let; covers this and
-        /// remaining statements in block
-        remainder_scope: region::Scope,
-
-        /// scope for the initialization itself; might be used as
-        /// lifetime of temporaries
-        init_scope: region::Scope,
-
-        /// `let <PAT> = ...`
-        ///
-        /// if a type is included, it is added as an ascription pattern
-        pattern: Pat<'tcx>,
-
-        /// let pat: ty = <INIT> ...
-        initializer: Option<ExprRef<'tcx>>,
-
-        /// the lint level for this let-statement
-        lint_level: LintLevel,
-    },
-}
-
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(target_arch = "x86_64")]
-rustc_data_structures::static_assert_size!(Expr<'_>, 168);
-
-/// The Hair trait implementor lowers their expressions (`&'tcx H::Expr`)
-/// into instances of this `Expr` enum. This lowering can be done
-/// basically as lazily or as eagerly as desired: every recursive
-/// reference to an expression in this enum is an `ExprRef<'tcx>`, which
-/// may in turn be another instance of this enum (boxed), or else an
-/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
-/// short-lived. They are created by `Hair::to_expr`, analyzed and
-/// converted into MIR, and then discarded.
-///
-/// If you compare `Expr` to the full compiler AST, you will see it is
-/// a good bit simpler. In fact, a number of the more straight-forward
-/// MIR simplifications are already done in the impl of `Hair`. For
-/// example, method calls and overloaded operators are absent: they are
-/// expected to be converted into `Expr::Call` instances.
-#[derive(Clone, Debug)]
-pub struct Expr<'tcx> {
-    /// type of this expression
-    pub ty: Ty<'tcx>,
-
-    /// lifetime of this expression if it should be spilled into a
-    /// temporary; should be None only if in a constant context
-    pub temp_lifetime: Option<region::Scope>,
-
-    /// span of the expression in the source
-    pub span: Span,
-
-    /// kind of expression
-    pub kind: ExprKind<'tcx>,
-}
-
-#[derive(Clone, Debug)]
-pub enum ExprKind<'tcx> {
-    Scope {
-        region_scope: region::Scope,
-        lint_level: LintLevel,
-        value: ExprRef<'tcx>,
-    },
-    Box {
-        value: ExprRef<'tcx>,
-    },
-    Call {
-        ty: Ty<'tcx>,
-        fun: ExprRef<'tcx>,
-        args: Vec<ExprRef<'tcx>>,
-        // Whether this is from a call in HIR, rather than from an overloaded
-        // operator. True for overloaded function call.
-        from_hir_call: bool,
-    },
-    Deref {
-        arg: ExprRef<'tcx>,
-    }, // NOT overloaded!
-    Binary {
-        op: BinOp,
-        lhs: ExprRef<'tcx>,
-        rhs: ExprRef<'tcx>,
-    }, // NOT overloaded!
-    LogicalOp {
-        op: LogicalOp,
-        lhs: ExprRef<'tcx>,
-        rhs: ExprRef<'tcx>,
-    }, // NOT overloaded!
-    // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
-    Unary {
-        op: UnOp,
-        arg: ExprRef<'tcx>,
-    }, // NOT overloaded!
-    Cast {
-        source: ExprRef<'tcx>,
-    },
-    Use {
-        source: ExprRef<'tcx>,
-    }, // Use a lexpr to get a vexpr.
-    NeverToAny {
-        source: ExprRef<'tcx>,
-    },
-    Pointer {
-        cast: PointerCast,
-        source: ExprRef<'tcx>,
-    },
-    Loop {
-        body: ExprRef<'tcx>,
-    },
-    Match {
-        scrutinee: ExprRef<'tcx>,
-        arms: Vec<Arm<'tcx>>,
-    },
-    Block {
-        body: &'tcx hir::Block<'tcx>,
-    },
-    Assign {
-        lhs: ExprRef<'tcx>,
-        rhs: ExprRef<'tcx>,
-    },
-    AssignOp {
-        op: BinOp,
-        lhs: ExprRef<'tcx>,
-        rhs: ExprRef<'tcx>,
-    },
-    Field {
-        lhs: ExprRef<'tcx>,
-        name: Field,
-    },
-    Index {
-        lhs: ExprRef<'tcx>,
-        index: ExprRef<'tcx>,
-    },
-    VarRef {
-        id: hir::HirId,
-    },
-    /// first argument, used for self in a closure
-    SelfRef,
-    Borrow {
-        borrow_kind: BorrowKind,
-        arg: ExprRef<'tcx>,
-    },
-    /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
-    AddressOf {
-        mutability: hir::Mutability,
-        arg: ExprRef<'tcx>,
-    },
-    Break {
-        label: region::Scope,
-        value: Option<ExprRef<'tcx>>,
-    },
-    Continue {
-        label: region::Scope,
-    },
-    Return {
-        value: Option<ExprRef<'tcx>>,
-    },
-    Repeat {
-        value: ExprRef<'tcx>,
-        count: u64,
-    },
-    Array {
-        fields: Vec<ExprRef<'tcx>>,
-    },
-    Tuple {
-        fields: Vec<ExprRef<'tcx>>,
-    },
-    Adt {
-        adt_def: &'tcx AdtDef,
-        variant_index: VariantIdx,
-        substs: SubstsRef<'tcx>,
-
-        /// Optional user-given substs: for something like `let x =
-        /// Bar::<T> { ... }`.
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-
-        fields: Vec<FieldExprRef<'tcx>>,
-        base: Option<FruInfo<'tcx>>,
-    },
-    PlaceTypeAscription {
-        source: ExprRef<'tcx>,
-        /// Type that the user gave to this expression
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-    },
-    ValueTypeAscription {
-        source: ExprRef<'tcx>,
-        /// Type that the user gave to this expression
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-    },
-    Closure {
-        closure_id: DefId,
-        substs: UpvarSubsts<'tcx>,
-        upvars: Vec<ExprRef<'tcx>>,
-        movability: Option<hir::Movability>,
-    },
-    Literal {
-        literal: &'tcx Const<'tcx>,
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-    },
-    /// A literal containing the address of a `static`.
-    ///
-    /// This is only distinguished from `Literal` so that we can register some
-    /// info for diagnostics.
-    StaticRef {
-        literal: &'tcx Const<'tcx>,
-        def_id: DefId,
-    },
-    InlineAsm {
-        asm: &'tcx hir::InlineAsmInner,
-        outputs: Vec<ExprRef<'tcx>>,
-        inputs: Vec<ExprRef<'tcx>>,
-    },
-    Yield {
-        value: ExprRef<'tcx>,
-    },
-}
-
-#[derive(Clone, Debug)]
-pub enum ExprRef<'tcx> {
-    Hair(&'tcx hir::Expr<'tcx>),
-    Mirror(Box<Expr<'tcx>>),
-}
-
-#[derive(Clone, Debug)]
-pub struct FieldExprRef<'tcx> {
-    pub name: Field,
-    pub expr: ExprRef<'tcx>,
-}
-
-#[derive(Clone, Debug)]
-pub struct FruInfo<'tcx> {
-    pub base: ExprRef<'tcx>,
-    pub field_types: Vec<Ty<'tcx>>,
-}
-
-#[derive(Clone, Debug)]
-pub struct Arm<'tcx> {
-    pub pattern: Pat<'tcx>,
-    pub guard: Option<Guard<'tcx>>,
-    pub body: ExprRef<'tcx>,
-    pub lint_level: LintLevel,
-    pub scope: region::Scope,
-    pub span: Span,
-}
-
-impl Arm<'tcx> {
-    // HACK(or_patterns; Centril | dlrobertson): Remove this and
-    // correctly handle each case in which this method is used.
-    pub fn top_pats_hack(&self) -> &[Pat<'tcx>] {
-        match &*self.pattern.kind {
-            PatKind::Or { pats } => pats,
-            _ => std::slice::from_ref(&self.pattern),
-        }
-    }
-}
-
-#[derive(Clone, Debug)]
-pub enum Guard<'tcx> {
-    If(ExprRef<'tcx>),
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum LogicalOp {
-    And,
-    Or,
-}
-
-impl<'tcx> ExprRef<'tcx> {
-    pub fn span(&self) -> Span {
-        match self {
-            ExprRef::Hair(expr) => expr.span,
-            ExprRef::Mirror(expr) => expr.span,
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// The Mirror trait
-
-/// "Mirroring" is the process of converting from a HIR type into one
-/// of the HAIR types defined in this file. This is basically a "on
-/// the fly" desugaring step that hides a lot of the messiness in the
-/// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
-/// `Expr<'tcx>`.
-///
-/// Mirroring is gradual: when you mirror an outer expression like `e1
-/// + e2`, the references to the inner expressions `e1` and `e2` are
-/// `ExprRef<'tcx>` instances, and they may or may not be eagerly
-/// mirrored. This allows a single AST node from the compiler to
-/// expand into one or more Hair nodes, which lets the Hair nodes be
-/// simpler.
-pub trait Mirror<'tcx> {
-    type Output;
-
-    fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output;
-}
-
-impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
-    type Output = Expr<'tcx>;
-
-    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
-        self
-    }
-}
-
-impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
-    type Output = Expr<'tcx>;
-
-    fn make_mirror(self, hir: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
-        match self {
-            ExprRef::Hair(h) => h.make_mirror(hir),
-            ExprRef::Mirror(m) => *m,
-        }
-    }
-}
-
-impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
-    type Output = Stmt<'tcx>;
-
-    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
-        self
-    }
-}
-
-impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
-    type Output = Stmt<'tcx>;
-
-    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
-        match self {
-            StmtRef::Mirror(m) => *m,
-        }
-    }
-}
-
-impl<'tcx> Mirror<'tcx> for Block<'tcx> {
-    type Output = Block<'tcx>;
-
-    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
-        self
-    }
-}
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
deleted file mode 100644 (file)
index 03120e8..0000000
+++ /dev/null
@@ -1,2503 +0,0 @@
-/// Note: most tests relevant to this file can be found (at the time of writing)
-/// in src/tests/ui/pattern/usefulness.
-///
-/// This file includes the logic for exhaustiveness and usefulness checking for
-/// pattern-matching. Specifically, given a list of patterns for a type, we can
-/// tell whether:
-/// (a) the patterns cover every possible constructor for the type [exhaustiveness]
-/// (b) each pattern is necessary [usefulness]
-///
-/// The algorithm implemented here is a modified version of the one described in:
-/// http://moscova.inria.fr/~maranget/papers/warn/index.html
-/// However, to save future implementors from reading the original paper, we
-/// summarise the algorithm here to hopefully save time and be a little clearer
-/// (without being so rigorous).
-///
-/// The core of the algorithm revolves about a "usefulness" check. In particular, we
-/// are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
-/// a matrix). `U(P, p)` represents whether, given an existing list of patterns
-/// `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously-
-/// uncovered values of the type).
-///
-/// If we have this predicate, then we can easily compute both exhaustiveness of an
-/// entire set of patterns and the individual usefulness of each one.
-/// (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard
-/// match doesn't increase the number of values we're matching)
-/// (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a
-/// pattern to those that have come before it doesn't increase the number of values
-/// we're matching).
-///
-/// During the course of the algorithm, the rows of the matrix won't just be individual patterns,
-/// but rather partially-deconstructed patterns in the form of a list of patterns. The paper
-/// calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
-/// new pattern `p`.
-///
-/// For example, say we have the following:
-/// ```
-///     // x: (Option<bool>, Result<()>)
-///     match x {
-///         (Some(true), _) => {}
-///         (None, Err(())) => {}
-///         (None, Err(_)) => {}
-///     }
-/// ```
-/// Here, the matrix `P` starts as:
-/// [
-///     [(Some(true), _)],
-///     [(None, Err(()))],
-///     [(None, Err(_))],
-/// ]
-/// We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
-/// `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
-/// all the values it covers are already covered by row 2.
-///
-/// A list of patterns can be thought of as a stack, because we are mainly interested in the top of
-/// the stack at any given point, and we can pop or apply constructors to get new pattern-stacks.
-/// To match the paper, the top of the stack is at the beginning / on the left.
-///
-/// There are two important operations on pattern-stacks necessary to understand the algorithm:
-///     1. We can pop a given constructor off the top of a stack. This operation is called
-///        `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
-///        `None`) and `p` a pattern-stack.
-///        If the pattern on top of the stack can cover `c`, this removes the constructor and
-///        pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
-///        Otherwise the pattern-stack is discarded.
-///        This essentially filters those pattern-stacks whose top covers the constructor `c` and
-///        discards the others.
-///
-///        For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
-///        pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
-///        `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
-///        nothing back.
-///
-///        This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
-///        on top of the stack, and we have four cases:
-///             1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
-///                  push onto the stack the arguments of this constructor, and return the result:
-///                     r_1, .., r_a, p_2, .., p_n
-///             1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
-///                  return nothing.
-///             1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
-///                  arguments (its arity), and return the resulting stack:
-///                     _, .., _, p_2, .., p_n
-///             1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-///                  stack:
-///                     S(c, (r_1, p_2, .., p_n))
-///                     S(c, (r_2, p_2, .., p_n))
-///
-///     2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
-///        a pattern-stack.
-///        This is used when we know there are missing constructor cases, but there might be
-///        existing wildcard patterns, so to check the usefulness of the matrix, we have to check
-///        all its *other* components.
-///
-///        It is computed as follows. We look at the pattern `p_1` on top of the stack,
-///        and we have three cases:
-///             1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
-///             1.2. `p_1 = _`. We return the rest of the stack:
-///                     p_2, .., p_n
-///             1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
-///               stack.
-///                     D((r_1, p_2, .., p_n))
-///                     D((r_2, p_2, .., p_n))
-///
-///     Note that the OR-patterns are not always used directly in Rust, but are used to derive the
-///     exhaustive integer matching rules, so they're written here for posterity.
-///
-/// Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
-/// working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
-/// the given constructor, and popping a wildcard keeps those rows that start with a wildcard.
-///
-///
-/// The algorithm for computing `U`
-/// -------------------------------
-/// The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
-/// That means we're going to check the components from left-to-right, so the algorithm
-/// operates principally on the first component of the matrix and new pattern-stack `p`.
-/// This algorithm is realised in the `is_useful` function.
-///
-/// Base case. (`n = 0`, i.e., an empty tuple pattern)
-///     - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`),
-///       then `U(P, p)` is false.
-///     - Otherwise, `P` must be empty, so `U(P, p)` is true.
-///
-/// Inductive step. (`n > 0`, i.e., whether there's at least one column
-///                  [which may then be expanded into further columns later])
-///     We're going to match on the top of the new pattern-stack, `p_1`.
-///         - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
-///           Then, the usefulness of `p_1` can be reduced to whether it is useful when
-///           we ignore all the patterns in the first column of `P` that involve other constructors.
-///           This is where `S(c, P)` comes in:
-///           `U(P, p) := U(S(c, P), S(c, p))`
-///           This special case is handled in `is_useful_specialized`.
-///
-///           For example, if `P` is:
-///           [
-///               [Some(true), _],
-///               [None, 0],
-///           ]
-///           and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
-///           matches values that row 2 doesn't. For row 1 however, we need to dig into the
-///           arguments of `Some` to know whether some new value is covered. So we compute
-///           `U([[true, _]], [false, 0])`.
-///
-///         - If `p_1 == _`, then we look at the list of constructors that appear in the first
-///               component of the rows of `P`:
-///             + If there are some constructors that aren't present, then we might think that the
-///               wildcard `_` is useful, since it covers those constructors that weren't covered
-///               before.
-///               That's almost correct, but only works if there were no wildcards in those first
-///               components. So we need to check that `p` is useful with respect to the rows that
-///               start with a wildcard, if there are any. This is where `D` comes in:
-///               `U(P, p) := U(D(P), D(p))`
-///
-///               For example, if `P` is:
-///               [
-///                   [_, true, _],
-///                   [None, false, 1],
-///               ]
-///               and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
-///               only had row 2, we'd know that `p` is useful. However row 1 starts with a
-///               wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
-///
-///             + Otherwise, all possible constructors (for the relevant type) are present. In this
-///               case we must check whether the wildcard pattern covers any unmatched value. For
-///               that, we can think of the `_` pattern as a big OR-pattern that covers all
-///               possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
-///               example. The wildcard pattern is useful in this case if it is useful when
-///               specialized to one of the possible constructors. So we compute:
-///               `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
-///
-///               For example, if `P` is:
-///               [
-///                   [Some(true), _],
-///                   [None, false],
-///               ]
-///               and `p` is [_, false], both `None` and `Some` constructors appear in the first
-///               components of `P`. We will therefore try popping both constructors in turn: we
-///               compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]],
-///               [false]) for the `None` constructor. The first case returns true, so we know that
-///               `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
-///               before.
-///
-///         - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
-///           `U(P, p) := U(P, (r_1, p_2, .., p_n))
-///                    || U(P, (r_2, p_2, .., p_n))`
-///
-/// Modifications to the algorithm
-/// ------------------------------
-/// The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for
-/// example uninhabited types and variable-length slice patterns. These are drawn attention to
-/// throughout the code below. I'll make a quick note here about how exhaustive integer matching is
-/// accounted for, though.
-///
-/// Exhaustive integer matching
-/// ---------------------------
-/// An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ...
-/// So to support exhaustive integer matching, we can make use of the logic in the paper for
-/// OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because
-/// they are likely gigantic. So we instead treat ranges as constructors of the integers. This means
-/// that we have a constructor *of* constructors (the integers themselves). We then need to work
-/// through all the inductive step rules above, deriving how the ranges would be treated as
-/// OR-patterns, and making sure that they're treated in the same way even when they're ranges.
-/// There are really only four special cases here:
-/// - When we match on a constructor that's actually a range, we have to treat it as if we would
-///   an OR-pattern.
-///     + It turns out that we can simply extend the case for single-value patterns in
-///      `specialize` to either be *equal* to a value constructor, or *contained within* a range
-///      constructor.
-///     + When the pattern itself is a range, you just want to tell whether any of the values in
-///       the pattern range coincide with values in the constructor range, which is precisely
-///       intersection.
-///   Since when encountering a range pattern for a value constructor, we also use inclusion, it
-///   means that whenever the constructor is a value/range and the pattern is also a value/range,
-///   we can simply use intersection to test usefulness.
-/// - When we're testing for usefulness of a pattern and the pattern's first component is a
-///   wildcard.
-///     + If all the constructors appear in the matrix, we have a slight complication. By default,
-///       the behaviour (i.e., a disjunction over specialised matrices for each constructor) is
-///       invalid, because we want a disjunction over every *integer* in each range, not just a
-///       disjunction over every range. This is a bit more tricky to deal with: essentially we need
-///       to form equivalence classes of subranges of the constructor range for which the behaviour
-///       of the matrix `P` and new pattern `p` are the same. This is described in more
-///       detail in `split_grouped_constructors`.
-///     + If some constructors are missing from the matrix, it turns out we don't need to do
-///       anything special (because we know none of the integers are actually wildcards: i.e., we
-///       can't span wildcards using ranges).
-use self::Constructor::*;
-use self::SliceKind::*;
-use self::Usefulness::*;
-use self::WitnessPreference::*;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::Idx;
-
-use super::{compare_const_vals, PatternFoldable, PatternFolder};
-use super::{FieldPat, Pat, PatKind, PatRange};
-
-use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
-use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
-use rustc_hir::def_id::DefId;
-use rustc_hir::{HirId, RangeEnd};
-
-use rustc::lint;
-use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
-use rustc::mir::Field;
-use rustc::util::captures::Captures;
-use rustc::util::common::ErrorReported;
-
-use rustc_span::{Span, DUMMY_SP};
-use syntax::attr::{SignedInt, UnsignedInt};
-
-use arena::TypedArena;
-
-use smallvec::{smallvec, SmallVec};
-use std::borrow::Cow;
-use std::cmp::{self, max, min, Ordering};
-use std::convert::TryInto;
-use std::fmt;
-use std::iter::{FromIterator, IntoIterator};
-use std::ops::RangeInclusive;
-use std::u128;
-
-pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
-    LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
-}
-
-struct LiteralExpander<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
-
-impl LiteralExpander<'tcx> {
-    /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice.
-    ///
-    /// `crty` and `rty` can differ because you can use array constants in the presence of slice
-    /// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
-    /// the array to a slice in that case.
-    fn fold_const_value_deref(
-        &mut self,
-        val: ConstValue<'tcx>,
-        // the pattern's pointee type
-        rty: Ty<'tcx>,
-        // the constant's pointee type
-        crty: Ty<'tcx>,
-    ) -> ConstValue<'tcx> {
-        debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
-        match (val, &crty.kind, &rty.kind) {
-            // the easy case, deref a reference
-            (ConstValue::Scalar(p), x, y) if x == y => {
-                match p {
-                    Scalar::Ptr(p) => {
-                        let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
-                        ConstValue::ByRef { alloc, offset: p.offset }
-                    }
-                    Scalar::Raw { .. } => {
-                        let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
-                        if layout.is_zst() {
-                            // Deref of a reference to a ZST is a nop.
-                            ConstValue::Scalar(Scalar::zst())
-                        } else {
-                            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
-                            bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
-                        }
-                    }
-                }
-            }
-            // unsize array to slice if pattern is array but match value or other patterns are slice
-            (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
-                assert_eq!(t, u);
-                ConstValue::Slice {
-                    data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
-                    start: p.offset.bytes().try_into().unwrap(),
-                    end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(),
-                }
-            }
-            // fat pointers stay the same
-            (ConstValue::Slice { .. }, _, _)
-            | (_, ty::Slice(_), ty::Slice(_))
-            | (_, ty::Str, ty::Str) => val,
-            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
-            _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
-        }
-    }
-}
-
-impl PatternFolder<'tcx> for LiteralExpander<'tcx> {
-    fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
-        debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind, pat.kind);
-        match (&pat.ty.kind, &*pat.kind) {
-            (
-                &ty::Ref(_, rty, _),
-                &PatKind::Constant {
-                    value:
-                        Const {
-                            val: ty::ConstKind::Value(val),
-                            ty: ty::TyS { kind: ty::Ref(_, crty, _), .. },
-                        },
-                },
-            ) => Pat {
-                ty: pat.ty,
-                span: pat.span,
-                kind: box PatKind::Deref {
-                    subpattern: Pat {
-                        ty: rty,
-                        span: pat.span,
-                        kind: box PatKind::Constant {
-                            value: self.tcx.mk_const(Const {
-                                val: ty::ConstKind::Value(
-                                    self.fold_const_value_deref(*val, rty, crty),
-                                ),
-                                ty: rty,
-                            }),
-                        },
-                    },
-                },
-            },
-
-            (
-                &ty::Ref(_, rty, _),
-                &PatKind::Constant {
-                    value: Const { val, ty: ty::TyS { kind: ty::Ref(_, crty, _), .. } },
-                },
-            ) => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
-
-            (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self),
-            (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self),
-            _ => pat.super_fold_with(self),
-        }
-    }
-}
-
-impl<'tcx> Pat<'tcx> {
-    pub(super) fn is_wildcard(&self) -> bool {
-        match *self.kind {
-            PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true,
-            _ => false,
-        }
-    }
-}
-
-/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
-/// works well.
-#[derive(Debug, Clone)]
-pub struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>);
-
-impl<'p, 'tcx> PatStack<'p, 'tcx> {
-    pub fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
-        PatStack(smallvec![pat])
-    }
-
-    fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
-        PatStack(vec)
-    }
-
-    fn from_slice(s: &[&'p Pat<'tcx>]) -> Self {
-        PatStack(SmallVec::from_slice(s))
-    }
-
-    fn is_empty(&self) -> bool {
-        self.0.is_empty()
-    }
-
-    fn len(&self) -> usize {
-        self.0.len()
-    }
-
-    fn head(&self) -> &'p Pat<'tcx> {
-        self.0[0]
-    }
-
-    fn to_tail(&self) -> Self {
-        PatStack::from_slice(&self.0[1..])
-    }
-
-    fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
-        self.0.iter().map(|p| *p)
-    }
-
-    // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
-    fn expand_or_pat(&self) -> Option<Vec<Self>> {
-        if self.is_empty() {
-            None
-        } else if let PatKind::Or { pats } = &*self.head().kind {
-            Some(
-                pats.iter()
-                    .map(|pat| {
-                        let mut new_patstack = PatStack::from_pattern(pat);
-                        new_patstack.0.extend_from_slice(&self.0[1..]);
-                        new_patstack
-                    })
-                    .collect(),
-            )
-        } else {
-            None
-        }
-    }
-
-    /// This computes `D(self)`. See top of the file for explanations.
-    fn specialize_wildcard(&self) -> Option<Self> {
-        if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
-    }
-
-    /// This computes `S(constructor, self)`. See top of the file for explanations.
-    fn specialize_constructor(
-        &self,
-        cx: &mut MatchCheckCtxt<'p, 'tcx>,
-        constructor: &Constructor<'tcx>,
-        ctor_wild_subpatterns: &'p [Pat<'tcx>],
-    ) -> Option<PatStack<'p, 'tcx>> {
-        let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
-        new_heads.map(|mut new_head| {
-            new_head.0.extend_from_slice(&self.0[1..]);
-            new_head
-        })
-    }
-}
-
-impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
-    fn default() -> Self {
-        PatStack(smallvec![])
-    }
-}
-
-impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
-    fn from_iter<T>(iter: T) -> Self
-    where
-        T: IntoIterator<Item = &'p Pat<'tcx>>,
-    {
-        PatStack(iter.into_iter().collect())
-    }
-}
-
-/// A 2D matrix.
-#[derive(Clone)]
-pub struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
-
-impl<'p, 'tcx> Matrix<'p, 'tcx> {
-    pub fn empty() -> Self {
-        Matrix(vec![])
-    }
-
-    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
-    pub fn push(&mut self, row: PatStack<'p, 'tcx>) {
-        if let Some(rows) = row.expand_or_pat() {
-            self.0.extend(rows);
-        } else {
-            self.0.push(row);
-        }
-    }
-
-    /// Iterate over the first component of each row
-    fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
-        self.0.iter().map(|r| r.head())
-    }
-
-    /// This computes `D(self)`. See top of the file for explanations.
-    fn specialize_wildcard(&self) -> Self {
-        self.0.iter().filter_map(|r| r.specialize_wildcard()).collect()
-    }
-
-    /// This computes `S(constructor, self)`. See top of the file for explanations.
-    fn specialize_constructor(
-        &self,
-        cx: &mut MatchCheckCtxt<'p, 'tcx>,
-        constructor: &Constructor<'tcx>,
-        ctor_wild_subpatterns: &'p [Pat<'tcx>],
-    ) -> Matrix<'p, 'tcx> {
-        self.0
-            .iter()
-            .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
-            .collect()
-    }
-}
-
-/// Pretty-printer for matrices of patterns, example:
-/// +++++++++++++++++++++++++++++
-/// + _     + []                +
-/// +++++++++++++++++++++++++++++
-/// + true  + [First]           +
-/// +++++++++++++++++++++++++++++
-/// + true  + [Second(true)]    +
-/// +++++++++++++++++++++++++++++
-/// + false + [_]               +
-/// +++++++++++++++++++++++++++++
-/// + _     + [_, _, tail @ ..] +
-/// +++++++++++++++++++++++++++++
-impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "\n")?;
-
-        let &Matrix(ref m) = self;
-        let pretty_printed_matrix: Vec<Vec<String>> =
-            m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect();
-
-        let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
-        assert!(m.iter().all(|row| row.len() == column_count));
-        let column_widths: Vec<usize> = (0..column_count)
-            .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0))
-            .collect();
-
-        let total_width = column_widths.iter().cloned().sum::<usize>() + column_count * 3 + 1;
-        let br = "+".repeat(total_width);
-        write!(f, "{}\n", br)?;
-        for row in pretty_printed_matrix {
-            write!(f, "+")?;
-            for (column, pat_str) in row.into_iter().enumerate() {
-                write!(f, " ")?;
-                write!(f, "{:1$}", pat_str, column_widths[column])?;
-                write!(f, " +")?;
-            }
-            write!(f, "\n")?;
-            write!(f, "{}\n", br)?;
-        }
-        Ok(())
-    }
-}
-
-impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
-    fn from_iter<T>(iter: T) -> Self
-    where
-        T: IntoIterator<Item = PatStack<'p, 'tcx>>,
-    {
-        let mut matrix = Matrix::empty();
-        for x in iter {
-            // Using `push` ensures we correctly expand or-patterns.
-            matrix.push(x);
-        }
-        matrix
-    }
-}
-
-pub struct MatchCheckCtxt<'a, 'tcx> {
-    pub tcx: TyCtxt<'tcx>,
-    /// The module in which the match occurs. This is necessary for
-    /// checking inhabited-ness of types because whether a type is (visibly)
-    /// inhabited can depend on whether it was defined in the current module or
-    /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
-    /// outside it's module and should not be matchable with an empty match
-    /// statement.
-    pub module: DefId,
-    param_env: ty::ParamEnv<'tcx>,
-    pub pattern_arena: &'a TypedArena<Pat<'tcx>>,
-    pub byte_array_map: FxHashMap<*const Pat<'tcx>, Vec<&'a Pat<'tcx>>>,
-}
-
-impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
-    pub fn create_and_enter<F, R>(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        module: DefId,
-        f: F,
-    ) -> R
-    where
-        F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
-    {
-        let pattern_arena = TypedArena::default();
-
-        f(MatchCheckCtxt {
-            tcx,
-            param_env,
-            module,
-            pattern_arena: &pattern_arena,
-            byte_array_map: FxHashMap::default(),
-        })
-    }
-
-    fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
-        if self.tcx.features().exhaustive_patterns {
-            self.tcx.is_ty_uninhabited_from(self.module, ty)
-        } else {
-            false
-        }
-    }
-
-    // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
-    pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
-        match ty.kind {
-            ty::Adt(def, ..) => {
-                def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
-            }
-            _ => false,
-        }
-    }
-
-    // Returns whether the given variant is from another crate and has its fields declared
-    // `#[non_exhaustive]`.
-    fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool {
-        match ty.kind {
-            ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(),
-            _ => false,
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum SliceKind {
-    /// Patterns of length `n` (`[x, y]`).
-    FixedLen(u64),
-    /// Patterns using the `..` notation (`[x, .., y]`).
-    /// Captures any array constructor of `length >= i + j`.
-    /// In the case where `array_len` is `Some(_)`,
-    /// this indicates that we only care about the first `i` and the last `j` values of the array,
-    /// and everything in between is a wildcard `_`.
-    VarLen(u64, u64),
-}
-
-impl SliceKind {
-    fn arity(self) -> u64 {
-        match self {
-            FixedLen(length) => length,
-            VarLen(prefix, suffix) => prefix + suffix,
-        }
-    }
-
-    /// Whether this pattern includes patterns of length `other_len`.
-    fn covers_length(self, other_len: u64) -> bool {
-        match self {
-            FixedLen(len) => len == other_len,
-            VarLen(prefix, suffix) => prefix + suffix <= other_len,
-        }
-    }
-
-    /// Returns a collection of slices that spans the values covered by `self`, subtracted by the
-    /// values covered by `other`: i.e., `self \ other` (in set notation).
-    fn subtract(self, other: Self) -> SmallVec<[Self; 1]> {
-        // Remember, `VarLen(i, j)` covers the union of `FixedLen` from `i + j` to infinity.
-        // Naming: we remove the "neg" constructors from the "pos" ones.
-        match self {
-            FixedLen(pos_len) => {
-                if other.covers_length(pos_len) {
-                    smallvec![]
-                } else {
-                    smallvec![self]
-                }
-            }
-            VarLen(pos_prefix, pos_suffix) => {
-                let pos_len = pos_prefix + pos_suffix;
-                match other {
-                    FixedLen(neg_len) => {
-                        if neg_len < pos_len {
-                            smallvec![self]
-                        } else {
-                            (pos_len..neg_len)
-                                .map(FixedLen)
-                                // We know that `neg_len + 1 >= pos_len >= pos_suffix`.
-                                .chain(Some(VarLen(neg_len + 1 - pos_suffix, pos_suffix)))
-                                .collect()
-                        }
-                    }
-                    VarLen(neg_prefix, neg_suffix) => {
-                        let neg_len = neg_prefix + neg_suffix;
-                        if neg_len <= pos_len {
-                            smallvec![]
-                        } else {
-                            (pos_len..neg_len).map(FixedLen).collect()
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-/// A constructor for array and slice patterns.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-struct Slice {
-    /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`.
-    array_len: Option<u64>,
-    /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`.
-    kind: SliceKind,
-}
-
-impl Slice {
-    /// Returns what patterns this constructor covers: either fixed-length patterns or
-    /// variable-length patterns.
-    fn pattern_kind(self) -> SliceKind {
-        match self {
-            Slice { array_len: Some(len), kind: VarLen(prefix, suffix) }
-                if prefix + suffix == len =>
-            {
-                FixedLen(len)
-            }
-            _ => self.kind,
-        }
-    }
-
-    /// Returns what values this constructor covers: either values of only one given length, or
-    /// values of length above a given length.
-    /// This is different from `pattern_kind()` because in some cases the pattern only takes into
-    /// account a subset of the entries of the array, but still only captures values of a given
-    /// length.
-    fn value_kind(self) -> SliceKind {
-        match self {
-            Slice { array_len: Some(len), kind: VarLen(_, _) } => FixedLen(len),
-            _ => self.kind,
-        }
-    }
-
-    fn arity(self) -> u64 {
-        self.pattern_kind().arity()
-    }
-}
-
-#[derive(Clone, Debug, PartialEq)]
-enum Constructor<'tcx> {
-    /// The constructor of all patterns that don't vary by constructor,
-    /// e.g., struct patterns and fixed-length arrays.
-    Single,
-    /// Enum variants.
-    Variant(DefId),
-    /// Literal values.
-    ConstantValue(&'tcx ty::Const<'tcx>),
-    /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
-    IntRange(IntRange<'tcx>),
-    /// Ranges of floating-point literal values (`2.0..=5.2`).
-    FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
-    /// Array and slice patterns.
-    Slice(Slice),
-    /// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
-    NonExhaustive,
-}
-
-impl<'tcx> Constructor<'tcx> {
-    fn is_slice(&self) -> bool {
-        match self {
-            Slice(_) => true,
-            _ => false,
-        }
-    }
-
-    fn variant_index_for_adt<'a>(
-        &self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
-        adt: &'tcx ty::AdtDef,
-    ) -> VariantIdx {
-        match self {
-            Variant(id) => adt.variant_index_with_id(*id),
-            Single => {
-                assert!(!adt.is_enum());
-                VariantIdx::new(0)
-            }
-            ConstantValue(c) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c),
-            _ => bug!("bad constructor {:?} for adt {:?}", self, adt),
-        }
-    }
-
-    // Returns the set of constructors covered by `self` but not by
-    // anything in `other_ctors`.
-    fn subtract_ctors(&self, other_ctors: &Vec<Constructor<'tcx>>) -> Vec<Constructor<'tcx>> {
-        if other_ctors.is_empty() {
-            return vec![self.clone()];
-        }
-
-        match self {
-            // Those constructors can only match themselves.
-            Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
-                if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] }
-            }
-            &Slice(slice) => {
-                let mut other_slices = other_ctors
-                    .iter()
-                    .filter_map(|c: &Constructor<'_>| match c {
-                        Slice(slice) => Some(*slice),
-                        // FIXME(oli-obk): implement `deref` for `ConstValue`
-                        ConstantValue(..) => None,
-                        _ => bug!("bad slice pattern constructor {:?}", c),
-                    })
-                    .map(Slice::value_kind);
-
-                match slice.value_kind() {
-                    FixedLen(self_len) => {
-                        if other_slices.any(|other_slice| other_slice.covers_length(self_len)) {
-                            vec![]
-                        } else {
-                            vec![Slice(slice)]
-                        }
-                    }
-                    kind @ VarLen(..) => {
-                        let mut remaining_slices = vec![kind];
-
-                        // For each used slice, subtract from the current set of slices.
-                        for other_slice in other_slices {
-                            remaining_slices = remaining_slices
-                                .into_iter()
-                                .flat_map(|remaining_slice| remaining_slice.subtract(other_slice))
-                                .collect();
-
-                            // If the constructors that have been considered so far already cover
-                            // the entire range of `self`, no need to look at more constructors.
-                            if remaining_slices.is_empty() {
-                                break;
-                            }
-                        }
-
-                        remaining_slices
-                            .into_iter()
-                            .map(|kind| Slice { array_len: slice.array_len, kind })
-                            .map(Slice)
-                            .collect()
-                    }
-                }
-            }
-            IntRange(self_range) => {
-                let mut remaining_ranges = vec![self_range.clone()];
-                for other_ctor in other_ctors {
-                    if let IntRange(other_range) = other_ctor {
-                        if other_range == self_range {
-                            // If the `self` range appears directly in a `match` arm, we can
-                            // eliminate it straight away.
-                            remaining_ranges = vec![];
-                        } else {
-                            // Otherwise explicitely compute the remaining ranges.
-                            remaining_ranges = other_range.subtract_from(remaining_ranges);
-                        }
-
-                        // If the ranges that have been considered so far already cover the entire
-                        // range of values, we can return early.
-                        if remaining_ranges.is_empty() {
-                            break;
-                        }
-                    }
-                }
-
-                // Convert the ranges back into constructors.
-                remaining_ranges.into_iter().map(IntRange).collect()
-            }
-            // This constructor is never covered by anything else
-            NonExhaustive => vec![NonExhaustive],
-        }
-    }
-
-    /// This returns one wildcard pattern for each argument to this constructor.
-    ///
-    /// This must be consistent with `apply`, `specialize_one_pattern`, and `arity`.
-    fn wildcard_subpatterns<'a>(
-        &self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Vec<Pat<'tcx>> {
-        debug!("wildcard_subpatterns({:#?}, {:?})", self, ty);
-
-        match self {
-            Single | Variant(_) => match ty.kind {
-                ty::Tuple(ref fs) => {
-                    fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect()
-                }
-                ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)],
-                ty::Adt(adt, substs) => {
-                    if adt.is_box() {
-                        // Use T as the sub pattern type of Box<T>.
-                        vec![Pat::wildcard_from_ty(substs.type_at(0))]
-                    } else {
-                        let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
-                        let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant);
-                        variant
-                            .fields
-                            .iter()
-                            .map(|field| {
-                                let is_visible = adt.is_enum()
-                                    || field.vis.is_accessible_from(cx.module, cx.tcx);
-                                let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs));
-                                match (is_visible, is_non_exhaustive, is_uninhabited) {
-                                    // Treat all uninhabited types in non-exhaustive variants as
-                                    // `TyErr`.
-                                    (_, true, true) => cx.tcx.types.err,
-                                    // Treat all non-visible fields as `TyErr`. They can't appear
-                                    // in any other pattern from this match (because they are
-                                    // private), so their type does not matter - but we don't want
-                                    // to know they are uninhabited.
-                                    (false, ..) => cx.tcx.types.err,
-                                    (true, ..) => {
-                                        let ty = field.ty(cx.tcx, substs);
-                                        match ty.kind {
-                                            // If the field type returned is an array of an unknown
-                                            // size return an TyErr.
-                                            ty::Array(_, len)
-                                                if len
-                                                    .try_eval_usize(cx.tcx, cx.param_env)
-                                                    .is_none() =>
-                                            {
-                                                cx.tcx.types.err
-                                            }
-                                            _ => ty,
-                                        }
-                                    }
-                                }
-                            })
-                            .map(Pat::wildcard_from_ty)
-                            .collect()
-                    }
-                }
-                _ => vec![],
-            },
-            Slice(_) => match ty.kind {
-                ty::Slice(ty) | ty::Array(ty, _) => {
-                    let arity = self.arity(cx, ty);
-                    (0..arity).map(|_| Pat::wildcard_from_ty(ty)).collect()
-                }
-                _ => bug!("bad slice pattern {:?} {:?}", self, ty),
-            },
-            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => vec![],
-        }
-    }
-
-    /// This computes the arity of a constructor. The arity of a constructor
-    /// is how many subpattern patterns of that constructor should be expanded to.
-    ///
-    /// For instance, a tuple pattern `(_, 42, Some([]))` has the arity of 3.
-    /// A struct pattern's arity is the number of fields it contains, etc.
-    ///
-    /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `apply`.
-    fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 {
-        debug!("Constructor::arity({:#?}, {:?})", self, ty);
-        match self {
-            Single | Variant(_) => match ty.kind {
-                ty::Tuple(ref fs) => fs.len() as u64,
-                ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
-                ty::Ref(..) => 1,
-                ty::Adt(adt, _) => {
-                    adt.variants[self.variant_index_for_adt(cx, adt)].fields.len() as u64
-                }
-                _ => 0,
-            },
-            Slice(slice) => slice.arity(),
-            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => 0,
-        }
-    }
-
-    /// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
-    /// must have as many elements as this constructor's arity.
-    ///
-    /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `arity`.
-    ///
-    /// Examples:
-    /// `self`: `Constructor::Single`
-    /// `ty`: `(u32, u32, u32)`
-    /// `pats`: `[10, 20, _]`
-    /// returns `(10, 20, _)`
-    ///
-    /// `self`: `Constructor::Variant(Option::Some)`
-    /// `ty`: `Option<bool>`
-    /// `pats`: `[false]`
-    /// returns `Some(false)`
-    fn apply<'a>(
-        &self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
-        ty: Ty<'tcx>,
-        pats: impl IntoIterator<Item = Pat<'tcx>>,
-    ) -> Pat<'tcx> {
-        let mut subpatterns = pats.into_iter();
-
-        let pat = match self {
-            Single | Variant(_) => match ty.kind {
-                ty::Adt(..) | ty::Tuple(..) => {
-                    let subpatterns = subpatterns
-                        .enumerate()
-                        .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
-                        .collect();
-
-                    if let ty::Adt(adt, substs) = ty.kind {
-                        if adt.is_enum() {
-                            PatKind::Variant {
-                                adt_def: adt,
-                                substs,
-                                variant_index: self.variant_index_for_adt(cx, adt),
-                                subpatterns,
-                            }
-                        } else {
-                            PatKind::Leaf { subpatterns }
-                        }
-                    } else {
-                        PatKind::Leaf { subpatterns }
-                    }
-                }
-                ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() },
-                ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
-                _ => PatKind::Wild,
-            },
-            Slice(slice) => match slice.pattern_kind() {
-                FixedLen(_) => {
-                    PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
-                }
-                VarLen(prefix, _) => {
-                    let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect();
-                    if slice.array_len.is_some() {
-                        // Improves diagnostics a bit: if the type is a known-size array, instead
-                        // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
-                        // This is incorrect if the size is not known, since `[_, ..]` captures
-                        // arrays of lengths `>= 1` whereas `[..]` captures any length.
-                        while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() {
-                            prefix.pop();
-                        }
-                    }
-                    let suffix: Vec<_> = if slice.array_len.is_some() {
-                        // Same as above.
-                        subpatterns.skip_while(Pat::is_wildcard).collect()
-                    } else {
-                        subpatterns.collect()
-                    };
-                    let wild = Pat::wildcard_from_ty(ty);
-                    PatKind::Slice { prefix, slice: Some(wild), suffix }
-                }
-            },
-            &ConstantValue(value) => PatKind::Constant { value },
-            &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
-            IntRange(range) => return range.to_pat(cx.tcx),
-            NonExhaustive => PatKind::Wild,
-        };
-
-        Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
-    }
-
-    /// Like `apply`, but where all the subpatterns are wildcards `_`.
-    fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
-        let subpatterns = self.wildcard_subpatterns(cx, ty).into_iter().rev();
-        self.apply(cx, ty, subpatterns)
-    }
-}
-
-#[derive(Clone, Debug)]
-pub enum Usefulness<'tcx, 'p> {
-    /// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
-    Useful(Vec<&'p Pat<'tcx>>),
-    /// Carries a list of witnesses of non-exhaustiveness.
-    UsefulWithWitness(Vec<Witness<'tcx>>),
-    NotUseful,
-}
-
-impl<'tcx, 'p> Usefulness<'tcx, 'p> {
-    fn new_useful(preference: WitnessPreference) -> Self {
-        match preference {
-            ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
-            LeaveOutWitness => Useful(vec![]),
-        }
-    }
-
-    fn is_useful(&self) -> bool {
-        match *self {
-            NotUseful => false,
-            _ => true,
-        }
-    }
-
-    fn apply_constructor(
-        self,
-        cx: &MatchCheckCtxt<'_, 'tcx>,
-        ctor: &Constructor<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Self {
-        match self {
-            UsefulWithWitness(witnesses) => UsefulWithWitness(
-                witnesses
-                    .into_iter()
-                    .map(|witness| witness.apply_constructor(cx, &ctor, ty))
-                    .collect(),
-            ),
-            x => x,
-        }
-    }
-
-    fn apply_wildcard(self, ty: Ty<'tcx>) -> Self {
-        match self {
-            UsefulWithWitness(witnesses) => {
-                let wild = Pat::wildcard_from_ty(ty);
-                UsefulWithWitness(
-                    witnesses
-                        .into_iter()
-                        .map(|mut witness| {
-                            witness.0.push(wild.clone());
-                            witness
-                        })
-                        .collect(),
-                )
-            }
-            x => x,
-        }
-    }
-
-    fn apply_missing_ctors(
-        self,
-        cx: &MatchCheckCtxt<'_, 'tcx>,
-        ty: Ty<'tcx>,
-        missing_ctors: &MissingConstructors<'tcx>,
-    ) -> Self {
-        match self {
-            UsefulWithWitness(witnesses) => {
-                let new_patterns: Vec<_> =
-                    missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, ty)).collect();
-                // Add the new patterns to each witness
-                UsefulWithWitness(
-                    witnesses
-                        .into_iter()
-                        .flat_map(|witness| {
-                            new_patterns.iter().map(move |pat| {
-                                let mut witness = witness.clone();
-                                witness.0.push(pat.clone());
-                                witness
-                            })
-                        })
-                        .collect(),
-                )
-            }
-            x => x,
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum WitnessPreference {
-    ConstructWitness,
-    LeaveOutWitness,
-}
-
-#[derive(Copy, Clone, Debug)]
-struct PatCtxt<'tcx> {
-    ty: Ty<'tcx>,
-    span: Span,
-}
-
-/// A witness of non-exhaustiveness for error reporting, represented
-/// as a list of patterns (in reverse order of construction) with
-/// wildcards inside to represent elements that can take any inhabitant
-/// of the type as a value.
-///
-/// A witness against a list of patterns should have the same types
-/// and length as the pattern matched against. Because Rust `match`
-/// is always against a single pattern, at the end the witness will
-/// have length 1, but in the middle of the algorithm, it can contain
-/// multiple patterns.
-///
-/// For example, if we are constructing a witness for the match against
-/// ```
-/// struct Pair(Option<(u32, u32)>, bool);
-///
-/// match (p: Pair) {
-///    Pair(None, _) => {}
-///    Pair(_, false) => {}
-/// }
-/// ```
-///
-/// We'll perform the following steps:
-/// 1. Start with an empty witness
-///     `Witness(vec![])`
-/// 2. Push a witness `Some(_)` against the `None`
-///     `Witness(vec![Some(_)])`
-/// 3. Push a witness `true` against the `false`
-///     `Witness(vec![Some(_), true])`
-/// 4. Apply the `Pair` constructor to the witnesses
-///     `Witness(vec![Pair(Some(_), true)])`
-///
-/// The final `Pair(Some(_), true)` is then the resulting witness.
-#[derive(Clone, Debug)]
-pub struct Witness<'tcx>(Vec<Pat<'tcx>>);
-
-impl<'tcx> Witness<'tcx> {
-    pub fn single_pattern(self) -> Pat<'tcx> {
-        assert_eq!(self.0.len(), 1);
-        self.0.into_iter().next().unwrap()
-    }
-
-    /// Constructs a partial witness for a pattern given a list of
-    /// patterns expanded by the specialization step.
-    ///
-    /// When a pattern P is discovered to be useful, this function is used bottom-up
-    /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset
-    /// of values, V, where each value in that set is not covered by any previously
-    /// used patterns and is covered by the pattern P'. Examples:
-    ///
-    /// left_ty: tuple of 3 elements
-    /// pats: [10, 20, _]           => (10, 20, _)
-    ///
-    /// left_ty: struct X { a: (bool, &'static str), b: usize}
-    /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor<'a>(
-        mut self,
-        cx: &MatchCheckCtxt<'a, 'tcx>,
-        ctor: &Constructor<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Self {
-        let arity = ctor.arity(cx, ty);
-        let pat = {
-            let len = self.0.len() as u64;
-            let pats = self.0.drain((len - arity) as usize..).rev();
-            ctor.apply(cx, ty, pats)
-        };
-
-        self.0.push(pat);
-
-        self
-    }
-}
-
-/// This determines the set of all possible constructors of a pattern matching
-/// values of type `left_ty`. For vectors, this would normally be an infinite set
-/// but is instead bounded by the maximum fixed length of slice patterns in
-/// the column of patterns being analyzed.
-///
-/// We make sure to omit constructors that are statically impossible. E.g., for
-/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
-/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
-/// `cx.is_uninhabited()`).
-fn all_constructors<'a, 'tcx>(
-    cx: &mut MatchCheckCtxt<'a, 'tcx>,
-    pcx: PatCtxt<'tcx>,
-) -> Vec<Constructor<'tcx>> {
-    debug!("all_constructors({:?})", pcx.ty);
-    let make_range = |start, end| {
-        IntRange(
-            // `unwrap()` is ok because we know the type is an integer.
-            IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included, pcx.span)
-                .unwrap(),
-        )
-    };
-    match pcx.ty.kind {
-        ty::Bool => {
-            [true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect()
-        }
-        ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
-            let len = len.eval_usize(cx.tcx, cx.param_env);
-            if len != 0 && cx.is_uninhabited(sub_ty) {
-                vec![]
-            } else {
-                vec![Slice(Slice { array_len: Some(len), kind: VarLen(0, 0) })]
-            }
-        }
-        // Treat arrays of a constant but unknown length like slices.
-        ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => {
-            let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
-            vec![Slice(Slice { array_len: None, kind })]
-        }
-        ty::Adt(def, substs) if def.is_enum() => {
-            let ctors: Vec<_> = if cx.tcx.features().exhaustive_patterns {
-                // If `exhaustive_patterns` is enabled, we exclude variants known to be
-                // uninhabited.
-                def.variants
-                    .iter()
-                    .filter(|v| {
-                        !v.uninhabited_from(cx.tcx, substs, def.adt_kind())
-                            .contains(cx.tcx, cx.module)
-                    })
-                    .map(|v| Variant(v.def_id))
-                    .collect()
-            } else {
-                def.variants.iter().map(|v| Variant(v.def_id)).collect()
-            };
-
-            // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
-            // additional "unknown" constructor.
-            // There is no point in enumerating all possible variants, because the user can't
-            // actually match against them all themselves. So we always return only the fictitious
-            // constructor.
-            // E.g., in an example like:
-            // ```
-            //     let err: io::ErrorKind = ...;
-            //     match err {
-            //         io::ErrorKind::NotFound => {},
-            //     }
-            // ```
-            // we don't want to show every possible IO error, but instead have only `_` as the
-            // witness.
-            let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
-
-            // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
-            // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
-            // an empty match will still be considered exhaustive because that case is handled
-            // separately in `check_match`.
-            let is_secretly_empty =
-                def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns;
-
-            if is_secretly_empty || is_declared_nonexhaustive { vec![NonExhaustive] } else { ctors }
-        }
-        ty::Char => {
-            vec![
-                // The valid Unicode Scalar Value ranges.
-                make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
-                make_range('\u{E000}' as u128, '\u{10FFFF}' as u128),
-            ]
-        }
-        ty::Int(_) | ty::Uint(_)
-            if pcx.ty.is_ptr_sized_integral()
-                && !cx.tcx.features().precise_pointer_size_matching =>
-        {
-            // `usize`/`isize` are not allowed to be matched exhaustively unless the
-            // `precise_pointer_size_matching` feature is enabled. So we treat those types like
-            // `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
-            vec![NonExhaustive]
-        }
-        ty::Int(ity) => {
-            let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
-            let min = 1u128 << (bits - 1);
-            let max = min - 1;
-            vec![make_range(min, max)]
-        }
-        ty::Uint(uty) => {
-            let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
-            let max = truncate(u128::max_value(), size);
-            vec![make_range(0, max)]
-        }
-        _ => {
-            if cx.is_uninhabited(pcx.ty) {
-                vec![]
-            } else {
-                vec![Single]
-            }
-        }
-    }
-}
-
-/// An inclusive interval, used for precise integer exhaustiveness checking.
-/// `IntRange`s always store a contiguous range. This means that values are
-/// encoded such that `0` encodes the minimum value for the integer,
-/// regardless of the signedness.
-/// For example, the pattern `-128..=127i8` is encoded as `0..=255`.
-/// This makes comparisons and arithmetic on interval endpoints much more
-/// straightforward. See `signed_bias` for details.
-///
-/// `IntRange` is never used to encode an empty range or a "range" that wraps
-/// around the (offset) space: i.e., `range.lo <= range.hi`.
-#[derive(Clone, Debug)]
-struct IntRange<'tcx> {
-    pub range: RangeInclusive<u128>,
-    pub ty: Ty<'tcx>,
-    pub span: Span,
-}
-
-impl<'tcx> IntRange<'tcx> {
-    #[inline]
-    fn is_integral(ty: Ty<'_>) -> bool {
-        match ty.kind {
-            ty::Char | ty::Int(_) | ty::Uint(_) => true,
-            _ => false,
-        }
-    }
-
-    fn is_singleton(&self) -> bool {
-        self.range.start() == self.range.end()
-    }
-
-    fn boundaries(&self) -> (u128, u128) {
-        (*self.range.start(), *self.range.end())
-    }
-
-    /// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching` feature
-    /// is enabled.
-    fn treat_exhaustively(&self, tcx: TyCtxt<'tcx>) -> bool {
-        !self.ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching
-    }
-
-    #[inline]
-    fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
-        match ty.kind {
-            ty::Char => Some((Size::from_bytes(4), 0)),
-            ty::Int(ity) => {
-                let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
-                Some((size, 1u128 << (size.bits() as u128 - 1)))
-            }
-            ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)),
-            _ => None,
-        }
-    }
-
-    #[inline]
-    fn from_const(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        value: &Const<'tcx>,
-        span: Span,
-    ) -> Option<IntRange<'tcx>> {
-        if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
-            let ty = value.ty;
-            let val = if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, size })) =
-                value.val
-            {
-                // For this specific pattern we can skip a lot of effort and go
-                // straight to the result, after doing a bit of checking. (We
-                // could remove this branch and just use the next branch, which
-                // is more general but much slower.)
-                Scalar::<()>::check_raw(data, size, target_size);
-                data
-            } else if let Some(val) = value.try_eval_bits(tcx, param_env, ty) {
-                // This is a more general form of the previous branch.
-                val
-            } else {
-                return None;
-            };
-            let val = val ^ bias;
-            Some(IntRange { range: val..=val, ty, span })
-        } else {
-            None
-        }
-    }
-
-    #[inline]
-    fn from_range(
-        tcx: TyCtxt<'tcx>,
-        lo: u128,
-        hi: u128,
-        ty: Ty<'tcx>,
-        end: &RangeEnd,
-        span: Span,
-    ) -> Option<IntRange<'tcx>> {
-        if Self::is_integral(ty) {
-            // Perform a shift if the underlying types are signed,
-            // which makes the interval arithmetic simpler.
-            let bias = IntRange::signed_bias(tcx, ty);
-            let (lo, hi) = (lo ^ bias, hi ^ bias);
-            let offset = (*end == RangeEnd::Excluded) as u128;
-            if lo > hi || (lo == hi && *end == RangeEnd::Excluded) {
-                // This should have been caught earlier by E0030.
-                bug!("malformed range pattern: {}..={}", lo, (hi - offset));
-            }
-            Some(IntRange { range: lo..=(hi - offset), ty, span })
-        } else {
-            None
-        }
-    }
-
-    fn from_pat(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        pat: &Pat<'tcx>,
-    ) -> Option<IntRange<'tcx>> {
-        match pat_constructor(tcx, param_env, pat)? {
-            IntRange(range) => Some(range),
-            _ => None,
-        }
-    }
-
-    // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
-    fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 {
-        match ty.kind {
-            ty::Int(ity) => {
-                let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
-                1u128 << (bits - 1)
-            }
-            _ => 0,
-        }
-    }
-
-    /// Returns a collection of ranges that spans the values covered by `ranges`, subtracted
-    /// by the values covered by `self`: i.e., `ranges \ self` (in set notation).
-    fn subtract_from(&self, ranges: Vec<IntRange<'tcx>>) -> Vec<IntRange<'tcx>> {
-        let mut remaining_ranges = vec![];
-        let ty = self.ty;
-        let span = self.span;
-        let (lo, hi) = self.boundaries();
-        for subrange in ranges {
-            let (subrange_lo, subrange_hi) = subrange.range.into_inner();
-            if lo > subrange_hi || subrange_lo > hi {
-                // The pattern doesn't intersect with the subrange at all,
-                // so the subrange remains untouched.
-                remaining_ranges.push(IntRange { range: subrange_lo..=subrange_hi, ty, span });
-            } else {
-                if lo > subrange_lo {
-                    // The pattern intersects an upper section of the
-                    // subrange, so a lower section will remain.
-                    remaining_ranges.push(IntRange { range: subrange_lo..=(lo - 1), ty, span });
-                }
-                if hi < subrange_hi {
-                    // The pattern intersects a lower section of the
-                    // subrange, so an upper section will remain.
-                    remaining_ranges.push(IntRange { range: (hi + 1)..=subrange_hi, ty, span });
-                }
-            }
-        }
-        remaining_ranges
-    }
-
-    fn is_subrange(&self, other: &Self) -> bool {
-        other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
-    }
-
-    fn intersection(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Option<Self> {
-        let ty = self.ty;
-        let (lo, hi) = self.boundaries();
-        let (other_lo, other_hi) = other.boundaries();
-        if self.treat_exhaustively(tcx) {
-            if lo <= other_hi && other_lo <= hi {
-                let span = other.span;
-                Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span })
-            } else {
-                None
-            }
-        } else {
-            // If the range should not be treated exhaustively, fallback to checking for inclusion.
-            if self.is_subrange(other) { Some(self.clone()) } else { None }
-        }
-    }
-
-    fn suspicious_intersection(&self, other: &Self) -> bool {
-        // `false` in the following cases:
-        // 1     ----      // 1  ----------   // 1 ----        // 1       ----
-        // 2  ----------   // 2     ----      // 2       ----  // 2 ----
-        //
-        // The following are currently `false`, but could be `true` in the future (#64007):
-        // 1 ---------       // 1     ---------
-        // 2     ----------  // 2 ----------
-        //
-        // `true` in the following cases:
-        // 1 -------          // 1       -------
-        // 2       --------   // 2 -------
-        let (lo, hi) = self.boundaries();
-        let (other_lo, other_hi) = other.boundaries();
-        (lo == other_hi || hi == other_lo)
-    }
-
-    fn to_pat(&self, tcx: TyCtxt<'tcx>) -> Pat<'tcx> {
-        let (lo, hi) = self.boundaries();
-
-        let bias = IntRange::signed_bias(tcx, self.ty);
-        let (lo, hi) = (lo ^ bias, hi ^ bias);
-
-        let ty = ty::ParamEnv::empty().and(self.ty);
-        let lo_const = ty::Const::from_bits(tcx, lo, ty);
-        let hi_const = ty::Const::from_bits(tcx, hi, ty);
-
-        let kind = if lo == hi {
-            PatKind::Constant { value: lo_const }
-        } else {
-            PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
-        };
-
-        // This is a brand new pattern, so we don't reuse `self.span`.
-        Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(kind) }
-    }
-}
-
-/// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
-impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
-    fn eq(&self, other: &Self) -> bool {
-        self.range == other.range && self.ty == other.ty
-    }
-}
-
-// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
-struct MissingConstructors<'tcx> {
-    all_ctors: Vec<Constructor<'tcx>>,
-    used_ctors: Vec<Constructor<'tcx>>,
-}
-
-impl<'tcx> MissingConstructors<'tcx> {
-    fn new(all_ctors: Vec<Constructor<'tcx>>, used_ctors: Vec<Constructor<'tcx>>) -> Self {
-        MissingConstructors { all_ctors, used_ctors }
-    }
-
-    fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
-        (self.all_ctors, self.used_ctors)
-    }
-
-    fn is_empty(&self) -> bool {
-        self.iter().next().is_none()
-    }
-    /// Whether this contains all the constructors for the given type or only a
-    /// subset.
-    fn all_ctors_are_missing(&self) -> bool {
-        self.used_ctors.is_empty()
-    }
-
-    /// Iterate over all_ctors \ used_ctors
-    fn iter<'a>(&'a self) -> impl Iterator<Item = Constructor<'tcx>> + Captures<'a> {
-        self.all_ctors.iter().flat_map(move |req_ctor| req_ctor.subtract_ctors(&self.used_ctors))
-    }
-}
-
-impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let ctors: Vec<_> = self.iter().collect();
-        write!(f, "{:?}", ctors)
-    }
-}
-
-/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
-/// The algorithm from the paper has been modified to correctly handle empty
-/// types. The changes are:
-///   (0) We don't exit early if the pattern matrix has zero rows. We just
-///       continue to recurse over columns.
-///   (1) all_constructors will only return constructors that are statically
-///       possible. E.g., it will only return `Ok` for `Result<T, !>`.
-///
-/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
-/// to a set of such vectors `m` - this is defined as there being a set of
-/// inputs that will match `v` but not any of the sets in `m`.
-///
-/// All the patterns at each column of the `matrix ++ v` matrix must
-/// have the same type, except that wildcard (PatKind::Wild) patterns
-/// with type `TyErr` are also allowed, even if the "type of the column"
-/// is not `TyErr`. That is used to represent private fields, as using their
-/// real type would assert that they are inhabited.
-///
-/// This is used both for reachability checking (if a pattern isn't useful in
-/// relation to preceding patterns, it is not reachable) and exhaustiveness
-/// checking (if a wildcard pattern is useful in relation to a matrix, the
-/// matrix isn't exhaustive).
-pub fn is_useful<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    matrix: &Matrix<'p, 'tcx>,
-    v: &PatStack<'p, 'tcx>,
-    witness_preference: WitnessPreference,
-    hir_id: HirId,
-    is_top_level: bool,
-) -> Usefulness<'tcx, 'p> {
-    let &Matrix(ref rows) = matrix;
-    debug!("is_useful({:#?}, {:#?})", matrix, v);
-
-    // The base case. We are pattern-matching on () and the return value is
-    // based on whether our matrix has a row or not.
-    // NOTE: This could potentially be optimized by checking rows.is_empty()
-    // first and then, if v is non-empty, the return value is based on whether
-    // the type of the tuple we're checking is inhabited or not.
-    if v.is_empty() {
-        return if rows.is_empty() {
-            Usefulness::new_useful(witness_preference)
-        } else {
-            NotUseful
-        };
-    };
-
-    assert!(rows.iter().all(|r| r.len() == v.len()));
-
-    // If the first pattern is an or-pattern, expand it.
-    if let Some(vs) = v.expand_or_pat() {
-        // We need to push the already-seen patterns into the matrix in order to detect redundant
-        // branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
-        let mut matrix = matrix.clone();
-        let mut unreachable_pats = Vec::new();
-        let mut any_is_useful = false;
-        for v in vs {
-            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
-            match res {
-                Useful(pats) => {
-                    any_is_useful = true;
-                    unreachable_pats.extend(pats);
-                }
-                NotUseful => unreachable_pats.push(v.head()),
-                UsefulWithWitness(_) => {
-                    bug!("Encountered or-pat in `v` during exhaustiveness checking")
-                }
-            }
-            matrix.push(v);
-        }
-        return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
-    }
-
-    let (ty, span) = matrix
-        .heads()
-        .map(|r| (r.ty, r.span))
-        .find(|(ty, _)| !ty.references_error())
-        .unwrap_or((v.head().ty, v.head().span));
-    let pcx = PatCtxt {
-        // TyErr is used to represent the type of wildcard patterns matching
-        // against inaccessible (private) fields of structs, so that we won't
-        // be able to observe whether the types of the struct's fields are
-        // inhabited.
-        //
-        // If the field is truly inaccessible, then all the patterns
-        // matching against it must be wildcard patterns, so its type
-        // does not matter.
-        //
-        // However, if we are matching against non-wildcard patterns, we
-        // need to know the real type of the field so we can specialize
-        // against it. This primarily occurs through constants - they
-        // can include contents for fields that are inaccessible at the
-        // location of the match. In that case, the field's type is
-        // inhabited - by the constant - so we can just use it.
-        //
-        // FIXME: this might lead to "unstable" behavior with macro hygiene
-        // introducing uninhabited patterns for inaccessible fields. We
-        // need to figure out how to model that.
-        ty,
-        span,
-    };
-
-    debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
-
-    if let Some(constructor) = pat_constructor(cx.tcx, cx.param_env, v.head()) {
-        debug!("is_useful - expanding constructor: {:#?}", constructor);
-        split_grouped_constructors(
-            cx.tcx,
-            cx.param_env,
-            pcx,
-            vec![constructor],
-            matrix,
-            pcx.span,
-            Some(hir_id),
-        )
-        .into_iter()
-        .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
-        .find(|result| result.is_useful())
-        .unwrap_or(NotUseful)
-    } else {
-        debug!("is_useful - expanding wildcard");
-
-        let used_ctors: Vec<Constructor<'_>> =
-            matrix.heads().filter_map(|p| pat_constructor(cx.tcx, cx.param_env, p)).collect();
-        debug!("used_ctors = {:#?}", used_ctors);
-        // `all_ctors` are all the constructors for the given type, which
-        // should all be represented (or caught with the wild pattern `_`).
-        let all_ctors = all_constructors(cx, pcx);
-        debug!("all_ctors = {:#?}", all_ctors);
-
-        // `missing_ctors` is the set of constructors from the same type as the
-        // first column of `matrix` that are matched only by wildcard patterns
-        // from the first column.
-        //
-        // Therefore, if there is some pattern that is unmatched by `matrix`,
-        // it will still be unmatched if the first constructor is replaced by
-        // any of the constructors in `missing_ctors`
-
-        // Missing constructors are those that are not matched by any non-wildcard patterns in the
-        // current column. We only fully construct them on-demand, because they're rarely used and
-        // can be big.
-        let missing_ctors = MissingConstructors::new(all_ctors, used_ctors);
-
-        debug!("missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
-
-        if missing_ctors.is_empty() {
-            let (all_ctors, _) = missing_ctors.into_inner();
-            split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None)
-                .into_iter()
-                .map(|c| {
-                    is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id)
-                })
-                .find(|result| result.is_useful())
-                .unwrap_or(NotUseful)
-        } else {
-            let matrix = matrix.specialize_wildcard();
-            let v = v.to_tail();
-            let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
-
-            // In this case, there's at least one "free"
-            // constructor that is only matched against by
-            // wildcard patterns.
-            //
-            // There are 2 ways we can report a witness here.
-            // Commonly, we can report all the "free"
-            // constructors as witnesses, e.g., if we have:
-            //
-            // ```
-            //     enum Direction { N, S, E, W }
-            //     let Direction::N = ...;
-            // ```
-            //
-            // we can report 3 witnesses: `S`, `E`, and `W`.
-            //
-            // However, there is a case where we don't want
-            // to do this and instead report a single `_` witness:
-            // if the user didn't actually specify a constructor
-            // in this arm, e.g., in
-            // ```
-            //     let x: (Direction, Direction, bool) = ...;
-            //     let (_, _, false) = x;
-            // ```
-            // we don't want to show all 16 possible witnesses
-            // `(<direction-1>, <direction-2>, true)` - we are
-            // satisfied with `(_, _, true)`. In this case,
-            // `used_ctors` is empty.
-            // The exception is: if we are at the top-level, for example in an empty match, we
-            // sometimes prefer reporting the list of constructors instead of just `_`.
-            let report_ctors_rather_than_wildcard = is_top_level && !IntRange::is_integral(pcx.ty);
-            if missing_ctors.all_ctors_are_missing() && !report_ctors_rather_than_wildcard {
-                // All constructors are unused. Add a wild pattern
-                // rather than each individual constructor.
-                usefulness.apply_wildcard(pcx.ty)
-            } else {
-                // Construct for each missing constructor a "wild" version of this
-                // constructor, that matches everything that can be built with
-                // it. For example, if `ctor` is a `Constructor::Variant` for
-                // `Option::Some`, we get the pattern `Some(_)`.
-                usefulness.apply_missing_ctors(cx, pcx.ty, &missing_ctors)
-            }
-        }
-    }
-}
-
-/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
-/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
-fn is_useful_specialized<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    matrix: &Matrix<'p, 'tcx>,
-    v: &PatStack<'p, 'tcx>,
-    ctor: Constructor<'tcx>,
-    lty: Ty<'tcx>,
-    witness_preference: WitnessPreference,
-    hir_id: HirId,
-) -> Usefulness<'tcx, 'p> {
-    debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
-
-    let ctor_wild_subpatterns =
-        cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
-    let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
-    v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
-        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false))
-        .map(|u| u.apply_constructor(cx, &ctor, lty))
-        .unwrap_or(NotUseful)
-}
-
-/// Determines the constructor that the given pattern can be specialized to.
-/// Returns `None` in case of a catch-all, which can't be specialized.
-fn pat_constructor<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    pat: &Pat<'tcx>,
-) -> Option<Constructor<'tcx>> {
-    match *pat.kind {
-        PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
-        PatKind::Binding { .. } | PatKind::Wild => None,
-        PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(Single),
-        PatKind::Variant { adt_def, variant_index, .. } => {
-            Some(Variant(adt_def.variants[variant_index].def_id))
-        }
-        PatKind::Constant { value } => {
-            if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
-                Some(IntRange(int_range))
-            } else {
-                match (value.val, &value.ty.kind) {
-                    (_, ty::Array(_, n)) => {
-                        let len = n.eval_usize(tcx, param_env);
-                        Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) }))
-                    }
-                    (ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => {
-                        let len = (end - start) as u64;
-                        Some(Slice(Slice { array_len: None, kind: FixedLen(len) }))
-                    }
-                    // FIXME(oli-obk): implement `deref` for `ConstValue`
-                    // (ty::ConstKind::Value(ConstValue::ByRef { .. }), ty::Slice(_)) => { ... }
-                    _ => Some(ConstantValue(value)),
-                }
-            }
-        }
-        PatKind::Range(PatRange { lo, hi, end }) => {
-            let ty = lo.ty;
-            if let Some(int_range) = IntRange::from_range(
-                tcx,
-                lo.eval_bits(tcx, param_env, lo.ty),
-                hi.eval_bits(tcx, param_env, hi.ty),
-                ty,
-                &end,
-                pat.span,
-            ) {
-                Some(IntRange(int_range))
-            } else {
-                Some(FloatRange(lo, hi, end))
-            }
-        }
-        PatKind::Array { ref prefix, ref slice, ref suffix }
-        | PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-            let array_len = match pat.ty.kind {
-                ty::Array(_, length) => Some(length.eval_usize(tcx, param_env)),
-                ty::Slice(_) => None,
-                _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
-            };
-            let prefix = prefix.len() as u64;
-            let suffix = suffix.len() as u64;
-            let kind =
-                if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
-            Some(Slice(Slice { array_len, kind }))
-        }
-        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
-    }
-}
-
-// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
-// meaning all other types will compare unequal and thus equal patterns often do not cause the
-// second pattern to lint about unreachable match arms.
-fn slice_pat_covered_by_const<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    _span: Span,
-    const_val: &'tcx ty::Const<'tcx>,
-    prefix: &[Pat<'tcx>],
-    slice: &Option<Pat<'tcx>>,
-    suffix: &[Pat<'tcx>],
-    param_env: ty::ParamEnv<'tcx>,
-) -> Result<bool, ErrorReported> {
-    let const_val_val = if let ty::ConstKind::Value(val) = const_val.val {
-        val
-    } else {
-        bug!(
-            "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
-            const_val,
-            prefix,
-            slice,
-            suffix,
-        )
-    };
-
-    let data: &[u8] = match (const_val_val, &const_val.ty.kind) {
-        (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => {
-            assert_eq!(*t, tcx.types.u8);
-            let n = n.eval_usize(tcx, param_env);
-            let ptr = Pointer::new(AllocId(0), offset);
-            alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
-        }
-        (ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
-            assert_eq!(*t, tcx.types.u8);
-            let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64));
-            data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap()
-        }
-        // FIXME(oli-obk): create a way to extract fat pointers from ByRef
-        (_, ty::Slice(_)) => return Ok(false),
-        _ => bug!(
-            "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
-            const_val,
-            prefix,
-            slice,
-            suffix,
-        ),
-    };
-
-    let pat_len = prefix.len() + suffix.len();
-    if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
-        return Ok(false);
-    }
-
-    for (ch, pat) in data[..prefix.len()]
-        .iter()
-        .zip(prefix)
-        .chain(data[data.len() - suffix.len()..].iter().zip(suffix))
-    {
-        match pat.kind {
-            box PatKind::Constant { value } => {
-                let b = value.eval_bits(tcx, param_env, pat.ty);
-                assert_eq!(b as u8 as u128, b);
-                if b as u8 != *ch {
-                    return Ok(false);
-                }
-            }
-            _ => {}
-        }
-    }
-
-    Ok(true)
-}
-
-/// For exhaustive integer matching, some constructors are grouped within other constructors
-/// (namely integer typed values are grouped within ranges). However, when specialising these
-/// constructors, we want to be specialising for the underlying constructors (the integers), not
-/// the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would
-/// mean creating a separate constructor for every single value in the range, which is clearly
-/// impractical. However, observe that for some ranges of integers, the specialisation will be
-/// identical across all values in that range (i.e., there are equivalence classes of ranges of
-/// constructors based on their `is_useful_specialized` outcome). These classes are grouped by
-/// the patterns that apply to them (in the matrix `P`). We can split the range whenever the
-/// patterns that apply to that range (specifically: the patterns that *intersect* with that range)
-/// change.
-/// Our solution, therefore, is to split the range constructor into subranges at every single point
-/// the group of intersecting patterns changes (using the method described below).
-/// And voilà! We're testing precisely those ranges that we need to, without any exhaustive matching
-/// on actual integers. The nice thing about this is that the number of subranges is linear in the
-/// number of rows in the matrix (i.e., the number of cases in the `match` statement), so we don't
-/// need to be worried about matching over gargantuan ranges.
-///
-/// Essentially, given the first column of a matrix representing ranges, looking like the following:
-///
-/// |------|  |----------| |-------|    ||
-///    |-------| |-------|            |----| ||
-///       |---------|
-///
-/// We split the ranges up into equivalence classes so the ranges are no longer overlapping:
-///
-/// |--|--|||-||||--||---|||-------|  |-|||| ||
-///
-/// The logic for determining how to split the ranges is fairly straightforward: we calculate
-/// boundaries for each interval range, sort them, then create constructors for each new interval
-/// between every pair of boundary points. (This essentially sums up to performing the intuitive
-/// merging operation depicted above.)
-///
-/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
-/// ranges that case.
-///
-/// This also splits variable-length slices into fixed-length slices.
-fn split_grouped_constructors<'p, 'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    pcx: PatCtxt<'tcx>,
-    ctors: Vec<Constructor<'tcx>>,
-    matrix: &Matrix<'p, 'tcx>,
-    span: Span,
-    hir_id: Option<HirId>,
-) -> Vec<Constructor<'tcx>> {
-    let ty = pcx.ty;
-    let mut split_ctors = Vec::with_capacity(ctors.len());
-    debug!("split_grouped_constructors({:#?}, {:#?})", matrix, ctors);
-
-    for ctor in ctors.into_iter() {
-        match ctor {
-            IntRange(ctor_range) if ctor_range.treat_exhaustively(tcx) => {
-                // Fast-track if the range is trivial. In particular, don't do the overlapping
-                // ranges check.
-                if ctor_range.is_singleton() {
-                    split_ctors.push(IntRange(ctor_range));
-                    continue;
-                }
-
-                /// Represents a border between 2 integers. Because the intervals spanning borders
-                /// must be able to cover every integer, we need to be able to represent
-                /// 2^128 + 1 such borders.
-                #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
-                enum Border {
-                    JustBefore(u128),
-                    AfterMax,
-                }
-
-                // A function for extracting the borders of an integer interval.
-                fn range_borders(r: IntRange<'_>) -> impl Iterator<Item = Border> {
-                    let (lo, hi) = r.range.into_inner();
-                    let from = Border::JustBefore(lo);
-                    let to = match hi.checked_add(1) {
-                        Some(m) => Border::JustBefore(m),
-                        None => Border::AfterMax,
-                    };
-                    vec![from, to].into_iter()
-                }
-
-                // Collect the span and range of all the intersecting ranges to lint on likely
-                // incorrect range patterns. (#63987)
-                let mut overlaps = vec![];
-                // `borders` is the set of borders between equivalence classes: each equivalence
-                // class lies between 2 borders.
-                let row_borders = matrix
-                    .0
-                    .iter()
-                    .flat_map(|row| {
-                        IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len()))
-                    })
-                    .flat_map(|(range, row_len)| {
-                        let intersection = ctor_range.intersection(tcx, &range);
-                        let should_lint = ctor_range.suspicious_intersection(&range);
-                        if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
-                            // FIXME: for now, only check for overlapping ranges on simple range
-                            // patterns. Otherwise with the current logic the following is detected
-                            // as overlapping:
-                            //   match (10u8, true) {
-                            //    (0 ..= 125, false) => {}
-                            //    (126 ..= 255, false) => {}
-                            //    (0 ..= 255, true) => {}
-                            //  }
-                            overlaps.push(range.clone());
-                        }
-                        intersection
-                    })
-                    .flat_map(|range| range_borders(range));
-                let ctor_borders = range_borders(ctor_range.clone());
-                let mut borders: Vec<_> = row_borders.chain(ctor_borders).collect();
-                borders.sort_unstable();
-
-                lint_overlapping_patterns(tcx, hir_id, ctor_range, ty, overlaps);
-
-                // We're going to iterate through every adjacent pair of borders, making sure that
-                // each represents an interval of nonnegative length, and convert each such
-                // interval into a constructor.
-                split_ctors.extend(
-                    borders
-                        .windows(2)
-                        .filter_map(|window| match (window[0], window[1]) {
-                            (Border::JustBefore(n), Border::JustBefore(m)) => {
-                                if n < m {
-                                    Some(IntRange { range: n..=(m - 1), ty, span })
-                                } else {
-                                    None
-                                }
-                            }
-                            (Border::JustBefore(n), Border::AfterMax) => {
-                                Some(IntRange { range: n..=u128::MAX, ty, span })
-                            }
-                            (Border::AfterMax, _) => None,
-                        })
-                        .map(IntRange),
-                );
-            }
-            Slice(Slice { array_len, kind: VarLen(self_prefix, self_suffix) }) => {
-                // The exhaustiveness-checking paper does not include any details on
-                // checking variable-length slice patterns. However, they are matched
-                // by an infinite collection of fixed-length array patterns.
-                //
-                // Checking the infinite set directly would take an infinite amount
-                // of time. However, it turns out that for each finite set of
-                // patterns `P`, all sufficiently large array lengths are equivalent:
-                //
-                // Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
-                // to exactly the subset `Pₜ` of `P` can be transformed to a slice
-                // `sₘ` for each sufficiently-large length `m` that applies to exactly
-                // the same subset of `P`.
-                //
-                // Because of that, each witness for reachability-checking from one
-                // of the sufficiently-large lengths can be transformed to an
-                // equally-valid witness from any other length, so we only have
-                // to check slice lengths from the "minimal sufficiently-large length"
-                // and below.
-                //
-                // Note that the fact that there is a *single* `sₘ` for each `m`
-                // not depending on the specific pattern in `P` is important: if
-                // you look at the pair of patterns
-                //     `[true, ..]`
-                //     `[.., false]`
-                // Then any slice of length ≥1 that matches one of these two
-                // patterns can be trivially turned to a slice of any
-                // other length ≥1 that matches them and vice-versa - for
-                // but the slice from length 2 `[false, true]` that matches neither
-                // of these patterns can't be turned to a slice from length 1 that
-                // matches neither of these patterns, so we have to consider
-                // slices from length 2 there.
-                //
-                // Now, to see that that length exists and find it, observe that slice
-                // patterns are either "fixed-length" patterns (`[_, _, _]`) or
-                // "variable-length" patterns (`[_, .., _]`).
-                //
-                // For fixed-length patterns, all slices with lengths *longer* than
-                // the pattern's length have the same outcome (of not matching), so
-                // as long as `L` is greater than the pattern's length we can pick
-                // any `sₘ` from that length and get the same result.
-                //
-                // For variable-length patterns, the situation is more complicated,
-                // because as seen above the precise value of `sₘ` matters.
-                //
-                // However, for each variable-length pattern `p` with a prefix of length
-                // `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
-                // `slₚ` elements are examined.
-                //
-                // Therefore, as long as `L` is positive (to avoid concerns about empty
-                // types), all elements after the maximum prefix length and before
-                // the maximum suffix length are not examined by any variable-length
-                // pattern, and therefore can be added/removed without affecting
-                // them - creating equivalent patterns from any sufficiently-large
-                // length.
-                //
-                // Of course, if fixed-length patterns exist, we must be sure
-                // that our length is large enough to miss them all, so
-                // we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
-                //
-                // for example, with the above pair of patterns, all elements
-                // but the first and last can be added/removed, so any
-                // witness of length ≥2 (say, `[false, false, true]`) can be
-                // turned to a witness from any other length ≥2.
-
-                let mut max_prefix_len = self_prefix;
-                let mut max_suffix_len = self_suffix;
-                let mut max_fixed_len = 0;
-
-                let head_ctors =
-                    matrix.heads().filter_map(|pat| pat_constructor(tcx, param_env, pat));
-                for ctor in head_ctors {
-                    match ctor {
-                        Slice(slice) => match slice.pattern_kind() {
-                            FixedLen(len) => {
-                                max_fixed_len = cmp::max(max_fixed_len, len);
-                            }
-                            VarLen(prefix, suffix) => {
-                                max_prefix_len = cmp::max(max_prefix_len, prefix);
-                                max_suffix_len = cmp::max(max_suffix_len, suffix);
-                            }
-                        },
-                        _ => {}
-                    }
-                }
-
-                // For diagnostics, we keep the prefix and suffix lengths separate, so in the case
-                // where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly,
-                // so that `L = max_prefix_len + max_suffix_len`.
-                if max_fixed_len + 1 >= max_prefix_len + max_suffix_len {
-                    // The subtraction can't overflow thanks to the above check.
-                    // The new `max_prefix_len` is also guaranteed to be larger than its previous
-                    // value.
-                    max_prefix_len = max_fixed_len + 1 - max_suffix_len;
-                }
-
-                match array_len {
-                    Some(len) => {
-                        let kind = if max_prefix_len + max_suffix_len < len {
-                            VarLen(max_prefix_len, max_suffix_len)
-                        } else {
-                            FixedLen(len)
-                        };
-                        split_ctors.push(Slice(Slice { array_len, kind }));
-                    }
-                    None => {
-                        // `ctor` originally covered the range `(self_prefix +
-                        // self_suffix..infinity)`. We now split it into two: lengths smaller than
-                        // `max_prefix_len + max_suffix_len` are treated independently as
-                        // fixed-lengths slices, and lengths above are captured by a final VarLen
-                        // constructor.
-                        split_ctors.extend(
-                            (self_prefix + self_suffix..max_prefix_len + max_suffix_len)
-                                .map(|len| Slice(Slice { array_len, kind: FixedLen(len) })),
-                        );
-                        split_ctors.push(Slice(Slice {
-                            array_len,
-                            kind: VarLen(max_prefix_len, max_suffix_len),
-                        }));
-                    }
-                }
-            }
-            // Any other constructor can be used unchanged.
-            _ => split_ctors.push(ctor),
-        }
-    }
-
-    debug!("split_grouped_constructors(..)={:#?}", split_ctors);
-    split_ctors
-}
-
-fn lint_overlapping_patterns(
-    tcx: TyCtxt<'tcx>,
-    hir_id: Option<HirId>,
-    ctor_range: IntRange<'tcx>,
-    ty: Ty<'tcx>,
-    overlaps: Vec<IntRange<'tcx>>,
-) {
-    if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
-        let mut err = tcx.struct_span_lint_hir(
-            lint::builtin::OVERLAPPING_PATTERNS,
-            hir_id,
-            ctor_range.span,
-            "multiple patterns covering the same range",
-        );
-        err.span_label(ctor_range.span, "overlapping patterns");
-        for int_range in overlaps {
-            // Use the real type for user display of the ranges:
-            err.span_label(
-                int_range.span,
-                &format!(
-                    "this range overlaps on `{}`",
-                    IntRange { range: int_range.range, ty, span: DUMMY_SP }.to_pat(tcx),
-                ),
-            );
-        }
-        err.emit();
-    }
-}
-
-fn constructor_covered_by_range<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ctor: &Constructor<'tcx>,
-    pat: &Pat<'tcx>,
-) -> Option<()> {
-    if let Single = ctor {
-        return Some(());
-    }
-
-    let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
-        PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
-        PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
-        _ => bug!("`constructor_covered_by_range` called with {:?}", pat),
-    };
-    let (ctor_from, ctor_to, ctor_end) = match *ctor {
-        ConstantValue(value) => (value, value, RangeEnd::Included),
-        FloatRange(from, to, ctor_end) => (from, to, ctor_end),
-        _ => bug!("`constructor_covered_by_range` called with {:?}", ctor),
-    };
-    trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, pat_from, pat_to, ty);
-
-    let to = compare_const_vals(tcx, ctor_to, pat_to, param_env, ty)?;
-    let from = compare_const_vals(tcx, ctor_from, pat_from, param_env, ty)?;
-    let intersects = (from == Ordering::Greater || from == Ordering::Equal)
-        && (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal));
-    if intersects { Some(()) } else { None }
-}
-
-fn patterns_for_variant<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    subpatterns: &'p [FieldPat<'tcx>],
-    ctor_wild_subpatterns: &'p [Pat<'tcx>],
-    is_non_exhaustive: bool,
-) -> PatStack<'p, 'tcx> {
-    let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect();
-
-    for subpat in subpatterns {
-        if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
-            result[subpat.field.index()] = &subpat.pattern;
-        }
-    }
-
-    debug!(
-        "patterns_for_variant({:#?}, {:#?}) = {:#?}",
-        subpatterns, ctor_wild_subpatterns, result
-    );
-    PatStack::from_vec(result)
-}
-
-/// This is the main specialization step. It expands the pattern
-/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
-/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
-/// Returns `None` if the pattern does not have the given constructor.
-///
-/// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
-/// different patterns.
-/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
-/// fields filled with wild patterns.
-fn specialize_one_pattern<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    pat: &'p Pat<'tcx>,
-    constructor: &Constructor<'tcx>,
-    ctor_wild_subpatterns: &'p [Pat<'tcx>],
-) -> Option<PatStack<'p, 'tcx>> {
-    if let NonExhaustive = constructor {
-        // Only a wildcard pattern can match the special extra constructor
-        return if pat.is_wildcard() { Some(PatStack::default()) } else { None };
-    }
-
-    let result = match *pat.kind {
-        PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
-
-        PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()),
-
-        PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
-            let ref variant = adt_def.variants[variant_index];
-            let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant);
-            Some(Variant(variant.def_id))
-                .filter(|variant_constructor| variant_constructor == constructor)
-                .map(|_| {
-                    patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, is_non_exhaustive)
-                })
-        }
-
-        PatKind::Leaf { ref subpatterns } => {
-            Some(patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, false))
-        }
-
-        PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
-
-        PatKind::Constant { value } if constructor.is_slice() => {
-            // We extract an `Option` for the pointer because slices of zero
-            // elements don't necessarily point to memory, they are usually
-            // just integers. The only time they should be pointing to memory
-            // is when they are subslices of nonzero slices.
-            let (alloc, offset, n, ty) = match value.ty.kind {
-                ty::Array(t, n) => {
-                    let n = n.eval_usize(cx.tcx, cx.param_env);
-                    // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce,
-                    // the result would be exactly what we early return here.
-                    if n == 0 {
-                        if ctor_wild_subpatterns.len() as u64 == 0 {
-                            return Some(PatStack::from_slice(&[]));
-                        } else {
-                            return None;
-                        }
-                    }
-                    match value.val {
-                        ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
-                            (Cow::Borrowed(alloc), offset, n, t)
-                        }
-                        _ => span_bug!(pat.span, "array pattern is {:?}", value,),
-                    }
-                }
-                ty::Slice(t) => {
-                    match value.val {
-                        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
-                            let offset = Size::from_bytes(start as u64);
-                            let n = (end - start) as u64;
-                            (Cow::Borrowed(data), offset, n, t)
-                        }
-                        ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
-                            // FIXME(oli-obk): implement `deref` for `ConstValue`
-                            return None;
-                        }
-                        _ => span_bug!(
-                            pat.span,
-                            "slice pattern constant must be scalar pair but is {:?}",
-                            value,
-                        ),
-                    }
-                }
-                _ => span_bug!(
-                    pat.span,
-                    "unexpected const-val {:?} with ctor {:?}",
-                    value,
-                    constructor,
-                ),
-            };
-            if ctor_wild_subpatterns.len() as u64 == n {
-                // convert a constant slice/array pattern to a list of patterns.
-                let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
-                let ptr = Pointer::new(AllocId(0), offset);
-                (0..n)
-                    .map(|i| {
-                        let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
-                        let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
-                        let scalar = scalar.not_undef().ok()?;
-                        let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
-                        let pattern =
-                            Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
-                        Some(&*cx.pattern_arena.alloc(pattern))
-                    })
-                    .collect()
-            } else {
-                None
-            }
-        }
-
-        PatKind::Constant { .. } | PatKind::Range { .. } => {
-            // If the constructor is a:
-            // - Single value: add a row if the pattern contains the constructor.
-            // - Range: add a row if the constructor intersects the pattern.
-            if let IntRange(ctor) = constructor {
-                match IntRange::from_pat(cx.tcx, cx.param_env, pat) {
-                    Some(pat) => ctor.intersection(cx.tcx, &pat).map(|_| {
-                        // Constructor splitting should ensure that all intersections we encounter
-                        // are actually inclusions.
-                        assert!(ctor.is_subrange(&pat));
-                        PatStack::default()
-                    }),
-                    _ => None,
-                }
-            } else {
-                // Fallback for non-ranges and ranges that involve
-                // floating-point numbers, which are not conveniently handled
-                // by `IntRange`. For these cases, the constructor may not be a
-                // range so intersection actually devolves into being covered
-                // by the pattern.
-                constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)
-                    .map(|()| PatStack::default())
-            }
-        }
-
-        PatKind::Array { ref prefix, ref slice, ref suffix }
-        | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
-            Slice(_) => {
-                let pat_len = prefix.len() + suffix.len();
-                if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
-                    if slice_count == 0 || slice.is_some() {
-                        Some(
-                            prefix
-                                .iter()
-                                .chain(
-                                    ctor_wild_subpatterns
-                                        .iter()
-                                        .skip(prefix.len())
-                                        .take(slice_count)
-                                        .chain(suffix.iter()),
-                                )
-                                .collect(),
-                        )
-                    } else {
-                        None
-                    }
-                } else {
-                    None
-                }
-            }
-            ConstantValue(cv) => {
-                match slice_pat_covered_by_const(
-                    cx.tcx,
-                    pat.span,
-                    cv,
-                    prefix,
-                    slice,
-                    suffix,
-                    cx.param_env,
-                ) {
-                    Ok(true) => Some(PatStack::default()),
-                    Ok(false) => None,
-                    Err(ErrorReported) => None,
-                }
-            }
-            _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
-        },
-
-        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
-    };
-    debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
-
-    result
-}
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
deleted file mode 100644 (file)
index ca7912b..0000000
+++ /dev/null
@@ -1,759 +0,0 @@
-use super::_match::Usefulness::*;
-use super::_match::WitnessPreference::*;
-use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack};
-
-use super::{PatCtxt, PatKind, PatternError};
-
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc::lint;
-use rustc::session::Session;
-use rustc::ty::subst::{InternalSubsts, SubstsRef};
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc_error_codes::*;
-use rustc_errors::{Applicability, DiagnosticBuilder};
-use rustc_hir as hir;
-use rustc_hir::def::*;
-use rustc_hir::def_id::DefId;
-use rustc_hir::{HirId, Pat};
-use rustc_span::symbol::sym;
-use rustc_span::{MultiSpan, Span};
-use syntax::ast::Mutability;
-use syntax::feature_gate::feature_err;
-
-use std::slice;
-
-crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
-    let body_id = match tcx.hir().as_local_hir_id(def_id) {
-        None => return,
-        Some(id) => tcx.hir().body_owned_by(id),
-    };
-
-    let mut visitor = MatchVisitor {
-        tcx,
-        tables: tcx.body_tables(body_id),
-        param_env: tcx.param_env(def_id),
-        identity_substs: InternalSubsts::identity_for_item(tcx, def_id),
-    };
-    visitor.visit_body(tcx.hir().body(body_id));
-}
-
-fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> {
-    struct_span_err!(sess, sp, E0004, "{}", &error_message)
-}
-
-struct MatchVisitor<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    tables: &'a ty::TypeckTables<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    identity_substs: SubstsRef<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
-        intravisit::walk_expr(self, ex);
-
-        if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.kind {
-            self.check_match(scrut, arms, source);
-        }
-    }
-
-    fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) {
-        intravisit::walk_local(self, loc);
-
-        let (msg, sp) = match loc.source {
-            hir::LocalSource::Normal => ("local binding", Some(loc.span)),
-            hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
-            hir::LocalSource::AsyncFn => ("async fn binding", None),
-            hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
-        };
-        self.check_irrefutable(&loc.pat, msg, sp);
-
-        // Check legality of move bindings and `@` patterns.
-        self.check_patterns(false, &loc.pat);
-    }
-
-    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
-        intravisit::walk_body(self, body);
-
-        for param in body.params {
-            self.check_irrefutable(&param.pat, "function argument", None);
-            self.check_patterns(false, &param.pat);
-        }
-    }
-}
-
-impl PatCtxt<'_, '_> {
-    fn report_inlining_errors(&self, pat_span: Span) {
-        for error in &self.errors {
-            match *error {
-                PatternError::StaticInPattern(span) => {
-                    self.span_e0158(span, "statics cannot be referenced in patterns")
-                }
-                PatternError::AssocConstInPattern(span) => {
-                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
-                }
-                PatternError::FloatBug => {
-                    // FIXME(#31407) this is only necessary because float parsing is buggy
-                    ::rustc::mir::interpret::struct_error(
-                        self.tcx.at(pat_span),
-                        "could not evaluate float literal (see issue #31407)",
-                    )
-                    .emit();
-                }
-                PatternError::NonConstPath(span) => {
-                    ::rustc::mir::interpret::struct_error(
-                        self.tcx.at(span),
-                        "runtime values cannot be referenced in patterns",
-                    )
-                    .emit();
-                }
-            }
-        }
-    }
-
-    fn span_e0158(&self, span: Span, text: &str) {
-        span_err!(self.tcx.sess, span, E0158, "{}", text)
-    }
-}
-
-impl<'tcx> MatchVisitor<'_, 'tcx> {
-    fn check_patterns(&mut self, has_guard: bool, pat: &Pat<'_>) {
-        check_legality_of_move_bindings(self, has_guard, pat);
-        check_borrow_conflicts_in_at_patterns(self, pat);
-        if !self.tcx.features().bindings_after_at {
-            check_legality_of_bindings_in_at_patterns(self, pat);
-        }
-    }
-
-    fn check_match(
-        &mut self,
-        scrut: &hir::Expr<'_>,
-        arms: &'tcx [hir::Arm<'tcx>],
-        source: hir::MatchSource,
-    ) {
-        for arm in arms {
-            // First, check legality of move bindings.
-            self.check_patterns(arm.guard.is_some(), &arm.pat);
-
-            // Second, perform some lints.
-            check_for_bindings_named_same_as_variants(self, &arm.pat);
-        }
-
-        let module = self.tcx.hir().get_module_parent(scrut.hir_id);
-        MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
-            let mut have_errors = false;
-
-            let inlined_arms: Vec<_> = arms
-                .iter()
-                .map(|arm| {
-                    let mut patcx = PatCtxt::new(
-                        self.tcx,
-                        self.param_env.and(self.identity_substs),
-                        self.tables,
-                    );
-                    patcx.include_lint_checks();
-                    let pattern = patcx.lower_pattern(&arm.pat);
-                    let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
-                    if !patcx.errors.is_empty() {
-                        patcx.report_inlining_errors(arm.pat.span);
-                        have_errors = true;
-                    }
-                    (pattern, &*arm.pat, arm.guard.is_some())
-                })
-                .collect();
-
-            // Bail out early if inlining failed.
-            if have_errors {
-                return;
-            }
-
-            // Fourth, check for unreachable arms.
-            let matrix = check_arms(cx, &inlined_arms, source);
-
-            // Fifth, check if the match is exhaustive.
-            let scrut_ty = self.tables.node_type(scrut.hir_id);
-            // 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 is_empty_match = inlined_arms.is_empty();
-            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
-        })
-    }
-
-    fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
-        let module = self.tcx.hir().get_module_parent(pat.hir_id);
-        MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
-            let mut patcx =
-                PatCtxt::new(self.tcx, self.param_env.and(self.identity_substs), self.tables);
-            patcx.include_lint_checks();
-            let pattern = patcx.lower_pattern(pat);
-            let pattern_ty = pattern.ty;
-            let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
-            let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
-
-            let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
-                Ok(_) => return,
-                Err(err) => err,
-            };
-
-            let joined_patterns = joined_uncovered_patterns(&witnesses);
-            let mut err = struct_span_err!(
-                self.tcx.sess,
-                pat.span,
-                E0005,
-                "refutable pattern in {}: {} not covered",
-                origin,
-                joined_patterns
-            );
-            let suggest_if_let = match &pat.kind {
-                hir::PatKind::Path(hir::QPath::Resolved(None, path))
-                    if path.segments.len() == 1 && path.segments[0].args.is_none() =>
-                {
-                    const_not_var(&mut err, cx.tcx, pat, path);
-                    false
-                }
-                _ => {
-                    err.span_label(
-                        pat.span,
-                        pattern_not_covered_label(&witnesses, &joined_patterns),
-                    );
-                    true
-                }
-            };
-
-            if let (Some(span), true) = (sp, suggest_if_let) {
-                err.note(
-                    "`let` bindings require an \"irrefutable pattern\", like a `struct` or \
-                     an `enum` with only one variant",
-                );
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    err.span_suggestion(
-                        span,
-                        "you might want to use `if let` to ignore the variant that isn't matched",
-                        format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
-                        Applicability::HasPlaceholders,
-                    );
-                }
-                err.note(
-                    "for more information, visit \
-                     https://doc.rust-lang.org/book/ch18-02-refutability.html",
-                );
-            }
-
-            adt_defined_here(cx, &mut err, pattern_ty, &witnesses);
-            err.emit();
-        });
-    }
-}
-
-/// A path pattern was interpreted as a constant, not a new variable.
-/// This caused an irrefutable match failure in e.g. `let`.
-fn const_not_var(
-    err: &mut DiagnosticBuilder<'_>,
-    tcx: TyCtxt<'_>,
-    pat: &Pat<'_>,
-    path: &hir::Path<'_>,
-) {
-    let descr = path.res.descr();
-    err.span_label(
-        pat.span,
-        format!("interpreted as {} {} pattern, not a new variable", path.res.article(), descr,),
-    );
-
-    err.span_suggestion(
-        pat.span,
-        "introduce a variable instead",
-        format!("{}_var", path.segments[0].ident).to_lowercase(),
-        // Cannot use `MachineApplicable` as it's not really *always* correct
-        // because there may be such an identifier in scope or the user maybe
-        // really wanted to match against the constant. This is quite unlikely however.
-        Applicability::MaybeIncorrect,
-    );
-
-    if let Some(span) = tcx.hir().res_span(path.res) {
-        err.span_label(span, format!("{} defined here", descr));
-    }
-}
-
-fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
-    pat.walk_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)
-            {
-                let pat_ty = cx.tables.pat_ty(p).peel_refs();
-                if let ty::Adt(edef, _) = pat_ty.kind {
-                    if edef.is_enum()
-                        && edef.variants.iter().any(|variant| {
-                            variant.ident == ident && variant.ctor_kind == CtorKind::Const
-                        })
-                    {
-                        // FIXME(Centril): Should be a lint?
-                        let ty_path = cx.tcx.def_path_str(edef.did);
-                        let mut err = struct_span_warn!(
-                            cx.tcx.sess,
-                            p.span,
-                            E0170,
-                            "pattern binding `{}` is named the same as one \
-                             of the variants of the type `{}`",
-                            ident,
-                            ty_path
-                        );
-                        err.span_suggestion(
-                            p.span,
-                            "to match on the variant, qualify the path",
-                            format!("{}::{}", ty_path, ident),
-                            Applicability::MachineApplicable,
-                        );
-                        err.emit();
-                    }
-                }
-            }
-        }
-    });
-}
-
-/// Checks for common cases of "catchall" patterns that may not be intended as such.
-fn pat_is_catchall(pat: &Pat<'_>) -> bool {
-    match pat.kind {
-        hir::PatKind::Binding(.., None) => true,
-        hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
-        hir::PatKind::Ref(ref s, _) => pat_is_catchall(s),
-        hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)),
-        _ => false,
-    }
-}
-
-/// Check for unreachable patterns.
-fn check_arms<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    arms: &[(&'p super::Pat<'tcx>, &hir::Pat<'_>, bool)],
-    source: hir::MatchSource,
-) -> Matrix<'p, 'tcx> {
-    let mut seen = Matrix::empty();
-    let mut catchall = None;
-    for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
-        let v = PatStack::from_pattern(pat);
-
-        match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
-            NotUseful => {
-                match source {
-                    hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
-
-                    hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
-                        // check which arm we're on.
-                        match arm_index {
-                            // The arm with the user-specified pattern.
-                            0 => {
-                                cx.tcx.lint_hir(
-                                    lint::builtin::UNREACHABLE_PATTERNS,
-                                    hir_pat.hir_id,
-                                    pat.span,
-                                    "unreachable pattern",
-                                );
-                            }
-                            // The arm with the wildcard pattern.
-                            1 => {
-                                let msg = match source {
-                                    hir::MatchSource::IfLetDesugar { .. } => {
-                                        "irrefutable if-let pattern"
-                                    }
-                                    hir::MatchSource::WhileLetDesugar => {
-                                        "irrefutable while-let pattern"
-                                    }
-                                    _ => bug!(),
-                                };
-                                cx.tcx.lint_hir(
-                                    lint::builtin::IRREFUTABLE_LET_PATTERNS,
-                                    hir_pat.hir_id,
-                                    pat.span,
-                                    msg,
-                                );
-                            }
-                            _ => bug!(),
-                        }
-                    }
-
-                    hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
-                        let mut err = cx.tcx.struct_span_lint_hir(
-                            lint::builtin::UNREACHABLE_PATTERNS,
-                            hir_pat.hir_id,
-                            pat.span,
-                            "unreachable pattern",
-                        );
-                        // if we had a catchall pattern, hint at that
-                        if let Some(catchall) = catchall {
-                            err.span_label(pat.span, "unreachable pattern");
-                            err.span_label(catchall, "matches any value");
-                        }
-                        err.emit();
-                    }
-
-                    // Unreachable patterns in try and await expressions occur when one of
-                    // the arms are an uninhabited type. Which is OK.
-                    hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
-                }
-            }
-            Useful(unreachable_subpatterns) => {
-                for pat in unreachable_subpatterns {
-                    cx.tcx.lint_hir(
-                        lint::builtin::UNREACHABLE_PATTERNS,
-                        hir_pat.hir_id,
-                        pat.span,
-                        "unreachable pattern",
-                    );
-                }
-            }
-            UsefulWithWitness(_) => bug!(),
-        }
-        if !has_guard {
-            seen.push(v);
-            if catchall.is_none() && pat_is_catchall(hir_pat) {
-                catchall = Some(pat.span);
-            }
-        }
-    }
-    seen
-}
-
-fn check_not_useful<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    ty: Ty<'tcx>,
-    matrix: &Matrix<'p, 'tcx>,
-    hir_id: HirId,
-) -> Result<(), Vec<super::Pat<'tcx>>> {
-    let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
-    let v = PatStack::from_pattern(wild_pattern);
-    match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) {
-        NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
-        UsefulWithWitness(pats) => Err(if pats.is_empty() {
-            bug!("Exhaustiveness check returned no witnesses")
-        } else {
-            pats.into_iter().map(|w| w.single_pattern()).collect()
-        }),
-        Useful(_) => bug!(),
-    }
-}
-
-fn check_exhaustive<'p, 'tcx>(
-    cx: &mut MatchCheckCtxt<'p, 'tcx>,
-    scrut_ty: Ty<'tcx>,
-    sp: Span,
-    matrix: &Matrix<'p, 'tcx>,
-    hir_id: HirId,
-    is_empty_match: bool,
-) {
-    // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by
-    // `is_useful` to exhaustively match uninhabited types, so we manually check here.
-    if is_empty_match && !cx.tcx.features().exhaustive_patterns {
-        let scrutinee_is_visibly_uninhabited = match scrut_ty.kind {
-            ty::Never => true,
-            ty::Adt(def, _) => {
-                def.is_enum()
-                    && def.variants.is_empty()
-                    && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
-            }
-            _ => false,
-        };
-        if scrutinee_is_visibly_uninhabited {
-            // If the type *is* uninhabited, an empty match is vacuously exhaustive.
-            return;
-        }
-    }
-
-    let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
-        Ok(_) => return,
-        Err(err) => err,
-    };
-
-    let non_empty_enum = match scrut_ty.kind {
-        ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
-        _ => false,
-    };
-    // In the case of an empty match, replace the '`_` not covered' diagnostic with something more
-    // informative.
-    let mut err;
-    if is_empty_match && !non_empty_enum {
-        err = create_e0004(
-            cx.tcx.sess,
-            sp,
-            format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
-        );
-    } else {
-        let joined_patterns = joined_uncovered_patterns(&witnesses);
-        err = create_e0004(
-            cx.tcx.sess,
-            sp,
-            format!("non-exhaustive patterns: {} not covered", joined_patterns),
-        );
-        err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
-    };
-
-    adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
-    err.help(
-        "ensure that all possible cases are being handled, \
-         possibly by adding wildcards or more match arms",
-    );
-    err.emit();
-}
-
-fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String {
-    const LIMIT: usize = 3;
-    match witnesses {
-        [] => bug!(),
-        [witness] => format!("`{}`", witness),
-        [head @ .., tail] if head.len() < LIMIT => {
-            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
-            format!("`{}` and `{}`", head.join("`, `"), tail)
-        }
-        _ => {
-            let (head, tail) = witnesses.split_at(LIMIT);
-            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
-            format!("`{}` and {} more", head.join("`, `"), tail.len())
-        }
-    }
-}
-
-fn pattern_not_covered_label(witnesses: &[super::Pat<'_>], joined_patterns: &str) -> String {
-    format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns)
-}
-
-/// Point at the definition of non-covered `enum` variants.
-fn adt_defined_here(
-    cx: &MatchCheckCtxt<'_, '_>,
-    err: &mut DiagnosticBuilder<'_>,
-    ty: Ty<'_>,
-    witnesses: &[super::Pat<'_>],
-) {
-    let ty = ty.peel_refs();
-    if let ty::Adt(def, _) = ty.kind {
-        if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
-            err.span_label(sp, format!("`{}` defined here", ty));
-        }
-
-        if witnesses.len() < 4 {
-            for sp in maybe_point_at_variant(ty, &witnesses) {
-                err.span_label(sp, "not covered");
-            }
-        }
-    }
-}
-
-fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec<Span> {
-    let mut covered = vec![];
-    if let ty::Adt(def, _) = ty.kind {
-        // Don't point at variants that have already been covered due to other patterns to avoid
-        // visual clutter.
-        for pattern in patterns {
-            use PatKind::{AscribeUserType, Deref, Leaf, Or, Variant};
-            match &*pattern.kind {
-                AscribeUserType { subpattern, .. } | Deref { subpattern } => {
-                    covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern)));
-                }
-                Variant { adt_def, variant_index, subpatterns, .. } if adt_def.did == def.did => {
-                    let sp = def.variants[*variant_index].ident.span;
-                    if covered.contains(&sp) {
-                        continue;
-                    }
-                    covered.push(sp);
-
-                    let pats = subpatterns
-                        .iter()
-                        .map(|field_pattern| field_pattern.pattern.clone())
-                        .collect::<Box<[_]>>();
-                    covered.extend(maybe_point_at_variant(ty, &pats));
-                }
-                Leaf { subpatterns } => {
-                    let pats = subpatterns
-                        .iter()
-                        .map(|field_pattern| field_pattern.pattern.clone())
-                        .collect::<Box<[_]>>();
-                    covered.extend(maybe_point_at_variant(ty, &pats));
-                }
-                Or { pats } => {
-                    let pats = pats.iter().cloned().collect::<Box<[_]>>();
-                    covered.extend(maybe_point_at_variant(ty, &pats));
-                }
-                _ => {}
-            }
-        }
-    }
-    covered
-}
-
-/// 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;
-
-    // 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) {
-            by_ref_spans.push(span);
-        }
-    });
-
-    // Find bad by-move spans:
-    let by_move_spans = &mut Vec::new();
-    let mut check_move = |p: &Pat<'_>, sub: Option<&Pat<'_>>| {
-        // Check legality of moving out of the enum.
-        //
-        // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't.
-        if sub.map_or(false, |p| p.contains_bindings()) {
-            struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings")
-                .span_label(p.span, "binds an already bound by-move value by moving it")
-                .emit();
-        } else if !has_guard && !by_ref_spans.is_empty() {
-            by_move_spans.push(p.span);
-        }
-    };
-    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) {
-                let pat_ty = tables.node_type(p.hir_id);
-                if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) {
-                    check_move(p, sub.as_deref());
-                }
-            }
-        }
-    });
-
-    // Found some bad by-move spans, error!
-    if !by_move_spans.is_empty() {
-        let mut err = struct_span_err!(
-            sess,
-            MultiSpan::from_spans(by_move_spans.clone()),
-            E0009,
-            "cannot bind by-move and by-ref in the same pattern",
-        );
-        for span in by_ref_spans.iter() {
-            err.span_label(*span, "by-ref pattern here");
-        }
-        for span in by_move_spans.iter() {
-            err.span_label(*span, "by-move pattern here");
-        }
-        err.emit();
-    }
-}
-
-/// Check that there are no borrow conflicts in `binding @ subpat` patterns.
-///
-/// For example, this would reject:
-/// - `ref x @ Some(ref mut y)`,
-/// - `ref mut x @ Some(ref y)`
-/// - `ref mut x @ Some(ref mut y)`.
-///
-/// This analysis is *not* subsumed by NLL.
-fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
-    let tab = cx.tables;
-    let sess = cx.tcx.sess;
-    // Get the mutability of `p` if it's by-ref.
-    let extract_binding_mut = |hir_id, span| match tab.extract_binding_mode(sess, hir_id, span)? {
-        ty::BindByValue(_) => None,
-        ty::BindByReference(m) => Some(m),
-    };
-    pat.walk_always(|pat| {
-        // Extract `sub` in `binding @ sub`.
-        let (name, sub) = match &pat.kind {
-            hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub),
-            _ => return,
-        };
-
-        // Extract the mutability.
-        let mut_outer = match extract_binding_mut(pat.hir_id, pat.span) {
-            None => return,
-            Some(m) => m,
-        };
-
-        // We now have `ref $mut_outer binding @ sub` (semantically).
-        // Recurse into each binding in `sub` and find mutability conflicts.
-        let mut conflicts_mut_mut = Vec::new();
-        let mut conflicts_mut_ref = Vec::new();
-        sub.each_binding(|_, hir_id, span, _| {
-            if let Some(mut_inner) = extract_binding_mut(hir_id, span) {
-                match (mut_outer, mut_inner) {
-                    (Mutability::Not, Mutability::Not) => {}
-                    (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push(span),
-                    _ => conflicts_mut_ref.push(span),
-                }
-            }
-        });
-
-        // Report errors if any.
-        let binding_span = pat.span.with_hi(name.span.hi());
-        if !conflicts_mut_mut.is_empty() {
-            // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
-            let msg = &format!("cannot borrow `{}` as mutable more than once at a time", name);
-            let mut err = sess.struct_span_err(pat.span, msg);
-            err.span_label(binding_span, "first mutable borrow occurs here");
-            for sp in conflicts_mut_mut {
-                err.span_label(sp, "another mutable borrow occurs here");
-            }
-            for sp in conflicts_mut_ref {
-                err.span_label(sp, "also borrowed as immutable here");
-            }
-            err.emit();
-        } else if !conflicts_mut_ref.is_empty() {
-            // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
-            let (primary, also) = match mut_outer {
-                Mutability::Mut => ("mutable", "immutable"),
-                Mutability::Not => ("immutable", "mutable"),
-            };
-            let msg = &format!(
-                "cannot borrow `{}` as {} because it is also borrowed as {}",
-                name, also, primary,
-            );
-            let mut err = sess.struct_span_err(pat.span, msg);
-            err.span_label(binding_span, &format!("{} borrow occurs here", primary));
-            for sp in conflicts_mut_ref {
-                err.span_label(sp, &format!("{} borrow occurs here", also));
-            }
-            err.emit();
-        }
-    });
-}
-
-/// Forbids bindings in `@` patterns. This used to be is necessary for memory safety,
-/// because of the way rvalues were handled in the borrow check. (See issue #14587.)
-fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
-    AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat);
-
-    struct AtBindingPatternVisitor<'a, 'b, 'tcx> {
-        cx: &'a MatchVisitor<'b, 'tcx>,
-        bindings_allowed: bool,
-    }
-
-    impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> {
-        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
-            NestedVisitorMap::None
-        }
-
-        fn visit_pat(&mut self, pat: &Pat<'_>) {
-            match pat.kind {
-                hir::PatKind::Binding(.., ref subpat) => {
-                    if !self.bindings_allowed {
-                        feature_err(
-                            &self.cx.tcx.sess.parse_sess,
-                            sym::bindings_after_at,
-                            pat.span,
-                            "pattern bindings after an `@` are unstable",
-                        )
-                        .emit();
-                    }
-
-                    if subpat.is_some() {
-                        let bindings_were_allowed = self.bindings_allowed;
-                        self.bindings_allowed = false;
-                        intravisit::walk_pat(self, pat);
-                        self.bindings_allowed = bindings_were_allowed;
-                    }
-                }
-                _ => intravisit::walk_pat(self, pat),
-            }
-        }
-    }
-}
diff --git a/src/librustc_mir/hair/pattern/const_to_pat.rs b/src/librustc_mir/hair/pattern/const_to_pat.rs
deleted file mode 100644 (file)
index d4975df..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-use crate::const_eval::const_variant_index;
-
-use rustc::infer::InferCtxt;
-use rustc::lint;
-use rustc::mir::Field;
-use rustc::traits::{ObligationCause, PredicateObligation};
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc_hir as hir;
-
-use rustc_index::vec::Idx;
-
-use rustc_span::Span;
-
-use std::cell::Cell;
-
-use super::{FieldPat, Pat, PatCtxt, PatKind};
-
-impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
-    /// Converts an evaluated constant to a pattern (if possible).
-    /// This means aggregate values (like structs and enums) are converted
-    /// to a pattern that matches the value (as if you'd compared via structural equality).
-    pub(super) fn const_to_pat(
-        &self,
-        cv: &'tcx ty::Const<'tcx>,
-        id: hir::HirId,
-        span: Span,
-    ) -> Pat<'tcx> {
-        debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
-        debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
-
-        self.tcx.infer_ctxt().enter(|infcx| {
-            let mut convert = ConstToPat::new(self, id, span, infcx);
-            convert.to_pat(cv)
-        })
-    }
-}
-
-struct ConstToPat<'a, 'tcx> {
-    id: hir::HirId,
-    span: Span,
-    param_env: ty::ParamEnv<'tcx>,
-
-    // This tracks if we signal some hard error for a given const value, so that
-    // we will not subsequently issue an irrelevant lint for the same const
-    // value.
-    saw_const_match_error: Cell<bool>,
-
-    // inference context used for checking `T: Structural` bounds.
-    infcx: InferCtxt<'a, 'tcx>,
-
-    include_lint_checks: bool,
-}
-
-impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
-    fn new(
-        pat_ctxt: &PatCtxt<'_, 'tcx>,
-        id: hir::HirId,
-        span: Span,
-        infcx: InferCtxt<'a, 'tcx>,
-    ) -> Self {
-        ConstToPat {
-            id,
-            span,
-            infcx,
-            param_env: pat_ctxt.param_env,
-            include_lint_checks: pat_ctxt.include_lint_checks,
-            saw_const_match_error: Cell::new(false),
-        }
-    }
-
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn search_for_structural_match_violation(
-        &self,
-        ty: Ty<'tcx>,
-    ) -> Option<ty::NonStructuralMatchTy<'tcx>> {
-        ty::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty)
-    }
-
-    fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
-        ty::type_marked_structural(self.id, self.span, &self.infcx, ty)
-    }
-
-    fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
-        // This method is just a wrapper handling a validity check; the heavy lifting is
-        // performed by the recursive `recur` method, which is not meant to be
-        // invoked except by this method.
-        //
-        // once indirect_structural_match is a full fledged error, this
-        // level of indirection can be eliminated
-
-        let inlined_const_as_pat = self.recur(cv);
-
-        if self.include_lint_checks && !self.saw_const_match_error.get() {
-            // If we were able to successfully convert the const to some pat,
-            // double-check that all types in the const implement `Structural`.
-
-            let structural = self.search_for_structural_match_violation(cv.ty);
-            debug!(
-                "search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
-                cv.ty, structural
-            );
-            if let Some(non_sm_ty) = structural {
-                let adt_def = match non_sm_ty {
-                    ty::NonStructuralMatchTy::Adt(adt_def) => adt_def,
-                    ty::NonStructuralMatchTy::Param => {
-                        bug!("use of constant whose type is a parameter inside a pattern")
-                    }
-                };
-                let path = self.tcx().def_path_str(adt_def.did);
-                let msg = format!(
-                    "to use a constant of type `{}` in a pattern, \
-                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                    path, path,
-                );
-
-                // double-check there even *is* a semantic `PartialEq` to dispatch to.
-                //
-                // (If there isn't, then we can safely issue a hard
-                // error, because that's never worked, due to compiler
-                // using `PartialEq::eq` in this scenario in the past.)
-                //
-                // Note: To fix rust-lang/rust#65466, one could lift this check
-                // *before* any structural-match checking, and unconditionally error
-                // if `PartialEq` is not implemented. However, that breaks stable
-                // code at the moment, because types like `for <'a> fn(&'a ())` do
-                // not *yet* implement `PartialEq`. So for now we leave this here.
-                let ty_is_partial_eq: bool = {
-                    let partial_eq_trait_id = self.tcx().lang_items().eq_trait().unwrap();
-                    let obligation: PredicateObligation<'_> = self.tcx().predicate_for_trait_def(
-                        self.param_env,
-                        ObligationCause::misc(self.span, self.id),
-                        partial_eq_trait_id,
-                        0,
-                        cv.ty,
-                        &[],
-                    );
-                    // FIXME: should this call a `predicate_must_hold` variant instead?
-                    self.infcx.predicate_may_hold(&obligation)
-                };
-
-                if !ty_is_partial_eq {
-                    // span_fatal avoids ICE from resolution of non-existent method (rare case).
-                    self.tcx().sess.span_fatal(self.span, &msg);
-                } else {
-                    self.tcx().lint_hir(
-                        lint::builtin::INDIRECT_STRUCTURAL_MATCH,
-                        self.id,
-                        self.span,
-                        &msg,
-                    );
-                }
-            }
-        }
-
-        inlined_const_as_pat
-    }
-
-    // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
-    fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
-        let id = self.id;
-        let span = self.span;
-        let tcx = self.tcx();
-        let param_env = self.param_env;
-
-        let adt_subpattern = |i, variant_opt| {
-            let field = Field::new(i);
-            let val = crate::const_eval::const_field(tcx, param_env, variant_opt, field, cv);
-            self.recur(val)
-        };
-        let adt_subpatterns = |n, variant_opt| {
-            (0..n)
-                .map(|i| {
-                    let field = Field::new(i);
-                    FieldPat { field, pattern: adt_subpattern(i, variant_opt) }
-                })
-                .collect::<Vec<_>>()
-        };
-
-        let kind = match cv.ty.kind {
-            ty::Float(_) => {
-                tcx.lint_hir(
-                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
-                    id,
-                    span,
-                    "floating-point types cannot be used in patterns",
-                );
-                PatKind::Constant { value: cv }
-            }
-            ty::Adt(adt_def, _) if adt_def.is_union() => {
-                // Matching on union fields is unsafe, we can't hide it in constants
-                self.saw_const_match_error.set(true);
-                tcx.sess.span_err(span, "cannot use unions in constant patterns");
-                PatKind::Wild
-            }
-            // keep old code until future-compat upgraded to errors.
-            ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => {
-                debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty);
-                let path = tcx.def_path_str(adt_def.did);
-                let msg = format!(
-                    "to use a constant of type `{}` in a pattern, \
-                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                    path, path,
-                );
-                self.saw_const_match_error.set(true);
-                tcx.sess.span_err(span, &msg);
-                PatKind::Wild
-            }
-            // keep old code until future-compat upgraded to errors.
-            ty::Ref(_, adt_ty @ ty::TyS { kind: ty::Adt(_, _), .. }, _)
-                if !self.type_marked_structural(adt_ty) =>
-            {
-                let adt_def =
-                    if let ty::Adt(adt_def, _) = adt_ty.kind { adt_def } else { unreachable!() };
-
-                debug!(
-                    "adt_def {:?} has !type_marked_structural for adt_ty: {:?}",
-                    adt_def, adt_ty
-                );
-
-                // HACK(estebank): Side-step ICE #53708, but anything other than erroring here
-                // would be wrong. Returnging `PatKind::Wild` is not technically correct.
-                let path = tcx.def_path_str(adt_def.did);
-                let msg = format!(
-                    "to use a constant of type `{}` in a pattern, \
-                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                    path, path,
-                );
-                self.saw_const_match_error.set(true);
-                tcx.sess.span_err(span, &msg);
-                PatKind::Wild
-            }
-            ty::Adt(adt_def, substs) if adt_def.is_enum() => {
-                let variant_index = const_variant_index(tcx, self.param_env, cv);
-                let subpatterns = adt_subpatterns(
-                    adt_def.variants[variant_index].fields.len(),
-                    Some(variant_index),
-                );
-                PatKind::Variant { adt_def, substs, variant_index, subpatterns }
-            }
-            ty::Adt(adt_def, _) => {
-                let struct_var = adt_def.non_enum_variant();
-                PatKind::Leaf { subpatterns: adt_subpatterns(struct_var.fields.len(), None) }
-            }
-            ty::Tuple(fields) => PatKind::Leaf { subpatterns: adt_subpatterns(fields.len(), None) },
-            ty::Array(_, n) => PatKind::Array {
-                prefix: (0..n.eval_usize(tcx, self.param_env))
-                    .map(|i| adt_subpattern(i as usize, None))
-                    .collect(),
-                slice: None,
-                suffix: Vec::new(),
-            },
-            _ => PatKind::Constant { value: cv },
-        };
-
-        Pat { span, ty: cv.ty, kind: Box::new(kind) }
-    }
-}
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
deleted file mode 100644 (file)
index bac40a0..0000000
+++ /dev/null
@@ -1,1050 +0,0 @@
-//! Validation of patterns/matches.
-
-mod _match;
-mod check_match;
-mod const_to_pat;
-
-pub(crate) use self::check_match::check_match;
-
-use crate::hair::constant::*;
-use crate::hair::util::UserAnnotatedTyHelpers;
-
-use rustc::mir::interpret::{get_slice_bytes, sign_extend, ConstValue, ErrorHandled};
-use rustc::mir::UserTypeProjection;
-use rustc::mir::{BorrowKind, Field, Mutability};
-use rustc::ty::layout::VariantIdx;
-use rustc::ty::subst::{GenericArg, SubstsRef};
-use rustc::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
-use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
-use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::pat_util::EnumerateAndAdjustIterator;
-use rustc_hir::RangeEnd;
-use rustc_index::vec::Idx;
-use rustc_span::{Span, DUMMY_SP};
-use syntax::ast;
-
-use std::cmp::Ordering;
-use std::fmt;
-
-use rustc_error_codes::*;
-
-#[derive(Clone, Debug)]
-pub enum PatternError {
-    AssocConstInPattern(Span),
-    StaticInPattern(Span),
-    FloatBug,
-    NonConstPath(Span),
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum BindingMode {
-    ByValue,
-    ByRef(BorrowKind),
-}
-
-#[derive(Clone, Debug)]
-pub struct FieldPat<'tcx> {
-    pub field: Field,
-    pub pattern: Pat<'tcx>,
-}
-
-#[derive(Clone, Debug)]
-pub struct Pat<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub span: Span,
-    pub kind: Box<PatKind<'tcx>>,
-}
-
-impl<'tcx> Pat<'tcx> {
-    pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
-        Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct PatTyProj<'tcx> {
-    pub user_ty: CanonicalUserType<'tcx>,
-}
-
-impl<'tcx> PatTyProj<'tcx> {
-    pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
-        Self { user_ty: user_annotation }
-    }
-
-    pub(crate) fn user_ty(
-        self,
-        annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
-        inferred_ty: Ty<'tcx>,
-        span: Span,
-    ) -> UserTypeProjection {
-        UserTypeProjection {
-            base: annotations.push(CanonicalUserTypeAnnotation {
-                span,
-                user_ty: self.user_ty,
-                inferred_ty,
-            }),
-            projs: Vec::new(),
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct Ascription<'tcx> {
-    pub user_ty: PatTyProj<'tcx>,
-    /// Variance to use when relating the type `user_ty` to the **type of the value being
-    /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
-    /// have a type that is some subtype of the ascribed type.
-    ///
-    /// Note that this variance does not apply for any bindings within subpatterns. The type
-    /// assigned to those bindings must be exactly equal to the `user_ty` given here.
-    ///
-    /// The only place where this field is not `Covariant` is when matching constants, where
-    /// we currently use `Contravariant` -- this is because the constant type just needs to
-    /// be "comparable" to the type of the input value. So, for example:
-    ///
-    /// ```text
-    /// match x { "foo" => .. }
-    /// ```
-    ///
-    /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
-    /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
-    /// of the old type-check for now. See #57280 for details.
-    pub variance: ty::Variance,
-    pub user_ty_span: Span,
-}
-
-#[derive(Clone, Debug)]
-pub enum PatKind<'tcx> {
-    Wild,
-
-    AscribeUserType {
-        ascription: Ascription<'tcx>,
-        subpattern: Pat<'tcx>,
-    },
-
-    /// `x`, `ref x`, `x @ P`, etc.
-    Binding {
-        mutability: Mutability,
-        name: ast::Name,
-        mode: BindingMode,
-        var: hir::HirId,
-        ty: Ty<'tcx>,
-        subpattern: Option<Pat<'tcx>>,
-    },
-
-    /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
-    /// multiple variants.
-    Variant {
-        adt_def: &'tcx AdtDef,
-        substs: SubstsRef<'tcx>,
-        variant_index: VariantIdx,
-        subpatterns: Vec<FieldPat<'tcx>>,
-    },
-
-    /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
-    /// a single variant.
-    Leaf {
-        subpatterns: Vec<FieldPat<'tcx>>,
-    },
-
-    /// `box P`, `&P`, `&mut P`, etc.
-    Deref {
-        subpattern: Pat<'tcx>,
-    },
-
-    Constant {
-        value: &'tcx ty::Const<'tcx>,
-    },
-
-    Range(PatRange<'tcx>),
-
-    /// Matches against a slice, checking the length and extracting elements.
-    /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
-    /// e.g., `&[ref xs @ ..]`.
-    Slice {
-        prefix: Vec<Pat<'tcx>>,
-        slice: Option<Pat<'tcx>>,
-        suffix: Vec<Pat<'tcx>>,
-    },
-
-    /// Fixed match against an array; irrefutable.
-    Array {
-        prefix: Vec<Pat<'tcx>>,
-        slice: Option<Pat<'tcx>>,
-        suffix: Vec<Pat<'tcx>>,
-    },
-
-    /// An or-pattern, e.g. `p | q`.
-    /// Invariant: `pats.len() >= 2`.
-    Or {
-        pats: Vec<Pat<'tcx>>,
-    },
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct PatRange<'tcx> {
-    pub lo: &'tcx ty::Const<'tcx>,
-    pub hi: &'tcx ty::Const<'tcx>,
-    pub end: RangeEnd,
-}
-
-impl<'tcx> fmt::Display for Pat<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Printing lists is a chore.
-        let mut first = true;
-        let mut start_or_continue = |s| {
-            if first {
-                first = false;
-                ""
-            } else {
-                s
-            }
-        };
-        let mut start_or_comma = || start_or_continue(", ");
-
-        match *self.kind {
-            PatKind::Wild => write!(f, "_"),
-            PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
-            PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
-                let is_mut = match mode {
-                    BindingMode::ByValue => mutability == Mutability::Mut,
-                    BindingMode::ByRef(bk) => {
-                        write!(f, "ref ")?;
-                        match bk {
-                            BorrowKind::Mut { .. } => true,
-                            _ => false,
-                        }
-                    }
-                };
-                if is_mut {
-                    write!(f, "mut ")?;
-                }
-                write!(f, "{}", name)?;
-                if let Some(ref subpattern) = *subpattern {
-                    write!(f, " @ {}", subpattern)?;
-                }
-                Ok(())
-            }
-            PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
-                let variant = match *self.kind {
-                    PatKind::Variant { adt_def, variant_index, .. } => {
-                        Some(&adt_def.variants[variant_index])
-                    }
-                    _ => {
-                        if let ty::Adt(adt, _) = self.ty.kind {
-                            if !adt.is_enum() {
-                                Some(&adt.variants[VariantIdx::new(0)])
-                            } else {
-                                None
-                            }
-                        } else {
-                            None
-                        }
-                    }
-                };
-
-                if let Some(variant) = variant {
-                    write!(f, "{}", variant.ident)?;
-
-                    // Only for Adt we can have `S {...}`,
-                    // which we handle separately here.
-                    if variant.ctor_kind == CtorKind::Fictive {
-                        write!(f, " {{ ")?;
-
-                        let mut printed = 0;
-                        for p in subpatterns {
-                            if let PatKind::Wild = *p.pattern.kind {
-                                continue;
-                            }
-                            let name = variant.fields[p.field.index()].ident;
-                            write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
-                            printed += 1;
-                        }
-
-                        if printed < variant.fields.len() {
-                            write!(f, "{}..", start_or_comma())?;
-                        }
-
-                        return write!(f, " }}");
-                    }
-                }
-
-                let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
-                if num_fields != 0 || variant.is_none() {
-                    write!(f, "(")?;
-                    for i in 0..num_fields {
-                        write!(f, "{}", start_or_comma())?;
-
-                        // Common case: the field is where we expect it.
-                        if let Some(p) = subpatterns.get(i) {
-                            if p.field.index() == i {
-                                write!(f, "{}", p.pattern)?;
-                                continue;
-                            }
-                        }
-
-                        // Otherwise, we have to go looking for it.
-                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
-                            write!(f, "{}", p.pattern)?;
-                        } else {
-                            write!(f, "_")?;
-                        }
-                    }
-                    write!(f, ")")?;
-                }
-
-                Ok(())
-            }
-            PatKind::Deref { ref subpattern } => {
-                match self.ty.kind {
-                    ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
-                    ty::Ref(_, _, mutbl) => {
-                        write!(f, "&{}", mutbl.prefix_str())?;
-                    }
-                    _ => bug!("{} is a bad Deref pattern type", self.ty),
-                }
-                write!(f, "{}", subpattern)
-            }
-            PatKind::Constant { value } => write!(f, "{}", value),
-            PatKind::Range(PatRange { lo, hi, end }) => {
-                write!(f, "{}", lo)?;
-                write!(f, "{}", end)?;
-                write!(f, "{}", hi)
-            }
-            PatKind::Slice { ref prefix, ref slice, ref suffix }
-            | PatKind::Array { ref prefix, ref slice, ref suffix } => {
-                write!(f, "[")?;
-                for p in prefix {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                if let Some(ref slice) = *slice {
-                    write!(f, "{}", start_or_comma())?;
-                    match *slice.kind {
-                        PatKind::Wild => {}
-                        _ => write!(f, "{}", slice)?,
-                    }
-                    write!(f, "..")?;
-                }
-                for p in suffix {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                write!(f, "]")
-            }
-            PatKind::Or { ref pats } => {
-                for pat in pats {
-                    write!(f, "{}{}", start_or_continue(" | "), pat)?;
-                }
-                Ok(())
-            }
-        }
-    }
-}
-
-pub struct PatCtxt<'a, 'tcx> {
-    pub tcx: TyCtxt<'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
-    pub tables: &'a ty::TypeckTables<'tcx>,
-    pub substs: SubstsRef<'tcx>,
-    pub errors: Vec<PatternError>,
-    include_lint_checks: bool,
-}
-
-impl<'a, 'tcx> Pat<'tcx> {
-    pub fn from_hir(
-        tcx: TyCtxt<'tcx>,
-        param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>,
-        tables: &'a ty::TypeckTables<'tcx>,
-        pat: &'tcx hir::Pat<'tcx>,
-    ) -> Self {
-        let mut pcx = PatCtxt::new(tcx, param_env_and_substs, tables);
-        let result = pcx.lower_pattern(pat);
-        if !pcx.errors.is_empty() {
-            let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
-            tcx.sess.delay_span_bug(pat.span, &msg);
-        }
-        debug!("Pat::from_hir({:?}) = {:?}", pat, result);
-        result
-    }
-}
-
-impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        param_env_and_substs: ty::ParamEnvAnd<'tcx, SubstsRef<'tcx>>,
-        tables: &'a ty::TypeckTables<'tcx>,
-    ) -> Self {
-        PatCtxt {
-            tcx,
-            param_env: param_env_and_substs.param_env,
-            tables,
-            substs: param_env_and_substs.value,
-            errors: vec![],
-            include_lint_checks: false,
-        }
-    }
-
-    pub fn include_lint_checks(&mut self) -> &mut Self {
-        self.include_lint_checks = true;
-        self
-    }
-
-    pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
-        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
-        // pattern has the type that results *after* dereferencing. For example, in this code:
-        //
-        // ```
-        // match &&Some(0i32) {
-        //     Some(n) => { ... },
-        //     _ => { ... },
-        // }
-        // ```
-        //
-        // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
-        // determined in rustc_typeck::check::match). The adjustments would be
-        //
-        // `vec![&&Option<i32>, &Option<i32>]`.
-        //
-        // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
-        // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
-        // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
-        // gets the least-dereferenced type).
-        let unadjusted_pat = self.lower_pattern_unadjusted(pat);
-        self.tables.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);
-                Pat {
-                    span: pat.span,
-                    ty: ref_ty,
-                    kind: Box::new(PatKind::Deref { subpattern: pat }),
-                }
-            },
-        )
-    }
-
-    fn lower_range_expr(
-        &mut self,
-        expr: &'tcx hir::Expr<'tcx>,
-    ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) {
-        match self.lower_lit(expr) {
-            PatKind::AscribeUserType {
-                ascription: lo_ascription,
-                subpattern: Pat { kind: box kind, .. },
-            } => (kind, Some(lo_ascription)),
-            kind => (kind, None),
-        }
-    }
-
-    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
-        let mut ty = self.tables.node_type(pat.hir_id);
-
-        if let ty::Error = ty.kind {
-            // Avoid ICEs (e.g., #50577 and #50585).
-            return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
-        }
-
-        let kind = match pat.kind {
-            hir::PatKind::Wild => PatKind::Wild,
-
-            hir::PatKind::Lit(ref value) => self.lower_lit(value),
-
-            hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
-                let (lo, lo_ascription) = self.lower_range_expr(lo_expr);
-                let (hi, hi_ascription) = self.lower_range_expr(hi_expr);
-
-                let mut kind = match (lo, hi) {
-                    (PatKind::Constant { value: lo }, PatKind::Constant { value: hi }) => {
-                        assert_eq!(lo.ty, ty);
-                        assert_eq!(hi.ty, ty);
-                        let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
-                        match (end, cmp) {
-                            (RangeEnd::Excluded, Some(Ordering::Less)) => {
-                                PatKind::Range(PatRange { lo, hi, end })
-                            }
-                            (RangeEnd::Excluded, _) => {
-                                span_err!(
-                                    self.tcx.sess,
-                                    lo_expr.span,
-                                    E0579,
-                                    "lower range bound must be less than upper",
-                                );
-                                PatKind::Wild
-                            }
-                            (RangeEnd::Included, Some(Ordering::Equal)) => {
-                                PatKind::Constant { value: lo }
-                            }
-                            (RangeEnd::Included, Some(Ordering::Less)) => {
-                                PatKind::Range(PatRange { lo, hi, end })
-                            }
-                            (RangeEnd::Included, _) => {
-                                let mut err = struct_span_err!(
-                                    self.tcx.sess,
-                                    lo_expr.span,
-                                    E0030,
-                                    "lower range bound must be less than or equal to upper"
-                                );
-                                err.span_label(lo_expr.span, "lower bound larger than upper bound");
-                                if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                                    err.note(
-                                        "When matching against a range, the compiler \
-                                              verifies that the range is non-empty. Range \
-                                              patterns include both end-points, so this is \
-                                              equivalent to requiring the start of the range \
-                                              to be less than or equal to the end of the range.",
-                                    );
-                                }
-                                err.emit();
-                                PatKind::Wild
-                            }
-                        }
-                    }
-                    ref pats => {
-                        self.tcx.sess.delay_span_bug(
-                            pat.span,
-                            &format!(
-                                "found bad range pattern `{:?}` outside of error recovery",
-                                pats,
-                            ),
-                        );
-
-                        PatKind::Wild
-                    }
-                };
-
-                // If we are handling a range with associated constants (e.g.
-                // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
-                // constants somewhere. Have them on the range pattern.
-                for ascription in &[lo_ascription, hi_ascription] {
-                    if let Some(ascription) = ascription {
-                        kind = PatKind::AscribeUserType {
-                            ascription: *ascription,
-                            subpattern: Pat { span: pat.span, ty, kind: Box::new(kind) },
-                        };
-                    }
-                }
-
-                kind
-            }
-
-            hir::PatKind::Path(ref qpath) => {
-                return self.lower_path(qpath, pat.hir_id, pat.span);
-            }
-
-            hir::PatKind::Ref(ref subpattern, _) | hir::PatKind::Box(ref subpattern) => {
-                PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
-            }
-
-            hir::PatKind::Slice(ref prefix, ref slice, ref suffix) => {
-                self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
-            }
-
-            hir::PatKind::Tuple(ref pats, ddpos) => {
-                let tys = match ty.kind {
-                    ty::Tuple(ref tys) => tys,
-                    _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty),
-                };
-                let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos);
-                PatKind::Leaf { subpatterns }
-            }
-
-            hir::PatKind::Binding(_, id, ident, ref sub) => {
-                let bm =
-                    *self.tables.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) => (
-                        Mutability::Not,
-                        BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }),
-                    ),
-                    ty::BindByReference(hir::Mutability::Not) => {
-                        (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared))
-                    }
-                };
-
-                // A ref x pattern is the same node used for x, and as such it has
-                // x's type, which is &T, where we want T (the type being matched).
-                let var_ty = ty;
-                if let ty::BindByReference(_) = bm {
-                    if let ty::Ref(_, rty, _) = ty.kind {
-                        ty = rty;
-                    } else {
-                        bug!("`ref {}` has wrong type {}", ident, ty);
-                    }
-                };
-
-                PatKind::Binding {
-                    mutability,
-                    mode,
-                    name: ident.name,
-                    var: id,
-                    ty: var_ty,
-                    subpattern: self.lower_opt_pattern(sub),
-                }
-            }
-
-            hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => {
-                let res = self.tables.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),
-                };
-                let variant_def = adt_def.variant_of_res(res);
-                let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
-                self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
-            }
-
-            hir::PatKind::Struct(ref qpath, ref fields, _) => {
-                let res = self.tables.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)),
-                        pattern: self.lower_pattern(&field.pat),
-                    })
-                    .collect();
-
-                self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
-            }
-
-            hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
-        };
-
-        Pat { span: pat.span, ty, kind: Box::new(kind) }
-    }
-
-    fn lower_tuple_subpats(
-        &mut self,
-        pats: &'tcx [&'tcx hir::Pat<'tcx>],
-        expected_len: usize,
-        gap_pos: Option<usize>,
-    ) -> Vec<FieldPat<'tcx>> {
-        pats.iter()
-            .enumerate_and_adjust(expected_len, gap_pos)
-            .map(|(i, subpattern)| FieldPat {
-                field: Field::new(i),
-                pattern: self.lower_pattern(subpattern),
-            })
-            .collect()
-    }
-
-    fn lower_patterns(&mut self, pats: &'tcx [&'tcx hir::Pat<'tcx>]) -> Vec<Pat<'tcx>> {
-        pats.iter().map(|p| self.lower_pattern(p)).collect()
-    }
-
-    fn lower_opt_pattern(&mut self, pat: &'tcx Option<&'tcx hir::Pat<'tcx>>) -> Option<Pat<'tcx>> {
-        pat.as_ref().map(|p| self.lower_pattern(p))
-    }
-
-    fn slice_or_array_pattern(
-        &mut self,
-        span: Span,
-        ty: Ty<'tcx>,
-        prefix: &'tcx [&'tcx hir::Pat<'tcx>],
-        slice: &'tcx Option<&'tcx hir::Pat<'tcx>>,
-        suffix: &'tcx [&'tcx hir::Pat<'tcx>],
-    ) -> PatKind<'tcx> {
-        let prefix = self.lower_patterns(prefix);
-        let slice = self.lower_opt_pattern(slice);
-        let suffix = self.lower_patterns(suffix);
-        match ty.kind {
-            // Matching a slice, `[T]`.
-            ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
-            // Fixed-length array, `[T; len]`.
-            ty::Array(_, len) => {
-                let len = len.eval_usize(self.tcx, self.param_env);
-                assert!(len >= prefix.len() as u64 + suffix.len() as u64);
-                PatKind::Array { prefix, slice, suffix }
-            }
-            _ => span_bug!(span, "bad slice pattern type {:?}", ty),
-        }
-    }
-
-    fn lower_variant_or_leaf(
-        &mut self,
-        res: Res,
-        hir_id: hir::HirId,
-        span: Span,
-        ty: Ty<'tcx>,
-        subpatterns: Vec<FieldPat<'tcx>>,
-    ) -> PatKind<'tcx> {
-        let res = match res {
-            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
-                let variant_id = self.tcx.parent(variant_ctor_id).unwrap();
-                Res::Def(DefKind::Variant, variant_id)
-            }
-            res => res,
-        };
-
-        let mut kind = match res {
-            Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
-                let adt_def = self.tcx.adt_def(enum_id);
-                if adt_def.is_enum() {
-                    let substs = match ty.kind {
-                        ty::Adt(_, substs) | ty::FnDef(_, substs) => substs,
-                        ty::Error => {
-                            // Avoid ICE (#50585)
-                            return PatKind::Wild;
-                        }
-                        _ => bug!("inappropriate type for def: {:?}", ty),
-                    };
-                    PatKind::Variant {
-                        adt_def,
-                        substs,
-                        variant_index: adt_def.variant_index_with_id(variant_id),
-                        subpatterns,
-                    }
-                } else {
-                    PatKind::Leaf { subpatterns }
-                }
-            }
-
-            Res::Def(DefKind::Struct, _)
-            | Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
-            | Res::Def(DefKind::Union, _)
-            | Res::Def(DefKind::TyAlias, _)
-            | Res::Def(DefKind::AssocTy, _)
-            | Res::SelfTy(..)
-            | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
-
-            _ => {
-                self.errors.push(PatternError::NonConstPath(span));
-                PatKind::Wild
-            }
-        };
-
-        if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
-            debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
-            kind = PatKind::AscribeUserType {
-                subpattern: Pat { span, ty, kind: Box::new(kind) },
-                ascription: Ascription {
-                    user_ty: PatTyProj::from_user_type(user_ty),
-                    user_ty_span: span,
-                    variance: ty::Variance::Covariant,
-                },
-            };
-        }
-
-        kind
-    }
-
-    /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
-    /// 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 is_associated_const = match res {
-            Res::Def(DefKind::AssocConst, _) => true,
-            _ => false,
-        };
-        let kind = match res {
-            Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
-                let substs = self.tables.node_substs(id);
-                // Use `Reveal::All` here because patterns are always monomorphic even if their function isn't.
-                match self.tcx.const_eval_resolve(
-                    self.param_env.with_reveal_all(),
-                    def_id,
-                    substs,
-                    Some(span),
-                ) {
-                    Ok(value) => {
-                        let pattern = self.const_to_pat(value, id, span);
-                        if !is_associated_const {
-                            return pattern;
-                        }
-
-                        let user_provided_types = self.tables().user_provided_types();
-                        return if let Some(u_ty) = user_provided_types.get(id) {
-                            let user_ty = PatTyProj::from_user_type(*u_ty);
-                            Pat {
-                                span,
-                                kind: Box::new(PatKind::AscribeUserType {
-                                    subpattern: pattern,
-                                    ascription: Ascription {
-                                        /// Note that use `Contravariant` here. See the
-                                        /// `variance` field documentation for details.
-                                        variance: ty::Variance::Contravariant,
-                                        user_ty,
-                                        user_ty_span: span,
-                                    },
-                                }),
-                                ty: value.ty,
-                            }
-                        } else {
-                            pattern
-                        };
-                    }
-                    Err(ErrorHandled::TooGeneric) => {
-                        self.errors.push(if is_associated_const {
-                            PatternError::AssocConstInPattern(span)
-                        } else {
-                            PatternError::StaticInPattern(span)
-                        });
-                        PatKind::Wild
-                    }
-                    Err(_) => {
-                        self.tcx.sess.span_err(span, "could not evaluate constant pattern");
-                        PatKind::Wild
-                    }
-                }
-            }
-            _ => self.lower_variant_or_leaf(res, id, span, ty, vec![]),
-        };
-
-        Pat { span, ty, kind: Box::new(kind) }
-    }
-
-    /// Converts literals, paths and negation of literals to patterns.
-    /// The special case for negation exists to allow things like `-128_i8`
-    /// which would overflow if we tried to evaluate `128_i8` and then negate
-    /// afterwards.
-    fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
-        match expr.kind {
-            hir::ExprKind::Lit(ref lit) => {
-                let ty = self.tables.expr_ty(expr);
-                match lit_to_const(&lit.node, self.tcx, ty, false) {
-                    Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
-                    Err(LitToConstError::UnparseableFloat) => {
-                        self.errors.push(PatternError::FloatBug);
-                        PatKind::Wild
-                    }
-                    Err(LitToConstError::Reported) => PatKind::Wild,
-                }
-            }
-            hir::ExprKind::Path(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
-            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
-                let ty = self.tables.expr_ty(expr);
-                let lit = match expr.kind {
-                    hir::ExprKind::Lit(ref lit) => lit,
-                    _ => span_bug!(expr.span, "not a literal: {:?}", expr),
-                };
-                match lit_to_const(&lit.node, self.tcx, ty, true) {
-                    Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
-                    Err(LitToConstError::UnparseableFloat) => {
-                        self.errors.push(PatternError::FloatBug);
-                        PatKind::Wild
-                    }
-                    Err(LitToConstError::Reported) => PatKind::Wild,
-                }
-            }
-            _ => span_bug!(expr.span, "not a literal: {:?}", expr),
-        }
-    }
-}
-
-impl UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn tables(&self) -> &ty::TypeckTables<'tcx> {
-        self.tables
-    }
-}
-
-pub trait PatternFoldable<'tcx>: Sized {
-    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.super_fold_with(folder)
-    }
-
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
-}
-
-pub trait PatternFolder<'tcx>: Sized {
-    fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> {
-        pattern.super_fold_with(self)
-    }
-
-    fn fold_pattern_kind(&mut self, kind: &PatKind<'tcx>) -> PatKind<'tcx> {
-        kind.super_fold_with(self)
-    }
-}
-
-impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let content: T = (**self).fold_with(folder);
-        box content
-    }
-}
-
-impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.iter().map(|t| t.fold_with(folder)).collect()
-    }
-}
-
-impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        self.as_ref().map(|t| t.fold_with(folder))
-    }
-}
-
-macro_rules! CloneImpls {
-    (<$lt_tcx:tt> $($ty:ty),+) => {
-        $(
-            impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
-                fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
-                    Clone::clone(self)
-                }
-            }
-        )+
-    }
-}
-
-CloneImpls! { <'tcx>
-    Span, Field, Mutability, ast::Name, hir::HirId, usize, ty::Const<'tcx>,
-    Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef,
-    SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
-    UserTypeProjection, PatTyProj<'tcx>
-}
-
-impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> {
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) }
-    }
-}
-
-impl<'tcx> PatternFoldable<'tcx> for Pat<'tcx> {
-    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_pattern(self)
-    }
-
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        Pat {
-            ty: self.ty.fold_with(folder),
-            span: self.span.fold_with(folder),
-            kind: self.kind.fold_with(folder),
-        }
-    }
-}
-
-impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
-    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        folder.fold_pattern_kind(self)
-    }
-
-    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        match *self {
-            PatKind::Wild => PatKind::Wild,
-            PatKind::AscribeUserType {
-                ref subpattern,
-                ascription: Ascription { variance, ref user_ty, user_ty_span },
-            } => PatKind::AscribeUserType {
-                subpattern: subpattern.fold_with(folder),
-                ascription: Ascription {
-                    user_ty: user_ty.fold_with(folder),
-                    variance,
-                    user_ty_span,
-                },
-            },
-            PatKind::Binding { mutability, name, mode, var, ty, ref subpattern } => {
-                PatKind::Binding {
-                    mutability: mutability.fold_with(folder),
-                    name: name.fold_with(folder),
-                    mode: mode.fold_with(folder),
-                    var: var.fold_with(folder),
-                    ty: ty.fold_with(folder),
-                    subpattern: subpattern.fold_with(folder),
-                }
-            }
-            PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
-                PatKind::Variant {
-                    adt_def: adt_def.fold_with(folder),
-                    substs: substs.fold_with(folder),
-                    variant_index,
-                    subpatterns: subpatterns.fold_with(folder),
-                }
-            }
-            PatKind::Leaf { ref subpatterns } => {
-                PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) }
-            }
-            PatKind::Deref { ref subpattern } => {
-                PatKind::Deref { subpattern: subpattern.fold_with(folder) }
-            }
-            PatKind::Constant { value } => PatKind::Constant { value },
-            PatKind::Range(range) => PatKind::Range(range),
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
-                prefix: prefix.fold_with(folder),
-                slice: slice.fold_with(folder),
-                suffix: suffix.fold_with(folder),
-            },
-            PatKind::Array { ref prefix, ref slice, ref suffix } => PatKind::Array {
-                prefix: prefix.fold_with(folder),
-                slice: slice.fold_with(folder),
-                suffix: suffix.fold_with(folder),
-            },
-            PatKind::Or { ref pats } => PatKind::Or { pats: pats.fold_with(folder) },
-        }
-    }
-}
-
-pub fn compare_const_vals<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    a: &'tcx ty::Const<'tcx>,
-    b: &'tcx ty::Const<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<Ordering> {
-    trace!("compare_const_vals: {:?}, {:?}", a, b);
-
-    let from_bool = |v: bool| v.then_some(Ordering::Equal);
-
-    let fallback = || from_bool(a == b);
-
-    // Use the fallback if any type differs
-    if a.ty != b.ty || a.ty != ty {
-        return fallback();
-    }
-
-    // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
-    // are just integer addresses).
-    if a.val == b.val {
-        return from_bool(true);
-    }
-
-    let a_bits = a.try_eval_bits(tcx, param_env, ty);
-    let b_bits = b.try_eval_bits(tcx, param_env, ty);
-
-    if let (Some(a), Some(b)) = (a_bits, b_bits) {
-        use ::rustc_apfloat::Float;
-        return match ty.kind {
-            ty::Float(ast::FloatTy::F32) => {
-                let l = ::rustc_apfloat::ieee::Single::from_bits(a);
-                let r = ::rustc_apfloat::ieee::Single::from_bits(b);
-                l.partial_cmp(&r)
-            }
-            ty::Float(ast::FloatTy::F64) => {
-                let l = ::rustc_apfloat::ieee::Double::from_bits(a);
-                let r = ::rustc_apfloat::ieee::Double::from_bits(b);
-                l.partial_cmp(&r)
-            }
-            ty::Int(ity) => {
-                use rustc::ty::layout::{Integer, IntegerExt};
-                use syntax::attr::SignedInt;
-                let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
-                let a = sign_extend(a, size);
-                let b = sign_extend(b, size);
-                Some((a as i128).cmp(&(b as i128)))
-            }
-            _ => Some(a.cmp(&b)),
-        };
-    }
-
-    if let ty::Str = ty.kind {
-        match (a.val, b.val) {
-            (
-                ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }),
-                ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }),
-            ) => {
-                let a_bytes = get_slice_bytes(&tcx, a_val);
-                let b_bytes = get_slice_bytes(&tcx, b_val);
-                return from_bool(a_bytes == b_bytes);
-            }
-            _ => (),
-        }
-    }
-
-    fallback()
-}
diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs
deleted file mode 100644 (file)
index c27844e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-use rustc::ty::{self, CanonicalUserType, TyCtxt, UserType};
-use rustc_hir as hir;
-
-crate trait UserAnnotatedTyHelpers<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx>;
-
-    fn tables(&self) -> &ty::TypeckTables<'tcx>;
-
-    /// Looks up the type associated with this hir-id and applies the
-    /// user-given substitutions; the hir-id must map to a suitable
-    /// type.
-    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 mut user_ty = *user_provided_types.get(hir_id)?;
-        debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty);
-        let ty = self.tables().node_type(hir_id);
-        match ty.kind {
-            ty::Adt(adt_def, ..) => {
-                if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value {
-                    *did = adt_def.did;
-                }
-                Some(user_ty)
-            }
-            ty::FnDef(..) => Some(user_ty),
-            _ => bug!("ty: {:?} should not have user provided type {:?} recorded ", ty, user_ty),
-        }
-    }
-}
index 551e3e837c988bf3c4c1cc0eb10a28a2d714535c..206d3d156735ec758b952e3dc5df5f06e5322511 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_span::source_map::{self, Span, DUMMY_SP};
 
 use super::{
-    Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy,
+    Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
     ScalarMaybeUndef, StackPopInfo,
 };
 
@@ -393,7 +393,7 @@ pub fn layout_of_local(
     /// This can fail to provide an answer for extern types.
     pub(super) fn size_and_align_of(
         &self,
-        metadata: Option<Scalar<M::PointerTag>>,
+        metadata: MemPlaceMeta<M::PointerTag>,
         layout: TyLayout<'tcx>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
         if !layout.is_unsized() {
@@ -465,14 +465,13 @@ pub(super) fn size_and_align_of(
                 Ok(Some((size, align)))
             }
             ty::Dynamic(..) => {
-                let vtable = metadata.expect("dyn trait fat ptr must have vtable");
+                let vtable = metadata.unwrap_meta();
                 // Read size and align from vtable (already checks size).
                 Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
             }
 
             ty::Slice(_) | ty::Str => {
-                let len =
-                    metadata.expect("slice fat ptr must have length").to_machine_usize(self)?;
+                let len = metadata.unwrap_meta().to_machine_usize(self)?;
                 let elem = layout.field(self, 0)?;
 
                 // Make sure the slice is not too big.
@@ -758,13 +757,22 @@ pub(super) fn const_eval(
         &self,
         gid: GlobalId<'tcx>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        let val = if self.tcx.is_static(gid.instance.def_id()) {
-            self.tcx.const_eval_poly(gid.instance.def_id())?
-        } else if let Some(promoted) = gid.promoted {
-            self.tcx.const_eval_promoted(gid.instance, promoted)?
+        // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
+        // and thus don't care about the parameter environment. While we could just use
+        // `self.param_env`, that would mean we invoke the query to evaluate the static
+        // with different parameter environments, thus causing the static to be evaluated
+        // multiple times.
+        let param_env = if self.tcx.is_static(gid.instance.def_id()) {
+            ty::ParamEnv::reveal_all()
         } else {
-            self.tcx.const_eval_instance(self.param_env, gid.instance, Some(self.tcx.span))?
+            self.param_env
         };
+        let val = if let Some(promoted) = gid.promoted {
+            self.tcx.const_eval_promoted(param_env, gid.instance, promoted)?
+        } else {
+            self.tcx.const_eval_instance(param_env, gid.instance, Some(self.tcx.span))?
+        };
+
         // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a
         // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not
         // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call
@@ -818,8 +826,8 @@ pub fn dump_place(&self, place: Place<M::PointerTag>) {
                                 " by align({}){} ref:",
                                 mplace.align.bytes(),
                                 match mplace.meta {
-                                    Some(meta) => format!(" meta({:?})", meta),
-                                    None => String::new(),
+                                    MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
+                                    MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
                                 }
                             )
                             .unwrap();
index 7c6129ef30ffd92503af84b97cb04de06be5c072..220761ce28d81db842b5bbb6dacc798d422c14e1 100644 (file)
@@ -41,6 +41,11 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
     /// despite the nested mutable reference!
     /// The field gets updated when an `UnsafeCell` is encountered.
     mutability: Mutability,
+
+    /// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants
+    /// for promoteds.
+    /// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field
+    ignore_interior_mut_in_const_validation: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
@@ -164,14 +169,16 @@ fn visit_aggregate(
                 // References we encounter inside here are interned as pointing to mutable
                 // allocations.
                 let old = std::mem::replace(&mut self.mutability, Mutability::Mut);
-                assert_ne!(
-                    self.mode,
-                    InternMode::Const,
-                    "UnsafeCells are not allowed behind references in constants. This should have \
-                    been prevented statically by const qualification. If this were allowed one \
-                    would be able to change a constant at one use site and other use sites could \
-                    observe that mutation.",
-                );
+                if !self.ignore_interior_mut_in_const_validation {
+                    assert_ne!(
+                        self.mode,
+                        InternMode::Const,
+                        "UnsafeCells are not allowed behind references in constants. This should \
+                        have been prevented statically by const qualification. If this were \
+                        allowed one would be able to change a constant at one use site and other \
+                        use sites could observe that mutation.",
+                    );
+                }
                 let walked = self.walk_aggregate(mplace, fields);
                 self.mutability = old;
                 return walked;
@@ -193,7 +200,7 @@ fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
             {
                 // Validation has already errored on an invalid vtable pointer so we can safely not
                 // do anything if this is not a real pointer.
-                if let Scalar::Ptr(vtable) = mplace.meta.unwrap() {
+                if let Scalar::Ptr(vtable) = mplace.meta.unwrap_meta() {
                     // Explicitly choose `Immutable` here, since vtables are immutable, even
                     // if the reference of the fat pointer is mutable.
                     self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?;
@@ -226,7 +233,8 @@ fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
                     | (InternMode::Const, hir::Mutability::Mut) => match referenced_ty.kind {
                         ty::Array(_, n)
                             if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {}
-                        ty::Slice(_) if mplace.meta.unwrap().to_machine_usize(self.ecx)? == 0 => {}
+                        ty::Slice(_)
+                            if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? == 0 => {}
                         _ => bug!("const qualif failed to prevent mutable references"),
                     },
                 }
@@ -265,6 +273,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
     // The `mutability` of the place, ignoring the type.
     place_mut: Option<hir::Mutability>,
     ret: MPlaceTy<'tcx>,
+    ignore_interior_mut_in_const_validation: bool,
 ) -> InterpResult<'tcx> {
     let tcx = ecx.tcx;
     let (base_mutability, base_intern_mode) = match place_mut {
@@ -301,6 +310,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
             mode,
             leftover_allocations,
             mutability,
+            ignore_interior_mut_in_const_validation,
         }
         .visit_value(mplace);
         if let Err(error) = interned {
index 6d15827536c556cb2911977a30dbcd075ba817b1..3309e9b9b622ae8d33360cd831dcfeef82191dbe 100644 (file)
@@ -212,7 +212,7 @@ fn access_local(
         frame.locals[local].access()
     }
 
-    /// Called before a `StaticKind::Static` value is accessed.
+    /// Called before a `Static` value is accessed.
     fn before_access_static(
         _memory_extra: &Self::MemoryExtra,
         _allocation: &Allocation,
index 0d35eae6ed08da45375bf1fcdbc2e58255b0f891..2e8fbb95ca2e58d143982323811de6817f27d678 100644 (file)
@@ -20,7 +20,7 @@
 
 pub use self::eval_context::{Frame, InterpCx, LocalState, LocalValue, StackPopCleanup};
 
-pub use self::place::{MPlaceTy, MemPlace, Place, PlaceTy};
+pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
 
 pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind};
 
index def979b63b52a5206ba3706ef5738f4102a08c05..b37eff3f40626a44691236aebd04761982d09822 100644 (file)
@@ -153,30 +153,6 @@ pub enum Operand<Tag = (), Id = AllocId> {
     Indirect(MemPlace<Tag, Id>),
 }
 
-impl<Tag> Operand<Tag> {
-    #[inline]
-    pub fn assert_mem_place(self) -> MemPlace<Tag>
-    where
-        Tag: ::std::fmt::Debug,
-    {
-        match self {
-            Operand::Indirect(mplace) => mplace,
-            _ => bug!("assert_mem_place: expected Operand::Indirect, got {:?}", self),
-        }
-    }
-
-    #[inline]
-    pub fn assert_immediate(self) -> Immediate<Tag>
-    where
-        Tag: ::std::fmt::Debug,
-    {
-        match self {
-            Operand::Immediate(imm) => imm,
-            _ => bug!("assert_immediate: expected Operand::Immediate, got {:?}", self),
-        }
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct OpTy<'tcx, Tag = ()> {
     op: Operand<Tag>, // Keep this private; it helps enforce invariants.
@@ -267,7 +243,7 @@ pub fn force_op_ptr(
         &self,
         op: OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        match op.try_as_mplace() {
+        match op.try_as_mplace(self) {
             Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
             Err(imm) => Ok(imm.into()), // Nothing to cast/force
         }
@@ -335,7 +311,7 @@ pub(crate) fn try_read_immediate(
         &self,
         src: OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
-        Ok(match src.try_as_mplace() {
+        Ok(match src.try_as_mplace(self) {
             Ok(mplace) => {
                 if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
                     Ok(val)
@@ -383,7 +359,7 @@ pub fn operand_field(
         op: OpTy<'tcx, M::PointerTag>,
         field: u64,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        let base = match op.try_as_mplace() {
+        let base = match op.try_as_mplace(self) {
             Ok(mplace) => {
                 // The easy case
                 let field = self.mplace_field(mplace, field)?;
@@ -420,7 +396,7 @@ pub fn operand_downcast(
         variant: VariantIdx,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
-        Ok(match op.try_as_mplace() {
+        Ok(match op.try_as_mplace(self) {
             Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(),
             Err(..) => {
                 let layout = op.layout.for_variant(self, variant);
@@ -439,30 +415,10 @@ pub fn operand_projection(
             Field(field, _) => self.operand_field(base, field.index() as u64)?,
             Downcast(_, variant) => self.operand_downcast(base, variant)?,
             Deref => self.deref_operand(base)?.into(),
-            ConstantIndex { .. } | Index(_) if base.layout.is_zst() => {
-                OpTy {
-                    op: Operand::Immediate(Scalar::zst().into()),
-                    // the actual index doesn't matter, so we just pick a convenient one like 0
-                    layout: base.layout.field(self, 0)?,
-                }
-            }
-            Subslice { from, to, from_end } if base.layout.is_zst() => {
-                let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind {
-                    elem_ty
-                } else {
-                    bug!("slices shouldn't be zero-sized");
-                };
-                assert!(!from_end, "arrays shouldn't be subsliced from the end");
-
-                OpTy {
-                    op: Operand::Immediate(Scalar::zst().into()),
-                    layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?,
-                }
-            }
             Subslice { .. } | ConstantIndex { .. } | Index(_) => {
                 // The rest should only occur as mplace, we do not use Immediates for types
                 // allowing such operations.  This matches place_projection forcing an allocation.
-                let mplace = base.assert_mem_place();
+                let mplace = base.assert_mem_place(self);
                 self.mplace_projection(mplace, proj_elem)?.into()
             }
         })
@@ -506,19 +462,15 @@ pub fn eval_place_to_op(
         place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        use rustc::mir::PlaceBase;
-
-        let base_op = match &place.base {
-            PlaceBase::Local(mir::RETURN_PLACE) => throw_unsup!(ReadFromReturnPointer),
-            PlaceBase::Local(local) => {
+        let base_op = match place.local {
+            mir::RETURN_PLACE => throw_unsup!(ReadFromReturnPointer),
+            local => {
                 // Do not use the layout passed in as argument if the base we are looking at
                 // here is not the entire place.
-                // FIXME use place_projection.is_empty() when is available
                 let layout = if place.projection.is_empty() { layout } else { None };
 
-                self.access_local(self.frame(), *local, layout)?
+                self.access_local(self.frame(), local, layout)?
             }
-            PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
         };
 
         let op = place
@@ -576,7 +528,7 @@ pub(super) fn eval_operands(
         // Early-return cases.
         let val_val = match val.val {
             ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
-            ty::ConstKind::Unevaluated(def_id, substs) => {
+            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
                 let instance = self.resolve(def_id, 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
@@ -584,9 +536,7 @@ pub(super) fn eval_operands(
                 // potentially requiring the current static to be evaluated again. This is not a
                 // problem here, because we are building an operand which means an actual read is
                 // happening.
-                // FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of
-                // `StaticKind` once and for all.
-                return self.const_eval(GlobalId { instance, promoted: None });
+                return Ok(OpTy::from(self.const_eval(GlobalId { instance, promoted })?));
             }
             ty::ConstKind::Infer(..)
             | ty::ConstKind::Bound(..)
index f4ac7de852af00dff61823b7642d02888e421036..8888e3fd4632a2a3e1549dea0f646c29e537257f 100644 (file)
 use rustc::ty::layout::{
     self, Align, HasDataLayout, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx,
 };
-use rustc::ty::TypeFoldable;
 use rustc::ty::{self, Ty};
 use rustc_macros::HashStable;
 
 use super::{
-    AllocId, AllocMap, Allocation, AllocationExtra, GlobalId, ImmTy, Immediate, InterpCx,
-    InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, PointerArithmetic,
-    RawConst, Scalar, ScalarMaybeUndef,
+    AllocId, AllocMap, Allocation, AllocationExtra, ImmTy, Immediate, InterpCx, InterpResult,
+    LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, PointerArithmetic, RawConst, Scalar,
+    ScalarMaybeUndef,
 };
 
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
+/// Information required for the sound usage of a `MemPlace`.
+pub enum MemPlaceMeta<Tag = (), Id = AllocId> {
+    /// The unsized payload (e.g. length for slices or vtable pointer for trait objects).
+    Meta(Scalar<Tag, Id>),
+    /// `Sized` types or unsized `extern type`
+    None,
+    /// The address of this place may not be taken. This protects the `MemPlace` from coming from
+    /// a ZST Operand with a backing allocation and being converted to an integer address. This
+    /// should be impossible, because you can't take the address of an operand, but this is a second
+    /// protection layer ensuring that we don't mess up.
+    Poison,
+}
+
+impl<Tag, Id> MemPlaceMeta<Tag, Id> {
+    pub fn unwrap_meta(self) -> Scalar<Tag, Id> {
+        match self {
+            Self::Meta(s) => s,
+            Self::None | Self::Poison => {
+                bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)")
+            }
+        }
+    }
+    fn has_meta(self) -> bool {
+        match self {
+            Self::Meta(_) => true,
+            Self::None | Self::Poison => false,
+        }
+    }
+}
+
+impl<Tag> MemPlaceMeta<Tag> {
+    pub fn erase_tag(self) -> MemPlaceMeta<()> {
+        match self {
+            Self::Meta(s) => MemPlaceMeta::Meta(s.erase_tag()),
+            Self::None => MemPlaceMeta::None,
+            Self::Poison => MemPlaceMeta::Poison,
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
 pub struct MemPlace<Tag = (), Id = AllocId> {
     /// A place may have an integral pointer for ZSTs, and since it might
@@ -30,7 +70,7 @@ pub struct MemPlace<Tag = (), Id = AllocId> {
     /// Metadata for unsized places. Interpretation is up to the type.
     /// Must not be present for sized types, but can be missing for unsized types
     /// (e.g., `extern type`).
-    pub meta: Option<Scalar<Tag, Id>>,
+    pub meta: MemPlaceMeta<Tag, Id>,
 }
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
@@ -88,21 +128,17 @@ pub fn replace_tag(self, new_tag: Tag) -> Self {
 
     #[inline]
     pub fn erase_tag(self) -> MemPlace {
-        MemPlace {
-            ptr: self.ptr.erase_tag(),
-            align: self.align,
-            meta: self.meta.map(Scalar::erase_tag),
-        }
+        MemPlace { ptr: self.ptr.erase_tag(), align: self.align, meta: self.meta.erase_tag() }
     }
 
     #[inline(always)]
-    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
-        MemPlace { ptr, align, meta: None }
+    fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
+        MemPlace { ptr, align, meta: MemPlaceMeta::None }
     }
 
     /// Produces a Place that will error if attempted to be read from or written to
     #[inline(always)]
-    pub fn null(cx: &impl HasDataLayout) -> Self {
+    fn null(cx: &impl HasDataLayout) -> Self {
         Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1).unwrap())
     }
 
@@ -116,15 +152,19 @@ pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
     #[inline(always)]
     pub fn to_ref(self) -> Immediate<Tag> {
         match self.meta {
-            None => Immediate::Scalar(self.ptr.into()),
-            Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
+            MemPlaceMeta::None => Immediate::Scalar(self.ptr.into()),
+            MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
+            MemPlaceMeta::Poison => bug!(
+                "MPlaceTy::dangling may never be used to produce a \
+                place that will have the address of its pointee taken"
+            ),
         }
     }
 
     pub fn offset(
         self,
         offset: Size,
-        meta: Option<Scalar<Tag>>,
+        meta: MemPlaceMeta<Tag>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
         Ok(MemPlace {
@@ -139,13 +179,10 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
     /// Produces a MemPlace that works for ZST but nothing else
     #[inline]
     pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
-        MPlaceTy {
-            mplace: MemPlace::from_scalar_ptr(
-                Scalar::from_uint(layout.align.abi.bytes(), cx.pointer_size()),
-                layout.align.abi,
-            ),
-            layout,
-        }
+        let align = layout.align.abi;
+        let ptr = Scalar::from_uint(align.bytes(), cx.pointer_size());
+        // `Poison` this to make sure that the pointer value `ptr` is never observable by the program.
+        MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout }
     }
 
     /// Replace ptr tag, maintain vtable tag (if any)
@@ -158,7 +195,7 @@ pub fn replace_tag(self, new_tag: Tag) -> Self {
     pub fn offset(
         self,
         offset: Size,
-        meta: Option<Scalar<Tag>>,
+        meta: MemPlaceMeta<Tag>,
         layout: TyLayout<'tcx>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
@@ -175,7 +212,9 @@ pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
             // We need to consult `meta` metadata
             match self.layout.ty.kind {
-                ty::Slice(..) | ty::Str => return self.mplace.meta.unwrap().to_machine_usize(cx),
+                ty::Slice(..) | ty::Str => {
+                    return self.mplace.meta.unwrap_meta().to_machine_usize(cx);
+                }
                 _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
             }
         } else {
@@ -191,7 +230,7 @@ pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
     #[inline]
     pub(super) fn vtable(self) -> Scalar<Tag> {
         match self.layout.ty.kind {
-            ty::Dynamic(..) => self.mplace.meta.unwrap(),
+            ty::Dynamic(..) => self.mplace.meta.unwrap_meta(),
             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
         }
     }
@@ -200,36 +239,36 @@ pub(super) fn vtable(self) -> Scalar<Tag> {
 // These are defined here because they produce a place.
 impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
     #[inline(always)]
-    pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
+    /// Note: do not call `as_ref` on the resulting place. This function should only be used to
+    /// read from the resulting mplace, not to get its address back.
+    pub fn try_as_mplace(
+        self,
+        cx: &impl HasDataLayout,
+    ) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
         match *self {
             Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
+            Operand::Immediate(_) if self.layout.is_zst() => {
+                Ok(MPlaceTy::dangling(self.layout, cx))
+            }
             Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }),
         }
     }
 
     #[inline(always)]
-    pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
-        self.try_as_mplace().unwrap()
+    /// Note: do not call `as_ref` on the resulting place. This function should only be used to
+    /// read from the resulting mplace, not to get its address back.
+    pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
+        self.try_as_mplace(cx).unwrap()
     }
 }
 
 impl<Tag: ::std::fmt::Debug> Place<Tag> {
     /// Produces a Place that will error if attempted to be read from or written to
     #[inline(always)]
-    pub fn null(cx: &impl HasDataLayout) -> Self {
+    fn null(cx: &impl HasDataLayout) -> Self {
         Place::Ptr(MemPlace::null(cx))
     }
 
-    #[inline(always)]
-    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
-        Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
-    }
-
-    #[inline(always)]
-    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
-        Place::Ptr(MemPlace::from_ptr(ptr, align))
-    }
-
     #[inline]
     pub fn assert_mem_place(self) -> MemPlace<Tag> {
         match self {
@@ -270,8 +309,10 @@ pub fn ref_to_mplace(
             val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
         let layout = self.layout_of(pointee_type)?;
         let (ptr, meta) = match *val {
-            Immediate::Scalar(ptr) => (ptr.not_undef()?, None),
-            Immediate::ScalarPair(ptr, meta) => (ptr.not_undef()?, Some(meta.not_undef()?)),
+            Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None),
+            Immediate::ScalarPair(ptr, meta) => {
+                (ptr.not_undef()?, MemPlaceMeta::Meta(meta.not_undef()?))
+            }
         };
 
         let mplace = MemPlace {
@@ -305,14 +346,14 @@ pub fn deref_operand(
     /// On success, returns `None` for zero-sized accesses (where nothing else is
     /// left to do) and a `Pointer` to use for the actual access otherwise.
     #[inline]
-    pub fn check_mplace_access(
+    pub(super) fn check_mplace_access(
         &self,
         place: MPlaceTy<'tcx, M::PointerTag>,
         size: Option<Size>,
     ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
         let size = size.unwrap_or_else(|| {
             assert!(!place.layout.is_unsized());
-            assert!(place.meta.is_none());
+            assert!(!place.meta.has_meta());
             place.layout.size
         });
         self.memory.check_ptr_access(place.ptr, size, place.align)
@@ -338,7 +379,7 @@ pub fn mplace_access_checked(
 
     /// Force `place.ptr` to a `Pointer`.
     /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
-    pub fn force_mplace_ptr(
+    pub(super) fn force_mplace_ptr(
         &self,
         mut place: MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
@@ -405,7 +446,7 @@ pub fn mplace_field(
         } else {
             // base.meta could be present; we might be accessing a sized field of an unsized
             // struct.
-            (None, offset)
+            (MemPlaceMeta::None, offset)
         };
 
         // We do not look at `base.layout.align` nor `field_layout.align`, unlike
@@ -415,7 +456,7 @@ pub fn mplace_field(
 
     // Iterates over all fields of an array. Much more efficient than doing the
     // same by repeatedly calling `mplace_array`.
-    pub fn mplace_array_fields(
+    pub(super) fn mplace_array_fields(
         &self,
         base: MPlaceTy<'tcx, Tag>,
     ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'tcx>
@@ -427,10 +468,10 @@ pub fn mplace_array_fields(
         };
         let layout = base.layout.field(self, 0)?;
         let dl = &self.tcx.data_layout;
-        Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
+        Ok((0..len).map(move |i| base.offset(i * stride, MemPlaceMeta::None, layout, dl)))
     }
 
-    pub fn mplace_subslice(
+    fn mplace_subslice(
         &self,
         base: MPlaceTy<'tcx, M::PointerTag>,
         from: u64,
@@ -460,10 +501,10 @@ pub fn mplace_subslice(
         let (meta, ty) = match base.layout.ty.kind {
             // It is not nice to match on the type, but that seems to be the only way to
             // implement this.
-            ty::Array(inner, _) => (None, self.tcx.mk_array(inner, inner_len)),
+            ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)),
             ty::Slice(..) => {
                 let len = Scalar::from_uint(inner_len, self.pointer_size());
-                (Some(len), base.layout.ty)
+                (MemPlaceMeta::Meta(len), base.layout.ty)
             }
             _ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
         };
@@ -471,18 +512,18 @@ pub fn mplace_subslice(
         base.offset(from_offset, meta, layout, self)
     }
 
-    pub fn mplace_downcast(
+    pub(super) fn mplace_downcast(
         &self,
         base: MPlaceTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
-        assert!(base.meta.is_none());
+        assert!(!base.meta.has_meta());
         Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
     }
 
     /// Project into an mplace
-    pub fn mplace_projection(
+    pub(super) fn mplace_projection(
         &self,
         base: MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: &mir::PlaceElem<'tcx>,
@@ -577,64 +618,14 @@ pub fn place_projection(
         })
     }
 
-    /// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
-    /// `eval_place` and `eval_place_to_op`.
-    pub(super) fn eval_static_to_mplace(
-        &self,
-        place_static: &mir::Static<'tcx>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
-        use rustc::mir::StaticKind;
-
-        Ok(match place_static.kind {
-            StaticKind::Promoted(promoted, promoted_substs) => {
-                let substs = self.subst_from_frame_and_normalize_erasing_regions(promoted_substs);
-                let instance = ty::Instance::new(place_static.def_id, substs);
-
-                // Even after getting `substs` from the frame, this instance may still be
-                // polymorphic because `ConstProp` will try to promote polymorphic MIR.
-                if instance.needs_subst() {
-                    throw_inval!(TooGeneric);
-                }
-
-                self.const_eval_raw(GlobalId { instance, promoted: Some(promoted) })?
-            }
-
-            StaticKind::Static => {
-                let ty = place_static.ty;
-                assert!(!ty.needs_subst());
-                let layout = self.layout_of(ty)?;
-                // Just create a lazy reference, so we can support recursive statics.
-                // tcx takes care of assigning every static one and only one unique AllocId.
-                // When the data here is ever actually used, memory will notice,
-                // and it knows how to deal with alloc_id that are present in the
-                // global table but not in its local memory: It calls back into tcx through
-                // a query, triggering the CTFE machinery to actually turn this lazy reference
-                // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
-                // this InterpCx uses another Machine (e.g., in miri).  This is what we
-                // want!  This way, computing statics works consistently between codegen
-                // and miri: They use the same query to eventually obtain a `ty::Const`
-                // and use that for further computation.
-                //
-                // Notice that statics have *two* AllocIds: the lazy one, and the resolved
-                // one.  Here we make sure that the interpreted program never sees the
-                // resolved ID.  Also see the doc comment of `Memory::get_static_alloc`.
-                let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(place_static.def_id);
-                let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id));
-                MPlaceTy::from_aligned_ptr(ptr, layout)
-            }
-        })
-    }
-
     /// Computes a place. You should only use this if you intend to write into this
     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
     pub fn eval_place(
         &mut self,
         place: &mir::Place<'tcx>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
-        use rustc::mir::PlaceBase;
-
-        let mut place_ty = match &place.base {
-            PlaceBase::Local(mir::RETURN_PLACE) => {
+        let mut place_ty = match place.local {
+            mir::RETURN_PLACE => {
                 // `return_place` has the *caller* layout, but we want to use our
                 // `layout to verify our assumption. The caller will validate
                 // their layout on return.
@@ -655,12 +646,11 @@ pub fn eval_place(
                     ))?,
                 }
             }
-            PlaceBase::Local(local) => PlaceTy {
+            local => PlaceTy {
                 // This works even for dead/uninitialized locals; we check further when writing
-                place: Place::Local { frame: self.cur_frame(), local: *local },
-                layout: self.layout_of_local(self.frame(), *local, None)?,
+                place: Place::Local { frame: self.cur_frame(), local: local },
+                layout: self.layout_of_local(self.frame(), local, None)?,
             },
-            PlaceBase::Static(place_static) => self.eval_static_to_mplace(&place_static)?.into(),
         };
 
         for elem in place.projection.iter() {
@@ -971,7 +961,7 @@ pub fn copy_op_transmute(
     pub fn force_allocation_maybe_sized(
         &mut self,
         place: PlaceTy<'tcx, M::PointerTag>,
-        meta: Option<Scalar<M::PointerTag>>,
+        meta: MemPlaceMeta<M::PointerTag>,
     ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
         let (mplace, size) = match place.place {
             Place::Local { frame, local } => {
@@ -1016,7 +1006,7 @@ pub fn force_allocation(
         &mut self,
         place: PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
-        Ok(self.force_allocation_maybe_sized(place, None)?.0)
+        Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0)
     }
 
     pub fn allocate(
@@ -1036,8 +1026,11 @@ pub fn allocate_str(
     ) -> MPlaceTy<'tcx, M::PointerTag> {
         let ptr = self.memory.allocate_static_bytes(str.as_bytes(), kind);
         let meta = Scalar::from_uint(str.len() as u128, self.pointer_size());
-        let mplace =
-            MemPlace { ptr: ptr.into(), align: Align::from_bytes(1).unwrap(), meta: Some(meta) };
+        let mplace = MemPlace {
+            ptr: ptr.into(),
+            align: Align::from_bytes(1).unwrap(),
+            meta: MemPlaceMeta::Meta(meta),
+        };
 
         let layout = self.layout_of(self.tcx.mk_static_str()).unwrap();
         MPlaceTy { mplace, layout }
@@ -1145,7 +1138,7 @@ pub(super) fn unpack_dyn_trait(
             assert_eq!(align, layout.align.abi);
         }
 
-        let mplace = MPlaceTy { mplace: MemPlace { meta: None, ..*mplace }, layout };
+        let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout };
         Ok((instance, mplace))
     }
 }
index 6790baf31ccb2cab12f85a14647ca65538f5c46f..a8e67c8f208a94f564877fda13a0619a37fc43a1 100644 (file)
@@ -23,7 +23,9 @@
 use syntax::ast::Mutability;
 
 use super::eval_context::{LocalState, StackPopCleanup};
-use super::{Frame, Immediate, LocalValue, MemPlace, Memory, Operand, Place, ScalarMaybeUndef};
+use super::{
+    Frame, Immediate, LocalValue, MemPlace, MemPlaceMeta, Memory, Operand, Place, ScalarMaybeUndef,
+};
 use crate::const_eval::CompileTimeInterpreter;
 
 #[derive(Default)]
@@ -205,6 +207,14 @@ enum ScalarMaybeUndef {
     }
 );
 
+impl_snapshot_for!(
+    enum MemPlaceMeta {
+        Meta(s),
+        None,
+        Poison,
+    }
+);
+
 impl_snapshot_for!(struct MemPlace {
     ptr,
     meta,
index a28bb539fd0703f6ef8ba947b1420029e3ac84e7..37dcab512b9918d65eb95f4fe02ddde69da3d72e 100644 (file)
@@ -378,7 +378,7 @@ fn eval_fn_call(
                     }
                     None => {
                         // Unsized self.
-                        args[0].assert_mem_place()
+                        args[0].assert_mem_place(self)
                     }
                 };
                 // Find and consult vtable
index 7b82bed2e7a61adf8ef1f744f7ee8905d27f3da9..2f0fb81fffd13db3322a64153e465dfdfa4d4fc5 100644 (file)
@@ -16,7 +16,7 @@
 use std::hash::Hash;
 
 use super::{
-    CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Scalar,
+    CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
     ValueVisitor,
 };
 
@@ -246,13 +246,13 @@ fn visit_elem(
 
     fn check_wide_ptr_meta(
         &mut self,
-        meta: Option<Scalar<M::PointerTag>>,
+        meta: MemPlaceMeta<M::PointerTag>,
         pointee: TyLayout<'tcx>,
     ) -> InterpResult<'tcx> {
         let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
         match tail.kind {
             ty::Dynamic(..) => {
-                let vtable = meta.unwrap();
+                let vtable = meta.unwrap_meta();
                 try_validation!(
                     self.ecx.memory.check_ptr_access(
                         vtable,
@@ -276,7 +276,7 @@ fn check_wide_ptr_meta(
             }
             ty::Slice(..) | ty::Str => {
                 let _len = try_validation!(
-                    meta.unwrap().to_machine_usize(self.ecx),
+                    meta.unwrap_meta().to_machine_usize(self.ecx),
                     "non-integer slice length in wide pointer",
                     self.path
                 );
@@ -571,7 +571,7 @@ fn visit_aggregate(
     ) -> InterpResult<'tcx> {
         match op.layout.ty.kind {
             ty::Str => {
-                let mplace = op.assert_mem_place(); // strings are never immediate
+                let mplace = op.assert_mem_place(self.ecx); // strings are never immediate
                 try_validation!(
                     self.ecx.read_str(mplace),
                     "uninitialized or non-UTF-8 data in str",
@@ -599,22 +599,23 @@ fn visit_aggregate(
             {
                 // Optimized handling for arrays of integer/float type.
 
-                // bailing out for zsts is ok, since the array element type can only be int/float
-                if op.layout.is_zst() {
-                    return Ok(());
-                }
-                // non-ZST array cannot be immediate, slices are never immediate
-                let mplace = op.assert_mem_place();
+                // Arrays cannot be immediate, slices are never immediate.
+                let mplace = op.assert_mem_place(self.ecx);
                 // This is the length of the array/slice.
                 let len = mplace.len(self.ecx)?;
-                // zero length slices have nothing to be checked
+                // Zero length slices have nothing to be checked.
                 if len == 0 {
                     return Ok(());
                 }
                 // This is the element type size.
-                let ty_size = self.ecx.layout_of(tys)?.size;
+                let layout = self.ecx.layout_of(tys)?;
+                // Empty tuples and fieldless structs (the only ZSTs that allow reaching this code)
+                // have no data to be checked.
+                if layout.is_zst() {
+                    return Ok(());
+                }
                 // This is the size in bytes of the whole array.
-                let size = ty_size * len;
+                let size = layout.size * len;
                 // Size is not 0, get a pointer.
                 let ptr = self.ecx.force_ptr(mplace.ptr)?;
 
@@ -644,7 +645,7 @@ fn visit_aggregate(
                                 // Some byte was undefined, determine which
                                 // element that byte belongs to so we can
                                 // provide an index.
-                                let i = (offset.bytes() / ty_size.bytes()) as usize;
+                                let i = (offset.bytes() / layout.size.bytes()) as usize;
                                 self.path.push(PathElem::ArrayElem(i));
 
                                 throw_validation_failure!("undefined bytes", self.path)
index 2cfcf0ff06d0fb2ec6c26fdacb398f09c21073db..d2594e8707104cf10e94f9c3cad066d7f3831fd7 100644 (file)
@@ -223,7 +223,7 @@ fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
                 match v.layout().ty.kind {
                     ty::Dynamic(..) => {
                         // immediate trait objects are not a thing
-                        let dest = v.to_op(self.ecx())?.assert_mem_place();
+                        let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
                         let inner = self.ecx().unpack_dyn_trait(dest)?.1;
                         trace!("walk_value: dyn object layout: {:#?}", inner.layout);
                         // recurse with the inner type
@@ -292,13 +292,7 @@ fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
                     },
                     layout::FieldPlacement::Array { .. } => {
                         // Let's get an mplace first.
-                        let mplace = if v.layout().is_zst() {
-                            // it's a ZST, the memory content cannot matter
-                            MPlaceTy::dangling(v.layout(), self.ecx())
-                        } else {
-                            // non-ZST array/slice/str cannot be immediate
-                            v.to_op(self.ecx())?.assert_mem_place()
-                        };
+                        let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
                         // Now we can go over all the fields.
                         let iter = self.ecx().mplace_array_fields(mplace)?
                             .map(|f| f.and_then(|f| {
index 32b35c4139dad1b321657a23e4c62fca038c7f70..1ff529181f7058e375fd33767e3a44169f1d37ec 100644 (file)
@@ -13,7 +13,6 @@
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
 #![feature(core_intrinsics)]
-#![feature(const_fn)]
 #![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(exhaustive_patterns)]
 extern crate log;
 #[macro_use]
 extern crate rustc;
-#[macro_use]
-extern crate syntax;
 
 mod borrow_check;
-mod build;
 pub mod const_eval;
 pub mod dataflow;
-mod hair;
 pub mod interpret;
-mod lints;
 pub mod monomorphize;
 mod shim;
 pub mod transform;
 
 pub fn provide(providers: &mut Providers<'_>) {
     borrow_check::provide(providers);
+    const_eval::provide(providers);
     shim::provide(providers);
     transform::provide(providers);
     monomorphize::partitioning::provide(providers);
     providers.const_eval_validated = const_eval::const_eval_validated_provider;
     providers.const_eval_raw = const_eval::const_eval_raw_provider;
-    providers.check_match = hair::pattern::check_match;
     providers.const_caller_location = const_eval::const_caller_location;
     providers.const_field = |tcx, param_env_and_value| {
         let (param_env, (value, field)) = param_env_and_value.into_parts();
         const_eval::const_field(tcx, param_env, None, field, value)
     };
+    providers.destructure_const = |tcx, param_env_and_value| {
+        let (param_env, value) = param_env_and_value.into_parts();
+        const_eval::destructure_const(tcx, param_env, value)
+    }
 }
diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs
deleted file mode 100644 (file)
index fc7f2eb..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-use rustc::hir::intravisit::FnKind;
-use rustc::hir::map::blocks::FnLikeNode;
-use rustc::lint::builtin::UNCONDITIONAL_RECURSION;
-use rustc::mir::{self, Body, TerminatorKind};
-use rustc::ty::subst::InternalSubsts;
-use rustc::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
-use rustc_hir::def_id::DefId;
-use rustc_index::bit_set::BitSet;
-
-pub fn check(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId) {
-    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-
-    if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
-        check_fn_for_unconditional_recursion(tcx, fn_like_node.kind(), body, def_id);
-    }
-}
-
-fn check_fn_for_unconditional_recursion(
-    tcx: TyCtxt<'tcx>,
-    fn_kind: FnKind<'_>,
-    body: &Body<'tcx>,
-    def_id: DefId,
-) {
-    if let FnKind::Closure(_) = fn_kind {
-        // closures can't recur, so they don't matter.
-        return;
-    }
-
-    //FIXME(#54444) rewrite this lint to use the dataflow framework
-
-    // Walk through this function (say `f`) looking to see if
-    // every possible path references itself, i.e., the function is
-    // called recursively unconditionally. This is done by trying
-    // to find a path from the entry node to the exit node that
-    // *doesn't* call `f` by traversing from the entry while
-    // pretending that calls of `f` are sinks (i.e., ignoring any
-    // exit edges from them).
-    //
-    // NB. this has an edge case with non-returning statements,
-    // like `loop {}` or `panic!()`: control flow never reaches
-    // the exit node through these, so one can have a function
-    // that never actually calls itself but is still picked up by
-    // this lint:
-    //
-    //     fn f(cond: bool) {
-    //         if !cond { panic!() } // could come from `assert!(cond)`
-    //         f(false)
-    //     }
-    //
-    // In general, functions of that form may be able to call
-    // itself a finite number of times and then diverge. The lint
-    // considers this to be an error for two reasons, (a) it is
-    // easier to implement, and (b) it seems rare to actually want
-    // to have behaviour like the above, rather than
-    // e.g., accidentally recursing after an assert.
-
-    let basic_blocks = body.basic_blocks();
-    let mut reachable_without_self_call_queue = vec![mir::START_BLOCK];
-    let mut reached_exit_without_self_call = false;
-    let mut self_call_locations = vec![];
-    let mut visited = BitSet::new_empty(basic_blocks.len());
-
-    let param_env = tcx.param_env(def_id);
-    let trait_substs_count = match tcx.opt_associated_item(def_id) {
-        Some(AssocItem { container: AssocItemContainer::TraitContainer(trait_def_id), .. }) => {
-            tcx.generics_of(trait_def_id).count()
-        }
-        _ => 0,
-    };
-    let caller_substs = &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count];
-
-    while let Some(bb) = reachable_without_self_call_queue.pop() {
-        if !visited.insert(bb) {
-            //already done
-            continue;
-        }
-
-        let block = &basic_blocks[bb];
-
-        if let Some(ref terminator) = block.terminator {
-            match terminator.kind {
-                TerminatorKind::Call { ref func, .. } => {
-                    let func_ty = func.ty(body, tcx);
-
-                    if let ty::FnDef(fn_def_id, substs) = func_ty.kind {
-                        let (call_fn_id, call_substs) = if let Some(instance) =
-                            Instance::resolve(tcx, param_env, fn_def_id, substs)
-                        {
-                            (instance.def_id(), instance.substs)
-                        } else {
-                            (fn_def_id, substs)
-                        };
-
-                        let is_self_call = call_fn_id == def_id
-                            && &call_substs[..caller_substs.len()] == caller_substs;
-
-                        if is_self_call {
-                            self_call_locations.push(terminator.source_info);
-
-                            //this is a self call so we shouldn't explore
-                            //further down this path
-                            continue;
-                        }
-                    }
-                }
-                TerminatorKind::Abort | TerminatorKind::Return => {
-                    //found a path!
-                    reached_exit_without_self_call = true;
-                    break;
-                }
-                _ => {}
-            }
-
-            for successor in terminator.successors() {
-                reachable_without_self_call_queue.push(*successor);
-            }
-        }
-    }
-
-    // Check the number of self calls because a function that
-    // doesn't return (e.g., calls a `-> !` function or `loop { /*
-    // no break */ }`) shouldn't be linted unless it actually
-    // recurs.
-    if !reached_exit_without_self_call && !self_call_locations.is_empty() {
-        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
-        let sp = tcx.sess.source_map().def_span(tcx.hir().span(hir_id));
-        let mut db = tcx.struct_span_lint_hir(
-            UNCONDITIONAL_RECURSION,
-            hir_id,
-            sp,
-            "function cannot return without recursing",
-        );
-        db.span_label(sp, "cannot return without recursing");
-        // offer some help to the programmer.
-        for location in &self_call_locations {
-            db.span_label(location.span, "recursive call site");
-        }
-        db.help("a `loop` may express intention better if this is on purpose");
-        db.emit();
-    }
-}
index 0943be9d95c38b71eec2b731fc5279416a589d3b..f5f00c9343561dd318954d91df45fe9258fa2be5 100644 (file)
 use rustc::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
 use rustc::mir::mono::{InstantiationMode, MonoItem};
 use rustc::mir::visit::Visitor as MirVisitor;
-use rustc::mir::{self, Location, PlaceBase, Static, StaticKind};
+use rustc::mir::{self, Local, Location};
 use rustc::session::config::EntryFnType;
 use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast};
 use rustc::ty::print::obsolete::DefPathBasedNames;
-use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use rustc::ty::subst::{InternalSubsts, SubstsRef};
 use rustc::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
 use rustc_hir::def_id::{DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_index::bit_set::GrowableBitSet;
-
+use smallvec::SmallVec;
 use std::iter;
 
 #[derive(PartialEq)]
@@ -227,12 +227,7 @@ fn new() -> InliningMap<'tcx> {
         }
     }
 
-    fn record_accesses<I>(&mut self, source: MonoItem<'tcx>, new_targets: I)
-    where
-        I: Iterator<Item = (MonoItem<'tcx>, bool)> + ExactSizeIterator,
-    {
-        assert!(!self.index.contains_key(&source));
-
+    fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) {
         let start_index = self.targets.len();
         let new_items_count = new_targets.len();
         let new_items_count_total = new_items_count + self.targets.len();
@@ -240,15 +235,15 @@ fn record_accesses<I>(&mut self, source: MonoItem<'tcx>, new_targets: I)
         self.targets.reserve(new_items_count);
         self.inlines.ensure(new_items_count_total);
 
-        for (i, (target, inline)) in new_targets.enumerate() {
-            self.targets.push(target);
-            if inline {
+        for (i, (target, inline)) in new_targets.iter().enumerate() {
+            self.targets.push(*target);
+            if *inline {
                 self.inlines.insert(i + start_index);
             }
         }
 
         let end_index = self.targets.len();
-        self.index.insert(source, (start_index, end_index));
+        assert!(self.index.insert(source, (start_index, end_index)).is_none());
     }
 
     // Internally iterate over all items referenced by `source` which will be
@@ -283,10 +278,8 @@ pub fn collect_crate_mono_items(
 ) -> (FxHashSet<MonoItem<'_>>, InliningMap<'_>) {
     let _prof_timer = tcx.prof.generic_activity("monomorphization_collector");
 
-    let roots = tcx.sess.time("collecting roots", || {
-        let _prof_timer = tcx.prof.generic_activity("monomorphization_collector_root_collections");
-        collect_roots(tcx, mode)
-    });
+    let roots =
+        tcx.sess.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode));
 
     debug!("building mono item graph, beginning at roots");
 
@@ -297,7 +290,7 @@ pub fn collect_crate_mono_items(
         let visited: MTRef<'_, _> = &mut visited;
         let inlining_map: MTRef<'_, _> = &mut inlining_map;
 
-        tcx.sess.time("collecting mono items", || {
+        tcx.sess.time("monomorphization_collector_graph_walk", || {
             par_iter(roots).for_each(|root| {
                 let mut recursion_depths = DefIdMap::default();
                 collect_items_rec(tcx, root, visited, &mut recursion_depths, inlining_map);
@@ -405,10 +398,15 @@ fn record_accesses<'tcx>(
         mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy
     };
 
-    let accesses =
-        callees.into_iter().map(|mono_item| (*mono_item, is_inlining_candidate(mono_item)));
+    // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock.
+    // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec`
+    // instead to avoid creating this `SmallVec`.
+    let accesses: SmallVec<[_; 128]> = callees
+        .into_iter()
+        .map(|mono_item| (*mono_item, is_inlining_candidate(mono_item)))
+        .collect();
 
-    inlining_map.lock_mut().record_accesses(caller, accesses);
+    inlining_map.lock_mut().record_accesses(caller, &accesses);
 }
 
 fn check_recursion_limit<'tcx>(
@@ -644,39 +642,10 @@ fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location:
 
     fn visit_place_base(
         &mut self,
-        place_base: &mir::PlaceBase<'tcx>,
+        _place_local: &Local,
         _context: mir::visit::PlaceContext,
-        location: Location,
+        _location: Location,
     ) {
-        match place_base {
-            PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => {
-                debug!("visiting static {:?} @ {:?}", def_id, location);
-
-                let tcx = self.tcx;
-                let instance = Instance::mono(tcx, *def_id);
-                if should_monomorphize_locally(tcx, &instance) {
-                    self.output.push(MonoItem::Static(*def_id));
-                }
-            }
-            PlaceBase::Static(box Static {
-                kind: StaticKind::Promoted(promoted, substs),
-                def_id,
-                ..
-            }) => {
-                let instance = Instance::new(*def_id, substs.subst(self.tcx, self.param_substs));
-                match self.tcx.const_eval_promoted(instance, *promoted) {
-                    Ok(val) => collect_const(self.tcx, val, substs, self.output),
-                    Err(ErrorHandled::Reported) => {}
-                    Err(ErrorHandled::TooGeneric) => {
-                        let span = self.tcx.promoted_mir(*def_id)[*promoted].span;
-                        span_bug!(span, "collection encountered polymorphic constant")
-                    }
-                }
-            }
-            PlaceBase::Local(_) => {
-                // Locals have no relevance for collector.
-            }
-        }
     }
 }
 
@@ -1251,8 +1220,8 @@ fn collect_const<'tcx>(
                 collect_miri(tcx, id, output);
             }
         }
-        ty::ConstKind::Unevaluated(def_id, substs) => {
-            match tcx.const_eval_resolve(param_env, def_id, substs, None) {
+        ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
+            match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
                 Ok(val) => collect_const(tcx, val, param_substs, output),
                 Err(ErrorHandled::Reported) => {}
                 Err(ErrorHandled::TooGeneric) => {
index c004417b3373f5dfbb1f2b2840bb34d29f307a5d..0def51a6a33e5410a1adeffc0fa2a2d15d65a9b1 100644 (file)
 use rustc::ty::query::Providers;
 use rustc::ty::{self, DefIdTree, InstanceDef, TyCtxt};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::sync;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_span::symbol::Symbol;
@@ -796,6 +797,8 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I)
     I: Iterator<Item = &'a MonoItem<'tcx>>,
     'tcx: 'a,
 {
+    let _prof_timer = tcx.prof.generic_activity("assert_symbols_are_distinct");
+
     let mut symbols: Vec<_> =
         mono_items.map(|mono_item| (mono_item, mono_item.symbol_name(tcx))).collect();
 
@@ -865,25 +868,26 @@ fn collect_and_partition_mono_items(
         }
     };
 
-    let (items, inlining_map) = tcx.sess.time("monomorphization collection", || {
-        collector::collect_crate_mono_items(tcx, collection_mode)
-    });
+    let (items, inlining_map) = collector::collect_crate_mono_items(tcx, collection_mode);
 
     tcx.sess.abort_if_errors();
 
-    assert_symbols_are_distinct(tcx, items.iter());
-
-    let strategy = if tcx.sess.opts.incremental.is_some() {
-        PartitioningStrategy::PerModule
-    } else {
-        PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units())
-    };
-
-    let codegen_units = tcx.sess.time("codegen unit partitioning", || {
-        partition(tcx, items.iter().cloned(), strategy, &inlining_map)
-            .into_iter()
-            .map(Arc::new)
-            .collect::<Vec<_>>()
+    let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || {
+        sync::join(
+            || {
+                let strategy = if tcx.sess.opts.incremental.is_some() {
+                    PartitioningStrategy::PerModule
+                } else {
+                    PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units())
+                };
+
+                partition(tcx, items.iter().cloned(), strategy, &inlining_map)
+                    .into_iter()
+                    .map(Arc::new)
+                    .collect::<Vec<_>>()
+            },
+            || assert_symbols_are_distinct(tcx, items.iter()),
+        )
     });
 
     let mono_items: DefIdSet = items
index 1583647a4d4141883384f9f66ffdc4c7940151e9..edb4eb4d7c34454617c03482c8a2fb2fa9f2f53a 100644 (file)
@@ -1,11 +1,12 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
 use rustc::session::config::nightly_options;
+use rustc::session::parse::feature_err;
 use rustc::ty::TyCtxt;
+use rustc_errors::struct_span_err;
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
-use syntax::feature_gate::feature_err;
 
 use super::{ConstKind, Item};
 
@@ -115,12 +116,7 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             &format!("`{}` is not yet stable as a const fn", item.tcx.def_path_str(def_id)),
         );
         if nightly_options::is_nightly_build() {
-            help!(
-                &mut err,
-                "add `#![feature({})]` to the \
-                   crate attributes to enable",
-                feature
-            );
+            err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
         }
         err.emit();
     }
@@ -197,13 +193,14 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
 pub struct CellBorrow;
 impl NonConstOp for CellBorrow {
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        span_err!(
+        struct_span_err!(
             item.tcx.sess,
             span,
             E0492,
             "cannot borrow a constant which may contain \
             interior mutability, create a static instead"
-        );
+        )
+        .emit();
     }
 }
 
@@ -353,16 +350,18 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
             item.tcx.sess,
             span,
             E0013,
-            "{}s cannot refer to statics, use \
-                                        a constant instead",
+            "{}s cannot refer to statics",
             item.const_kind()
         );
+        err.help(
+            "consider extracting the value of the `static` to a `const`, and referring to that",
+        );
         if item.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
-                "Static and const variables can refer to other const variables. \
-                    But a const variable cannot refer to a static variable.",
+                "`static` and `const` variables can refer to other `const` variables. \
+                    A `const` variable, however, cannot refer to a `static` variable.",
             );
-            err.help("To fix this, the value can be extracted as a const and then used.");
+            err.help("To fix this, the value can be extracted to a `const` and then used.");
         }
         err.emit();
     }
@@ -375,13 +374,14 @@ impl NonConstOp for ThreadLocalAccess {
     const IS_SUPPORTED_IN_MIRI: bool = false;
 
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        span_err!(
+        struct_span_err!(
             item.tcx.sess,
             span,
             E0625,
             "thread-local statics cannot be \
             accessed at compile-time"
-        );
+        )
+        .emit();
     }
 }
 
index 0799cc2374ad4747c5e414a3f2f848e32edf9611..577736f9bd11df64a011adb3f6745890e086d3fc 100644 (file)
@@ -38,12 +38,15 @@ fn in_projection_structurally(
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
         if let [proj_base @ .., elem] = place.projection {
-            let base_qualif =
-                Self::in_place(cx, per_local, PlaceRef { base: place.base, projection: proj_base });
+            let base_qualif = Self::in_place(
+                cx,
+                per_local,
+                PlaceRef { local: place.local, projection: proj_base },
+            );
             let qualif = base_qualif
                 && Self::in_any_value_of_ty(
                     cx,
-                    Place::ty_from(place.base, proj_base, *cx.body, cx.tcx)
+                    Place::ty_from(place.local, proj_base, *cx.body, cx.tcx)
                         .projection_ty(cx.tcx, elem)
                         .ty,
                 );
@@ -75,11 +78,8 @@ fn in_place(
         place: PlaceRef<'_, 'tcx>,
     ) -> bool {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => per_local(*local),
-            PlaceRef { base: PlaceBase::Static(_), projection: [] } => {
-                bug!("qualifying already promoted MIR")
-            }
-            PlaceRef { base: _, projection: [.., _] } => Self::in_projection(cx, per_local, place),
+            PlaceRef { local, projection: [] } => per_local(*local),
+            PlaceRef { local: _, projection: [.., _] } => Self::in_projection(cx, per_local, place),
         }
     }
 
@@ -102,7 +102,9 @@ fn in_operand(
                     // Note: this uses `constant.literal.ty` which is a reference or pointer to the
                     // type of the actual `static` item.
                     Self::in_any_value_of_ty(cx, constant.literal.ty)
-                } else if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val {
+                } else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val
+                {
+                    assert!(promoted.is_none());
                     // Don't peek inside trait associated constants.
                     if cx.tcx.trait_of_item(def_id).is_some() {
                         Self::in_any_value_of_ty(cx, constant.literal.ty)
@@ -147,12 +149,12 @@ fn in_rvalue_structurally(
             Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
                 if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
-                    let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, *cx.body, cx.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
                         return Self::in_place(
                             cx,
                             per_local,
-                            PlaceRef { base: &place.base, projection: proj_base },
+                            PlaceRef { local: &place.local, projection: proj_base },
                         );
                     }
                 }
index 207683054f9251ff30d7e8df919168983a85acf1..c445568dd2a9b4043b5677beebf1cbd19adcb6bf 100644 (file)
@@ -47,15 +47,15 @@ fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
         debug_assert!(!place.is_indirect());
 
         match (value, place.as_ref()) {
-            (true, mir::PlaceRef { base: &mir::PlaceBase::Local(local), .. }) => {
-                self.qualifs_per_local.insert(local);
+            (true, mir::PlaceRef { local, .. }) => {
+                self.qualifs_per_local.insert(*local);
             }
 
             // For now, we do not clear the qualif if a local is overwritten in full by
             // an unqualified rvalue (e.g. `y = 5`). This is to be consistent
             // with aggregates where we overwrite all fields with assignments, which would not
             // get this feature.
-            (false, mir::PlaceRef { base: &mir::PlaceBase::Local(_local), projection: &[] }) => {
+            (false, mir::PlaceRef { local: _, projection: &[] }) => {
                 // self.qualifs_per_local.remove(*local);
             }
 
index 3c52a2e0dd270fb888a65dbc474518175c216e2d..10a4b7d92b764a266610c206fcfe978bf6384457 100644 (file)
@@ -7,6 +7,7 @@
 use rustc::ty::cast::CastTy;
 use rustc::ty::{self, TyCtxt};
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir::{def_id::DefId, HirId};
 use rustc_index::bit_set::BitSet;
 use rustc_span::symbol::sym;
@@ -20,6 +21,7 @@
 use super::qualifs::{self, HasMutInterior, NeedsDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{is_lang_panic_fn, ConstKind, Item, Qualif};
+use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::dataflow::{self as old_dataflow, generic as dataflow};
 
 pub type IndirectlyMutableResults<'mir, 'tcx> =
@@ -172,7 +174,7 @@ pub fn check_body(&mut self) {
         let Item { tcx, body, def_id, const_kind, .. } = *self.item;
 
         let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
-            && tcx.is_min_const_fn(def_id))
+            && crate::const_eval::is_min_const_fn(tcx, def_id))
             && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
 
         if use_min_const_fn_checks {
@@ -302,8 +304,8 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                             PlaceContext::MutatingUse(MutatingUseContext::Borrow)
                         }
                     };
-                    self.visit_place_base(&place.base, ctx, location);
-                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    self.visit_place_base(&place.local, ctx, location);
+                    self.visit_projection(&place.local, reborrowed_proj, ctx, location);
                     return;
                 }
             }
@@ -315,8 +317,8 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                         }
                         Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
                     };
-                    self.visit_place_base(&place.base, ctx, location);
-                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    self.visit_place_base(&place.local, ctx, location);
+                    self.visit_projection(&place.local, reborrowed_proj, ctx, location);
                     return;
                 }
             }
@@ -367,15 +369,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
             Rvalue::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf),
 
-            // At the moment, `PlaceBase::Static` is only used for promoted MIR.
-            Rvalue::Ref(_, BorrowKind::Shared, ref place)
-            | Rvalue::Ref(_, BorrowKind::Shallow, ref place)
-            | Rvalue::AddressOf(Mutability::Not, ref place)
-                if matches!(place.base, PlaceBase::Static(_)) =>
-            {
-                bug!("Saw a promoted during const-checking, which must run before promotion")
-            }
-
             Rvalue::Ref(_, BorrowKind::Shared, ref place)
             | Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
                 self.check_immutable_borrow_like(location, place)
@@ -419,26 +412,14 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         }
     }
 
-    fn visit_place_base(
-        &mut self,
-        place_base: &PlaceBase<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
+    fn visit_place_base(&mut self, place_local: &Local, context: PlaceContext, location: Location) {
         trace!(
-            "visit_place_base: place_base={:?} context={:?} location={:?}",
-            place_base,
+            "visit_place_base: place_local={:?} context={:?} location={:?}",
+            place_local,
             context,
             location,
         );
-        self.super_place_base(place_base, context, location);
-
-        match place_base {
-            PlaceBase::Local(_) => {}
-            PlaceBase::Static(_) => {
-                bug!("Promotion must be run after const validation");
-            }
-        }
+        self.super_place_base(place_local, context, location);
     }
 
     fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
@@ -451,30 +432,30 @@ fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
     }
     fn visit_projection_elem(
         &mut self,
-        place_base: &PlaceBase<'tcx>,
+        place_local: &Local,
         proj_base: &[PlaceElem<'tcx>],
         elem: &PlaceElem<'tcx>,
         context: PlaceContext,
         location: Location,
     ) {
         trace!(
-            "visit_projection_elem: place_base={:?} proj_base={:?} elem={:?} \
+            "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
             context={:?} location={:?}",
-            place_base,
+            place_local,
             proj_base,
             elem,
             context,
             location,
         );
 
-        self.super_projection_elem(place_base, proj_base, elem, context, location);
+        self.super_projection_elem(place_local, proj_base, elem, context, location);
 
         match elem {
             ProjectionElem::Deref => {
-                let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty;
+                let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
                 if let ty::RawPtr(_) = base_ty.kind {
                     if proj_base.is_empty() {
-                        if let (PlaceBase::Local(local), []) = (place_base, proj_base) {
+                        if let (local, []) = (place_local, proj_base) {
                             let decl = &self.body.local_decls[*local];
                             if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
                                 let span = decl.source_info.span;
@@ -495,7 +476,7 @@ fn visit_projection_elem(
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(_) => {
-                let base_ty = Place::ty_from(place_base, proj_base, *self.body, self.tcx).ty;
+                let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
                 match base_ty.ty_adt_def() {
                     Some(def) if def.is_union() => {
                         self.check_op(ops::UnionAccess);
@@ -559,13 +540,13 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
                 };
 
                 // At this point, we are calling a function whose `DefId` is known...
-                if self.tcx.is_const_fn(def_id) {
+                if is_const_fn(self.tcx, def_id) {
                     return;
                 }
 
                 if is_lang_panic_fn(self.tcx, def_id) {
                     self.check_op(ops::Panic);
-                } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
+                } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
                     // Exempt unstable const fns inside of macros with
                     // `#[allow_internal_unstable]`.
                     if !self.span.allows_unstable(feature) {
@@ -679,17 +660,15 @@ fn place_as_reborrow(
 
         // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
         // that points to the allocation for the static. Don't treat these as reborrows.
-        if let PlaceBase::Local(local) = place.base {
-            if body.local_decls[local].is_ref_to_static() {
-                return None;
-            }
+        if body.local_decls[place.local].is_ref_to_static() {
+            return None;
         }
 
         // Ensure the type being derefed is a reference and not a raw pointer.
         //
         // This is sufficient to prevent an access to a `static mut` from being marked as a
         // reborrow, even if the check above were to disappear.
-        let inner_ty = Place::ty_from(&place.base, inner, body, tcx).ty;
+        let inner_ty = Place::ty_from(&place.local, inner, body, tcx).ty;
         match inner_ty.kind {
             ty::Ref(..) => Some(inner),
             _ => None,
index b333bc681f6bbadf8163e310d06faf149e2ac536..072cdf2ebba3a26386190276493c2e5f37490ab5 100644 (file)
@@ -1,4 +1,4 @@
-use rustc::hir::intravisit;
+use rustc::hir::map::Map;
 use rustc::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE};
 use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc::mir::*;
@@ -6,13 +6,16 @@
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit;
 use rustc_hir::Node;
 use rustc_span::symbol::{sym, Symbol};
 
 use std::ops::Bound;
 
+use crate::const_eval::{is_const_fn, is_min_const_fn};
 use crate::util;
 
 use rustc_error_codes::*;
@@ -187,18 +190,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
     }
 
     fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-        match place.base {
-            PlaceBase::Local(..) => {
-                // Locals are safe.
-            }
-            PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => {
-                bug!("unsafety checking should happen before promotion");
-            }
-            PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => {
-                bug!("StaticKind::Static should not exist");
-            }
-        }
-
         for (i, elem) in place.projection.iter().enumerate() {
             let proj_base = &place.projection[..i];
 
@@ -226,7 +217,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                 }
             }
             let is_borrow_of_interior_mut = context.is_borrow()
-                && !Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty.is_freeze(
+                && !Place::ty_from(&place.local, proj_base, self.body, self.tcx).ty.is_freeze(
                     self.tcx,
                     self.param_env,
                     self.source_info.span,
@@ -241,7 +232,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                 self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
             }
             let old_source_info = self.source_info;
-            if let (PlaceBase::Local(local), []) = (&place.base, proj_base) {
+            if let (local, []) = (&place.local, proj_base) {
                 let decl = &self.body.local_decls[*local];
                 if decl.internal {
                     // Internal locals are used in the `move_val_init` desugaring.
@@ -269,7 +260,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                     }
                 }
             }
-            let base_ty = Place::ty_from(&place.base, proj_base, self.body, self.tcx).ty;
+            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",
@@ -423,7 +414,8 @@ fn check_mut_borrowing_layout_constrained_field(
             match elem {
                 ProjectionElem::Field(..) => {
                     let ty =
-                        Place::ty_from(&place.base, proj_base, &self.body.local_decls, self.tcx).ty;
+                        Place::ty_from(&place.local, proj_base, &self.body.local_decls, self.tcx)
+                            .ty;
                     match ty.kind {
                         ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) {
                             (Bound::Unbounded, Bound::Unbounded) => {}
@@ -474,7 +466,9 @@ struct UnusedUnsafeVisitor<'a> {
 }
 
 impl<'a, 'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> {
-    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> {
         intravisit::NestedVisitorMap::None
     }
 
@@ -522,7 +516,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult
     let id = tcx.hir().as_local_hir_id(def_id).unwrap();
     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(def_id), tcx.is_min_const_fn(def_id)),
+        hir::BodyOwnerKind::Fn => (is_const_fn(tcx, def_id), is_min_const_fn(tcx, def_id)),
         hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
     };
     let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);
@@ -643,17 +637,17 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
                 if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) {
                     tcx.unsafe_derive_on_repr_packed(impl_def_id);
                 } else {
-                    tcx.lint_node_note(
+                    tcx.struct_span_lint_hir(
                         SAFE_PACKED_BORROWS,
                         lint_hir_id,
                         source_info.span,
                         &format!(
-                            "{} is unsafe and requires unsafe function or block \
-                                            (error E0133)",
+                            "{} is unsafe and requires unsafe function or block (error E0133)",
                             description
                         ),
-                        &details.as_str(),
-                    );
+                    )
+                    .note(&details.as_str())
+                    .emit();
                 }
             }
         }
index 6b0f7be86841ebc5869f73a6ede6dba8e7f4d920..1d5a643484a73d53b4efa5b72a31eb65b4f35e6e 100644 (file)
 };
 use rustc::mir::{
     read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, Constant,
-    Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, ReadOnlyBodyAndCache, Rvalue,
+    Local, LocalDecl, LocalKind, Location, Operand, Place, ReadOnlyBodyAndCache, Rvalue,
     SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
     UnOp, RETURN_PLACE,
 };
 use rustc::ty::layout::{
     HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
 };
-use rustc::ty::subst::InternalSubsts;
-use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::subst::{InternalSubsts, Subst};
+use rustc::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -33,7 +33,6 @@
     LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
     ScalarMaybeUndef, StackPopCleanup,
 };
-use crate::rustc::ty::subst::Subst;
 use crate::transform::{MirPass, MirSource};
 
 /// The maximum number of bytes that we'll allocate space for a return value.
@@ -432,12 +431,25 @@ fn eval_constant(
         source_info: SourceInfo,
     ) -> Option<Const<'tcx>> {
         self.ecx.tcx.span = c.span;
+
+        // FIXME we need to revisit this for #67176
+        if c.needs_subst() {
+            return None;
+        }
+
         match self.ecx.eval_const_to_op(c.literal, None) {
             Ok(op) => Some(op),
             Err(error) => {
                 let err = error_to_const_error(&self.ecx, error);
-                match self.lint_root(source_info) {
-                    Some(lint_root) if c.literal.needs_subst() => {
+                if let Some(lint_root) = self.lint_root(source_info) {
+                    let lint_only = match c.literal.val {
+                        // Promoteds must lint and not error as the user didn't ask for them
+                        ConstKind::Unevaluated(_, _, Some(_)) => true,
+                        // Out of backwards compatibility we cannot report hard errors in unused
+                        // generic functions using associated constants of the generic parameters.
+                        _ => c.literal.needs_subst(),
+                    };
+                    if lint_only {
                         // Out of backwards compatibility we cannot report hard errors in unused
                         // generic functions using associated constants of the generic parameters.
                         err.report_as_lint(
@@ -446,10 +458,11 @@ fn eval_constant(
                             lint_root,
                             Some(c.span),
                         );
-                    }
-                    _ => {
+                    } else {
                         err.report_as_error(self.ecx.tcx, "erroneous constant used");
                     }
+                } else {
+                    err.report_as_error(self.ecx.tcx, "erroneous constant used");
                 }
                 None
             }
@@ -552,6 +565,11 @@ fn const_prop(
             return None;
         }
 
+        // FIXME we need to revisit this for #67176
+        if rvalue.needs_subst() {
+            return None;
+        }
+
         let overflow_check = self.tcx.sess.overflow_checks();
 
         // Perform any special handling for specific Rvalue types.
@@ -707,7 +725,8 @@ fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
                 ScalarMaybeUndef::Scalar(r),
             )) => l.is_bits() && r.is_bits(),
             interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
-                intern_const_alloc_recursive(&mut self.ecx, None, op.assert_mem_place())
+                let mplace = op.assert_mem_place(&self.ecx);
+                intern_const_alloc_recursive(&mut self.ecx, None, mplace, false)
                     .expect("failed to intern alloc");
                 true
             }
@@ -865,9 +884,7 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
                         // doesn't use the invalid value
                         match cond {
                             Operand::Move(ref place) | Operand::Copy(ref place) => {
-                                if let PlaceBase::Local(local) = place.base {
-                                    self.remove_const(local);
-                                }
+                                self.remove_const(place.local);
                             }
                             Operand::Constant(_) => {}
                         }
index 86baf4deb5197e463b9692539389d232416a4aea..b9d9ed592fc72856ad3da1fb16d6d31aecf26b14 100644 (file)
@@ -28,7 +28,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCa
         let param_env = tcx.param_env(src.def_id()).with_reveal_all();
         let move_data = match MoveData::gather_moves(body, tcx, param_env) {
             Ok(move_data) => move_data,
-            Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"),
+            Err((move_data, _)) => {
+                tcx.sess.delay_span_bug(
+                    body.span,
+                    "No `move_errors` should be allowed in MIR borrowck",
+                );
+                move_data
+            }
         };
         let elaborate_patch = {
             let body = &*body;
index 96fb992e53b23631ea4f4479e305cf063ebaf334..825ac4a28d86925a9e2f5266edd961121a7cd402 100644 (file)
@@ -112,17 +112,17 @@ fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if place.base == PlaceBase::Local(self_arg()) {
+        if place.local == self_arg() {
             replace_base(
                 place,
                 Place {
-                    base: PlaceBase::Local(self_arg()),
+                    local: self_arg(),
                     projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Deref]),
                 },
                 self.tcx,
             );
         } else {
-            self.visit_place_base(&mut place.base, context, location);
+            self.visit_place_base(&mut place.local, context, location);
 
             for elem in place.projection.iter() {
                 if let PlaceElem::Index(local) = elem {
@@ -148,11 +148,11 @@ fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if place.base == PlaceBase::Local(self_arg()) {
+        if place.local == self_arg() {
             replace_base(
                 place,
                 Place {
-                    base: PlaceBase::Local(self_arg()),
+                    local: self_arg(),
                     projection: self.tcx().intern_place_elems(&vec![ProjectionElem::Field(
                         Field::new(0),
                         self.ref_gen_ty,
@@ -161,7 +161,7 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, locati
                 self.tcx,
             );
         } else {
-            self.visit_place_base(&mut place.base, context, location);
+            self.visit_place_base(&mut place.local, context, location);
 
             for elem in place.projection.iter() {
                 if let PlaceElem::Index(local) = elem {
@@ -173,7 +173,7 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, locati
 }
 
 fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) {
-    place.base = new_base.base;
+    place.local = new_base.local;
 
     let mut new_projection = new_base.projection.to_vec();
     new_projection.append(&mut place.projection.to_vec());
@@ -236,7 +236,7 @@ fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Pla
         let mut projection = base.projection.to_vec();
         projection.push(ProjectionElem::Field(Field::new(idx), ty));
 
-        Place { base: base.base, projection: self.tcx.intern_place_elems(&projection) }
+        Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) }
     }
 
     // Create a statement which changes the discriminant
@@ -275,20 +275,15 @@ fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
         assert_eq!(self.remap.get(local), None);
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if let PlaceBase::Local(l) = place.base {
-            // Replace an Local in the remap with a generator struct access
-            if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
-                replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
-            }
-        } else {
-            self.visit_place_base(&mut place.base, context, location);
-
-            for elem in place.projection.iter() {
-                if let PlaceElem::Index(local) = elem {
-                    assert_ne!(*local, self_arg());
-                }
-            }
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        _context: PlaceContext,
+        _location: Location,
+    ) {
+        // Replace an Local in the remap with a generator struct access
+        if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) {
+            replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
         }
     }
 
index 3c5d2c9f310bb5675e541d0bd86f803789d96b37..2dd00fe2fee195038aef34f998364cc2d06f262c 100644 (file)
@@ -430,12 +430,7 @@ fn dest_needs_borrow(place: &Place<'_>) -> bool {
                         }
                     }
 
-                    match place.base {
-                        // Static variables need a borrow because the callee
-                        // might modify the same static.
-                        PlaceBase::Static(_) => true,
-                        _ => false,
-                    }
+                    false
                 }
 
                 let dest = if dest_needs_borrow(&destination.0) {
@@ -647,10 +642,7 @@ fn update_target(&self, tgt: BasicBlock) -> BasicBlock {
 
     fn make_integrate_local(&self, local: &Local) -> Local {
         if *local == RETURN_PLACE {
-            match self.destination.base {
-                PlaceBase::Local(l) => return l,
-                PlaceBase::Static(ref s) => bug!("Return place is {:?}, not local", s),
-            }
+            return self.destination.local;
         }
 
         let idx = local.index() - 1;
@@ -672,19 +664,14 @@ fn visit_local(&mut self, local: &mut Local, _ctxt: PlaceContext, _location: Loc
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        match &mut place.base {
-            PlaceBase::Static(_) => {}
-            PlaceBase::Local(l) => {
-                // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
-                let dest_proj_len = self.destination.projection.len();
-                if *l == RETURN_PLACE && dest_proj_len > 0 {
-                    let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
-                    projs.extend(self.destination.projection);
-                    projs.extend(place.projection);
-
-                    place.projection = self.tcx.intern_place_elems(&*projs);
-                }
-            }
+        // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
+        let dest_proj_len = self.destination.projection.len();
+        if place.local == RETURN_PLACE && dest_proj_len > 0 {
+            let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
+            projs.extend(self.destination.projection);
+            projs.extend(place.projection);
+
+            place.projection = self.tcx.intern_place_elems(&*projs);
         }
         // Handles integrating any locals that occur in the base
         // or projections
index a2f3fcea7569a6d50ca2103bf8083756333b74c6..69eedb1ae1876971a62a8b1fc17afd7c8c0ea998 100644 (file)
@@ -3,7 +3,7 @@
 use crate::transform::{MirPass, MirSource};
 use rustc::mir::visit::{MutVisitor, Visitor};
 use rustc::mir::{
-    read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceBase, PlaceRef,
+    read_only, Body, BodyAndCache, Constant, Local, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue,
 };
 use rustc::ty::{self, TyCtxt};
@@ -55,7 +55,7 @@ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
 
                         Place {
                             // Replace with dummy
-                            base: mem::replace(&mut place.base, PlaceBase::Local(Local::new(0))),
+                            local: mem::replace(&mut place.local, Local::new(0)),
                             projection: self.tcx().intern_place_elems(proj_l),
                         }
                     } else {
@@ -92,10 +92,10 @@ fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx>
 impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         if let Rvalue::Ref(_, _, place) = rvalue {
-            if let PlaceRef { base, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
+            if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
                 place.as_ref()
             {
-                if Place::ty_from(base, proj_base, self.body, self.tcx).ty.is_region_ptr() {
+                if Place::ty_from(local, proj_base, self.body, self.tcx).ty.is_region_ptr() {
                     self.optimizations.and_stars.insert(location);
                 }
             }
index 82c31a09ce377ceaf64557cd39447b7de71510d1..22aed9a9e66bd0383e0ebdb50b1f90444ef326ac 100644 (file)
@@ -1,11 +1,12 @@
-use crate::{build, shim};
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use crate::{shim, util};
+use rustc::hir::map::Map;
 use rustc::mir::{BodyAndCache, ConstQualifs, MirPhase, Promoted};
 use rustc::ty::query::Providers;
 use rustc::ty::steal::Steal;
 use rustc::ty::{InstanceDef, TyCtxt, TypeFoldable};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_index::vec::IndexVec;
 use rustc_span::Span;
 use std::borrow::Cow;
@@ -40,7 +41,6 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
     self::check_unsafety::provide(providers);
     *providers = Providers {
         mir_keys,
-        mir_built,
         mir_const,
         mir_const_qualif,
         mir_validated,
@@ -85,7 +85,8 @@ fn visit_variant_data(
             }
             intravisit::walk_struct_def(self, v)
         }
-        fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
+        type Map = Map<'tcx>;
+        fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, Self::Map> {
             NestedVisitorMap::None
         }
     }
@@ -96,11 +97,6 @@ fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
     tcx.arena.alloc(set)
 }
 
-fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
-    let mir = build::mir_build(tcx, def_id);
-    tcx.alloc_steal_mir(mir)
-}
-
 /// Where a specific `mir::Body` comes from.
 #[derive(Debug, Copy, Clone)]
 pub struct MirSource<'tcx> {
@@ -220,6 +216,9 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
     let _ = tcx.unsafety_check_result(def_id);
 
     let mut body = tcx.mir_built(def_id).steal();
+
+    util::dump_mir(tcx, None, "mir_map", &0, MirSource::item(def_id), &body, |_, _| Ok(()));
+
     run_passes(
         tcx,
         &mut body,
index b6656e720c5c35d671652ecfdb7bcdf7667bb6a1..f058ac834ef3457c4b06dac954cfa8ab6e028bc8 100644 (file)
@@ -27,8 +27,9 @@
 use rustc_target::spec::abi::Abi;
 
 use std::cell::Cell;
-use std::{iter, mem, usize};
+use std::{cmp, iter, mem, usize};
 
+use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
 use crate::transform::{MirPass, MirSource};
 
@@ -38,7 +39,7 @@
 /// errors when promotion of `#[rustc_args_required_const]` arguments fails.
 ///
 /// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each
-/// newly created `StaticKind::Promoted`.
+/// newly created `Constant`.
 #[derive(Default)]
 pub struct PromoteTemps<'tcx> {
     pub promoted_fragments: Cell<IndexVec<Promoted, BodyAndCache<'tcx>>>,
@@ -307,18 +308,14 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
 
                         // We can only promote interior borrows of promotable temps (non-temps
                         // don't get promoted anyway).
-                        let base = match place.base {
-                            PlaceBase::Local(local) => local,
-                            _ => return Err(Unpromotable),
-                        };
-                        self.validate_local(base)?;
+                        self.validate_local(place.local)?;
 
                         if place.projection.contains(&ProjectionElem::Deref) {
                             return Err(Unpromotable);
                         }
 
                         let mut has_mut_interior =
-                            self.qualif_local::<qualifs::HasMutInterior>(base);
+                            self.qualif_local::<qualifs::HasMutInterior>(place.local);
                         // HACK(eddyb) this should compute the same thing as
                         // `<HasMutInterior as Qualif>::in_projection` from
                         // `check_consts::qualifs` but without recursion.
@@ -332,7 +329,7 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
                                 // FIXME(eddyb) this is probably excessive, with
                                 // the exception of `union` member accesses.
                                 let ty =
-                                    Place::ty_from(&place.base, proj_base, *self.body, self.tcx)
+                                    Place::ty_from(&place.local, proj_base, *self.body, self.tcx)
                                         .projection_ty(self.tcx, elem)
                                         .ty;
                                 if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
@@ -348,7 +345,7 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
                         if has_mut_interior {
                             return Err(Unpromotable);
                         }
-                        if self.qualif_local::<qualifs::NeedsDrop>(base) {
+                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
                             return Err(Unpromotable);
                         }
 
@@ -478,13 +475,8 @@ fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
 
     fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable> {
         match place {
-            PlaceRef { base: PlaceBase::Local(local), projection: [] } => {
-                self.validate_local(*local)
-            }
-            PlaceRef { base: PlaceBase::Static(_), projection: [] } => {
-                bug!("qualifying already promoted MIR")
-            }
-            PlaceRef { base: _, projection: [proj_base @ .., elem] } => {
+            PlaceRef { local, projection: [] } => self.validate_local(*local),
+            PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
                 match *elem {
                     ProjectionElem::Deref | ProjectionElem::Downcast(..) => {
                         return Err(Unpromotable);
@@ -499,7 +491,7 @@ fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable>
                     ProjectionElem::Field(..) => {
                         if self.const_kind.is_none() {
                             let base_ty =
-                                Place::ty_from(place.base, proj_base, *self.body, self.tcx).ty;
+                                Place::ty_from(place.local, proj_base, *self.body, self.tcx).ty;
                             if let Some(def) = base_ty.ty_adt_def() {
                                 // No promotion of union field accesses.
                                 if def.is_union() {
@@ -510,7 +502,7 @@ fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable>
                     }
                 }
 
-                self.validate_place(PlaceRef { base: place.base, projection: proj_base })
+                self.validate_place(PlaceRef { local: place.local, projection: proj_base })
             }
         }
     }
@@ -597,10 +589,12 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                 // Raw reborrows can come from reference to pointer coercions,
                 // so are allowed.
                 if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
-                    let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, *self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
-                        return self
-                            .validate_place(PlaceRef { base: &place.base, projection: proj_base });
+                        return self.validate_place(PlaceRef {
+                            local: &place.local,
+                            projection: proj_base,
+                        });
                     }
                 }
                 Err(Unpromotable)
@@ -634,9 +628,9 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                 // Special-case reborrows to be more like a copy of the reference.
                 let mut place = place.as_ref();
                 if let [proj_base @ .., ProjectionElem::Deref] = &place.projection {
-                    let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
+                    let base_ty = Place::ty_from(&place.local, proj_base, *self.body, self.tcx).ty;
                     if let ty::Ref(..) = base_ty.kind {
-                        place = PlaceRef { base: &place.base, projection: proj_base };
+                        place = PlaceRef { local: &place.local, projection: proj_base };
                     }
                 }
 
@@ -645,17 +639,15 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                 // HACK(eddyb) this should compute the same thing as
                 // `<HasMutInterior as Qualif>::in_projection` from
                 // `check_consts::qualifs` but without recursion.
-                let mut has_mut_interior = match place.base {
-                    PlaceBase::Local(local) => self.qualif_local::<qualifs::HasMutInterior>(*local),
-                    PlaceBase::Static(_) => false,
-                };
+                let mut has_mut_interior =
+                    self.qualif_local::<qualifs::HasMutInterior>(*place.local);
                 if has_mut_interior {
                     let mut place_projection = place.projection;
                     // FIXME(eddyb) use a forward loop instead of a reverse one.
                     while let [proj_base @ .., elem] = place_projection {
                         // FIXME(eddyb) this is probably excessive, with
                         // the exception of `union` member accesses.
-                        let ty = Place::ty_from(place.base, proj_base, *self.body, self.tcx)
+                        let ty = Place::ty_from(place.local, proj_base, *self.body, self.tcx)
                             .projection_ty(self.tcx, elem)
                             .ty;
                         if ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) {
@@ -702,8 +694,8 @@ fn validate_call(
 
         let is_const_fn = match fn_ty.kind {
             ty::FnDef(def_id, _) => {
-                self.tcx.is_const_fn(def_id)
-                    || self.tcx.is_unstable_const_fn(def_id).is_some()
+                is_const_fn(self.tcx, def_id)
+                    || is_unstable_const_fn(self.tcx, def_id).is_some()
                     || is_lang_panic_fn(self.tcx, self.def_id)
             }
             _ => false,
@@ -760,6 +752,7 @@ struct Promoter<'a, 'tcx> {
     source: &'a mut BodyAndCache<'tcx>,
     promoted: BodyAndCache<'tcx>,
     temps: &'a mut IndexVec<Local, TempState>,
+    extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -902,39 +895,76 @@ fn promote_candidate(
         candidate: Candidate,
         next_promoted_id: usize,
     ) -> Option<BodyAndCache<'tcx>> {
-        let mut operand = {
+        let mut rvalue = {
             let promoted = &mut self.promoted;
             let promoted_id = Promoted::new(next_promoted_id);
             let tcx = self.tcx;
-            let mut promoted_place = |ty, span| {
+            let mut promoted_operand = |ty, span| {
                 promoted.span = span;
                 promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span);
-                Place {
-                    base: PlaceBase::Static(box Static {
-                        kind: StaticKind::Promoted(
-                            promoted_id,
+
+                Operand::Constant(Box::new(Constant {
+                    span,
+                    user_ty: None,
+                    literal: tcx.mk_const(ty::Const {
+                        ty,
+                        val: ty::ConstKind::Unevaluated(
+                            def_id,
                             InternalSubsts::identity_for_item(tcx, def_id),
+                            Some(promoted_id),
                         ),
-                        ty,
-                        def_id,
                     }),
-                    projection: List::empty(),
-                }
+                }))
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
             match candidate {
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
+                        StatementKind::Assign(box (
+                            _,
+                            Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
+                        )) => {
                             // Use the underlying local for this (necessarily interior) borrow.
-                            let ty = place.base.ty(local_decls).ty;
+                            let ty = local_decls.local_decls()[place.local].ty;
                             let span = statement.source_info.span;
 
-                            Operand::Move(Place {
-                                base: mem::replace(&mut place.base, promoted_place(ty, span).base),
-                                projection: List::empty(),
-                            })
+                            let ref_ty = tcx.mk_ref(
+                                tcx.lifetimes.re_erased,
+                                ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
+                            );
+
+                            *region = tcx.lifetimes.re_erased;
+
+                            let mut projection = vec![PlaceElem::Deref];
+                            projection.extend(place.projection);
+                            place.projection = tcx.intern_place_elems(&projection);
+
+                            // Create a temp to hold the promoted reference.
+                            // This is because `*r` requires `r` to be a local,
+                            // otherwise we would use the `promoted` directly.
+                            let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
+                            promoted_ref.source_info = statement.source_info;
+                            let promoted_ref = local_decls.push(promoted_ref);
+                            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+
+                            let promoted_ref_statement = Statement {
+                                source_info: statement.source_info,
+                                kind: StatementKind::Assign(Box::new((
+                                    Place::from(promoted_ref),
+                                    Rvalue::Use(promoted_operand(ref_ty, span)),
+                                ))),
+                            };
+                            self.extra_statements.push((loc, promoted_ref_statement));
+
+                            Rvalue::Ref(
+                                tcx.lifetimes.re_erased,
+                                borrow_kind,
+                                Place {
+                                    local: mem::replace(&mut place.local, promoted_ref),
+                                    projection: List::empty(),
+                                },
+                            )
                         }
                         _ => bug!(),
                     }
@@ -945,7 +975,8 @@ fn promote_candidate(
                         StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => {
                             let ty = operand.ty(local_decls, self.tcx);
                             let span = statement.source_info.span;
-                            mem::replace(operand, Operand::Copy(promoted_place(ty, span)))
+
+                            Rvalue::Use(mem::replace(operand, promoted_operand(ty, span)))
                         }
                         _ => bug!(),
                     }
@@ -956,8 +987,8 @@ fn promote_candidate(
                         TerminatorKind::Call { ref mut args, .. } => {
                             let ty = args[index].ty(local_decls, self.tcx);
                             let span = terminator.source_info.span;
-                            let operand = Operand::Copy(promoted_place(ty, span));
-                            mem::replace(&mut args[index], operand)
+
+                            Rvalue::Use(mem::replace(&mut args[index], promoted_operand(ty, span)))
                         }
                         // We expected a `TerminatorKind::Call` for which we'd like to promote an
                         // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
@@ -974,13 +1005,13 @@ fn promote_candidate(
         };
 
         assert_eq!(self.new_block(), START_BLOCK);
-        self.visit_operand(
-            &mut operand,
+        self.visit_rvalue(
+            &mut rvalue,
             Location { block: BasicBlock::new(0), statement_index: usize::MAX },
         );
 
         let span = self.promoted.span;
-        self.assign(RETURN_PLACE, Rvalue::Use(operand), span);
+        self.assign(RETURN_PLACE, rvalue, span);
         Some(self.promoted)
     }
 }
@@ -1019,6 +1050,7 @@ pub fn promote_candidates<'tcx>(
 
     let mut promotions = IndexVec::new();
 
+    let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
         match candidate {
             Candidate::Repeat(Location { block, statement_index })
@@ -1042,23 +1074,27 @@ pub fn promote_candidates<'tcx>(
         let initial_locals =
             iter::once(LocalDecl::new_return_place(tcx.types.never, body.span)).collect();
 
+        let mut promoted = Body::new(
+            IndexVec::new(),
+            // FIXME: maybe try to filter this to avoid blowing up
+            // memory usage?
+            body.source_scopes.clone(),
+            initial_locals,
+            IndexVec::new(),
+            0,
+            vec![],
+            body.span,
+            vec![],
+            body.generator_kind,
+        );
+        promoted.ignore_interior_mut_in_const_validation = true;
+
         let promoter = Promoter {
-            promoted: BodyAndCache::new(Body::new(
-                IndexVec::new(),
-                // FIXME: maybe try to filter this to avoid blowing up
-                // memory usage?
-                body.source_scopes.clone(),
-                initial_locals,
-                IndexVec::new(),
-                0,
-                vec![],
-                body.span,
-                vec![],
-                body.generator_kind,
-            )),
+            promoted: BodyAndCache::new(promoted),
             tcx,
             source: body,
             temps: &mut temps,
+            extra_statements: &mut extra_statements,
             keep_original: false,
         };
 
@@ -1068,6 +1104,13 @@ pub fn promote_candidates<'tcx>(
         }
     }
 
+    // Insert each of `extra_statements` before its indicated location, which
+    // has to be done in reverse location order, to not invalidate the rest.
+    extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc));
+    for (loc, statement) in extra_statements {
+        body[loc.block].statements.insert(loc.statement_index, statement);
+    }
+
     // Eliminate assignments to, and drops of promoted temps.
     let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in body.basic_blocks_mut() {
index 9dea44e02001095daca56d5b9b2c9b79260f4654..7034556740849f7a260e3baa5f034117cf0ca043 100644 (file)
@@ -261,7 +261,7 @@ fn check_place(
             ProjectionElem::Downcast(_symbol, _variant_index) => {}
 
             ProjectionElem::Field(..) => {
-                let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty;
+                let base_ty = Place::ty_from(&place.local, &proj_base, body, tcx).ty;
                 if let Some(def) = base_ty.ty_adt_def() {
                     // No union field accesses in `const fn`
                     if def.is_union() {
@@ -281,8 +281,22 @@ fn check_place(
     Ok(())
 }
 
-/// Returns whether `allow_internal_unstable(..., <feature_gate>, ...)` is present.
+/// Returns `true` if the given feature gate is allowed within the function with the given `DefId`.
 fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
+    // All features require that the corresponding gate be enabled,
+    // even if the function has `#[allow_internal_unstable(the_gate)]`.
+    if !tcx.features().enabled(feature_gate) {
+        return false;
+    }
+
+    // If this crate is not using stability attributes, or this function is not claiming to be a
+    // stable `const fn`, that is all that is required.
+    if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
+        return true;
+    }
+
+    // However, we cannot allow stable `const fn`s to use unstable features without an explicit
+    // opt-in via `allow_internal_unstable`.
     attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
         .map_or(false, |mut features| features.any(|name| name == feature_gate))
 }
@@ -327,7 +341,7 @@ fn check_terminator(
         TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(def_id, _) = fn_ty.kind {
-                if !tcx.is_min_const_fn(def_id) {
+                if !crate::const_eval::is_min_const_fn(tcx, def_id) {
                     return Err((
                         span,
                         format!(
index fb7f4fac4dca48769813bc24d8b22f06c6e7a20c..ddf8d73e5481f82d1ecbccc8f8cb8defc2d2adf1 100644 (file)
@@ -388,13 +388,7 @@ fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockDat
         // Remove unnecessary StorageLive and StorageDead annotations.
         data.statements.retain(|stmt| match &stmt.kind {
             StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => self.map[*l].is_some(),
-            StatementKind::Assign(box (place, _)) => {
-                if let PlaceBase::Local(local) = place.base {
-                    self.map[local].is_some()
-                } else {
-                    true
-                }
-            }
+            StatementKind::Assign(box (place, _)) => self.map[place.local].is_some(),
             _ => true,
         });
         self.super_basic_block_data(block, data);
index 3b8871f86b28924073e09373eeecf91d87c48220..e733b0a5b5928dffdd04d888ceb5f591a56d9863 100644 (file)
@@ -137,9 +137,9 @@ struct VarField<'tcx> {
 fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
     match place.as_ref() {
         PlaceRef {
-            base: &PlaceBase::Local(local),
+            local,
             projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
-        } => Some((local, VarField { field, field_ty: ty, var_idx })),
+        } => Some((*local, VarField { field, field_ty: ty, var_idx })),
         _ => None,
     }
 }
index 70d6aaf70eb09c87399dbc1e0d5e9e2d825e602f..e17c7a80f1a7617184e26ac3c6768a0dd1ae65bc 100644 (file)
@@ -46,7 +46,7 @@ fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: &Place<'
             // encountered a Deref, which is ABI-aligned
             ProjectionElem::Deref => break,
             ProjectionElem::Field(..) => {
-                let ty = Place::ty_from(&place.base, proj_base, local_decls, tcx).ty;
+                let ty = Place::ty_from(&place.local, proj_base, local_decls, tcx).ty;
                 match ty.kind {
                     ty::Adt(def, _) if def.repr.packed() => return true,
                     _ => {}
index 9f67109b34a1bbe1260b4929d8756d65475f397f..c275eecfb33b629f574d521ef0a03f8e843e911b 100644 (file)
@@ -1,8 +1,7 @@
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc_errors::{DiagnosticBuilder, DiagnosticId};
-use rustc_span::{MultiSpan, Span};
-
 use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId};
+use rustc_span::{MultiSpan, Span};
 
 impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> {
     crate fn cannot_move_when_borrowed(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> {
diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml
new file mode 100644 (file)
index 0000000..79c7303
--- /dev/null
@@ -0,0 +1,28 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_mir_build"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+name = "rustc_mir_build"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+arena = { path = "../libarena" }
+itertools = "0.8"
+log = "0.4"
+rustc = { path = "../librustc" }
+rustc_apfloat = { path = "../librustc_apfloat" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_index = { path = "../librustc_index" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_hir = { path = "../librustc_hir" }
+rustc_macros = { path = "../librustc_macros" }
+rustc_serialize = { path = "../libserialize", package = "serialize" }
+rustc_span = { path = "../librustc_span" }
+rustc_target = { path = "../librustc_target" }
+syntax = { path = "../libsyntax" }
+smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs
new file mode 100644 (file)
index 0000000..c517d31
--- /dev/null
@@ -0,0 +1,236 @@
+use crate::build::matches::ArmHasGuard;
+use crate::build::ForGuard::OutsideGuard;
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
+use crate::hair::*;
+use rustc::mir::*;
+use rustc_hir as hir;
+use rustc_span::Span;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    crate fn ast_block(
+        &mut self,
+        destination: &Place<'tcx>,
+        block: BasicBlock,
+        ast_block: &'tcx hir::Block<'tcx>,
+        source_info: SourceInfo,
+    ) -> BlockAnd<()> {
+        let Block {
+            region_scope,
+            opt_destruction_scope,
+            span,
+            stmts,
+            expr,
+            targeted_by_break,
+            safety_mode,
+        } = self.hir.mirror(ast_block);
+        self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
+            this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
+                if targeted_by_break {
+                    // This is a `break`-able block
+                    let exit_block = this.cfg.start_new_block();
+                    let block_exit =
+                        this.in_breakable_scope(None, exit_block, destination.clone(), |this| {
+                            this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
+                        });
+                    this.cfg.goto(unpack!(block_exit), source_info, exit_block);
+                    exit_block.unit()
+                } else {
+                    this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
+                }
+            })
+        })
+    }
+
+    fn ast_block_stmts(
+        &mut self,
+        destination: &Place<'tcx>,
+        mut block: BasicBlock,
+        span: Span,
+        stmts: Vec<StmtRef<'tcx>>,
+        expr: Option<ExprRef<'tcx>>,
+        safety_mode: BlockSafety,
+    ) -> BlockAnd<()> {
+        let this = self;
+
+        // This convoluted structure is to avoid using recursion as we walk down a list
+        // of statements. Basically, the structure we get back is something like:
+        //
+        //    let x = <init> in {
+        //       expr1;
+        //       let y = <init> in {
+        //           expr2;
+        //           expr3;
+        //           ...
+        //       }
+        //    }
+        //
+        // The let bindings are valid till the end of block so all we have to do is to pop all
+        // the let-scopes at the end.
+        //
+        // First we build all the statements in the block.
+        let mut let_scope_stack = Vec::with_capacity(8);
+        let outer_source_scope = this.source_scope;
+        let outer_push_unsafe_count = this.push_unsafe_count;
+        let outer_unpushed_unsafe = this.unpushed_unsafe;
+        this.update_source_scope_for_safety_mode(span, safety_mode);
+
+        let source_info = this.source_info(span);
+        for stmt in stmts {
+            let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
+            match kind {
+                StmtKind::Expr { scope, expr } => {
+                    this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
+                    unpack!(
+                        block = this.in_opt_scope(
+                            opt_destruction_scope.map(|de| (de, source_info)),
+                            |this| {
+                                let si = (scope, source_info);
+                                this.in_scope(si, LintLevel::Inherited, |this| {
+                                    let expr = this.hir.mirror(expr);
+                                    this.stmt_expr(block, expr, Some(scope))
+                                })
+                            }
+                        )
+                    );
+                }
+                StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => {
+                    let ignores_expr_result =
+                        if let PatKind::Wild = *pattern.kind { true } else { false };
+                    this.block_context.push(BlockFrame::Statement { ignores_expr_result });
+
+                    // Enter the remainder scope, i.e., the bindings' destruction scope.
+                    this.push_scope((remainder_scope, source_info));
+                    let_scope_stack.push(remainder_scope);
+
+                    // Declare the bindings, which may create a source scope.
+                    let remainder_span =
+                        remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree);
+
+                    let visibility_scope =
+                        Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
+
+                    // Evaluate the initializer, if present.
+                    if let Some(init) = initializer {
+                        let initializer_span = init.span();
+
+                        unpack!(
+                            block = this.in_opt_scope(
+                                opt_destruction_scope.map(|de| (de, source_info)),
+                                |this| {
+                                    let scope = (init_scope, source_info);
+                                    this.in_scope(scope, lint_level, |this| {
+                                        this.declare_bindings(
+                                            visibility_scope,
+                                            remainder_span,
+                                            &pattern,
+                                            ArmHasGuard(false),
+                                            Some((None, initializer_span)),
+                                        );
+                                        this.expr_into_pattern(block, pattern, init)
+                                    })
+                                }
+                            )
+                        );
+                    } else {
+                        let scope = (init_scope, source_info);
+                        unpack!(this.in_scope(scope, lint_level, |this| {
+                            this.declare_bindings(
+                                visibility_scope,
+                                remainder_span,
+                                &pattern,
+                                ArmHasGuard(false),
+                                None,
+                            );
+                            block.unit()
+                        }));
+
+                        debug!("ast_block_stmts: pattern={:?}", pattern);
+                        this.visit_bindings(
+                            &pattern,
+                            UserTypeProjections::none(),
+                            &mut |this, _, _, _, node, span, _, _| {
+                                this.storage_live_binding(block, node, span, OutsideGuard);
+                                this.schedule_drop_for_binding(node, span, OutsideGuard);
+                            },
+                        )
+                    }
+
+                    // Enter the visibility scope, after evaluating the initializer.
+                    if let Some(source_scope) = visibility_scope {
+                        this.source_scope = source_scope;
+                    }
+                }
+            }
+
+            let popped = this.block_context.pop();
+            assert!(popped.map_or(false, |bf| bf.is_statement()));
+        }
+
+        // Then, the block may have an optional trailing expression which is a “return” value
+        // of the block, which is stored into `destination`.
+        let tcx = this.hir.tcx();
+        let destination_ty = destination.ty(&this.local_decls, tcx).ty;
+        if let Some(expr) = expr {
+            let tail_result_is_ignored =
+                destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
+            this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored });
+
+            unpack!(block = this.into(destination, block, expr));
+            let popped = this.block_context.pop();
+
+            assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
+        } else {
+            // If a block has no trailing expression, then it is given an implicit return type.
+            // This return type is usually `()`, unless the block is diverging, in which case the
+            // return type is `!`. For the unit type, we need to actually return the unit, but in
+            // the case of `!`, no return value is required, as the block will never return.
+            if destination_ty.is_unit() {
+                // We only want to assign an implicit `()` as the return value of the block if the
+                // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
+                this.cfg.push_assign_unit(block, source_info, destination);
+            }
+        }
+        // Finally, we pop all the let scopes before exiting out from the scope of block
+        // itself.
+        for scope in let_scope_stack.into_iter().rev() {
+            unpack!(block = this.pop_scope((scope, source_info), block));
+        }
+        // Restore the original source scope.
+        this.source_scope = outer_source_scope;
+        this.push_unsafe_count = outer_push_unsafe_count;
+        this.unpushed_unsafe = outer_unpushed_unsafe;
+        block.unit()
+    }
+
+    /// If we are changing the safety mode, create a new source scope
+    fn update_source_scope_for_safety_mode(&mut self, span: Span, safety_mode: BlockSafety) {
+        debug!("update_source_scope_for({:?}, {:?})", span, safety_mode);
+        let new_unsafety = match safety_mode {
+            BlockSafety::Safe => None,
+            BlockSafety::ExplicitUnsafe(hir_id) => {
+                assert_eq!(self.push_unsafe_count, 0);
+                match self.unpushed_unsafe {
+                    Safety::Safe => {}
+                    _ => return,
+                }
+                self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id);
+                Some(Safety::ExplicitUnsafe(hir_id))
+            }
+            BlockSafety::PushUnsafe => {
+                self.push_unsafe_count += 1;
+                Some(Safety::BuiltinUnsafe)
+            }
+            BlockSafety::PopUnsafe => {
+                self.push_unsafe_count = self
+                    .push_unsafe_count
+                    .checked_sub(1)
+                    .unwrap_or_else(|| span_bug!(span, "unsafe count underflow"));
+                if self.push_unsafe_count == 0 { Some(self.unpushed_unsafe) } else { None }
+            }
+        };
+
+        if let Some(unsafety) = new_unsafety {
+            self.source_scope = self.new_source_scope(span, LintLevel::Inherited, Some(unsafety));
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/cfg.rs b/src/librustc_mir_build/build/cfg.rs
new file mode 100644 (file)
index 0000000..e197110
--- /dev/null
@@ -0,0 +1,102 @@
+//! Routines for manipulating the control-flow graph.
+
+use crate::build::CFG;
+use rustc::mir::*;
+
+impl<'tcx> CFG<'tcx> {
+    crate fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
+        &self.basic_blocks[blk]
+    }
+
+    crate fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
+        &mut self.basic_blocks[blk]
+    }
+
+    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
+    // it as #[inline(never)] to keep rustc's stack use in check.
+    #[inline(never)]
+    crate fn start_new_block(&mut self) -> BasicBlock {
+        self.basic_blocks.push(BasicBlockData::new(None))
+    }
+
+    crate fn start_new_cleanup_block(&mut self) -> BasicBlock {
+        let bb = self.start_new_block();
+        self.block_data_mut(bb).is_cleanup = true;
+        bb
+    }
+
+    crate fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
+        debug!("push({:?}, {:?})", block, statement);
+        self.block_data_mut(block).statements.push(statement);
+    }
+
+    crate fn push_assign(
+        &mut self,
+        block: BasicBlock,
+        source_info: SourceInfo,
+        place: &Place<'tcx>,
+        rvalue: Rvalue<'tcx>,
+    ) {
+        self.push(
+            block,
+            Statement { source_info, kind: StatementKind::Assign(box (place.clone(), rvalue)) },
+        );
+    }
+
+    crate fn push_assign_constant(
+        &mut self,
+        block: BasicBlock,
+        source_info: SourceInfo,
+        temp: &Place<'tcx>,
+        constant: Constant<'tcx>,
+    ) {
+        self.push_assign(block, source_info, temp, Rvalue::Use(Operand::Constant(box constant)));
+    }
+
+    crate fn push_assign_unit(
+        &mut self,
+        block: BasicBlock,
+        source_info: SourceInfo,
+        place: &Place<'tcx>,
+    ) {
+        self.push_assign(
+            block,
+            source_info,
+            place,
+            Rvalue::Aggregate(box AggregateKind::Tuple, vec![]),
+        );
+    }
+
+    crate fn push_fake_read(
+        &mut self,
+        block: BasicBlock,
+        source_info: SourceInfo,
+        cause: FakeReadCause,
+        place: Place<'tcx>,
+    ) {
+        let kind = StatementKind::FakeRead(cause, box place);
+        let stmt = Statement { source_info, kind };
+        self.push(block, stmt);
+    }
+
+    crate fn terminate(
+        &mut self,
+        block: BasicBlock,
+        source_info: SourceInfo,
+        kind: TerminatorKind<'tcx>,
+    ) {
+        debug!("terminating block {:?} <- {:?}", block, kind);
+        debug_assert!(
+            self.block_data(block).terminator.is_none(),
+            "terminate: block {:?}={:?} already has a terminator set",
+            block,
+            self.block_data(block)
+        );
+        self.block_data_mut(block).terminator = Some(Terminator { source_info, kind });
+    }
+
+    /// In the `origin` block, push a `goto -> target` terminator.
+    crate fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) {
+        self.terminate(origin, source_info, TerminatorKind::Goto { target })
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/as_constant.rs b/src/librustc_mir_build/build/expr/as_constant.rs
new file mode 100644 (file)
index 0000000..e485626
--- /dev/null
@@ -0,0 +1,39 @@
+//! See docs in build/expr/mod.rs
+
+use crate::build::Builder;
+use crate::hair::*;
+use rustc::mir::*;
+use rustc::ty::CanonicalUserTypeAnnotation;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Compile `expr`, yielding a compile-time constant. Assumes that
+    /// `expr` is a valid compile-time constant!
+    crate fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let expr = self.hir.mirror(expr);
+        self.expr_as_constant(expr)
+    }
+
+    fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
+        let this = self;
+        let Expr { ty, temp_lifetime: _, span, kind } = expr;
+        match kind {
+            ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value),
+            ExprKind::Literal { literal, user_ty } => {
+                let user_ty = user_ty.map(|user_ty| {
+                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+                        span,
+                        user_ty,
+                        inferred_ty: ty,
+                    })
+                });
+                assert_eq!(literal.ty, ty);
+                Constant { span, user_ty, literal }
+            }
+            ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal },
+            _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/as_operand.rs b/src/librustc_mir_build/build/expr/as_operand.rs
new file mode 100644 (file)
index 0000000..efe328d
--- /dev/null
@@ -0,0 +1,72 @@
+//! See docs in build/expr/mod.rs
+
+use crate::build::expr::category::Category;
+use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::hair::*;
+use rustc::middle::region;
+use rustc::mir::*;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Returns an operand suitable for use until the end of the current
+    /// scope expression.
+    ///
+    /// The operand returned from this function will *not be valid* after
+    /// an ExprKind::Scope is passed, so please do *not* return it from
+    /// functions to avoid bad miscompiles.
+    crate fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let local_scope = self.local_scope();
+        self.as_operand(block, local_scope, expr)
+    }
+
+    /// Compile `expr` into a value that can be used as an operand.
+    /// If `expr` is a place like `x`, this will introduce a
+    /// temporary `tmp = x`, so that we capture the value of `x` at
+    /// this time.
+    ///
+    /// The operand is known to be live until the end of `scope`.
+    crate fn as_operand<M>(
+        &mut self,
+        block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: M,
+    ) -> BlockAnd<Operand<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let expr = self.hir.mirror(expr);
+        self.expr_as_operand(block, scope, expr)
+    }
+
+    fn expr_as_operand(
+        &mut self,
+        mut block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: Expr<'tcx>,
+    ) -> BlockAnd<Operand<'tcx>> {
+        debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
+        let this = self;
+
+        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
+            let source_info = this.source_info(expr.span);
+            let region_scope = (region_scope, source_info);
+            return this
+                .in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value));
+        }
+
+        let category = Category::of(&expr.kind).unwrap();
+        debug!("expr_as_operand: category={:?} for={:?}", category, expr.kind);
+        match category {
+            Category::Constant => {
+                let constant = this.as_constant(expr);
+                block.and(Operand::Constant(box constant))
+            }
+            Category::Place | Category::Rvalue(..) => {
+                let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
+                block.and(Operand::Move(Place::from(operand)))
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/as_place.rs b/src/librustc_mir_build/build/expr/as_place.rs
new file mode 100644 (file)
index 0000000..fd6882f
--- /dev/null
@@ -0,0 +1,441 @@
+//! See docs in build/expr/mod.rs
+
+use crate::build::expr::category::Category;
+use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
+use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::hair::*;
+use rustc::middle::region;
+use rustc::mir::interpret::PanicInfo::BoundsCheck;
+use rustc::mir::*;
+use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
+use rustc_span::Span;
+
+use rustc_index::vec::Idx;
+
+/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
+/// place by pushing more and more projections onto the end, and then convert the final set into a
+/// place using the `into_place` method.
+///
+/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
+/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
+#[derive(Clone)]
+struct PlaceBuilder<'tcx> {
+    local: Local,
+    projection: Vec<PlaceElem<'tcx>>,
+}
+
+impl<'tcx> PlaceBuilder<'tcx> {
+    fn into_place(self, tcx: TyCtxt<'tcx>) -> Place<'tcx> {
+        Place { local: self.local, projection: tcx.intern_place_elems(&self.projection) }
+    }
+
+    fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
+        self.project(PlaceElem::Field(f, ty))
+    }
+
+    fn deref(self) -> Self {
+        self.project(PlaceElem::Deref)
+    }
+
+    fn index(self, index: Local) -> Self {
+        self.project(PlaceElem::Index(index))
+    }
+
+    fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
+        self.projection.push(elem);
+        self
+    }
+}
+
+impl<'tcx> From<Local> for PlaceBuilder<'tcx> {
+    fn from(local: Local) -> Self {
+        Self { local, projection: Vec::new() }
+    }
+}
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Compile `expr`, yielding a place that we can move from etc.
+    ///
+    /// WARNING: Any user code might:
+    /// * Invalidate any slice bounds checks performed.
+    /// * Change the address that this `Place` refers to.
+    /// * Modify the memory that this place refers to.
+    /// * Invalidate the memory that this place refers to, this will be caught
+    ///   by borrow checking.
+    ///
+    /// Extra care is needed if any user code is allowed to run between calling
+    /// this method and using it, as is the case for `match` and index
+    /// expressions.
+    crate fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let place_builder = unpack!(block = self.as_place_builder(block, expr));
+        block.and(place_builder.into_place(self.hir.tcx()))
+    }
+
+    /// This is used when constructing a compound `Place`, so that we can avoid creating
+    /// intermediate `Place` values until we know the full set of projections.
+    fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let expr = self.hir.mirror(expr);
+        self.expr_as_place(block, expr, Mutability::Mut, None)
+    }
+
+    /// Compile `expr`, yielding a place that we can move from etc.
+    /// Mutability note: The caller of this method promises only to read from the resulting
+    /// place. The place itself may or may not be mutable:
+    /// * If this expr is a place expr like a.b, then we will return that place.
+    /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
+    crate fn as_read_only_place<M>(
+        &mut self,
+        mut block: BasicBlock,
+        expr: M,
+    ) -> BlockAnd<Place<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
+        block.and(place_builder.into_place(self.hir.tcx()))
+    }
+
+    /// This is used when constructing a compound `Place`, so that we can avoid creating
+    /// intermediate `Place` values until we know the full set of projections.
+    /// Mutability note: The caller of this method promises only to read from the resulting
+    /// place. The place itself may or may not be mutable:
+    /// * If this expr is a place expr like a.b, then we will return that place.
+    /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
+    fn as_read_only_place_builder<M>(
+        &mut self,
+        block: BasicBlock,
+        expr: M,
+    ) -> BlockAnd<PlaceBuilder<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let expr = self.hir.mirror(expr);
+        self.expr_as_place(block, expr, Mutability::Not, None)
+    }
+
+    fn expr_as_place(
+        &mut self,
+        mut block: BasicBlock,
+        expr: Expr<'tcx>,
+        mutability: Mutability,
+        fake_borrow_temps: Option<&mut Vec<Local>>,
+    ) -> BlockAnd<PlaceBuilder<'tcx>> {
+        debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability);
+
+        let this = self;
+        let expr_span = expr.span;
+        let source_info = this.source_info(expr_span);
+        match expr.kind {
+            ExprKind::Scope { region_scope, lint_level, value } => {
+                this.in_scope((region_scope, source_info), lint_level, |this| {
+                    let value = this.hir.mirror(value);
+                    this.expr_as_place(block, value, mutability, fake_borrow_temps)
+                })
+            }
+            ExprKind::Field { lhs, name } => {
+                let lhs = this.hir.mirror(lhs);
+                let place_builder =
+                    unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
+                block.and(place_builder.field(name, expr.ty))
+            }
+            ExprKind::Deref { arg } => {
+                let arg = this.hir.mirror(arg);
+                let place_builder =
+                    unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
+                block.and(place_builder.deref())
+            }
+            ExprKind::Index { lhs, index } => this.lower_index_expression(
+                block,
+                lhs,
+                index,
+                mutability,
+                fake_borrow_temps,
+                expr.temp_lifetime,
+                expr_span,
+                source_info,
+            ),
+            ExprKind::SelfRef => block.and(PlaceBuilder::from(Local::new(1))),
+            ExprKind::VarRef { id } => {
+                let place_builder = if this.is_bound_var_in_guard(id) {
+                    let index = this.var_local_id(id, RefWithinGuard);
+                    PlaceBuilder::from(index).deref()
+                } else {
+                    let index = this.var_local_id(id, OutsideGuard);
+                    PlaceBuilder::from(index)
+                };
+                block.and(place_builder)
+            }
+
+            ExprKind::PlaceTypeAscription { source, user_ty } => {
+                let source = this.hir.mirror(source);
+                let place_builder = unpack!(
+                    block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
+                );
+                if let Some(user_ty) = user_ty {
+                    let annotation_index =
+                        this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+                            span: source_info.span,
+                            user_ty,
+                            inferred_ty: expr.ty,
+                        });
+
+                    let place = place_builder.clone().into_place(this.hir.tcx());
+                    this.cfg.push(
+                        block,
+                        Statement {
+                            source_info,
+                            kind: StatementKind::AscribeUserType(
+                                box (
+                                    place,
+                                    UserTypeProjection { base: annotation_index, projs: vec![] },
+                                ),
+                                Variance::Invariant,
+                            ),
+                        },
+                    );
+                }
+                block.and(place_builder)
+            }
+            ExprKind::ValueTypeAscription { source, user_ty } => {
+                let source = this.hir.mirror(source);
+                let temp =
+                    unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
+                if let Some(user_ty) = user_ty {
+                    let annotation_index =
+                        this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+                            span: source_info.span,
+                            user_ty,
+                            inferred_ty: expr.ty,
+                        });
+                    this.cfg.push(
+                        block,
+                        Statement {
+                            source_info,
+                            kind: StatementKind::AscribeUserType(
+                                box (
+                                    Place::from(temp.clone()),
+                                    UserTypeProjection { base: annotation_index, projs: vec![] },
+                                ),
+                                Variance::Invariant,
+                            ),
+                        },
+                    );
+                }
+                block.and(PlaceBuilder::from(temp))
+            }
+
+            ExprKind::Array { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Adt { .. }
+            | ExprKind::Closure { .. }
+            | ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
+            | ExprKind::LogicalOp { .. }
+            | ExprKind::Box { .. }
+            | ExprKind::Cast { .. }
+            | ExprKind::Use { .. }
+            | ExprKind::NeverToAny { .. }
+            | ExprKind::Pointer { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::AddressOf { .. }
+            | ExprKind::Match { .. }
+            | ExprKind::Loop { .. }
+            | ExprKind::Block { .. }
+            | ExprKind::Assign { .. }
+            | ExprKind::AssignOp { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Return { .. }
+            | ExprKind::Literal { .. }
+            | ExprKind::StaticRef { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::Yield { .. }
+            | ExprKind::Call { .. } => {
+                // these are not places, so we need to make a temporary.
+                debug_assert!(match Category::of(&expr.kind) {
+                    Some(Category::Place) => false,
+                    _ => true,
+                });
+                let temp =
+                    unpack!(block = this.as_temp(block, expr.temp_lifetime, expr, mutability));
+                block.and(PlaceBuilder::from(temp))
+            }
+        }
+    }
+
+    /// Lower an index expression
+    ///
+    /// This has two complications;
+    ///
+    /// * We need to do a bounds check.
+    /// * We need to ensure that the bounds check can't be invalidated using an
+    ///   expression like `x[1][{x = y; 2}]`. We use fake borrows here to ensure
+    ///   that this is the case.
+    fn lower_index_expression(
+        &mut self,
+        mut block: BasicBlock,
+        base: ExprRef<'tcx>,
+        index: ExprRef<'tcx>,
+        mutability: Mutability,
+        fake_borrow_temps: Option<&mut Vec<Local>>,
+        temp_lifetime: Option<region::Scope>,
+        expr_span: Span,
+        source_info: SourceInfo,
+    ) -> BlockAnd<PlaceBuilder<'tcx>> {
+        let lhs = self.hir.mirror(base);
+
+        let base_fake_borrow_temps = &mut Vec::new();
+        let is_outermost_index = fake_borrow_temps.is_none();
+        let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
+
+        let base_place =
+            unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),));
+
+        // Making this a *fresh* temporary means we do not have to worry about
+        // the index changing later: Nothing will ever change this temporary.
+        // The "retagging" transformation (for Stacked Borrows) relies on this.
+        let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,));
+
+        block = self.bounds_check(
+            block,
+            base_place.clone().into_place(self.hir.tcx()),
+            idx,
+            expr_span,
+            source_info,
+        );
+
+        if is_outermost_index {
+            self.read_fake_borrows(block, fake_borrow_temps, source_info)
+        } else {
+            self.add_fake_borrows_of_base(
+                &base_place,
+                block,
+                fake_borrow_temps,
+                expr_span,
+                source_info,
+            );
+        }
+
+        block.and(base_place.index(idx))
+    }
+
+    fn bounds_check(
+        &mut self,
+        block: BasicBlock,
+        slice: Place<'tcx>,
+        index: Local,
+        expr_span: Span,
+        source_info: SourceInfo,
+    ) -> BasicBlock {
+        let usize_ty = self.hir.usize_ty();
+        let bool_ty = self.hir.bool_ty();
+        // bounds check:
+        let len = self.temp(usize_ty, expr_span);
+        let lt = self.temp(bool_ty, expr_span);
+
+        // len = len(slice)
+        self.cfg.push_assign(block, source_info, &len, Rvalue::Len(slice));
+        // lt = idx < len
+        self.cfg.push_assign(
+            block,
+            source_info,
+            &lt,
+            Rvalue::BinaryOp(
+                BinOp::Lt,
+                Operand::Copy(Place::from(index)),
+                Operand::Copy(len.clone()),
+            ),
+        );
+        let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
+        // assert!(lt, "...")
+        self.assert(block, Operand::Move(lt), true, msg, expr_span)
+    }
+
+    fn add_fake_borrows_of_base(
+        &mut self,
+        base_place: &PlaceBuilder<'tcx>,
+        block: BasicBlock,
+        fake_borrow_temps: &mut Vec<Local>,
+        expr_span: Span,
+        source_info: SourceInfo,
+    ) {
+        let tcx = self.hir.tcx();
+        let place_ty =
+            Place::ty_from(&base_place.local, &base_place.projection, &self.local_decls, tcx);
+        if let ty::Slice(_) = place_ty.ty.kind {
+            // We need to create fake borrows to ensure that the bounds
+            // check that we just did stays valid. Since we can't assign to
+            // unsized values, we only need to ensure that none of the
+            // pointers in the base place are modified.
+            for (idx, elem) in base_place.projection.iter().enumerate().rev() {
+                match elem {
+                    ProjectionElem::Deref => {
+                        let fake_borrow_deref_ty = Place::ty_from(
+                            &base_place.local,
+                            &base_place.projection[..idx],
+                            &self.local_decls,
+                            tcx,
+                        )
+                        .ty;
+                        let fake_borrow_ty =
+                            tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
+                        let fake_borrow_temp =
+                            self.local_decls.push(LocalDecl::new_temp(fake_borrow_ty, expr_span));
+                        let projection = tcx.intern_place_elems(&base_place.projection[..idx]);
+                        self.cfg.push_assign(
+                            block,
+                            source_info,
+                            &fake_borrow_temp.into(),
+                            Rvalue::Ref(
+                                tcx.lifetimes.re_erased,
+                                BorrowKind::Shallow,
+                                Place { local: base_place.local.clone(), projection },
+                            ),
+                        );
+                        fake_borrow_temps.push(fake_borrow_temp);
+                    }
+                    ProjectionElem::Index(_) => {
+                        let index_ty = Place::ty_from(
+                            &base_place.local,
+                            &base_place.projection[..idx],
+                            &self.local_decls,
+                            tcx,
+                        );
+                        match index_ty.ty.kind {
+                            // The previous index expression has already
+                            // done any index expressions needed here.
+                            ty::Slice(_) => break,
+                            ty::Array(..) => (),
+                            _ => bug!("unexpected index base"),
+                        }
+                    }
+                    ProjectionElem::Field(..)
+                    | ProjectionElem::Downcast(..)
+                    | ProjectionElem::ConstantIndex { .. }
+                    | ProjectionElem::Subslice { .. } => (),
+                }
+            }
+        }
+    }
+
+    fn read_fake_borrows(
+        &mut self,
+        bb: BasicBlock,
+        fake_borrow_temps: &mut Vec<Local>,
+        source_info: SourceInfo,
+    ) {
+        // All indexes have been evaluated now, read all of the
+        // fake borrows so that they are live across those index
+        // expressions.
+        for temp in fake_borrow_temps {
+            self.cfg.push_fake_read(bb, source_info, FakeReadCause::ForIndex, Place::from(*temp));
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/src/librustc_mir_build/build/expr/as_rvalue.rs
new file mode 100644 (file)
index 0000000..5959b85
--- /dev/null
@@ -0,0 +1,475 @@
+//! See docs in `build/expr/mod.rs`.
+
+use rustc_index::vec::Idx;
+
+use crate::build::expr::category::{Category, RvalueFunc};
+use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::hair::*;
+use rustc::middle::region;
+use rustc::mir::interpret::PanicInfo;
+use rustc::mir::*;
+use rustc::ty::{self, Ty, UpvarSubsts};
+use rustc_span::Span;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Returns an rvalue suitable for use until the end of the current
+    /// scope expression.
+    ///
+    /// The operand returned from this function will *not be valid* after
+    /// an ExprKind::Scope is passed, so please do *not* return it from
+    /// functions to avoid bad miscompiles.
+    crate fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let local_scope = self.local_scope();
+        self.as_rvalue(block, local_scope, expr)
+    }
+
+    /// Compile `expr`, yielding an rvalue.
+    fn as_rvalue<M>(
+        &mut self,
+        block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: M,
+    ) -> BlockAnd<Rvalue<'tcx>>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let expr = self.hir.mirror(expr);
+        self.expr_as_rvalue(block, scope, expr)
+    }
+
+    fn expr_as_rvalue(
+        &mut self,
+        mut block: BasicBlock,
+        scope: Option<region::Scope>,
+        expr: Expr<'tcx>,
+    ) -> BlockAnd<Rvalue<'tcx>> {
+        debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
+
+        let this = self;
+        let expr_span = expr.span;
+        let source_info = this.source_info(expr_span);
+
+        match expr.kind {
+            ExprKind::Scope { region_scope, lint_level, value } => {
+                let region_scope = (region_scope, source_info);
+                this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
+            }
+            ExprKind::Repeat { value, count } => {
+                let value_operand = unpack!(block = this.as_operand(block, scope, value));
+                block.and(Rvalue::Repeat(value_operand, count))
+            }
+            ExprKind::Binary { op, lhs, rhs } => {
+                let lhs = unpack!(block = this.as_operand(block, scope, lhs));
+                let rhs = unpack!(block = this.as_operand(block, scope, rhs));
+                this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
+            }
+            ExprKind::Unary { op, arg } => {
+                let arg = unpack!(block = this.as_operand(block, scope, arg));
+                // Check for -MIN on signed integers
+                if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
+                    let bool_ty = this.hir.bool_ty();
+
+                    let minval = this.minval_literal(expr_span, expr.ty);
+                    let is_min = this.temp(bool_ty, expr_span);
+
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        &is_min,
+                        Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval),
+                    );
+
+                    block = this.assert(
+                        block,
+                        Operand::Move(is_min),
+                        false,
+                        PanicInfo::OverflowNeg,
+                        expr_span,
+                    );
+                }
+                block.and(Rvalue::UnaryOp(op, arg))
+            }
+            ExprKind::Box { value } => {
+                let value = this.hir.mirror(value);
+                // The `Box<T>` temporary created here is not a part of the HIR,
+                // and therefore is not considered during generator OIBIT
+                // determination. See the comment about `box` at `yield_in_scope`.
+                let result = this.local_decls.push(LocalDecl::new_internal(expr.ty, expr_span));
+                this.cfg.push(
+                    block,
+                    Statement { source_info, kind: StatementKind::StorageLive(result) },
+                );
+                if let Some(scope) = scope {
+                    // schedule a shallow free of that memory, lest we unwind:
+                    this.schedule_drop_storage_and_value(expr_span, scope, result);
+                }
+
+                // malloc some memory of suitable type (thus far, uninitialized):
+                let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
+                this.cfg.push_assign(block, source_info, &Place::from(result), box_);
+
+                // initialize the box contents:
+                unpack!(
+                    block = this.into(
+                        &this.hir.tcx().mk_place_deref(Place::from(result)),
+                        block,
+                        value
+                    )
+                );
+                block.and(Rvalue::Use(Operand::Move(Place::from(result))))
+            }
+            ExprKind::Cast { source } => {
+                let source = unpack!(block = this.as_operand(block, scope, source));
+                block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
+            }
+            ExprKind::Pointer { cast, source } => {
+                let source = unpack!(block = this.as_operand(block, scope, source));
+                block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
+            }
+            ExprKind::Array { fields } => {
+                // (*) We would (maybe) be closer to codegen if we
+                // handled this and other aggregate cases via
+                // `into()`, not `as_rvalue` -- in that case, instead
+                // of generating
+                //
+                //     let tmp1 = ...1;
+                //     let tmp2 = ...2;
+                //     dest = Rvalue::Aggregate(Foo, [tmp1, tmp2])
+                //
+                // we could just generate
+                //
+                //     dest.f = ...1;
+                //     dest.g = ...2;
+                //
+                // The problem is that then we would need to:
+                //
+                // (a) have a more complex mechanism for handling
+                //     partial cleanup;
+                // (b) distinguish the case where the type `Foo` has a
+                //     destructor, in which case creating an instance
+                //     as a whole "arms" the destructor, and you can't
+                //     write individual fields; and,
+                // (c) handle the case where the type Foo has no
+                //     fields. We don't want `let x: ();` to compile
+                //     to the same MIR as `let x = ();`.
+
+                // first process the set of fields
+                let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
+                let fields: Vec<_> = fields
+                    .into_iter()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .collect();
+
+                block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
+            }
+            ExprKind::Tuple { fields } => {
+                // see (*) above
+                // first process the set of fields
+                let fields: Vec<_> = fields
+                    .into_iter()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .collect();
+
+                block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
+            }
+            ExprKind::Closure { closure_id, substs, upvars, movability } => {
+                // see (*) above
+                let operands: Vec<_> = upvars
+                    .into_iter()
+                    .map(|upvar| {
+                        let upvar = this.hir.mirror(upvar);
+                        match Category::of(&upvar.kind) {
+                            // Use as_place to avoid creating a temporary when
+                            // moving a variable into a closure, so that
+                            // borrowck knows which variables to mark as being
+                            // used as mut. This is OK here because the upvar
+                            // expressions have no side effects and act on
+                            // disjoint places.
+                            // This occurs when capturing by copy/move, while
+                            // by reference captures use as_operand
+                            Some(Category::Place) => {
+                                let place = unpack!(block = this.as_place(block, upvar));
+                                this.consume_by_copy_or_move(place)
+                            }
+                            _ => {
+                                // Turn mutable borrow captures into unique
+                                // borrow captures when capturing an immutable
+                                // variable. This is sound because the mutation
+                                // that caused the capture will cause an error.
+                                match upvar.kind {
+                                    ExprKind::Borrow {
+                                        borrow_kind:
+                                            BorrowKind::Mut { allow_two_phase_borrow: false },
+                                        arg,
+                                    } => unpack!(
+                                        block = this.limit_capture_mutability(
+                                            upvar.span, upvar.ty, scope, block, arg,
+                                        )
+                                    ),
+                                    _ => unpack!(block = this.as_operand(block, scope, upvar)),
+                                }
+                            }
+                        }
+                    })
+                    .collect();
+                let result = match substs {
+                    UpvarSubsts::Generator(substs) => {
+                        // We implicitly set the discriminant to 0. See
+                        // librustc_mir/transform/deaggregator.rs for details.
+                        let movability = movability.unwrap();
+                        box AggregateKind::Generator(closure_id, substs, movability)
+                    }
+                    UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
+                };
+                block.and(Rvalue::Aggregate(result, operands))
+            }
+            ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
+                block = unpack!(this.stmt_expr(block, expr, None));
+                block.and(this.unit_rvalue())
+            }
+            ExprKind::Yield { value } => {
+                let value = unpack!(block = this.as_operand(block, scope, value));
+                let resume = this.cfg.start_new_block();
+                let cleanup = this.generator_drop_cleanup();
+                this.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Yield { value: value, resume: resume, drop: cleanup },
+                );
+                resume.and(this.unit_rvalue())
+            }
+            ExprKind::Literal { .. }
+            | ExprKind::StaticRef { .. }
+            | ExprKind::Block { .. }
+            | ExprKind::Match { .. }
+            | ExprKind::NeverToAny { .. }
+            | ExprKind::Use { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::AddressOf { .. }
+            | ExprKind::Adt { .. }
+            | ExprKind::Loop { .. }
+            | ExprKind::LogicalOp { .. }
+            | ExprKind::Call { .. }
+            | ExprKind::Field { .. }
+            | ExprKind::Deref { .. }
+            | ExprKind::Index { .. }
+            | ExprKind::VarRef { .. }
+            | ExprKind::SelfRef
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Return { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::PlaceTypeAscription { .. }
+            | ExprKind::ValueTypeAscription { .. } => {
+                // these do not have corresponding `Rvalue` variants,
+                // so make an operand and then return that
+                debug_assert!(match Category::of(&expr.kind) {
+                    Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
+                    _ => true,
+                });
+                let operand = unpack!(block = this.as_operand(block, scope, expr));
+                block.and(Rvalue::Use(operand))
+            }
+        }
+    }
+
+    crate fn build_binary_op(
+        &mut self,
+        mut block: BasicBlock,
+        op: BinOp,
+        span: Span,
+        ty: Ty<'tcx>,
+        lhs: Operand<'tcx>,
+        rhs: Operand<'tcx>,
+    ) -> BlockAnd<Rvalue<'tcx>> {
+        let source_info = self.source_info(span);
+        let bool_ty = self.hir.bool_ty();
+        if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
+            let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
+            let result_value = self.temp(result_tup, span);
+
+            self.cfg.push_assign(
+                block,
+                source_info,
+                &result_value,
+                Rvalue::CheckedBinaryOp(op, lhs, rhs),
+            );
+            let val_fld = Field::new(0);
+            let of_fld = Field::new(1);
+
+            let tcx = self.hir.tcx();
+            let val = tcx.mk_place_field(result_value.clone(), val_fld, ty);
+            let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
+
+            let err = PanicInfo::Overflow(op);
+
+            block = self.assert(block, Operand::Move(of), false, err, span);
+
+            block.and(Rvalue::Use(Operand::Move(val)))
+        } else {
+            if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
+                // Checking division and remainder is more complex, since we 1. always check
+                // and 2. there are two possible failure cases, divide-by-zero and overflow.
+
+                let zero_err = if op == BinOp::Div {
+                    PanicInfo::DivisionByZero
+                } else {
+                    PanicInfo::RemainderByZero
+                };
+                let overflow_err = PanicInfo::Overflow(op);
+
+                // Check for / 0
+                let is_zero = self.temp(bool_ty, span);
+                let zero = self.zero_literal(span, ty);
+                self.cfg.push_assign(
+                    block,
+                    source_info,
+                    &is_zero,
+                    Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero),
+                );
+
+                block = self.assert(block, Operand::Move(is_zero), false, zero_err, span);
+
+                // We only need to check for the overflow in one case:
+                // MIN / -1, and only for signed values.
+                if ty.is_signed() {
+                    let neg_1 = self.neg_1_literal(span, ty);
+                    let min = self.minval_literal(span, ty);
+
+                    let is_neg_1 = self.temp(bool_ty, span);
+                    let is_min = self.temp(bool_ty, span);
+                    let of = self.temp(bool_ty, span);
+
+                    // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
+
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &is_neg_1,
+                        Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), neg_1),
+                    );
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &is_min,
+                        Rvalue::BinaryOp(BinOp::Eq, lhs.to_copy(), min),
+                    );
+
+                    let is_neg_1 = Operand::Move(is_neg_1);
+                    let is_min = Operand::Move(is_min);
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &of,
+                        Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min),
+                    );
+
+                    block = self.assert(block, Operand::Move(of), false, overflow_err, span);
+                }
+            }
+
+            block.and(Rvalue::BinaryOp(op, lhs, rhs))
+        }
+    }
+
+    fn limit_capture_mutability(
+        &mut self,
+        upvar_span: Span,
+        upvar_ty: Ty<'tcx>,
+        temp_lifetime: Option<region::Scope>,
+        mut block: BasicBlock,
+        arg: ExprRef<'tcx>,
+    ) -> BlockAnd<Operand<'tcx>> {
+        let this = self;
+
+        let source_info = this.source_info(upvar_span);
+        let temp = this.local_decls.push(LocalDecl::new_temp(upvar_ty, upvar_span));
+
+        this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
+
+        let arg_place = unpack!(block = this.as_place(block, arg));
+
+        let mutability = match arg_place.as_ref() {
+            PlaceRef { local, projection: &[] } => this.local_decls[*local].mutability,
+            PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
+                debug_assert!(
+                    this.local_decls[*local].is_ref_for_guard(),
+                    "Unexpected capture place",
+                );
+                this.local_decls[*local].mutability
+            }
+            PlaceRef {
+                ref local,
+                projection: &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _)],
+            }
+            | PlaceRef {
+                ref local,
+                projection:
+                    &[ref proj_base @ .., ProjectionElem::Field(upvar_index, _), ProjectionElem::Deref],
+            } => {
+                let place = PlaceRef { local, projection: proj_base };
+
+                // Not projected from the implicit `self` in a closure.
+                debug_assert!(
+                    match place.local_or_deref_local() {
+                        Some(local) => local == Local::new(1),
+                        None => false,
+                    },
+                    "Unexpected capture place"
+                );
+                // Not in a closure
+                debug_assert!(
+                    this.upvar_mutbls.len() > upvar_index.index(),
+                    "Unexpected capture place"
+                );
+                this.upvar_mutbls[upvar_index.index()]
+            }
+            _ => bug!("Unexpected capture place"),
+        };
+
+        let borrow_kind = match mutability {
+            Mutability::Not => BorrowKind::Unique,
+            Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
+        };
+
+        this.cfg.push_assign(
+            block,
+            source_info,
+            &Place::from(temp),
+            Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
+        );
+
+        // In constants, temp_lifetime is None. We should not need to drop
+        // anything because no values with a destructor can be created in
+        // a constant at this time, even if the type may need dropping.
+        if let Some(temp_lifetime) = temp_lifetime {
+            this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp);
+        }
+
+        block.and(Operand::Move(Place::from(temp)))
+    }
+
+    // Helper to get a `-1` value of the appropriate type
+    fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
+        let param_ty = ty::ParamEnv::empty().and(ty);
+        let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
+        let n = (!0u128) >> (128 - bits);
+        let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
+
+        self.literal_operand(span, literal)
+    }
+
+    // Helper to get the minimum value of the appropriate type
+    fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
+        assert!(ty.is_signed());
+        let param_ty = ty::ParamEnv::empty().and(ty);
+        let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
+        let n = 1 << (bits - 1);
+        let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
+
+        self.literal_operand(span, literal)
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/src/librustc_mir_build/build/expr/as_temp.rs
new file mode 100644 (file)
index 0000000..f47987c
--- /dev/null
@@ -0,0 +1,110 @@
+//! See docs in build/expr/mod.rs
+
+use crate::build::scope::DropKind;
+use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::hair::*;
+use rustc::middle::region;
+use rustc::mir::*;
+use rustc_hir as hir;
+use rustc_span::symbol::sym;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Compile `expr` into a fresh temporary. This is used when building
+    /// up rvalues so as to freeze the value that will be consumed.
+    crate fn as_temp<M>(
+        &mut self,
+        block: BasicBlock,
+        temp_lifetime: Option<region::Scope>,
+        expr: M,
+        mutability: Mutability,
+    ) -> BlockAnd<Local>
+    where
+        M: Mirror<'tcx, Output = Expr<'tcx>>,
+    {
+        let expr = self.hir.mirror(expr);
+        self.expr_as_temp(block, temp_lifetime, expr, mutability)
+    }
+
+    fn expr_as_temp(
+        &mut self,
+        mut block: BasicBlock,
+        temp_lifetime: Option<region::Scope>,
+        expr: Expr<'tcx>,
+        mutability: Mutability,
+    ) -> BlockAnd<Local> {
+        debug!(
+            "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
+            block, temp_lifetime, expr, mutability
+        );
+        let this = self;
+
+        let expr_span = expr.span;
+        let source_info = this.source_info(expr_span);
+        if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
+            return this.in_scope((region_scope, source_info), lint_level, |this| {
+                this.as_temp(block, temp_lifetime, value, mutability)
+            });
+        }
+
+        let expr_ty = expr.ty;
+        let temp = {
+            let mut local_decl = LocalDecl::new_temp(expr_ty, expr_span);
+            if mutability == Mutability::Not {
+                local_decl = local_decl.immutable();
+            }
+
+            debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
+            // Find out whether this temp is being created within the
+            // tail expression of a block whose result is ignored.
+            if let Some(tail_info) = this.block_context.currently_in_block_tail() {
+                local_decl = local_decl.block_tail(tail_info);
+            }
+            if let ExprKind::StaticRef { def_id, .. } = expr.kind {
+                let is_thread_local = this.hir.tcx().has_attr(def_id, sym::thread_local);
+                local_decl.local_info = LocalInfo::StaticRef { def_id, is_thread_local };
+            }
+            this.local_decls.push(local_decl)
+        };
+        let temp_place = &Place::from(temp);
+
+        match expr.kind {
+            // Don't bother with StorageLive and Dead for these temporaries,
+            // they are never assigned.
+            ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
+            ExprKind::Block { body: hir::Block { expr: None, targeted_by_break: false, .. } }
+                if expr_ty.is_never() =>
+            {
+                ()
+            }
+            _ => {
+                this.cfg
+                    .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
+
+                // In constants, `temp_lifetime` is `None` for temporaries that
+                // live for the `'static` lifetime. Thus we do not drop these
+                // temporaries and simply leak them.
+                // This is equivalent to what `let x = &foo();` does in
+                // functions. The temporary is lifted to their surrounding
+                // scope. In a function that means the temporary lives until
+                // just before the function returns. In constants that means it
+                // outlives the constant's initialization value computation.
+                // Anything outliving a constant must have the `'static`
+                // lifetime and live forever.
+                // Anything with a shorter lifetime (e.g the `&foo()` in
+                // `bar(&foo())` or anything within a block will keep the
+                // regular drops just like runtime code.
+                if let Some(temp_lifetime) = temp_lifetime {
+                    this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage);
+                }
+            }
+        }
+
+        unpack!(block = this.into(temp_place, block, expr));
+
+        if let Some(temp_lifetime) = temp_lifetime {
+            this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
+        }
+
+        block.and(temp)
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/category.rs b/src/librustc_mir_build/build/expr/category.rs
new file mode 100644 (file)
index 0000000..c4d3409
--- /dev/null
@@ -0,0 +1,83 @@
+use crate::hair::*;
+
+#[derive(Debug, PartialEq)]
+crate enum Category {
+    // An assignable memory location like `x`, `x.f`, `foo()[3]`, that
+    // sort of thing. Something that could appear on the LHS of an `=`
+    // sign.
+    Place,
+
+    // A literal like `23` or `"foo"`. Does not include constant
+    // expressions like `3 + 5`.
+    Constant,
+
+    // Something that generates a new value at runtime, like `x + y`
+    // or `foo()`.
+    Rvalue(RvalueFunc),
+}
+
+// Rvalues fall into different "styles" that will determine which fn
+// is best suited to generate them.
+#[derive(Debug, PartialEq)]
+crate enum RvalueFunc {
+    // Best generated by `into`. This is generally exprs that
+    // cause branching, like `match`, but also includes calls.
+    Into,
+
+    // Best generated by `as_rvalue`. This is usually the case.
+    AsRvalue,
+}
+
+/// Determines the category for a given expression. Note that scope
+/// and paren expressions have no category.
+impl Category {
+    crate fn of(ek: &ExprKind<'_>) -> Option<Category> {
+        match *ek {
+            ExprKind::Scope { .. } => None,
+
+            ExprKind::Field { .. }
+            | ExprKind::Deref { .. }
+            | ExprKind::Index { .. }
+            | ExprKind::SelfRef
+            | ExprKind::VarRef { .. }
+            | ExprKind::PlaceTypeAscription { .. }
+            | ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
+
+            ExprKind::LogicalOp { .. }
+            | ExprKind::Match { .. }
+            | ExprKind::NeverToAny { .. }
+            | ExprKind::Use { .. }
+            | ExprKind::Adt { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::AddressOf { .. }
+            | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
+
+            ExprKind::Array { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Closure { .. }
+            | ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
+            | ExprKind::Box { .. }
+            | ExprKind::Cast { .. }
+            | ExprKind::Pointer { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Assign { .. }
+            | ExprKind::AssignOp { .. }
+            | ExprKind::Yield { .. }
+            | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
+
+            ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => Some(Category::Constant),
+
+            ExprKind::Loop { .. }
+            | ExprKind::Block { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Return { .. } =>
+            // FIXME(#27840) these probably want their own
+            // category, like "nonterminating"
+            {
+                Some(Category::Rvalue(RvalueFunc::Into))
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs
new file mode 100644 (file)
index 0000000..503dfb6
--- /dev/null
@@ -0,0 +1,406 @@
+//! See docs in build/expr/mod.rs
+
+use crate::build::expr::category::{Category, RvalueFunc};
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
+use crate::hair::*;
+use rustc::mir::*;
+use rustc::ty::{self, CanonicalUserTypeAnnotation};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_span::symbol::sym;
+
+use rustc_target::spec::abi::Abi;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Compile `expr`, storing the result into `destination`, which
+    /// is assumed to be uninitialized.
+    crate fn into_expr(
+        &mut self,
+        destination: &Place<'tcx>,
+        mut block: BasicBlock,
+        expr: Expr<'tcx>,
+    ) -> BlockAnd<()> {
+        debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
+
+        // since we frequently have to reference `self` from within a
+        // closure, where `self` would be shadowed, it's easier to
+        // just use the name `this` uniformly
+        let this = self;
+        let expr_span = expr.span;
+        let source_info = this.source_info(expr_span);
+
+        let expr_is_block_or_scope = match expr.kind {
+            ExprKind::Block { .. } => true,
+            ExprKind::Scope { .. } => true,
+            _ => false,
+        };
+
+        if !expr_is_block_or_scope {
+            this.block_context.push(BlockFrame::SubExpr);
+        }
+
+        let block_and = match expr.kind {
+            ExprKind::Scope { region_scope, lint_level, value } => {
+                let region_scope = (region_scope, source_info);
+                this.in_scope(region_scope, lint_level, |this| this.into(destination, block, value))
+            }
+            ExprKind::Block { body: ast_block } => {
+                this.ast_block(destination, block, ast_block, source_info)
+            }
+            ExprKind::Match { scrutinee, arms } => {
+                this.match_expr(destination, expr_span, block, scrutinee, arms)
+            }
+            ExprKind::NeverToAny { source } => {
+                let source = this.hir.mirror(source);
+                let is_call = match source.kind {
+                    ExprKind::Call { .. } => true,
+                    _ => false,
+                };
+
+                // (#66975) Source could be a const of type `!`, so has to
+                // exist in the generated MIR.
+                unpack!(block = this.as_temp(block, this.local_scope(), source, Mutability::Mut,));
+
+                // This is an optimization. If the expression was a call then we already have an
+                // unreachable block. Don't bother to terminate it and create a new one.
+                if is_call {
+                    block.unit()
+                } else {
+                    this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
+                    let end_block = this.cfg.start_new_block();
+                    end_block.unit()
+                }
+            }
+            ExprKind::LogicalOp { op, lhs, rhs } => {
+                // And:
+                //
+                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
+                //        |                          | (false)
+                //        +----------false-----------+------------------> [false_block]
+                //
+                // Or:
+                //
+                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
+                //        | (true)                   | (false)
+                //  [true_block]               [false_block]
+
+                let (true_block, false_block, mut else_block, join_block) = (
+                    this.cfg.start_new_block(),
+                    this.cfg.start_new_block(),
+                    this.cfg.start_new_block(),
+                    this.cfg.start_new_block(),
+                );
+
+                let lhs = unpack!(block = this.as_local_operand(block, lhs));
+                let blocks = match op {
+                    LogicalOp::And => (else_block, false_block),
+                    LogicalOp::Or => (true_block, else_block),
+                };
+                let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
+                this.cfg.terminate(block, source_info, term);
+
+                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
+                let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
+                this.cfg.terminate(else_block, source_info, term);
+
+                this.cfg.push_assign_constant(
+                    true_block,
+                    source_info,
+                    destination,
+                    Constant { span: expr_span, user_ty: None, literal: this.hir.true_literal() },
+                );
+
+                this.cfg.push_assign_constant(
+                    false_block,
+                    source_info,
+                    destination,
+                    Constant { span: expr_span, user_ty: None, literal: this.hir.false_literal() },
+                );
+
+                // Link up both branches:
+                this.cfg.goto(true_block, source_info, join_block);
+                this.cfg.goto(false_block, source_info, join_block);
+                join_block.unit()
+            }
+            ExprKind::Loop { body } => {
+                // [block]
+                //    |
+                //   [loop_block] -> [body_block] -/eval. body/-> [body_block_end]
+                //    |        ^                                         |
+                // false link  |                                         |
+                //    |        +-----------------------------------------+
+                //    +-> [diverge_cleanup]
+                // The false link is required to make sure borrowck considers unwinds through the
+                // body, even when the exact code in the body cannot unwind
+
+                let loop_block = this.cfg.start_new_block();
+                let exit_block = this.cfg.start_new_block();
+
+                // Start the loop.
+                this.cfg.goto(block, source_info, loop_block);
+
+                this.in_breakable_scope(
+                    Some(loop_block),
+                    exit_block,
+                    destination.clone(),
+                    move |this| {
+                        // conduct the test, if necessary
+                        let body_block = this.cfg.start_new_block();
+                        let diverge_cleanup = this.diverge_cleanup();
+                        this.cfg.terminate(
+                            loop_block,
+                            source_info,
+                            TerminatorKind::FalseUnwind {
+                                real_target: body_block,
+                                unwind: Some(diverge_cleanup),
+                            },
+                        );
+
+                        // The “return” value of the loop body must always be an unit. We therefore
+                        // introduce a unit temporary as the destination for the loop body.
+                        let tmp = this.get_unit_temp();
+                        // Execute the body, branching back to the test.
+                        let body_block_end = unpack!(this.into(&tmp, body_block, body));
+                        this.cfg.goto(body_block_end, source_info, loop_block);
+                    },
+                );
+                exit_block.unit()
+            }
+            ExprKind::Call { ty, fun, args, from_hir_call } => {
+                let intrinsic = match ty.kind {
+                    ty::FnDef(def_id, _) => {
+                        let f = ty.fn_sig(this.hir.tcx());
+                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
+                            Some(this.hir.tcx().item_name(def_id))
+                        } else {
+                            None
+                        }
+                    }
+                    _ => None,
+                };
+                let fun = unpack!(block = this.as_local_operand(block, fun));
+                if let Some(sym::move_val_init) = intrinsic {
+                    // `move_val_init` has "magic" semantics - the second argument is
+                    // always evaluated "directly" into the first one.
+
+                    let mut args = args.into_iter();
+                    let ptr = args.next().expect("0 arguments to `move_val_init`");
+                    let val = args.next().expect("1 argument to `move_val_init`");
+                    assert!(args.next().is_none(), ">2 arguments to `move_val_init`");
+
+                    let ptr = this.hir.mirror(ptr);
+                    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 {
+                        mutability: Mutability::Mut,
+                        ty: ptr_ty,
+                        user_ty: UserTypeProjections::none(),
+                        source_info,
+                        internal: true,
+                        local_info: LocalInfo::Other,
+                        is_block_tail: None,
+                    });
+                    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)
+                } else {
+                    let args: Vec<_> = args
+                        .into_iter()
+                        .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
+                        .collect();
+
+                    let success = this.cfg.start_new_block();
+                    let cleanup = this.diverge_cleanup();
+
+                    this.record_operands_moved(&args);
+
+                    this.cfg.terminate(
+                        block,
+                        source_info,
+                        TerminatorKind::Call {
+                            func: fun,
+                            args,
+                            cleanup: Some(cleanup),
+                            // FIXME(varkor): replace this with an uninhabitedness-based check.
+                            // This requires getting access to the current module to call
+                            // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
+                            destination: if expr.ty.is_never() {
+                                None
+                            } else {
+                                Some((destination.clone(), success))
+                            },
+                            from_hir_call,
+                        },
+                    );
+                    success.unit()
+                }
+            }
+            ExprKind::Use { source } => this.into(destination, block, source),
+            ExprKind::Borrow { arg, borrow_kind } => {
+                // We don't do this in `as_rvalue` because we use `as_place`
+                // for borrow expressions, so we cannot create an `RValue` that
+                // remains valid across user code. `as_rvalue` is usually called
+                // by this method anyway, so this shouldn't cause too many
+                // unnecessary temporaries.
+                let arg_place = match borrow_kind {
+                    BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
+                    _ => unpack!(block = this.as_place(block, arg)),
+                };
+                let borrow =
+                    Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place);
+                this.cfg.push_assign(block, source_info, destination, borrow);
+                block.unit()
+            }
+            ExprKind::AddressOf { mutability, arg } => {
+                let place = match mutability {
+                    hir::Mutability::Not => this.as_read_only_place(block, arg),
+                    hir::Mutability::Mut => this.as_place(block, arg),
+                };
+                let address_of = Rvalue::AddressOf(mutability, unpack!(block = place));
+                this.cfg.push_assign(block, source_info, destination, address_of);
+                block.unit()
+            }
+            ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, base } => {
+                // See the notes for `ExprKind::Array` in `as_rvalue` and for
+                // `ExprKind::Borrow` above.
+                let is_union = adt_def.is_union();
+                let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
+
+                let scope = this.local_scope();
+
+                // first process the set of fields that were provided
+                // (evaluating them in order given by user)
+                let fields_map: FxHashMap<_, _> = fields
+                    .into_iter()
+                    .map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
+                    .collect();
+
+                let field_names = this.hir.all_fields(adt_def, variant_index);
+
+                let fields =
+                    if let Some(FruInfo { base, field_types }) = base {
+                        let base = unpack!(block = this.as_place(block, base));
+
+                        // MIR does not natively support FRU, so for each
+                        // base-supplied field, generate an operand that
+                        // reads it from the base.
+                        field_names
+                            .into_iter()
+                            .zip(field_types.into_iter())
+                            .map(|(n, ty)| match fields_map.get(&n) {
+                                Some(v) => v.clone(),
+                                None => this.consume_by_copy_or_move(
+                                    this.hir.tcx().mk_place_field(base.clone(), n, ty),
+                                ),
+                            })
+                            .collect()
+                    } else {
+                        field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
+                    };
+
+                let inferred_ty = expr.ty;
+                let user_ty = user_ty.map(|ty| {
+                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+                        span: source_info.span,
+                        user_ty: ty,
+                        inferred_ty,
+                    })
+                });
+                let adt = box AggregateKind::Adt(
+                    adt_def,
+                    variant_index,
+                    substs,
+                    user_ty,
+                    active_field_index,
+                );
+                this.cfg.push_assign(
+                    block,
+                    source_info,
+                    destination,
+                    Rvalue::Aggregate(adt, fields),
+                );
+                block.unit()
+            }
+
+            // These cases don't actually need a destination
+            ExprKind::Assign { .. }
+            | ExprKind::AssignOp { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::Return { .. } => {
+                unpack!(block = this.stmt_expr(block, expr, None));
+                this.cfg.push_assign_unit(block, source_info, destination);
+                block.unit()
+            }
+
+            // Avoid creating a temporary
+            ExprKind::VarRef { .. }
+            | ExprKind::SelfRef
+            | ExprKind::PlaceTypeAscription { .. }
+            | ExprKind::ValueTypeAscription { .. } => {
+                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
+
+                let place = unpack!(block = this.as_place(block, expr));
+                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
+                this.cfg.push_assign(block, source_info, destination, rvalue);
+                block.unit()
+            }
+            ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
+                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
+
+                // Create a "fake" temporary variable so that we check that the
+                // value is Sized. Usually, this is caught in type checking, but
+                // in the case of box expr there is no such check.
+                if !destination.projection.is_empty() {
+                    this.local_decls.push(LocalDecl::new_temp(expr.ty, expr.span));
+                }
+
+                debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
+
+                let place = unpack!(block = this.as_place(block, expr));
+                let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
+                this.cfg.push_assign(block, source_info, destination, rvalue);
+                block.unit()
+            }
+
+            // these are the cases that are more naturally handled by some other mode
+            ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
+            | ExprKind::Box { .. }
+            | ExprKind::Cast { .. }
+            | ExprKind::Pointer { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Array { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Closure { .. }
+            | ExprKind::Literal { .. }
+            | ExprKind::StaticRef { .. }
+            | ExprKind::Yield { .. } => {
+                debug_assert!(match Category::of(&expr.kind).unwrap() {
+                    // should be handled above
+                    Category::Rvalue(RvalueFunc::Into) => false,
+
+                    // must be handled above or else we get an
+                    // infinite loop in the builder; see
+                    // e.g., `ExprKind::VarRef` above
+                    Category::Place => false,
+
+                    _ => true,
+                });
+
+                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
+                this.cfg.push_assign(block, source_info, destination, rvalue);
+                block.unit()
+            }
+        };
+
+        if !expr_is_block_or_scope {
+            let popped = this.block_context.pop();
+            assert!(popped.is_some());
+        }
+
+        block_and
+    }
+}
diff --git a/src/librustc_mir_build/build/expr/mod.rs b/src/librustc_mir_build/build/expr/mod.rs
new file mode 100644 (file)
index 0000000..ac8c7e7
--- /dev/null
@@ -0,0 +1,70 @@
+//! Builds MIR from expressions. As a caller into this module, you
+//! have many options, but the first thing you have to decide is
+//! whether you are evaluating this expression for its *value*, its
+//! *location*, or as a *constant*.
+//!
+//! Typically, you want the value: e.g., if you are doing `expr_a +
+//! expr_b`, you want the values of those expressions. In that case,
+//! you want one of the following functions. Note that if the expr has
+//! a type that is not `Copy`, then using any of these functions will
+//! "move" the value out of its current home (if any).
+//!
+//! - `into` -- writes the value into a specific location, which
+//!   should be uninitialized
+//! - `as_operand` -- evaluates the value and yields an `Operand`,
+//!   suitable for use as an argument to an `Rvalue`
+//! - `as_temp` -- evaluates into a temporary; this is similar to `as_operand`
+//!   except it always returns a fresh place, even for constants
+//! - `as_rvalue` -- yields an `Rvalue`, suitable for use in an assignment;
+//!   as of this writing, never needed outside of the `expr` module itself
+//!
+//! Sometimes though want the expression's *location*. An example
+//! would be during a match statement, or the operand of the `&`
+//! operator. In that case, you want `as_place`. This will create a
+//! temporary if necessary.
+//!
+//! Finally, if it's a constant you seek, then call
+//! `as_constant`. This creates a `Constant<H>`, but naturally it can
+//! only be used on constant expressions and hence is needed only in
+//! very limited contexts.
+//!
+//! ### Implementation notes
+//!
+//! For any given kind of expression, there is generally one way that
+//! can be lowered most naturally. This is specified by the
+//! `Category::of` function in the `category` module. For example, a
+//! struct expression (or other expression that creates a new value)
+//! is typically easiest to write in terms of `as_rvalue` or `into`,
+//! whereas a reference to a field is easiest to write in terms of
+//! `as_place`. (The exception to this is scope and paren
+//! expressions, which have no category.)
+//!
+//! Therefore, the various functions above make use of one another in
+//! a descending fashion. For any given expression, you should pick
+//! the most suitable spot to implement it, and then just let the
+//! other fns cycle around. The handoff works like this:
+//!
+//! - `into(place)` -> fallback is to create a rvalue with `as_rvalue` and assign it to `place`
+//! - `as_rvalue` -> fallback is to create an Operand with `as_operand` and use `Rvalue::use`
+//! - `as_operand` -> either invokes `as_constant` or `as_temp`
+//! - `as_constant` -> (no fallback)
+//! - `as_temp` -> creates a temporary and either calls `as_place` or `into`
+//! - `as_place` -> for rvalues, falls back to `as_temp` and returns that
+//!
+//! As you can see, there is a cycle where `into` can (in theory) fallback to `as_temp`
+//! which can fallback to `into`. So if one of the `ExprKind` variants is not, in fact,
+//! implemented in the category where it is supposed to be, there will be a problem.
+//!
+//! Of those fallbacks, the most interesting one is `into`, because
+//! it discriminates based on the category of the expression. This is
+//! basically the point where the "by value" operations are bridged
+//! over to the "by reference" mode (`as_place`).
+
+mod as_constant;
+mod as_operand;
+mod as_place;
+mod as_rvalue;
+mod as_temp;
+mod category;
+mod into;
+mod stmt;
diff --git a/src/librustc_mir_build/build/expr/stmt.rs b/src/librustc_mir_build/build/expr/stmt.rs
new file mode 100644 (file)
index 0000000..fd61cb8
--- /dev/null
@@ -0,0 +1,179 @@
+use crate::build::scope::BreakableTarget;
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
+use crate::hair::*;
+use rustc::middle::region;
+use rustc::mir::*;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Builds a block of MIR statements to evaluate the HAIR `expr`.
+    /// If the original expression was an AST statement,
+    /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the
+    /// span of that statement (including its semicolon, if any).
+    /// The scope is used if a statement temporary must be dropped.
+    crate fn stmt_expr(
+        &mut self,
+        mut block: BasicBlock,
+        expr: Expr<'tcx>,
+        statement_scope: Option<region::Scope>,
+    ) -> BlockAnd<()> {
+        let this = self;
+        let expr_span = expr.span;
+        let source_info = this.source_info(expr.span);
+        // Handle a number of expressions that don't need a destination at all. This
+        // avoids needing a mountain of temporary `()` variables.
+        let expr2 = expr.clone();
+        match expr.kind {
+            ExprKind::Scope { region_scope, lint_level, value } => {
+                let value = this.hir.mirror(value);
+                this.in_scope((region_scope, source_info), lint_level, |this| {
+                    this.stmt_expr(block, value, statement_scope)
+                })
+            }
+            ExprKind::Assign { lhs, rhs } => {
+                let lhs = this.hir.mirror(lhs);
+                let rhs = this.hir.mirror(rhs);
+                let lhs_span = lhs.span;
+
+                // Note: we evaluate assignments right-to-left. This
+                // is better for borrowck interaction with overloaded
+                // operators like x[j] = x[i].
+
+                debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr2);
+                this.block_context.push(BlockFrame::SubExpr);
+
+                // Generate better code for things that don't need to be
+                // dropped.
+                if this.hir.needs_drop(lhs.ty) {
+                    let rhs = unpack!(block = this.as_local_operand(block, rhs));
+                    let lhs = unpack!(block = this.as_place(block, lhs));
+                    unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
+                } else {
+                    let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
+                    let lhs = unpack!(block = this.as_place(block, lhs));
+                    this.cfg.push_assign(block, source_info, &lhs, rhs);
+                }
+
+                this.block_context.pop();
+                block.unit()
+            }
+            ExprKind::AssignOp { op, lhs, rhs } => {
+                // FIXME(#28160) there is an interesting semantics
+                // question raised here -- should we "freeze" the
+                // value of the lhs here?  I'm inclined to think not,
+                // since it seems closer to the semantics of the
+                // overloaded version, which takes `&mut self`.  This
+                // only affects weird things like `x += {x += 1; x}`
+                // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
+
+                let lhs = this.hir.mirror(lhs);
+                let lhs_ty = lhs.ty;
+
+                debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2);
+                this.block_context.push(BlockFrame::SubExpr);
+
+                // As above, RTL.
+                let rhs = unpack!(block = this.as_local_operand(block, rhs));
+                let lhs = unpack!(block = this.as_place(block, lhs));
+
+                // we don't have to drop prior contents or anything
+                // because AssignOp is only legal for Copy types
+                // (overloaded ops should be desugared into a call).
+                let result = unpack!(
+                    block = this.build_binary_op(
+                        block,
+                        op,
+                        expr_span,
+                        lhs_ty,
+                        Operand::Copy(lhs.clone()),
+                        rhs
+                    )
+                );
+                this.cfg.push_assign(block, source_info, &lhs, result);
+
+                this.block_context.pop();
+                block.unit()
+            }
+            ExprKind::Continue { label } => {
+                this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
+            }
+            ExprKind::Break { label, value } => {
+                this.break_scope(block, value, BreakableTarget::Break(label), source_info)
+            }
+            ExprKind::Return { value } => {
+                this.break_scope(block, value, BreakableTarget::Return, source_info)
+            }
+            ExprKind::InlineAsm { asm, outputs, inputs } => {
+                debug!("stmt_expr InlineAsm block_context.push(SubExpr) : {:?}", expr2);
+                this.block_context.push(BlockFrame::SubExpr);
+                let outputs = outputs
+                    .into_iter()
+                    .map(|output| unpack!(block = this.as_place(block, output)))
+                    .collect::<Vec<_>>()
+                    .into_boxed_slice();
+                let inputs = inputs
+                    .into_iter()
+                    .map(|input| {
+                        (input.span(), unpack!(block = this.as_local_operand(block, input)))
+                    })
+                    .collect::<Vec<_>>()
+                    .into_boxed_slice();
+                this.cfg.push(
+                    block,
+                    Statement {
+                        source_info,
+                        kind: StatementKind::InlineAsm(box InlineAsm {
+                            asm: asm.clone(),
+                            outputs,
+                            inputs,
+                        }),
+                    },
+                );
+                this.block_context.pop();
+                block.unit()
+            }
+            _ => {
+                assert!(
+                    statement_scope.is_some(),
+                    "Should not be calling `stmt_expr` on a general expression \
+                     without a statement scope",
+                );
+
+                // Issue #54382: When creating temp for the value of
+                // expression like:
+                //
+                // `{ side_effects(); { let l = stuff(); the_value } }`
+                //
+                // it is usually better to focus on `the_value` rather
+                // than the entirety of block(s) surrounding it.
+                let adjusted_span = (|| {
+                    if let ExprKind::Block { body } = expr.kind {
+                        if let Some(tail_expr) = &body.expr {
+                            let mut expr = tail_expr;
+                            while let rustc_hir::ExprKind::Block(subblock, _label) = &expr.kind {
+                                if let Some(subtail_expr) = &subblock.expr {
+                                    expr = subtail_expr
+                                } else {
+                                    break;
+                                }
+                            }
+                            this.block_context
+                                .push(BlockFrame::TailExpr { tail_result_is_ignored: true });
+                            return Some(expr.span);
+                        }
+                    }
+                    None
+                })();
+
+                let temp =
+                    unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not));
+
+                if let Some(span) = adjusted_span {
+                    this.local_decls[temp].source_info.span = span;
+                    this.block_context.pop();
+                }
+
+                block.unit()
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/into.rs b/src/librustc_mir_build/build/into.rs
new file mode 100644 (file)
index 0000000..1a2a9d2
--- /dev/null
@@ -0,0 +1,55 @@
+//! In general, there are a number of things for which it's convenient
+//! to just call `builder.into` and have it emit its result into a
+//! given location. This is basically for expressions or things that can be
+//! wrapped up as expressions (e.g., blocks). To make this ergonomic, we use this
+//! latter `EvalInto` trait.
+
+use crate::build::{BlockAnd, Builder};
+use crate::hair::*;
+use rustc::mir::*;
+
+pub(in crate::build) trait EvalInto<'tcx> {
+    fn eval_into(
+        self,
+        builder: &mut Builder<'_, 'tcx>,
+        destination: &Place<'tcx>,
+        block: BasicBlock,
+    ) -> BlockAnd<()>;
+}
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    crate fn into<E>(
+        &mut self,
+        destination: &Place<'tcx>,
+        block: BasicBlock,
+        expr: E,
+    ) -> BlockAnd<()>
+    where
+        E: EvalInto<'tcx>,
+    {
+        expr.eval_into(self, destination, block)
+    }
+}
+
+impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
+    fn eval_into(
+        self,
+        builder: &mut Builder<'_, 'tcx>,
+        destination: &Place<'tcx>,
+        block: BasicBlock,
+    ) -> BlockAnd<()> {
+        let expr = builder.hir.mirror(self);
+        builder.into_expr(destination, block, expr)
+    }
+}
+
+impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
+    fn eval_into(
+        self,
+        builder: &mut Builder<'_, 'tcx>,
+        destination: &Place<'tcx>,
+        block: BasicBlock,
+    ) -> BlockAnd<()> {
+        builder.into_expr(destination, block, self)
+    }
+}
diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs
new file mode 100644 (file)
index 0000000..f9f10b5
--- /dev/null
@@ -0,0 +1,1671 @@
+//! Code related to match expressions. These are sufficiently complex to
+//! warrant their own module and submodules. :) This main module includes the
+//! high-level algorithm, the submodules contain the details.
+//!
+//! This also includes code for pattern bindings in `let` statements and
+//! function parameters.
+
+use crate::build::scope::DropKind;
+use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
+use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
+use crate::hair::{self, *};
+use rustc::middle::region;
+use rustc::mir::*;
+use rustc::ty::layout::VariantIdx;
+use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::HirId;
+use rustc_index::bit_set::BitSet;
+use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
+use syntax::ast::Name;
+
+// helper functions, broken out by category:
+mod simplify;
+mod test;
+mod util;
+
+use itertools::Itertools;
+use std::convert::TryFrom;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Generates MIR for a `match` expression.
+    ///
+    /// The MIR that we generate for a match looks like this.
+    ///
+    /// ```text
+    /// [ 0. Pre-match ]
+    ///        |
+    /// [ 1. Evaluate Scrutinee (expression being matched on) ]
+    /// [ (fake read of scrutinee) ]
+    ///        |
+    /// [ 2. Decision tree -- check discriminants ] <--------+
+    ///        |                                             |
+    ///        | (once a specific arm is chosen)             |
+    ///        |                                             |
+    /// [pre_binding_block]                           [otherwise_block]
+    ///        |                                             |
+    /// [ 3. Create "guard bindings" for arm ]               |
+    /// [ (create fake borrows) ]                            |
+    ///        |                                             |
+    /// [ 4. Execute guard code ]                            |
+    /// [ (read fake borrows) ] --(guard is false)-----------+
+    ///        |
+    ///        | (guard results in true)
+    ///        |
+    /// [ 5. Create real bindings and execute arm ]
+    ///        |
+    /// [ Exit match ]
+    /// ```
+    ///
+    /// All of the different arms have been stacked on top of each other to
+    /// simplify the diagram. For an arm with no guard the blocks marked 3 and
+    /// 4 and the fake borrows are omitted.
+    ///
+    /// We generate MIR in the following steps:
+    ///
+    /// 1. Evaluate the scrutinee and add the fake read of it ([Builder::lower_scrutinee]).
+    /// 2. Create the prebinding and otherwise blocks ([Builder::create_match_candidates]).
+    /// 3. Create the decision tree ([Builder::lower_match_tree]).
+    /// 4. Determine the fake borrows that are needed from the places that were
+    ///    matched against and create the required temporaries for them
+    ///    ([Builder::calculate_fake_borrows]).
+    /// 5. Create everything else: the guards and the arms ([Builder::lower_match_arms]).
+    ///
+    /// ## False edges
+    ///
+    /// We don't want to have the exact structure of the decision tree be
+    /// visible through borrow checking. False edges ensure that the CFG as
+    /// seen by borrow checking doesn't encode this. False edges are added:
+    ///
+    /// * From each prebinding block to the next prebinding block.
+    /// * From each otherwise block to the next prebinding block.
+    crate fn match_expr(
+        &mut self,
+        destination: &Place<'tcx>,
+        span: Span,
+        mut block: BasicBlock,
+        scrutinee: ExprRef<'tcx>,
+        arms: Vec<Arm<'tcx>>,
+    ) -> BlockAnd<()> {
+        let scrutinee_span = scrutinee.span();
+        let scrutinee_place =
+            unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
+
+        let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms);
+
+        let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
+        let candidates =
+            arm_candidates.iter_mut().flat_map(|(_, candidates)| candidates).collect::<Vec<_>>();
+
+        let fake_borrow_temps =
+            self.lower_match_tree(block, scrutinee_span, match_has_guard, candidates);
+
+        self.lower_match_arms(
+            &destination,
+            scrutinee_place,
+            scrutinee_span,
+            arm_candidates,
+            self.source_info(span),
+            fake_borrow_temps,
+        )
+    }
+
+    /// Evaluate the scrutinee and add the fake read of it.
+    fn lower_scrutinee(
+        &mut self,
+        mut block: BasicBlock,
+        scrutinee: ExprRef<'tcx>,
+        scrutinee_span: Span,
+    ) -> BlockAnd<Place<'tcx>> {
+        let scrutinee_place = unpack!(block = self.as_place(block, scrutinee));
+        // Matching on a `scrutinee_place` with an uninhabited type doesn't
+        // generate any memory reads by itself, and so if the place "expression"
+        // contains unsafe operations like raw pointer dereferences or union
+        // field projections, we wouldn't know to require an `unsafe` block
+        // around a `match` equivalent to `std::intrinsics::unreachable()`.
+        // See issue #47412 for this hole being discovered in the wild.
+        //
+        // HACK(eddyb) Work around the above issue by adding a dummy inspection
+        // of `scrutinee_place`, specifically by applying `ReadForMatch`.
+        //
+        // NOTE: ReadForMatch also checks that the scrutinee is initialized.
+        // This is currently needed to not allow matching on an uninitialized,
+        // uninhabited value. If we get never patterns, those will check that
+        // the place is initialized, and so this read would only be used to
+        // check safety.
+        let cause_matched_place = FakeReadCause::ForMatchedPlace;
+        let source_info = self.source_info(scrutinee_span);
+        self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place.clone());
+
+        block.and(scrutinee_place)
+    }
+
+    /// Create the initial `Candidate`s for a `match` expression.
+    fn create_match_candidates<'pat>(
+        &mut self,
+        scrutinee: &Place<'tcx>,
+        arms: &'pat [Arm<'tcx>],
+    ) -> Vec<(&'pat Arm<'tcx>, Vec<Candidate<'pat, 'tcx>>)> {
+        let candidate_count = arms.iter().map(|c| c.top_pats_hack().len()).sum::<usize>();
+        let pre_binding_blocks: Vec<_> =
+            (0..candidate_count).map(|_| self.cfg.start_new_block()).collect();
+
+        let mut candidate_pre_binding_blocks = pre_binding_blocks.iter();
+        let mut next_candidate_pre_binding_blocks = pre_binding_blocks.iter().skip(1);
+
+        // Assemble a list of candidates: there is one candidate per pattern,
+        // which means there may be more than one candidate *per arm*.
+        arms.iter()
+            .map(|arm| {
+                let arm_has_guard = arm.guard.is_some();
+                let arm_candidates: Vec<_> = arm
+                    .top_pats_hack()
+                    .iter()
+                    .zip(candidate_pre_binding_blocks.by_ref())
+                    .map(|(pattern, pre_binding_block)| Candidate {
+                        span: pattern.span,
+                        match_pairs: smallvec![MatchPair::new(scrutinee.clone(), pattern)],
+                        bindings: vec![],
+                        ascriptions: vec![],
+                        otherwise_block: if arm_has_guard {
+                            Some(self.cfg.start_new_block())
+                        } else {
+                            None
+                        },
+                        pre_binding_block: *pre_binding_block,
+                        next_candidate_pre_binding_block: next_candidate_pre_binding_blocks
+                            .next()
+                            .copied(),
+                    })
+                    .collect();
+                (arm, arm_candidates)
+            })
+            .collect()
+    }
+
+    /// Create the decision tree for the match expression, starting from `block`.
+    ///
+    /// Modifies `candidates` to store the bindings and type ascriptions for
+    /// that candidate.
+    ///
+    /// Returns the places that need fake borrows because we bind or test them.
+    fn lower_match_tree<'pat>(
+        &mut self,
+        block: BasicBlock,
+        scrutinee_span: Span,
+        match_has_guard: bool,
+        mut candidates: Vec<&mut Candidate<'pat, 'tcx>>,
+    ) -> Vec<(Place<'tcx>, Local)> {
+        // The set of places that we are creating fake borrows of. If there are
+        // no match guards then we don't need any fake borrows, so don't track
+        // them.
+        let mut fake_borrows = if match_has_guard { Some(FxHashSet::default()) } else { None };
+
+        // This will generate code to test scrutinee_place and
+        // branch to the appropriate arm block
+        self.match_candidates(
+            scrutinee_span,
+            &mut Some(block),
+            None,
+            &mut candidates,
+            &mut fake_borrows,
+        );
+
+        if let Some(ref borrows) = fake_borrows {
+            self.calculate_fake_borrows(borrows, scrutinee_span)
+        } else {
+            Vec::new()
+        }
+    }
+
+    /// Lower the bindings, guards and arm bodies of a `match` expression.
+    ///
+    /// The decision tree should have already been created
+    /// (by [Builder::lower_match_tree]).
+    ///
+    /// `outer_source_info` is the SourceInfo for the whole match.
+    fn lower_match_arms(
+        &mut self,
+        destination: &Place<'tcx>,
+        scrutinee_place: Place<'tcx>,
+        scrutinee_span: Span,
+        arm_candidates: Vec<(&'_ Arm<'tcx>, Vec<Candidate<'_, 'tcx>>)>,
+        outer_source_info: SourceInfo,
+        fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
+    ) -> BlockAnd<()> {
+        let match_scope = self.scopes.topmost();
+
+        let arm_end_blocks: Vec<_> = arm_candidates
+            .into_iter()
+            .map(|(arm, candidates)| {
+                debug!("lowering arm {:?}\ncanidates = {:?}", arm, candidates);
+
+                let arm_source_info = self.source_info(arm.span);
+                let arm_scope = (arm.scope, arm_source_info);
+                self.in_scope(arm_scope, arm.lint_level, |this| {
+                    let body = this.hir.mirror(arm.body.clone());
+                    let scope = this.declare_bindings(
+                        None,
+                        arm.span,
+                        &arm.top_pats_hack()[0],
+                        ArmHasGuard(arm.guard.is_some()),
+                        Some((Some(&scrutinee_place), scrutinee_span)),
+                    );
+
+                    let arm_block = this.bind_pattern(
+                        outer_source_info,
+                        candidates,
+                        arm.guard.as_ref().map(|g| (g, match_scope)),
+                        &fake_borrow_temps,
+                        scrutinee_span,
+                        arm.scope,
+                    );
+
+                    if let Some(source_scope) = scope {
+                        this.source_scope = source_scope;
+                    }
+
+                    this.into(destination, arm_block, body)
+                })
+            })
+            .collect();
+
+        // all the arm blocks will rejoin here
+        let end_block = self.cfg.start_new_block();
+
+        for arm_block in arm_end_blocks {
+            self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
+        }
+
+        self.source_scope = outer_source_info.scope;
+
+        end_block.unit()
+    }
+
+    /// Binds the variables and ascribes types for a given `match` arm.
+    ///
+    /// Also check if the guard matches, if it's provided.
+    fn bind_pattern(
+        &mut self,
+        outer_source_info: SourceInfo,
+        mut candidates: Vec<Candidate<'_, 'tcx>>,
+        guard: Option<(&Guard<'tcx>, region::Scope)>,
+        fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
+        scrutinee_span: Span,
+        arm_scope: region::Scope,
+    ) -> BasicBlock {
+        if candidates.len() == 1 {
+            // Avoid generating another `BasicBlock` when we only have one
+            // candidate.
+            self.bind_and_guard_matched_candidate(
+                candidates.pop().unwrap(),
+                guard,
+                fake_borrow_temps,
+                scrutinee_span,
+            )
+        } else {
+            let arm_block = self.cfg.start_new_block();
+            for candidate in candidates {
+                // Avoid scheduling drops multiple times.
+                self.clear_top_scope(arm_scope);
+                let binding_end = self.bind_and_guard_matched_candidate(
+                    candidate,
+                    guard,
+                    fake_borrow_temps,
+                    scrutinee_span,
+                );
+                self.cfg.goto(binding_end, outer_source_info, arm_block);
+            }
+            arm_block
+        }
+    }
+
+    pub(super) fn expr_into_pattern(
+        &mut self,
+        mut block: BasicBlock,
+        irrefutable_pat: Pat<'tcx>,
+        initializer: ExprRef<'tcx>,
+    ) -> BlockAnd<()> {
+        match *irrefutable_pat.kind {
+            // Optimize the case of `let x = ...` to write directly into `x`
+            PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
+                let place =
+                    self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
+                unpack!(block = self.into(&place, block, initializer));
+
+                // Inject a fake read, see comments on `FakeReadCause::ForLet`.
+                let source_info = self.source_info(irrefutable_pat.span);
+                self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place);
+
+                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
+                block.unit()
+            }
+
+            // Optimize the case of `let x: T = ...` to write directly
+            // into `x` and then require that `T == typeof(x)`.
+            //
+            // Weirdly, this is needed to prevent the
+            // `intrinsic-move-val.rs` test case from crashing. That
+            // test works with uninitialized values in a rather
+            // dubious way, so it may be that the test is kind of
+            // broken.
+            PatKind::AscribeUserType {
+                subpattern:
+                    Pat {
+                        kind:
+                            box PatKind::Binding {
+                                mode: BindingMode::ByValue,
+                                var,
+                                subpattern: None,
+                                ..
+                            },
+                        ..
+                    },
+                ascription:
+                    hair::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
+            } => {
+                let place =
+                    self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
+                unpack!(block = self.into(&place, block, initializer));
+
+                // Inject a fake read, see comments on `FakeReadCause::ForLet`.
+                let pattern_source_info = self.source_info(irrefutable_pat.span);
+                let cause_let = FakeReadCause::ForLet;
+                self.cfg.push_fake_read(block, pattern_source_info, cause_let, place.clone());
+
+                let ty_source_info = self.source_info(user_ty_span);
+                let user_ty = pat_ascription_ty.user_ty(
+                    &mut self.canonical_user_type_annotations,
+                    place.ty(&self.local_decls, self.hir.tcx()).ty,
+                    ty_source_info.span,
+                );
+                self.cfg.push(
+                    block,
+                    Statement {
+                        source_info: ty_source_info,
+                        kind: StatementKind::AscribeUserType(
+                            box (place, user_ty),
+                            // We always use invariant as the variance here. This is because the
+                            // variance field from the ascription refers to the variance to use
+                            // when applying the type to the value being matched, but this
+                            // ascription applies rather to the type of the binding. e.g., in this
+                            // example:
+                            //
+                            // ```
+                            // let x: T = <expr>
+                            // ```
+                            //
+                            // We are creating an ascription that defines the type of `x` to be
+                            // exactly `T` (i.e., with invariance). The variance field, in
+                            // contrast, is intended to be used to relate `T` to the type of
+                            // `<expr>`.
+                            ty::Variance::Invariant,
+                        ),
+                    },
+                );
+
+                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
+                block.unit()
+            }
+
+            _ => {
+                let place = unpack!(block = self.as_place(block, initializer));
+                self.place_into_pattern(block, irrefutable_pat, &place, true)
+            }
+        }
+    }
+
+    crate fn place_into_pattern(
+        &mut self,
+        block: BasicBlock,
+        irrefutable_pat: Pat<'tcx>,
+        initializer: &Place<'tcx>,
+        set_match_place: bool,
+    ) -> BlockAnd<()> {
+        // create a dummy candidate
+        let mut candidate = Candidate {
+            span: irrefutable_pat.span,
+            match_pairs: smallvec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
+            bindings: vec![],
+            ascriptions: vec![],
+
+            // since we don't call `match_candidates`, next fields are unused
+            otherwise_block: None,
+            pre_binding_block: block,
+            next_candidate_pre_binding_block: None,
+        };
+
+        // Simplify the candidate. Since the pattern is irrefutable, this should
+        // always convert all match-pairs into bindings.
+        self.simplify_candidate(&mut candidate);
+
+        if !candidate.match_pairs.is_empty() {
+            // ICE if no other errors have been emitted. This used to be a hard error that wouldn't
+            // be reached because `hair::pattern::check_match::check_match` wouldn't have let the
+            // compiler continue. In our tests this is only ever hit by
+            // `ui/consts/const-match-check.rs` with `--cfg eval1`, and that file already generates
+            // a different error before hand.
+            self.hir.tcx().sess.delay_span_bug(
+                candidate.match_pairs[0].pattern.span,
+                &format!(
+                    "match pairs {:?} remaining after simplifying irrefutable pattern",
+                    candidate.match_pairs,
+                ),
+            );
+        }
+
+        // for matches and function arguments, the place that is being matched
+        // can be set when creating the variables. But the place for
+        // let PATTERN = ... might not even exist until we do the assignment.
+        // so we set it here instead
+        if set_match_place {
+            for binding in &candidate.bindings {
+                let local = self.var_local_id(binding.var_id, OutsideGuard);
+
+                if let LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                    opt_match_place: Some((ref mut match_place, _)),
+                    ..
+                }))) = self.local_decls[local].local_info
+                {
+                    *match_place = Some(initializer.clone());
+                } else {
+                    bug!("Let binding to non-user variable.")
+                }
+            }
+        }
+
+        self.ascribe_types(block, &candidate.ascriptions);
+
+        // now apply the bindings, which will also declare the variables
+        self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
+
+        block.unit()
+    }
+
+    /// Declares the bindings of the given patterns and returns the visibility
+    /// scope for the bindings in these patterns, if such a scope had to be
+    /// created. NOTE: Declaring the bindings should always be done in their
+    /// drop scope.
+    crate fn declare_bindings(
+        &mut self,
+        mut visibility_scope: Option<SourceScope>,
+        scope_span: Span,
+        pattern: &Pat<'tcx>,
+        has_guard: ArmHasGuard,
+        opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
+    ) -> Option<SourceScope> {
+        debug!("declare_bindings: pattern={:?}", pattern);
+        self.visit_bindings(
+            &pattern,
+            UserTypeProjections::none(),
+            &mut |this, mutability, name, mode, var, span, ty, user_ty| {
+                if visibility_scope.is_none() {
+                    visibility_scope =
+                        Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
+                }
+                let source_info = SourceInfo { span, scope: this.source_scope };
+                let visibility_scope = visibility_scope.unwrap();
+                this.declare_binding(
+                    source_info,
+                    visibility_scope,
+                    mutability,
+                    name,
+                    mode,
+                    var,
+                    ty,
+                    user_ty,
+                    has_guard,
+                    opt_match_place.map(|(x, y)| (x.cloned(), y)),
+                    pattern.span,
+                );
+            },
+        );
+        visibility_scope
+    }
+
+    crate fn storage_live_binding(
+        &mut self,
+        block: BasicBlock,
+        var: HirId,
+        span: Span,
+        for_guard: ForGuard,
+    ) -> Place<'tcx> {
+        let local_id = self.var_local_id(var, for_guard);
+        let source_info = self.source_info(span);
+        self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
+        let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
+        self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
+        Place::from(local_id)
+    }
+
+    crate fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
+        let local_id = self.var_local_id(var, for_guard);
+        let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
+        self.schedule_drop(span, region_scope, local_id, DropKind::Value);
+    }
+
+    pub(super) fn visit_bindings(
+        &mut self,
+        pattern: &Pat<'tcx>,
+        pattern_user_ty: UserTypeProjections,
+        f: &mut impl FnMut(
+            &mut Self,
+            Mutability,
+            Name,
+            BindingMode,
+            HirId,
+            Span,
+            Ty<'tcx>,
+            UserTypeProjections,
+        ),
+    ) {
+        debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
+        match *pattern.kind {
+            PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, .. } => {
+                f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
+                if let Some(subpattern) = subpattern.as_ref() {
+                    self.visit_bindings(subpattern, pattern_user_ty, f);
+                }
+            }
+
+            PatKind::Array { ref prefix, ref slice, ref suffix }
+            | PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+                let from = u32::try_from(prefix.len()).unwrap();
+                let to = u32::try_from(suffix.len()).unwrap();
+                for subpattern in prefix {
+                    self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
+                }
+                for subpattern in slice {
+                    self.visit_bindings(subpattern, pattern_user_ty.clone().subslice(from, to), f);
+                }
+                for subpattern in suffix {
+                    self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
+                }
+            }
+
+            PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {}
+
+            PatKind::Deref { ref subpattern } => {
+                self.visit_bindings(subpattern, pattern_user_ty.deref(), f);
+            }
+
+            PatKind::AscribeUserType {
+                ref subpattern,
+                ascription: hair::pattern::Ascription { ref user_ty, user_ty_span, variance: _ },
+            } => {
+                // This corresponds to something like
+                //
+                // ```
+                // let A::<'a>(_): A<'static> = ...;
+                // ```
+                //
+                // Note that the variance doesn't apply here, as we are tracking the effect
+                // of `user_ty` on any bindings contained with subpattern.
+                let annotation = CanonicalUserTypeAnnotation {
+                    span: user_ty_span,
+                    user_ty: user_ty.user_ty,
+                    inferred_ty: subpattern.ty,
+                };
+                let projection = UserTypeProjection {
+                    base: self.canonical_user_type_annotations.push(annotation),
+                    projs: Vec::new(),
+                };
+                let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
+                self.visit_bindings(subpattern, subpattern_user_ty, f)
+            }
+
+            PatKind::Leaf { ref subpatterns } => {
+                for subpattern in subpatterns {
+                    let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
+                    debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
+                    self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
+                }
+            }
+
+            PatKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => {
+                for subpattern in subpatterns {
+                    let subpattern_user_ty =
+                        pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field);
+                    self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
+                }
+            }
+            PatKind::Or { ref pats } => {
+                for pat in pats {
+                    self.visit_bindings(&pat, pattern_user_ty.clone(), f);
+                }
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+crate struct Candidate<'pat, 'tcx> {
+    // span of the original pattern that gave rise to this candidate
+    span: Span,
+
+    // all of these must be satisfied...
+    match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
+
+    // ...these bindings established...
+    bindings: Vec<Binding<'tcx>>,
+
+    // ...and these types asserted...
+    ascriptions: Vec<Ascription<'tcx>>,
+
+    // ...and the guard must be evaluated, if false branch to Block...
+    otherwise_block: Option<BasicBlock>,
+
+    // ...and the blocks for add false edges between candidates
+    pre_binding_block: BasicBlock,
+    next_candidate_pre_binding_block: Option<BasicBlock>,
+}
+
+#[derive(Clone, Debug)]
+struct Binding<'tcx> {
+    span: Span,
+    source: Place<'tcx>,
+    name: Name,
+    var_id: HirId,
+    var_ty: Ty<'tcx>,
+    mutability: Mutability,
+    binding_mode: BindingMode,
+}
+
+/// Indicates that the type of `source` must be a subtype of the
+/// user-given type `user_ty`; this is basically a no-op but can
+/// influence region inference.
+#[derive(Clone, Debug)]
+struct Ascription<'tcx> {
+    span: Span,
+    source: Place<'tcx>,
+    user_ty: PatTyProj<'tcx>,
+    variance: ty::Variance,
+}
+
+#[derive(Clone, Debug)]
+crate struct MatchPair<'pat, 'tcx> {
+    // this place...
+    place: Place<'tcx>,
+
+    // ... must match this pattern.
+    pattern: &'pat Pat<'tcx>,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+enum TestKind<'tcx> {
+    /// Test the branches of enum.
+    Switch {
+        /// The enum being tested
+        adt_def: &'tcx ty::AdtDef,
+        /// The set of variants that we should create a branch for. We also
+        /// create an additional "otherwise" case.
+        variants: BitSet<VariantIdx>,
+    },
+
+    /// Test what value an `integer`, `bool` or `char` has.
+    SwitchInt {
+        /// The type of the value that we're testing.
+        switch_ty: Ty<'tcx>,
+        /// The (ordered) set of values that we test for.
+        ///
+        /// For integers and `char`s we create a branch to each of the values in
+        /// `options`, as well as an "otherwise" branch for all other values, even
+        /// in the (rare) case that options is exhaustive.
+        ///
+        /// For `bool` we always generate two edges, one for `true` and one for
+        /// `false`.
+        options: Vec<u128>,
+        /// Reverse map used to ensure that the values in `options` are unique.
+        indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+    },
+
+    /// Test for equality with value, possibly after an unsizing coercion to
+    /// `ty`,
+    Eq {
+        value: &'tcx ty::Const<'tcx>,
+        // Integer types are handled by `SwitchInt`, and constants with ADT
+        // types are converted back into patterns, so this can only be `&str`,
+        // `&[T]`, `f32` or `f64`.
+        ty: Ty<'tcx>,
+    },
+
+    /// Test whether the value falls within an inclusive or exclusive range
+    Range(PatRange<'tcx>),
+
+    /// Test length of the slice is equal to len
+    Len { len: u64, op: BinOp },
+}
+
+#[derive(Debug)]
+crate struct Test<'tcx> {
+    span: Span,
+    kind: TestKind<'tcx>,
+}
+
+/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether
+/// a match arm has a guard expression attached to it.
+#[derive(Copy, Clone, Debug)]
+crate struct ArmHasGuard(crate bool);
+
+///////////////////////////////////////////////////////////////////////////
+// Main matching algorithm
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// The main match algorithm. It begins with a set of candidates
+    /// `candidates` and has the job of generating code to determine
+    /// which of these candidates, if any, is the correct one. The
+    /// candidates are sorted such that the first item in the list
+    /// has the highest priority. When a candidate is found to match
+    /// the value, we will generate a branch to the appropriate
+    /// prebinding block.
+    ///
+    /// If we find that *NONE* of the candidates apply, we branch to the
+    /// `otherwise_block`. In principle, this means that the input list was not
+    /// exhaustive, though at present we sometimes are not smart enough to
+    /// recognize all exhaustive inputs.
+    ///
+    /// It might be surprising that the input can be inexhaustive.
+    /// Indeed, initially, it is not, because all matches are
+    /// exhaustive in Rust. But during processing we sometimes divide
+    /// up the list of candidates and recurse with a non-exhaustive
+    /// list. This is important to keep the size of the generated code
+    /// under control. See `test_candidates` for more details.
+    ///
+    /// If `fake_borrows` is Some, then places which need fake borrows
+    /// will be added to it.
+    fn match_candidates<'pat>(
+        &mut self,
+        span: Span,
+        start_block: &mut Option<BasicBlock>,
+        otherwise_block: Option<BasicBlock>,
+        candidates: &mut [&mut Candidate<'pat, 'tcx>],
+        fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
+    ) {
+        debug!(
+            "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
+            span, candidates, start_block, otherwise_block,
+        );
+
+        // Start by simplifying candidates. Once this process is complete, all
+        // the match pairs which remain require some form of test, whether it
+        // be a switch or pattern comparison.
+        for candidate in &mut *candidates {
+            self.simplify_candidate(candidate);
+        }
+
+        // The candidates are sorted by priority. Check to see whether the
+        // higher priority candidates (and hence at the front of the slice)
+        // have satisfied all their match pairs.
+        let fully_matched = candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
+        debug!("match_candidates: {:?} candidates fully matched", fully_matched);
+        let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched);
+
+        let block: BasicBlock = if !matched_candidates.is_empty() {
+            let otherwise_block =
+                self.select_matched_candidates(matched_candidates, start_block, fake_borrows);
+
+            if let Some(last_otherwise_block) = otherwise_block {
+                last_otherwise_block
+            } else {
+                // Any remaining candidates are unreachable.
+                if unmatched_candidates.is_empty() {
+                    return;
+                }
+                self.cfg.start_new_block()
+            }
+        } else {
+            *start_block.get_or_insert_with(|| self.cfg.start_new_block())
+        };
+
+        // If there are no candidates that still need testing, we're
+        // done. Since all matches are exhaustive, execution should
+        // never reach this point.
+        if unmatched_candidates.is_empty() {
+            let source_info = self.source_info(span);
+            match otherwise_block {
+                Some(otherwise) => self.cfg.goto(block, source_info, otherwise),
+                None => self.cfg.terminate(block, source_info, TerminatorKind::Unreachable),
+            }
+            return;
+        }
+
+        // Test for the remaining candidates.
+        self.test_candidates(span, unmatched_candidates, block, otherwise_block, fake_borrows);
+    }
+
+    /// Link up matched candidates. For example, if we have something like
+    /// this:
+    ///
+    /// ...
+    /// Some(x) if cond => ...
+    /// Some(x) => ...
+    /// Some(x) if cond => ...
+    /// ...
+    ///
+    /// We generate real edges from:
+    /// * `start_block` to the `prebinding_block` of the first pattern,
+    /// * the otherwise block of the first pattern to the second pattern,
+    /// * the otherwise block of the third pattern to the a block with an
+    ///   Unreachable terminator.
+    ///
+    /// As well as that we add fake edges from the otherwise blocks to the
+    /// prebinding block of the next candidate in the original set of
+    /// candidates.
+    fn select_matched_candidates(
+        &mut self,
+        matched_candidates: &mut [&mut Candidate<'_, 'tcx>],
+        start_block: &mut Option<BasicBlock>,
+        fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
+    ) -> Option<BasicBlock> {
+        debug_assert!(
+            !matched_candidates.is_empty(),
+            "select_matched_candidates called with no candidates",
+        );
+
+        // Insert a borrows of prefixes of places that are bound and are
+        // behind a dereference projection.
+        //
+        // These borrows are taken to avoid situations like the following:
+        //
+        // match x[10] {
+        //     _ if { x = &[0]; false } => (),
+        //     y => (), // Out of bounds array access!
+        // }
+        //
+        // match *x {
+        //     // y is bound by reference in the guard and then by copy in the
+        //     // arm, so y is 2 in the arm!
+        //     y if { y == 1 && (x = &2) == () } => y,
+        //     _ => 3,
+        // }
+        if let Some(fake_borrows) = fake_borrows {
+            for Binding { source, .. } in
+                matched_candidates.iter().flat_map(|candidate| &candidate.bindings)
+            {
+                if let Some(i) =
+                    source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref)
+                {
+                    let proj_base = &source.projection[..i];
+
+                    fake_borrows.insert(Place {
+                        local: source.local.clone(),
+                        projection: self.hir.tcx().intern_place_elems(proj_base),
+                    });
+                }
+            }
+        }
+
+        let fully_matched_with_guard = matched_candidates
+            .iter()
+            .position(|c| c.otherwise_block.is_none())
+            .unwrap_or(matched_candidates.len() - 1);
+
+        let (reachable_candidates, unreachable_candidates) =
+            matched_candidates.split_at_mut(fully_matched_with_guard + 1);
+
+        let first_candidate = &reachable_candidates[0];
+        let first_prebinding_block = first_candidate.pre_binding_block;
+
+        // `goto -> first_prebinding_block` from the `start_block` if there is one.
+        if let Some(start_block) = *start_block {
+            let source_info = self.source_info(first_candidate.span);
+            self.cfg.goto(start_block, source_info, first_prebinding_block);
+        } else {
+            *start_block = Some(first_prebinding_block);
+        }
+
+        for (first_candidate, second_candidate) in reachable_candidates.iter().tuple_windows() {
+            let source_info = self.source_info(first_candidate.span);
+            if let Some(otherwise_block) = first_candidate.otherwise_block {
+                self.false_edges(
+                    otherwise_block,
+                    second_candidate.pre_binding_block,
+                    first_candidate.next_candidate_pre_binding_block,
+                    source_info,
+                );
+            } else {
+                bug!("candidate other than the last has no guard");
+            }
+        }
+
+        debug!("match_candidates: add false edges for unreachable {:?}", unreachable_candidates);
+        for candidate in unreachable_candidates {
+            if let Some(otherwise) = candidate.otherwise_block {
+                let source_info = self.source_info(candidate.span);
+                let unreachable = self.cfg.start_new_block();
+                self.false_edges(
+                    otherwise,
+                    unreachable,
+                    candidate.next_candidate_pre_binding_block,
+                    source_info,
+                );
+                self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
+            }
+        }
+
+        let last_candidate = reachable_candidates.last().unwrap();
+        if let Some(otherwise) = last_candidate.otherwise_block {
+            let source_info = self.source_info(last_candidate.span);
+            let block = self.cfg.start_new_block();
+            self.false_edges(
+                otherwise,
+                block,
+                last_candidate.next_candidate_pre_binding_block,
+                source_info,
+            );
+            Some(block)
+        } else {
+            None
+        }
+    }
+
+    /// This is the most subtle part of the matching algorithm. At
+    /// this point, the input candidates have been fully simplified,
+    /// and so we know that all remaining match-pairs require some
+    /// sort of test. To decide what test to do, we take the highest
+    /// priority candidate (last one in the list) and extract the
+    /// first match-pair from the list. From this we decide what kind
+    /// of test is needed using `test`, defined in the `test` module.
+    ///
+    /// *Note:* taking the first match pair is somewhat arbitrary, and
+    /// we might do better here by choosing more carefully what to
+    /// test.
+    ///
+    /// For example, consider the following possible match-pairs:
+    ///
+    /// 1. `x @ Some(P)` -- we will do a `Switch` to decide what variant `x` has
+    /// 2. `x @ 22` -- we will do a `SwitchInt`
+    /// 3. `x @ 3..5` -- we will do a range test
+    /// 4. etc.
+    ///
+    /// Once we know what sort of test we are going to perform, this
+    /// Tests may also help us with other candidates. So we walk over
+    /// the candidates (from high to low priority) and check. This
+    /// gives us, for each outcome of the test, a transformed list of
+    /// candidates. For example, if we are testing the current
+    /// variant of `x.0`, and we have a candidate `{x.0 @ Some(v), x.1
+    /// @ 22}`, then we would have a resulting candidate of `{(x.0 as
+    /// Some).0 @ v, x.1 @ 22}`. Note that the first match-pair is now
+    /// simpler (and, in fact, irrefutable).
+    ///
+    /// But there may also be candidates that the test just doesn't
+    /// apply to. The classical example involves wildcards:
+    ///
+    /// ```
+    /// # let (x, y, z) = (true, true, true);
+    /// match (x, y, z) {
+    ///     (true, _, true) => true,    // (0)
+    ///     (_, true, _) => true,       // (1)
+    ///     (false, false, _) => false, // (2)
+    ///     (true, _, false) => false,  // (3)
+    /// }
+    /// ```
+    ///
+    /// In that case, after we test on `x`, there are 2 overlapping candidate
+    /// sets:
+    ///
+    /// - If the outcome is that `x` is true, candidates 0, 1, and 3
+    /// - If the outcome is that `x` is false, candidates 1 and 2
+    ///
+    /// Here, the traditional "decision tree" method would generate 2
+    /// separate code-paths for the 2 separate cases.
+    ///
+    /// In some cases, this duplication can create an exponential amount of
+    /// code. This is most easily seen by noticing that this method terminates
+    /// with precisely the reachable arms being reachable - but that problem
+    /// is trivially NP-complete:
+    ///
+    /// ```rust
+    ///     match (var0, var1, var2, var3, ..) {
+    ///         (true, _, _, false, true, ...) => false,
+    ///         (_, true, true, false, _, ...) => false,
+    ///         (false, _, false, false, _, ...) => false,
+    ///         ...
+    ///         _ => true
+    ///     }
+    /// ```
+    ///
+    /// Here the last arm is reachable only if there is an assignment to
+    /// the variables that does not match any of the literals. Therefore,
+    /// compilation would take an exponential amount of time in some cases.
+    ///
+    /// That kind of exponential worst-case might not occur in practice, but
+    /// our simplistic treatment of constants and guards would make it occur
+    /// in very common situations - for example #29740:
+    ///
+    /// ```rust
+    /// match x {
+    ///     "foo" if foo_guard => ...,
+    ///     "bar" if bar_guard => ...,
+    ///     "baz" if baz_guard => ...,
+    ///     ...
+    /// }
+    /// ```
+    ///
+    /// Here we first test the match-pair `x @ "foo"`, which is an `Eq` test.
+    ///
+    /// It might seem that we would end up with 2 disjoint candidate
+    /// sets, consisting of the first candidate or the other 3, but our
+    /// algorithm doesn't reason about "foo" being distinct from the other
+    /// constants; it considers the latter arms to potentially match after
+    /// both outcomes, which obviously leads to an exponential amount
+    /// of tests.
+    ///
+    /// To avoid these kinds of problems, our algorithm tries to ensure
+    /// the amount of generated tests is linear. When we do a k-way test,
+    /// we return an additional "unmatched" set alongside the obvious `k`
+    /// sets. When we encounter a candidate that would be present in more
+    /// than one of the sets, we put it and all candidates below it into the
+    /// "unmatched" set. This ensures these `k+1` sets are disjoint.
+    ///
+    /// After we perform our test, we branch into the appropriate candidate
+    /// set and recurse with `match_candidates`. These sub-matches are
+    /// obviously inexhaustive - as we discarded our otherwise set - so
+    /// we set their continuation to do `match_candidates` on the
+    /// "unmatched" set (which is again inexhaustive).
+    ///
+    /// If you apply this to the above test, you basically wind up
+    /// with an if-else-if chain, testing each candidate in turn,
+    /// which is precisely what we want.
+    ///
+    /// In addition to avoiding exponential-time blowups, this algorithm
+    /// also has nice property that each guard and arm is only generated
+    /// once.
+    fn test_candidates<'pat, 'b, 'c>(
+        &mut self,
+        span: Span,
+        mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
+        block: BasicBlock,
+        mut otherwise_block: Option<BasicBlock>,
+        fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
+    ) {
+        // extract the match-pair from the highest priority candidate
+        let match_pair = &candidates.first().unwrap().match_pairs[0];
+        let mut test = self.test(match_pair);
+        let match_place = match_pair.place.clone();
+
+        // most of the time, the test to perform is simply a function
+        // of the main candidate; but for a test like SwitchInt, we
+        // may want to add cases based on the candidates that are
+        // available
+        match test.kind {
+            TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
+                for candidate in candidates.iter() {
+                    if !self.add_cases_to_switch(
+                        &match_place,
+                        candidate,
+                        switch_ty,
+                        options,
+                        indices,
+                    ) {
+                        break;
+                    }
+                }
+            }
+            TestKind::Switch { adt_def: _, ref mut variants } => {
+                for candidate in candidates.iter() {
+                    if !self.add_variants_to_switch(&match_place, candidate, variants) {
+                        break;
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        // Insert a Shallow borrow of any places that is switched on.
+        fake_borrows.as_mut().map(|fb| fb.insert(match_place.clone()));
+
+        // perform the test, branching to one of N blocks. For each of
+        // those N possible outcomes, create a (initially empty)
+        // vector of candidates. Those are the candidates that still
+        // apply if the test has that particular outcome.
+        debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
+        let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![];
+        target_candidates.resize_with(test.targets(), Default::default);
+
+        let total_candidate_count = candidates.len();
+
+        // Sort the candidates into the appropriate vector in
+        // `target_candidates`. Note that at some point we may
+        // encounter a candidate where the test is not relevant; at
+        // that point, we stop sorting.
+        while let Some(candidate) = candidates.first_mut() {
+            if let Some(idx) = self.sort_candidate(&match_place, &test, candidate) {
+                let (candidate, rest) = candidates.split_first_mut().unwrap();
+                target_candidates[idx].push(candidate);
+                candidates = rest;
+            } else {
+                break;
+            }
+        }
+        // at least the first candidate ought to be tested
+        assert!(total_candidate_count > candidates.len());
+        debug!("tested_candidates: {}", total_candidate_count - candidates.len());
+        debug!("untested_candidates: {}", candidates.len());
+
+        // HACK(matthewjasper) This is a closure so that we can let the test
+        // create its blocks before the rest of the match. This currently
+        // improves the speed of llvm when optimizing long string literal
+        // matches
+        let make_target_blocks = move |this: &mut Self| -> Vec<BasicBlock> {
+            // For each outcome of test, process the candidates that still
+            // apply. Collect a list of blocks where control flow will
+            // branch if one of the `target_candidate` sets is not
+            // exhaustive.
+            if !candidates.is_empty() {
+                let remainder_start = &mut None;
+                this.match_candidates(
+                    span,
+                    remainder_start,
+                    otherwise_block,
+                    candidates,
+                    fake_borrows,
+                );
+                otherwise_block = Some(remainder_start.unwrap());
+            };
+
+            target_candidates
+                .into_iter()
+                .map(|mut candidates| {
+                    if candidates.len() != 0 {
+                        let candidate_start = &mut None;
+                        this.match_candidates(
+                            span,
+                            candidate_start,
+                            otherwise_block,
+                            &mut *candidates,
+                            fake_borrows,
+                        );
+                        candidate_start.unwrap()
+                    } else {
+                        *otherwise_block.get_or_insert_with(|| {
+                            let unreachable = this.cfg.start_new_block();
+                            let source_info = this.source_info(span);
+                            this.cfg.terminate(
+                                unreachable,
+                                source_info,
+                                TerminatorKind::Unreachable,
+                            );
+                            unreachable
+                        })
+                    }
+                })
+                .collect()
+        };
+
+        self.perform_test(block, &match_place, &test, make_target_blocks);
+    }
+
+    /// Determine the fake borrows that are needed from a set of places that
+    /// have to be stable across match guards.
+    ///
+    /// Returns a list of places that need a fake borrow and the temporary
+    /// that's used to store the fake borrow.
+    ///
+    /// Match exhaustiveness checking is not able to handle the case where the
+    /// place being matched on is mutated in the guards. We add "fake borrows"
+    /// to the guards that prevent any mutation of the place being matched.
+    /// There are a some subtleties:
+    ///
+    /// 1. Borrowing `*x` doesn't prevent assigning to `x`. If `x` is a shared
+    ///    reference, the borrow isn't even tracked. As such we have to add fake
+    ///    borrows of any prefixes of a place
+    /// 2. We don't want `match x { _ => (), }` to conflict with mutable
+    ///    borrows of `x`, so we only add fake borrows for places which are
+    ///    bound or tested by the match.
+    /// 3. We don't want the fake borrows to conflict with `ref mut` bindings,
+    ///    so we use a special BorrowKind for them.
+    /// 4. The fake borrows may be of places in inactive variants, so it would
+    ///    be UB to generate code for them. They therefore have to be removed
+    ///    by a MIR pass run after borrow checking.
+    fn calculate_fake_borrows<'b>(
+        &mut self,
+        fake_borrows: &'b FxHashSet<Place<'tcx>>,
+        temp_span: Span,
+    ) -> Vec<(Place<'tcx>, Local)> {
+        let tcx = self.hir.tcx();
+
+        debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows);
+
+        let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len());
+
+        // Insert a Shallow borrow of the prefixes of any fake borrows.
+        for place in fake_borrows {
+            let mut cursor = place.projection.as_ref();
+            while let [proj_base @ .., elem] = cursor {
+                cursor = proj_base;
+
+                if let ProjectionElem::Deref = elem {
+                    // Insert a shallow borrow after a deref. For other
+                    // projections the borrow of prefix_cursor will
+                    // conflict with any mutation of base.
+                    all_fake_borrows.push(PlaceRef { local: &place.local, projection: proj_base });
+                }
+            }
+
+            all_fake_borrows.push(place.as_ref());
+        }
+
+        // Deduplicate and ensure a deterministic order.
+        all_fake_borrows.sort();
+        all_fake_borrows.dedup();
+
+        debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
+
+        all_fake_borrows
+            .into_iter()
+            .map(|matched_place_ref| {
+                let matched_place = Place {
+                    local: matched_place_ref.local.clone(),
+                    projection: tcx.intern_place_elems(matched_place_ref.projection),
+                };
+                let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
+                let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
+                let fake_borrow_temp =
+                    self.local_decls.push(LocalDecl::new_temp(fake_borrow_ty, temp_span));
+
+                (matched_place, fake_borrow_temp)
+            })
+            .collect()
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Pat binding - used for `let` and function parameters as well.
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Initializes each of the bindings from the candidate by
+    /// moving/copying/ref'ing the source as appropriate. Tests the guard, if
+    /// any, and then branches to the arm. Returns the block for the case where
+    /// the guard fails.
+    ///
+    /// Note: we do not check earlier that if there is a guard,
+    /// there cannot be move bindings. We avoid a use-after-move by only
+    /// moving the binding once the guard has evaluated to true (see below).
+    fn bind_and_guard_matched_candidate<'pat>(
+        &mut self,
+        candidate: Candidate<'pat, 'tcx>,
+        guard: Option<(&Guard<'tcx>, region::Scope)>,
+        fake_borrows: &Vec<(Place<'tcx>, Local)>,
+        scrutinee_span: Span,
+    ) -> BasicBlock {
+        debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
+
+        debug_assert!(candidate.match_pairs.is_empty());
+
+        let candidate_source_info = self.source_info(candidate.span);
+
+        let mut block = candidate.pre_binding_block;
+
+        // If we are adding our own statements, then we need a fresh block.
+        let create_fresh_block = candidate.next_candidate_pre_binding_block.is_some()
+            || !candidate.bindings.is_empty()
+            || !candidate.ascriptions.is_empty()
+            || guard.is_some();
+
+        if create_fresh_block {
+            let fresh_block = self.cfg.start_new_block();
+            self.false_edges(
+                block,
+                fresh_block,
+                candidate.next_candidate_pre_binding_block,
+                candidate_source_info,
+            );
+            block = fresh_block;
+            self.ascribe_types(block, &candidate.ascriptions);
+        } else {
+            return block;
+        }
+
+        // rust-lang/rust#27282: The `autoref` business deserves some
+        // explanation here.
+        //
+        // The intent of the `autoref` flag is that when it is true,
+        // then any pattern bindings of type T will map to a `&T`
+        // within the context of the guard expression, but will
+        // continue to map to a `T` in the context of the arm body. To
+        // avoid surfacing this distinction in the user source code
+        // (which would be a severe change to the language and require
+        // far more revision to the compiler), when `autoref` is true,
+        // then any occurrence of the identifier in the guard
+        // expression will automatically get a deref op applied to it.
+        //
+        // So an input like:
+        //
+        // ```
+        // let place = Foo::new();
+        // match place { foo if inspect(foo)
+        //     => feed(foo), ...  }
+        // ```
+        //
+        // will be treated as if it were really something like:
+        //
+        // ```
+        // let place = Foo::new();
+        // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
+        //     => { let tmp2 = place; feed(tmp2) }, ... }
+        //
+        // And an input like:
+        //
+        // ```
+        // let place = Foo::new();
+        // match place { ref mut foo if inspect(foo)
+        //     => feed(foo), ...  }
+        // ```
+        //
+        // will be treated as if it were really something like:
+        //
+        // ```
+        // let place = Foo::new();
+        // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
+        //     => { let tmp2 = &mut place; feed(tmp2) }, ... }
+        // ```
+        //
+        // In short, any pattern binding will always look like *some*
+        // kind of `&T` within the guard at least in terms of how the
+        // MIR-borrowck views it, and this will ensure that guard
+        // expressions cannot mutate their the match inputs via such
+        // bindings. (It also ensures that guard expressions can at
+        // most *copy* values from such bindings; non-Copy things
+        // cannot be moved via pattern bindings in guard expressions.)
+        //
+        // ----
+        //
+        // Implementation notes (under assumption `autoref` is true).
+        //
+        // To encode the distinction above, we must inject the
+        // temporaries `tmp1` and `tmp2`.
+        //
+        // There are two cases of interest: binding by-value, and binding by-ref.
+        //
+        // 1. Binding by-value: Things are simple.
+        //
+        //    * Establishing `tmp1` creates a reference into the
+        //      matched place. This code is emitted by
+        //      bind_matched_candidate_for_guard.
+        //
+        //    * `tmp2` is only initialized "lazily", after we have
+        //      checked the guard. Thus, the code that can trigger
+        //      moves out of the candidate can only fire after the
+        //      guard evaluated to true. This initialization code is
+        //      emitted by bind_matched_candidate_for_arm.
+        //
+        // 2. Binding by-reference: Things are tricky.
+        //
+        //    * Here, the guard expression wants a `&&` or `&&mut`
+        //      into the original input. This means we need to borrow
+        //      the reference that we create for the arm.
+        //    * So we eagerly create the reference for the arm and then take a
+        //      reference to that.
+        if let Some((guard, region_scope)) = guard {
+            let tcx = self.hir.tcx();
+
+            self.bind_matched_candidate_for_guard(block, &candidate.bindings);
+            let guard_frame = GuardFrame {
+                locals: candidate
+                    .bindings
+                    .iter()
+                    .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode))
+                    .collect(),
+            };
+            debug!("entering guard building context: {:?}", guard_frame);
+            self.guard_context.push(guard_frame);
+
+            let re_erased = tcx.lifetimes.re_erased;
+            let scrutinee_source_info = self.source_info(scrutinee_span);
+            for (place, temp) in fake_borrows {
+                let borrow = Rvalue::Ref(re_erased, BorrowKind::Shallow, place.clone());
+                self.cfg.push_assign(block, scrutinee_source_info, &Place::from(*temp), borrow);
+            }
+
+            // the block to branch to if the guard fails; if there is no
+            // guard, this block is simply unreachable
+            let guard = match guard {
+                Guard::If(e) => self.hir.mirror(e.clone()),
+            };
+            let source_info = self.source_info(guard.span);
+            let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span));
+            let (post_guard_block, otherwise_post_guard_block) =
+                self.test_bool(block, guard, source_info);
+            let guard_frame = self.guard_context.pop().unwrap();
+            debug!("Exiting guard building context with locals: {:?}", guard_frame);
+
+            for &(_, temp) in fake_borrows {
+                let cause = FakeReadCause::ForMatchGuard;
+                self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
+            }
+
+            self.exit_scope(
+                source_info.span,
+                region_scope,
+                otherwise_post_guard_block,
+                candidate.otherwise_block.unwrap(),
+            );
+
+            // We want to ensure that the matched candidates are bound
+            // after we have confirmed this candidate *and* any
+            // associated guard; Binding them on `block` is too soon,
+            // because that would be before we've checked the result
+            // from the guard.
+            //
+            // But binding them on the arm is *too late*, because
+            // then all of the candidates for a single arm would be
+            // bound in the same place, that would cause a case like:
+            //
+            // ```rust
+            // match (30, 2) {
+            //     (mut x, 1) | (2, mut x) if { true } => { ... }
+            //     ...                                 // ^^^^^^^ (this is `arm_block`)
+            // }
+            // ```
+            //
+            // would yield a `arm_block` something like:
+            //
+            // ```
+            // StorageLive(_4);        // _4 is `x`
+            // _4 = &mut (_1.0: i32);  // this is handling `(mut x, 1)` case
+            // _4 = &mut (_1.1: i32);  // this is handling `(2, mut x)` case
+            // ```
+            //
+            // and that is clearly not correct.
+            let by_value_bindings = candidate.bindings.iter().filter(|binding| {
+                if let BindingMode::ByValue = binding.binding_mode { true } else { false }
+            });
+            // Read all of the by reference bindings to ensure that the
+            // place they refer to can't be modified by the guard.
+            for binding in by_value_bindings.clone() {
+                let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
+                let cause = FakeReadCause::ForGuardBinding;
+                self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id));
+            }
+            self.bind_matched_candidate_for_arm_body(post_guard_block, by_value_bindings);
+
+            post_guard_block
+        } else {
+            assert!(candidate.otherwise_block.is_none());
+            // (Here, it is not too early to bind the matched
+            // candidate on `block`, because there is no guard result
+            // that we have to inspect before we bind them.)
+            self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
+            block
+        }
+    }
+
+    /// Append `AscribeUserType` statements onto the end of `block`
+    /// for each ascription
+    fn ascribe_types(&mut self, block: BasicBlock, ascriptions: &[Ascription<'tcx>]) {
+        for ascription in ascriptions {
+            let source_info = self.source_info(ascription.span);
+
+            debug!(
+                "adding user ascription at span {:?} of place {:?} and {:?}",
+                source_info.span, ascription.source, ascription.user_ty,
+            );
+
+            let user_ty = ascription.user_ty.clone().user_ty(
+                &mut self.canonical_user_type_annotations,
+                ascription.source.ty(&self.local_decls, self.hir.tcx()).ty,
+                source_info.span,
+            );
+            self.cfg.push(
+                block,
+                Statement {
+                    source_info,
+                    kind: StatementKind::AscribeUserType(
+                        box (ascription.source.clone(), user_ty),
+                        ascription.variance,
+                    ),
+                },
+            );
+        }
+    }
+
+    fn bind_matched_candidate_for_guard(&mut self, block: BasicBlock, bindings: &[Binding<'tcx>]) {
+        debug!("bind_matched_candidate_for_guard(block={:?}, bindings={:?})", block, bindings);
+
+        // Assign each of the bindings. Since we are binding for a
+        // guard expression, this will never trigger moves out of the
+        // candidate.
+        let re_erased = self.hir.tcx().lifetimes.re_erased;
+        for binding in bindings {
+            let source_info = self.source_info(binding.span);
+
+            // For each pattern ident P of type T, `ref_for_guard` is
+            // a reference R: &T pointing to the location matched by
+            // the pattern, and every occurrence of P within a guard
+            // denotes *R.
+            let ref_for_guard =
+                self.storage_live_binding(block, binding.var_id, binding.span, RefWithinGuard);
+            match binding.binding_mode {
+                BindingMode::ByValue => {
+                    let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source.clone());
+                    self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
+                }
+                BindingMode::ByRef(borrow_kind) => {
+                    let value_for_arm = self.storage_live_binding(
+                        block,
+                        binding.var_id,
+                        binding.span,
+                        OutsideGuard,
+                    );
+
+                    let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source.clone());
+                    self.cfg.push_assign(block, source_info, &value_for_arm, rvalue);
+                    let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
+                    self.cfg.push_assign(block, source_info, &ref_for_guard, rvalue);
+                }
+            }
+        }
+    }
+
+    fn bind_matched_candidate_for_arm_body<'b>(
+        &mut self,
+        block: BasicBlock,
+        bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
+    ) where
+        'tcx: 'b,
+    {
+        debug!("bind_matched_candidate_for_arm_body(block={:?})", block);
+
+        let re_erased = self.hir.tcx().lifetimes.re_erased;
+        // Assign each of the bindings. This may trigger moves out of the candidate.
+        for binding in bindings {
+            let source_info = self.source_info(binding.span);
+            let local =
+                self.storage_live_binding(block, binding.var_id, binding.span, OutsideGuard);
+            self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
+            let rvalue = match binding.binding_mode {
+                BindingMode::ByValue => {
+                    Rvalue::Use(self.consume_by_copy_or_move(binding.source.clone()))
+                }
+                BindingMode::ByRef(borrow_kind) => {
+                    Rvalue::Ref(re_erased, borrow_kind, binding.source.clone())
+                }
+            };
+            self.cfg.push_assign(block, source_info, &local, rvalue);
+        }
+    }
+
+    /// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where the bound
+    /// `var` has type `T` in the arm body) in a pattern maps to 2 locals. The
+    /// first local is a binding for occurrences of `var` in the guard, which
+    /// will have type `&T`. The second local is a binding for occurrences of
+    /// `var` in the arm body, which will have type `T`.
+    fn declare_binding(
+        &mut self,
+        source_info: SourceInfo,
+        visibility_scope: SourceScope,
+        mutability: Mutability,
+        name: Name,
+        mode: BindingMode,
+        var_id: HirId,
+        var_ty: Ty<'tcx>,
+        user_ty: UserTypeProjections,
+        has_guard: ArmHasGuard,
+        opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
+        pat_span: Span,
+    ) {
+        debug!(
+            "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
+             visibility_scope={:?}, source_info={:?})",
+            var_id, name, mode, var_ty, visibility_scope, source_info
+        );
+
+        let tcx = self.hir.tcx();
+        let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
+        let binding_mode = match mode {
+            BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
+            BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability.into()),
+        };
+        debug!("declare_binding: user_ty={:?}", user_ty);
+        let local = LocalDecl::<'tcx> {
+            mutability,
+            ty: var_ty,
+            user_ty,
+            source_info,
+            internal: false,
+            is_block_tail: None,
+            local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                binding_mode,
+                // hypothetically, `visit_bindings` could try to unzip
+                // an outermost hir::Ty as we descend, matching up
+                // idents in pat; but complex w/ unclear UI payoff.
+                // Instead, just abandon providing diagnostic info.
+                opt_ty_info: None,
+                opt_match_place,
+                pat_span,
+            }))),
+        };
+        let for_arm_body = self.local_decls.push(local);
+        self.var_debug_info.push(VarDebugInfo {
+            name,
+            source_info: debug_source_info,
+            place: for_arm_body.into(),
+        });
+        let locals = if has_guard.0 {
+            let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
+                // This variable isn't mutated but has a name, so has to be
+                // immutable to avoid the unused mut lint.
+                mutability: Mutability::Not,
+                ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty),
+                user_ty: UserTypeProjections::none(),
+                source_info,
+                internal: false,
+                is_block_tail: None,
+                local_info: LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)),
+            });
+            self.var_debug_info.push(VarDebugInfo {
+                name,
+                source_info: debug_source_info,
+                place: ref_for_guard.into(),
+            });
+            LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
+        } else {
+            LocalsForNode::One(for_arm_body)
+        };
+        debug!("declare_binding: vars={:?}", locals);
+        self.var_indices.insert(var_id, locals);
+    }
+}
diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/src/librustc_mir_build/build/matches/simplify.rs
new file mode 100644 (file)
index 0000000..a5f691a
--- /dev/null
@@ -0,0 +1,204 @@
+//! Simplifying Candidates
+//!
+//! *Simplifying* a match pair `place @ pattern` means breaking it down
+//! into bindings or other, simpler match pairs. For example:
+//!
+//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
+//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
+//!
+//! The `simplify_candidate` routine just repeatedly applies these
+//! sort of simplifications until there is nothing left to
+//! simplify. Match pairs cannot be simplified if they require some
+//! sort of test: for example, testing which variant an enum is, or
+//! testing a value against a constant.
+
+use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
+use crate::build::Builder;
+use crate::hair::{self, *};
+use rustc::mir::interpret::truncate;
+use rustc::ty;
+use rustc::ty::layout::{Integer, IntegerExt, Size};
+use rustc_hir::RangeEnd;
+use syntax::attr::{SignedInt, UnsignedInt};
+
+use std::mem;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    crate fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) {
+        // repeatedly simplify match pairs until fixed point is reached
+        loop {
+            let match_pairs = mem::take(&mut candidate.match_pairs);
+            let mut changed = false;
+            for match_pair in match_pairs {
+                match self.simplify_match_pair(match_pair, candidate) {
+                    Ok(()) => {
+                        changed = true;
+                    }
+                    Err(match_pair) => {
+                        candidate.match_pairs.push(match_pair);
+                    }
+                }
+            }
+            if !changed {
+                return; // if we were not able to simplify any, done.
+            }
+        }
+    }
+
+    /// Tries to simplify `match_pair`, returning `Ok(())` if
+    /// successful. If successful, new match pairs and bindings will
+    /// have been pushed into the candidate. If no simplification is
+    /// possible, `Err` is returned and no changes are made to
+    /// candidate.
+    fn simplify_match_pair<'pat>(
+        &mut self,
+        match_pair: MatchPair<'pat, 'tcx>,
+        candidate: &mut Candidate<'pat, 'tcx>,
+    ) -> Result<(), MatchPair<'pat, 'tcx>> {
+        let tcx = self.hir.tcx();
+        match *match_pair.pattern.kind {
+            PatKind::AscribeUserType {
+                ref subpattern,
+                ascription: hair::pattern::Ascription { variance, ref user_ty, user_ty_span },
+            } => {
+                // Apply the type ascription to the value at `match_pair.place`, which is the
+                // value being matched, taking the variance field into account.
+                candidate.ascriptions.push(Ascription {
+                    span: user_ty_span,
+                    user_ty: user_ty.clone(),
+                    source: match_pair.place.clone(),
+                    variance,
+                });
+
+                candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+
+                Ok(())
+            }
+
+            PatKind::Wild => {
+                // nothing left to do
+                Ok(())
+            }
+
+            PatKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
+                candidate.bindings.push(Binding {
+                    name,
+                    mutability,
+                    span: match_pair.pattern.span,
+                    source: match_pair.place.clone(),
+                    var_id: var,
+                    var_ty: ty,
+                    binding_mode: mode,
+                });
+
+                if let Some(subpattern) = subpattern.as_ref() {
+                    // this is the `x @ P` case; have to keep matching against `P` now
+                    candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+                }
+
+                Ok(())
+            }
+
+            PatKind::Constant { .. } => {
+                // FIXME normalize patterns when possible
+                Err(match_pair)
+            }
+
+            PatKind::Range(PatRange { lo, hi, end }) => {
+                let (range, bias) = match lo.ty.kind {
+                    ty::Char => {
+                        (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
+                    }
+                    ty::Int(ity) => {
+                        let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+                        let max = truncate(u128::max_value(), size);
+                        let bias = 1u128 << (size.bits() - 1);
+                        (Some((0, max, size)), bias)
+                    }
+                    ty::Uint(uty) => {
+                        let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
+                        let max = truncate(u128::max_value(), size);
+                        (Some((0, max, size)), 0)
+                    }
+                    _ => (None, 0),
+                };
+                if let Some((min, max, sz)) = range {
+                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
+                        // We want to compare ranges numerically, but the order of the bitwise
+                        // representation of signed integers does not match their numeric order.
+                        // Thus, to correct the ordering, we need to shift the range of signed
+                        // integers to correct the comparison. This is achieved by XORing with a
+                        // bias (see pattern/_match.rs for another pertinent example of this
+                        // pattern).
+                        let (lo, hi) = (lo ^ bias, hi ^ bias);
+                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
+                            // Irrefutable pattern match.
+                            return Ok(());
+                        }
+                    }
+                }
+                Err(match_pair)
+            }
+
+            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
+                    // irrefutable
+                    self.prefix_slice_suffix(
+                        &mut candidate.match_pairs,
+                        &match_pair.place,
+                        prefix,
+                        slice.as_ref(),
+                        suffix,
+                    );
+                    Ok(())
+                } else {
+                    Err(match_pair)
+                }
+            }
+
+            PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
+                let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
+                    i == variant_index || {
+                        self.hir.tcx().features().exhaustive_patterns
+                            && !v
+                                .uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind())
+                                .is_empty()
+                    }
+                }) && (adt_def.did.is_local()
+                    || !adt_def.is_variant_list_non_exhaustive());
+                if irrefutable {
+                    let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
+                    candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
+                    Ok(())
+                } else {
+                    Err(match_pair)
+                }
+            }
+
+            PatKind::Array { ref prefix, ref slice, ref suffix } => {
+                self.prefix_slice_suffix(
+                    &mut candidate.match_pairs,
+                    &match_pair.place,
+                    prefix,
+                    slice.as_ref(),
+                    suffix,
+                );
+                Ok(())
+            }
+
+            PatKind::Leaf { ref subpatterns } => {
+                // tuple struct, match subpats (if any)
+                candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
+                Ok(())
+            }
+
+            PatKind::Deref { ref subpattern } => {
+                let place = tcx.mk_place_deref(match_pair.place);
+                candidate.match_pairs.push(MatchPair::new(place, subpattern));
+                Ok(())
+            }
+
+            PatKind::Or { .. } => Err(match_pair),
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/matches/test.rs b/src/librustc_mir_build/build/matches/test.rs
new file mode 100644 (file)
index 0000000..31fc0d1
--- /dev/null
@@ -0,0 +1,835 @@
+// Testing candidates
+//
+// After candidates have been simplified, the only match pairs that
+// remain are those that require some sort of test. The functions here
+// identify what tests are needed, perform the tests, and then filter
+// the candidates based on the result.
+
+use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
+use crate::build::Builder;
+use crate::hair::pattern::compare_const_vals;
+use crate::hair::*;
+use rustc::mir::*;
+use rustc::ty::layout::VariantIdx;
+use rustc::ty::util::IntTypeExt;
+use rustc::ty::{self, adjustment::PointerCast, Ty};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::RangeEnd;
+use rustc_index::bit_set::BitSet;
+use rustc_span::symbol::sym;
+
+use std::cmp::Ordering;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Identifies what test is needed to decide if `match_pair` is applicable.
+    ///
+    /// It is a bug to call this with a simplifiable pattern.
+    crate fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
+        match *match_pair.pattern.kind {
+            PatKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
+                span: match_pair.pattern.span,
+                kind: TestKind::Switch {
+                    adt_def,
+                    variants: BitSet::new_empty(adt_def.variants.len()),
+                },
+            },
+
+            PatKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
+                // For integers, we use a `SwitchInt` match, which allows
+                // us to handle more cases.
+                Test {
+                    span: match_pair.pattern.span,
+                    kind: TestKind::SwitchInt {
+                        switch_ty: match_pair.pattern.ty,
+
+                        // these maps are empty to start; cases are
+                        // added below in add_cases_to_switch
+                        options: vec![],
+                        indices: Default::default(),
+                    },
+                }
+            }
+
+            PatKind::Constant { value } => Test {
+                span: match_pair.pattern.span,
+                kind: TestKind::Eq { value, ty: match_pair.pattern.ty.clone() },
+            },
+
+            PatKind::Range(range) => {
+                assert_eq!(range.lo.ty, match_pair.pattern.ty);
+                assert_eq!(range.hi.ty, match_pair.pattern.ty);
+                Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
+            }
+
+            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+                let len = prefix.len() + suffix.len();
+                let op = if slice.is_some() { BinOp::Ge } else { BinOp::Eq };
+                Test {
+                    span: match_pair.pattern.span,
+                    kind: TestKind::Len { len: len as u64, op: op },
+                }
+            }
+
+            PatKind::Or { .. } => self
+                .hir
+                .tcx()
+                .sess
+                .span_fatal(match_pair.pattern.span, "or-patterns are not fully implemented yet"),
+
+            PatKind::AscribeUserType { .. }
+            | PatKind::Array { .. }
+            | PatKind::Wild
+            | PatKind::Binding { .. }
+            | PatKind::Leaf { .. }
+            | PatKind::Deref { .. } => self.error_simplifyable(match_pair),
+        }
+    }
+
+    crate fn add_cases_to_switch<'pat>(
+        &mut self,
+        test_place: &Place<'tcx>,
+        candidate: &Candidate<'pat, 'tcx>,
+        switch_ty: Ty<'tcx>,
+        options: &mut Vec<u128>,
+        indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+    ) -> bool {
+        let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
+            Some(match_pair) => match_pair,
+            _ => {
+                return false;
+            }
+        };
+
+        match *match_pair.pattern.kind {
+            PatKind::Constant { value } => {
+                indices.entry(value).or_insert_with(|| {
+                    options.push(value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty));
+                    options.len() - 1
+                });
+                true
+            }
+            PatKind::Variant { .. } => {
+                panic!("you should have called add_variants_to_switch instead!");
+            }
+            PatKind::Range(range) => {
+                // Check that none of the switch values are in the range.
+                self.values_not_contained_in_range(range, indices).unwrap_or(false)
+            }
+            PatKind::Slice { .. }
+            | PatKind::Array { .. }
+            | PatKind::Wild
+            | PatKind::Or { .. }
+            | PatKind::Binding { .. }
+            | PatKind::AscribeUserType { .. }
+            | PatKind::Leaf { .. }
+            | PatKind::Deref { .. } => {
+                // don't know how to add these patterns to a switch
+                false
+            }
+        }
+    }
+
+    crate fn add_variants_to_switch<'pat>(
+        &mut self,
+        test_place: &Place<'tcx>,
+        candidate: &Candidate<'pat, 'tcx>,
+        variants: &mut BitSet<VariantIdx>,
+    ) -> bool {
+        let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
+            Some(match_pair) => match_pair,
+            _ => {
+                return false;
+            }
+        };
+
+        match *match_pair.pattern.kind {
+            PatKind::Variant { adt_def: _, variant_index, .. } => {
+                // We have a pattern testing for variant `variant_index`
+                // set the corresponding index to true
+                variants.insert(variant_index);
+                true
+            }
+            _ => {
+                // don't know how to add these patterns to a switch
+                false
+            }
+        }
+    }
+
+    crate fn perform_test(
+        &mut self,
+        block: BasicBlock,
+        place: &Place<'tcx>,
+        test: &Test<'tcx>,
+        make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
+    ) {
+        debug!(
+            "perform_test({:?}, {:?}: {:?}, {:?})",
+            block,
+            place,
+            place.ty(&self.local_decls, self.hir.tcx()),
+            test
+        );
+
+        let source_info = self.source_info(test.span);
+        match test.kind {
+            TestKind::Switch { adt_def, ref variants } => {
+                let target_blocks = make_target_blocks(self);
+                // Variants is a BitVec of indexes into adt_def.variants.
+                let num_enum_variants = adt_def.variants.len();
+                let used_variants = variants.count();
+                debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
+                let otherwise_block = *target_blocks.last().unwrap();
+                let mut targets = Vec::with_capacity(used_variants + 1);
+                let mut values = Vec::with_capacity(used_variants);
+                let tcx = self.hir.tcx();
+                for (idx, discr) in adt_def.discriminants(tcx) {
+                    if variants.contains(idx) {
+                        debug_assert_ne!(
+                            target_blocks[idx.index()],
+                            otherwise_block,
+                            "no canididates for tested discriminant: {:?}",
+                            discr,
+                        );
+                        values.push(discr.val);
+                        targets.push(target_blocks[idx.index()]);
+                    } else {
+                        debug_assert_eq!(
+                            target_blocks[idx.index()],
+                            otherwise_block,
+                            "found canididates for untested discriminant: {:?}",
+                            discr,
+                        );
+                    }
+                }
+                targets.push(otherwise_block);
+                debug!(
+                    "num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
+                    num_enum_variants, values, variants
+                );
+                let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
+                let discr = self.temp(discr_ty, test.span);
+                self.cfg.push_assign(
+                    block,
+                    source_info,
+                    &discr,
+                    Rvalue::Discriminant(place.clone()),
+                );
+                assert_eq!(values.len() + 1, targets.len());
+                self.cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::SwitchInt {
+                        discr: Operand::Move(discr),
+                        switch_ty: discr_ty,
+                        values: From::from(values),
+                        targets,
+                    },
+                );
+            }
+
+            TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
+                let target_blocks = make_target_blocks(self);
+                let terminator = if switch_ty.kind == ty::Bool {
+                    assert!(options.len() > 0 && options.len() <= 2);
+                    if let [first_bb, second_bb] = *target_blocks {
+                        let (true_bb, false_bb) = match options[0] {
+                            1 => (first_bb, second_bb),
+                            0 => (second_bb, first_bb),
+                            v => span_bug!(test.span, "expected boolean value but got {:?}", v),
+                        };
+                        TerminatorKind::if_(
+                            self.hir.tcx(),
+                            Operand::Copy(place.clone()),
+                            true_bb,
+                            false_bb,
+                        )
+                    } else {
+                        bug!("`TestKind::SwitchInt` on `bool` should have two targets")
+                    }
+                } else {
+                    // The switch may be inexhaustive so we have a catch all block
+                    debug_assert_eq!(options.len() + 1, target_blocks.len());
+                    TerminatorKind::SwitchInt {
+                        discr: Operand::Copy(place.clone()),
+                        switch_ty,
+                        values: options.clone().into(),
+                        targets: target_blocks,
+                    }
+                };
+                self.cfg.terminate(block, source_info, terminator);
+            }
+
+            TestKind::Eq { value, ty } => {
+                if !ty.is_scalar() {
+                    // Use `PartialEq::eq` instead of `BinOp::Eq`
+                    // (the binop can only handle primitives)
+                    self.non_scalar_compare(
+                        block,
+                        make_target_blocks,
+                        source_info,
+                        value,
+                        place,
+                        ty,
+                    );
+                } else {
+                    if let [success, fail] = *make_target_blocks(self) {
+                        assert_eq!(value.ty, ty);
+                        let expect = self.literal_operand(test.span, value);
+                        let val = Operand::Copy(place.clone());
+                        self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
+                    } else {
+                        bug!("`TestKind::Eq` should have two target blocks");
+                    }
+                }
+            }
+
+            TestKind::Range(PatRange { ref lo, ref hi, ref end }) => {
+                let lower_bound_success = self.cfg.start_new_block();
+                let target_blocks = make_target_blocks(self);
+
+                // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
+                let lo = self.literal_operand(test.span, lo);
+                let hi = self.literal_operand(test.span, hi);
+                let val = Operand::Copy(place.clone());
+
+                if let [success, fail] = *target_blocks {
+                    self.compare(
+                        block,
+                        lower_bound_success,
+                        fail,
+                        source_info,
+                        BinOp::Le,
+                        lo,
+                        val.clone(),
+                    );
+                    let op = match *end {
+                        RangeEnd::Included => BinOp::Le,
+                        RangeEnd::Excluded => BinOp::Lt,
+                    };
+                    self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
+                } else {
+                    bug!("`TestKind::Range` should have two target blocks");
+                }
+            }
+
+            TestKind::Len { len, op } => {
+                let target_blocks = make_target_blocks(self);
+
+                let usize_ty = self.hir.usize_ty();
+                let actual = self.temp(usize_ty, test.span);
+
+                // actual = len(place)
+                self.cfg.push_assign(block, source_info, &actual, Rvalue::Len(place.clone()));
+
+                // expected = <N>
+                let expected = self.push_usize(block, source_info, len);
+
+                if let [true_bb, false_bb] = *target_blocks {
+                    // result = actual == expected OR result = actual < expected
+                    // branch based on result
+                    self.compare(
+                        block,
+                        true_bb,
+                        false_bb,
+                        source_info,
+                        op,
+                        Operand::Move(actual),
+                        Operand::Move(expected),
+                    );
+                } else {
+                    bug!("`TestKind::Len` should have two target blocks");
+                }
+            }
+        }
+    }
+
+    /// Compare using the provided built-in comparison operator
+    fn compare(
+        &mut self,
+        block: BasicBlock,
+        success_block: BasicBlock,
+        fail_block: BasicBlock,
+        source_info: SourceInfo,
+        op: BinOp,
+        left: Operand<'tcx>,
+        right: Operand<'tcx>,
+    ) {
+        let bool_ty = self.hir.bool_ty();
+        let result = self.temp(bool_ty, source_info.span);
+
+        // result = op(left, right)
+        self.cfg.push_assign(block, source_info, &result, Rvalue::BinaryOp(op, left, right));
+
+        // branch based on result
+        self.cfg.terminate(
+            block,
+            source_info,
+            TerminatorKind::if_(self.hir.tcx(), Operand::Move(result), success_block, fail_block),
+        );
+    }
+
+    /// Compare two `&T` values using `<T as std::compare::PartialEq>::eq`
+    fn non_scalar_compare(
+        &mut self,
+        block: BasicBlock,
+        make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
+        source_info: SourceInfo,
+        value: &'tcx ty::Const<'tcx>,
+        place: &Place<'tcx>,
+        mut ty: Ty<'tcx>,
+    ) {
+        use rustc::middle::lang_items::EqTraitLangItem;
+
+        let mut expect = self.literal_operand(source_info.span, value);
+        let mut val = Operand::Copy(place.clone());
+
+        // If we're using `b"..."` as a pattern, we need to insert an
+        // unsizing coercion, as the byte string has the type `&[u8; N]`.
+        //
+        // We want to do this even when the scrutinee is a reference to an
+        // array, so we can call `<[u8]>::eq` rather than having to find an
+        // `<[u8; N]>::eq`.
+        let unsize = |ty: Ty<'tcx>| match ty.kind {
+            ty::Ref(region, rty, _) => match rty.kind {
+                ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
+                _ => None,
+            },
+            _ => None,
+        };
+        let opt_ref_ty = unsize(ty);
+        let opt_ref_test_ty = unsize(value.ty);
+        match (opt_ref_ty, opt_ref_test_ty) {
+            // nothing to do, neither is an array
+            (None, None) => {}
+            (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
+                let tcx = self.hir.tcx();
+                // make both a slice
+                ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
+                if opt_ref_ty.is_some() {
+                    let temp = self.temp(ty, source_info.span);
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &temp,
+                        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty),
+                    );
+                    val = Operand::Move(temp);
+                }
+                if opt_ref_test_ty.is_some() {
+                    let slice = self.temp(ty, source_info.span);
+                    self.cfg.push_assign(
+                        block,
+                        source_info,
+                        &slice,
+                        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), expect, ty),
+                    );
+                    expect = Operand::Move(slice);
+                }
+            }
+        }
+
+        let deref_ty = match ty.kind {
+            ty::Ref(_, deref_ty, _) => deref_ty,
+            _ => bug!("non_scalar_compare called on non-reference type: {}", ty),
+        };
+
+        let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem, None);
+        let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]);
+
+        let bool_ty = self.hir.bool_ty();
+        let eq_result = self.temp(bool_ty, source_info.span);
+        let eq_block = self.cfg.start_new_block();
+        let cleanup = self.diverge_cleanup();
+        self.cfg.terminate(
+            block,
+            source_info,
+            TerminatorKind::Call {
+                func: Operand::Constant(box Constant {
+                    span: source_info.span,
+
+                    // FIXME(#54571): This constant comes from user input (a
+                    // constant in a pattern).  Are there forms where users can add
+                    // type annotations here?  For example, an associated constant?
+                    // Need to experiment.
+                    user_ty: None,
+
+                    literal: method,
+                }),
+                args: vec![val, expect],
+                destination: Some((eq_result.clone(), eq_block)),
+                cleanup: Some(cleanup),
+                from_hir_call: false,
+            },
+        );
+
+        if let [success_block, fail_block] = *make_target_blocks(self) {
+            // check the result
+            self.cfg.terminate(
+                eq_block,
+                source_info,
+                TerminatorKind::if_(
+                    self.hir.tcx(),
+                    Operand::Move(eq_result),
+                    success_block,
+                    fail_block,
+                ),
+            );
+        } else {
+            bug!("`TestKind::Eq` should have two target blocks")
+        }
+    }
+
+    /// Given that we are performing `test` against `test_place`, this job
+    /// sorts out what the status of `candidate` will be after the test. See
+    /// `test_candidates` for the usage of this function. The returned index is
+    /// the index that this candidate should be placed in the
+    /// `target_candidates` vec. The candidate may be modified to update its
+    /// `match_pairs`.
+    ///
+    /// So, for example, if this candidate is `x @ Some(P0)` and the `Test` is
+    /// a variant test, then we would modify the candidate to be `(x as
+    /// Option).0 @ P0` and return the index corresponding to the variant
+    /// `Some`.
+    ///
+    /// However, in some cases, the test may just not be relevant to candidate.
+    /// For example, suppose we are testing whether `foo.x == 22`, but in one
+    /// match arm we have `Foo { x: _, ... }`... in that case, the test for
+    /// what value `x` has has no particular relevance to this candidate. In
+    /// such cases, this function just returns None without doing anything.
+    /// This is used by the overall `match_candidates` algorithm to structure
+    /// the match as a whole. See `match_candidates` for more details.
+    ///
+    /// FIXME(#29623). In some cases, we have some tricky choices to make.  for
+    /// example, if we are testing that `x == 22`, but the candidate is `x @
+    /// 13..55`, what should we do? In the event that the test is true, we know
+    /// that the candidate applies, but in the event of false, we don't know
+    /// that it *doesn't* apply. For now, we return false, indicate that the
+    /// test does not apply to this candidate, but it might be we can get
+    /// tighter match code if we do something a bit different.
+    crate fn sort_candidate<'pat>(
+        &mut self,
+        test_place: &Place<'tcx>,
+        test: &Test<'tcx>,
+        candidate: &mut Candidate<'pat, 'tcx>,
+    ) -> Option<usize> {
+        // Find the match_pair for this place (if any). At present,
+        // afaik, there can be at most one. (In the future, if we
+        // adopted a more general `@` operator, there might be more
+        // than one, but it'd be very unusual to have two sides that
+        // both require tests; you'd expect one side to be simplified
+        // away.)
+        let (match_pair_index, match_pair) =
+            candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
+
+        match (&test.kind, &*match_pair.pattern.kind) {
+            // If we are performing a variant switch, then this
+            // informs variant patterns, but nothing else.
+            (
+                &TestKind::Switch { adt_def: tested_adt_def, .. },
+                &PatKind::Variant { adt_def, variant_index, ref subpatterns, .. },
+            ) => {
+                assert_eq!(adt_def, tested_adt_def);
+                self.candidate_after_variant_switch(
+                    match_pair_index,
+                    adt_def,
+                    variant_index,
+                    subpatterns,
+                    candidate,
+                );
+                Some(variant_index.as_usize())
+            }
+
+            (&TestKind::Switch { .. }, _) => None,
+
+            // If we are performing a switch over integers, then this informs integer
+            // equality, but nothing else.
+            //
+            // FIXME(#29623) we could use PatKind::Range to rule
+            // things out here, in some cases.
+            (
+                &TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
+                &PatKind::Constant { ref value },
+            ) if is_switch_ty(match_pair.pattern.ty) => {
+                let index = indices[value];
+                self.candidate_without_match_pair(match_pair_index, candidate);
+                Some(index)
+            }
+
+            (
+                &TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
+                &PatKind::Range(range),
+            ) => {
+                let not_contained =
+                    self.values_not_contained_in_range(range, indices).unwrap_or(false);
+
+                if not_contained {
+                    // No switch values are contained in the pattern range,
+                    // so the pattern can be matched only if this test fails.
+                    let otherwise = options.len();
+                    Some(otherwise)
+                } else {
+                    None
+                }
+            }
+
+            (&TestKind::SwitchInt { .. }, _) => None,
+
+            (
+                &TestKind::Len { len: test_len, op: BinOp::Eq },
+                &PatKind::Slice { ref prefix, ref slice, ref suffix },
+            ) => {
+                let pat_len = (prefix.len() + suffix.len()) as u64;
+                match (test_len.cmp(&pat_len), slice) {
+                    (Ordering::Equal, &None) => {
+                        // on true, min_len = len = $actual_length,
+                        // on false, len != $actual_length
+                        self.candidate_after_slice_test(
+                            match_pair_index,
+                            candidate,
+                            prefix,
+                            slice.as_ref(),
+                            suffix,
+                        );
+                        Some(0)
+                    }
+                    (Ordering::Less, _) => {
+                        // test_len < pat_len. If $actual_len = test_len,
+                        // then $actual_len < pat_len and we don't have
+                        // enough elements.
+                        Some(1)
+                    }
+                    (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
+                        // This can match both if $actual_len = test_len >= pat_len,
+                        // and if $actual_len > test_len. We can't advance.
+                        None
+                    }
+                    (Ordering::Greater, &None) => {
+                        // test_len != pat_len, so if $actual_len = test_len, then
+                        // $actual_len != pat_len.
+                        Some(1)
+                    }
+                }
+            }
+
+            (
+                &TestKind::Len { len: test_len, op: BinOp::Ge },
+                &PatKind::Slice { ref prefix, ref slice, ref suffix },
+            ) => {
+                // the test is `$actual_len >= test_len`
+                let pat_len = (prefix.len() + suffix.len()) as u64;
+                match (test_len.cmp(&pat_len), slice) {
+                    (Ordering::Equal, &Some(_)) => {
+                        // $actual_len >= test_len = pat_len,
+                        // so we can match.
+                        self.candidate_after_slice_test(
+                            match_pair_index,
+                            candidate,
+                            prefix,
+                            slice.as_ref(),
+                            suffix,
+                        );
+                        Some(0)
+                    }
+                    (Ordering::Less, _) | (Ordering::Equal, &None) => {
+                        // test_len <= pat_len. If $actual_len < test_len,
+                        // then it is also < pat_len, so the test passing is
+                        // necessary (but insufficient).
+                        Some(0)
+                    }
+                    (Ordering::Greater, &None) => {
+                        // test_len > pat_len. If $actual_len >= test_len > pat_len,
+                        // then we know we won't have a match.
+                        Some(1)
+                    }
+                    (Ordering::Greater, &Some(_)) => {
+                        // test_len < pat_len, and is therefore less
+                        // strict. This can still go both ways.
+                        None
+                    }
+                }
+            }
+
+            (&TestKind::Range(test), &PatKind::Range(pat)) => {
+                if test == pat {
+                    self.candidate_without_match_pair(match_pair_index, candidate);
+                    return Some(0);
+                }
+
+                let no_overlap = (|| {
+                    use rustc_hir::RangeEnd::*;
+                    use std::cmp::Ordering::*;
+
+                    let tcx = self.hir.tcx();
+
+                    let test_ty = test.lo.ty;
+                    let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test_ty)?;
+                    let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test_ty)?;
+
+                    match (test.end, pat.end, lo, hi) {
+                        // pat < test
+                        (_, _, Greater, _) |
+                        (_, Excluded, Equal, _) |
+                        // pat > test
+                        (_, _, _, Less) |
+                        (Excluded, _, _, Equal) => Some(true),
+                        _ => Some(false),
+                    }
+                })();
+
+                if let Some(true) = no_overlap {
+                    // Testing range does not overlap with pattern range,
+                    // so the pattern can be matched only if this test fails.
+                    Some(1)
+                } else {
+                    None
+                }
+            }
+
+            (&TestKind::Range(range), &PatKind::Constant { value }) => {
+                if let Some(false) = self.const_range_contains(range, value) {
+                    // `value` is not contained in the testing range,
+                    // so `value` can be matched only if this test fails.
+                    Some(1)
+                } else {
+                    None
+                }
+            }
+
+            (&TestKind::Range { .. }, _) => None,
+
+            (&TestKind::Eq { .. }, _) | (&TestKind::Len { .. }, _) => {
+                // These are all binary tests.
+                //
+                // FIXME(#29623) we can be more clever here
+                let pattern_test = self.test(&match_pair);
+                if pattern_test.kind == test.kind {
+                    self.candidate_without_match_pair(match_pair_index, candidate);
+                    Some(0)
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    fn candidate_without_match_pair(
+        &mut self,
+        match_pair_index: usize,
+        candidate: &mut Candidate<'_, 'tcx>,
+    ) {
+        candidate.match_pairs.remove(match_pair_index);
+    }
+
+    fn candidate_after_slice_test<'pat>(
+        &mut self,
+        match_pair_index: usize,
+        candidate: &mut Candidate<'pat, 'tcx>,
+        prefix: &'pat [Pat<'tcx>],
+        opt_slice: Option<&'pat Pat<'tcx>>,
+        suffix: &'pat [Pat<'tcx>],
+    ) {
+        let removed_place = candidate.match_pairs.remove(match_pair_index).place;
+        self.prefix_slice_suffix(
+            &mut candidate.match_pairs,
+            &removed_place,
+            prefix,
+            opt_slice,
+            suffix,
+        );
+    }
+
+    fn candidate_after_variant_switch<'pat>(
+        &mut self,
+        match_pair_index: usize,
+        adt_def: &'tcx ty::AdtDef,
+        variant_index: VariantIdx,
+        subpatterns: &'pat [FieldPat<'tcx>],
+        candidate: &mut Candidate<'pat, 'tcx>,
+    ) {
+        let match_pair = candidate.match_pairs.remove(match_pair_index);
+        let tcx = self.hir.tcx();
+
+        // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
+        // we want to create a set of derived match-patterns like
+        // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
+        let elem = ProjectionElem::Downcast(
+            Some(adt_def.variants[variant_index].ident.name),
+            variant_index,
+        );
+        let downcast_place = tcx.mk_place_elem(match_pair.place, elem); // `(x as Variant)`
+        let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
+            // e.g., `(x as Variant).0`
+            let place =
+                tcx.mk_place_field(downcast_place.clone(), subpattern.field, subpattern.pattern.ty);
+            // e.g., `(x as Variant).0 @ P1`
+            MatchPair::new(place, &subpattern.pattern)
+        });
+
+        candidate.match_pairs.extend(consequent_match_pairs);
+    }
+
+    fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
+        span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
+    }
+
+    fn const_range_contains(
+        &self,
+        range: PatRange<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
+    ) -> Option<bool> {
+        use std::cmp::Ordering::*;
+
+        let tcx = self.hir.tcx();
+
+        let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.lo.ty)?;
+        let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.lo.ty)?;
+
+        match (b, range.end) {
+            (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
+            _ => Some(false),
+        }
+    }
+
+    fn values_not_contained_in_range(
+        &self,
+        range: PatRange<'tcx>,
+        indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+    ) -> Option<bool> {
+        for &val in indices.keys() {
+            if self.const_range_contains(range, val)? {
+                return Some(false);
+            }
+        }
+
+        Some(true)
+    }
+}
+
+impl Test<'_> {
+    pub(super) fn targets(&self) -> usize {
+        match self.kind {
+            TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => 2,
+            TestKind::Switch { adt_def, .. } => {
+                // While the switch that we generate doesn't test for all
+                // variants, we have a target for each variant and the
+                // otherwise case, and we make sure that all of the cases not
+                // specified have the same block.
+                adt_def.variants.len() + 1
+            }
+            TestKind::SwitchInt { switch_ty, ref options, .. } => {
+                if switch_ty.is_bool() {
+                    // `bool` is special cased in `perform_test` to always
+                    // branch to two blocks.
+                    2
+                } else {
+                    options.len() + 1
+                }
+            }
+        }
+    }
+}
+
+fn is_switch_ty(ty: Ty<'_>) -> bool {
+    ty.is_integral() || ty.is_char() || ty.is_bool()
+}
diff --git a/src/librustc_mir_build/build/matches/util.rs b/src/librustc_mir_build/build/matches/util.rs
new file mode 100644 (file)
index 0000000..def8d1b
--- /dev/null
@@ -0,0 +1,104 @@
+use crate::build::matches::MatchPair;
+use crate::build::Builder;
+use crate::hair::*;
+use rustc::mir::*;
+use rustc::ty;
+use smallvec::SmallVec;
+use std::convert::TryInto;
+use std::u32;
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    crate fn field_match_pairs<'pat>(
+        &mut self,
+        place: Place<'tcx>,
+        subpatterns: &'pat [FieldPat<'tcx>],
+    ) -> Vec<MatchPair<'pat, 'tcx>> {
+        subpatterns
+            .iter()
+            .map(|fieldpat| {
+                let place = self.hir.tcx().mk_place_field(
+                    place.clone(),
+                    fieldpat.field,
+                    fieldpat.pattern.ty,
+                );
+                MatchPair::new(place, &fieldpat.pattern)
+            })
+            .collect()
+    }
+
+    crate fn prefix_slice_suffix<'pat>(
+        &mut self,
+        match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
+        place: &Place<'tcx>,
+        prefix: &'pat [Pat<'tcx>],
+        opt_slice: Option<&'pat Pat<'tcx>>,
+        suffix: &'pat [Pat<'tcx>],
+    ) {
+        let tcx = self.hir.tcx();
+        let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind {
+            ty::Array(_, length) => {
+                (length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), true)
+            }
+            _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+        };
+
+        match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
+            let elem =
+                ProjectionElem::ConstantIndex { offset: idx as u32, min_length, from_end: false };
+            let place = tcx.mk_place_elem(place.clone(), elem);
+            MatchPair::new(place, subpattern)
+        }));
+
+        if let Some(subslice_pat) = opt_slice {
+            let suffix_len = suffix.len() as u32;
+            let subslice = tcx.mk_place_elem(
+                place.clone(),
+                ProjectionElem::Subslice {
+                    from: prefix.len() as u32,
+                    to: if exact_size { min_length - suffix_len } else { suffix_len },
+                    from_end: !exact_size,
+                },
+            );
+            match_pairs.push(MatchPair::new(subslice, subslice_pat));
+        }
+
+        match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
+            let end_offset = (idx + 1) as u32;
+            let elem = ProjectionElem::ConstantIndex {
+                offset: if exact_size { min_length - end_offset } else { end_offset },
+                min_length,
+                from_end: !exact_size,
+            };
+            let place = tcx.mk_place_elem(place.clone(), elem);
+            MatchPair::new(place, subpattern)
+        }));
+    }
+
+    /// Creates a false edge to `imaginary_target` and a real edge to
+    /// real_target. If `imaginary_target` is none, or is the same as the real
+    /// target, a Goto is generated instead to simplify the generated MIR.
+    crate fn false_edges(
+        &mut self,
+        from_block: BasicBlock,
+        real_target: BasicBlock,
+        imaginary_target: Option<BasicBlock>,
+        source_info: SourceInfo,
+    ) {
+        match imaginary_target {
+            Some(target) if target != real_target => {
+                self.cfg.terminate(
+                    from_block,
+                    source_info,
+                    TerminatorKind::FalseEdges { real_target, imaginary_target: target },
+                );
+            }
+            _ => self.cfg.goto(from_block, source_info, real_target),
+        }
+    }
+}
+
+impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
+    crate fn new(place: Place<'tcx>, pattern: &'pat Pat<'tcx>) -> MatchPair<'pat, 'tcx> {
+        MatchPair { place, pattern }
+    }
+}
diff --git a/src/librustc_mir_build/build/misc.rs b/src/librustc_mir_build/build/misc.rs
new file mode 100644 (file)
index 0000000..3d5145b
--- /dev/null
@@ -0,0 +1,77 @@
+//! Miscellaneous builder routines that are not specific to building any particular
+//! kind of thing.
+
+use crate::build::Builder;
+
+use rustc::ty::{self, Ty};
+
+use rustc::mir::*;
+use rustc_span::{Span, DUMMY_SP};
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    /// Adds a new temporary value of type `ty` storing the result of
+    /// evaluating `expr`.
+    ///
+    /// N.B., **No cleanup is scheduled for this temporary.** You should
+    /// call `schedule_drop` once the temporary is initialized.
+    crate fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> {
+        let temp = self.local_decls.push(LocalDecl::new_temp(ty, span));
+        let place = Place::from(temp);
+        debug!("temp: created temp {:?} with type {:?}", place, self.local_decls[temp].ty);
+        place
+    }
+
+    /// Convenience function for creating a literal operand, one
+    /// without any user type annotation.
+    crate fn literal_operand(
+        &mut self,
+        span: Span,
+        literal: &'tcx ty::Const<'tcx>,
+    ) -> Operand<'tcx> {
+        let constant = box Constant { span, user_ty: None, literal };
+        Operand::Constant(constant)
+    }
+
+    crate fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
+        Rvalue::Aggregate(box AggregateKind::Tuple, vec![])
+    }
+
+    // Returns a zero literal operand for the appropriate type, works for
+    // bool, char and integers.
+    crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
+        let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty));
+
+        self.literal_operand(span, literal)
+    }
+
+    crate fn push_usize(
+        &mut self,
+        block: BasicBlock,
+        source_info: SourceInfo,
+        value: u64,
+    ) -> Place<'tcx> {
+        let usize_ty = self.hir.usize_ty();
+        let temp = self.temp(usize_ty, source_info.span);
+        self.cfg.push_assign_constant(
+            block,
+            source_info,
+            &temp,
+            Constant {
+                span: source_info.span,
+                user_ty: None,
+                literal: self.hir.usize_literal(value),
+            },
+        );
+        temp
+    }
+
+    crate fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
+        let tcx = self.hir.tcx();
+        let ty = place.ty(&self.local_decls, tcx).ty;
+        if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) {
+            Operand::Move(place)
+        } else {
+            Operand::Copy(place)
+        }
+    }
+}
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
new file mode 100644 (file)
index 0000000..6214453
--- /dev/null
@@ -0,0 +1,976 @@
+use crate::build;
+use crate::build::scope::DropKind;
+use crate::hair::cx::Cx;
+use crate::hair::{BindingMode, LintLevel, PatKind};
+use rustc::middle::lang_items;
+use rustc::middle::region;
+use rustc::mir::*;
+use rustc::ty::subst::Subst;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{GeneratorKind, HirIdMap, Node};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_span::symbol::kw;
+use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
+use rustc_target::spec::PanicStrategy;
+use std::u32;
+use syntax::attr::{self, UnwindAttr};
+
+use super::lints;
+
+crate fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::steal::Steal<BodyAndCache<'_>> {
+    tcx.alloc_steal_mir(mir_build(tcx, def_id))
+}
+
+/// Construct the MIR for a given `DefId`.
+fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
+    let id = tcx.hir().as_local_hir_id(def_id).unwrap();
+
+    // Figure out what primary body this item has.
+    let (body_id, return_ty_span) = match tcx.hir().get(id) {
+        Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => {
+            (*body_id, decl.output.span())
+        }
+        Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
+            ..
+        })
+        | Node::ImplItem(hir::ImplItem {
+            kind: hir::ImplItemKind::Method(hir::FnSig { decl, .. }, body_id),
+            ..
+        })
+        | Node::TraitItem(hir::TraitItem {
+            kind:
+                hir::TraitItemKind::Method(hir::FnSig { decl, .. }, hir::TraitMethod::Provided(body_id)),
+            ..
+        }) => (*body_id, decl.output.span()),
+        Node::Item(hir::Item { kind: hir::ItemKind::Static(ty, _, body_id), .. })
+        | Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, body_id), .. })
+        | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, body_id), .. })
+        | Node::TraitItem(hir::TraitItem {
+            kind: hir::TraitItemKind::Const(ty, Some(body_id)),
+            ..
+        }) => (*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),
+    };
+
+    tcx.infer_ctxt().enter(|infcx| {
+        let cx = Cx::new(&infcx, id);
+        let body = if cx.tables().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].clone();
+            let fn_def_id = tcx.hir().local_def_id(id);
+
+            let ty = tcx.type_of(fn_def_id);
+            let mut abi = fn_sig.abi;
+            let implicit_argument = match ty.kind {
+                ty::Closure(..) => {
+                    // HACK(eddyb) Avoid having RustCall on closures,
+                    // as it adds unnecessary (and wrong) auto-tupling.
+                    abi = Abi::Rust;
+                    Some(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);
+                    Some(ArgInfo(gen_ty, None, None, None))
+                }
+                _ => None,
+            };
+
+            let safety = match fn_sig.unsafety {
+                hir::Unsafety::Normal => Safety::Safe,
+                hir::Unsafety::Unsafe => Safety::FnUnsafe,
+            };
+
+            let body = tcx.hir().body(body_id);
+            let explicit_arguments = body.params.iter().enumerate().map(|(index, arg)| {
+                let owner_id = tcx.hir().body_owner(body_id);
+                let opt_ty_info;
+                let self_arg;
+                if let Some(ref fn_decl) = tcx.hir().fn_decl_by_hir_id(owner_id) {
+                    opt_ty_info = fn_decl.inputs.get(index).map(|ty| ty.span);
+                    self_arg = if index == 0 && fn_decl.implicit_self.has_implicit_self() {
+                        match fn_decl.implicit_self {
+                            hir::ImplicitSelfKind::Imm => Some(ImplicitSelfKind::Imm),
+                            hir::ImplicitSelfKind::Mut => Some(ImplicitSelfKind::Mut),
+                            hir::ImplicitSelfKind::ImmRef => Some(ImplicitSelfKind::ImmRef),
+                            hir::ImplicitSelfKind::MutRef => Some(ImplicitSelfKind::MutRef),
+                            _ => None,
+                        }
+                    } else {
+                        None
+                    };
+                } else {
+                    opt_ty_info = None;
+                    self_arg = None;
+                }
+
+                // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+                // (as it's created inside the body itself, not passed in from outside).
+                let ty = if fn_sig.c_variadic && index == fn_sig.inputs().len() {
+                    let va_list_did =
+                        tcx.require_lang_item(lang_items::VaListTypeLangItem, Some(arg.span));
+                    let region = tcx.mk_region(ty::ReScope(region::Scope {
+                        id: body.value.hir_id.local_id,
+                        data: region::ScopeData::CallSite,
+                    }));
+
+                    tcx.type_of(va_list_did).subst(tcx, &[region.into()])
+                } else {
+                    fn_sig.inputs()[index]
+                };
+
+                ArgInfo(ty, opt_ty_info, Some(&arg), self_arg)
+            });
+
+            let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+
+            let (yield_ty, return_ty) = if body.generator_kind.is_some() {
+                let gen_sig = match ty.kind {
+                    ty::Generator(gen_def_id, gen_substs, ..) => {
+                        gen_substs.as_generator().sig(gen_def_id, tcx)
+                    }
+                    _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty),
+                };
+                (Some(gen_sig.yield_ty), gen_sig.return_ty)
+            } else {
+                (None, fn_sig.output())
+            };
+
+            let mut mir = build::construct_fn(
+                cx,
+                id,
+                arguments,
+                safety,
+                abi,
+                return_ty,
+                return_ty_span,
+                body,
+            );
+            mir.yield_ty = yield_ty;
+            mir
+        } else {
+            // Get the revealed type of this const. This is *not* the adjusted
+            // type of its body, which may be a subtype of this type. For
+            // example:
+            //
+            // fn foo(_: &()) {}
+            // static X: fn(&'static ()) = foo;
+            //
+            // The adjusted type of the body of X is `for<'a> fn(&'a ())` which
+            // is not the same as the type of X. We need the type of the return
+            // place to be the type of the constant because NLL typeck will
+            // equate them.
+
+            let return_ty = cx.tables().node_type(id);
+
+            build::construct_const(cx, body_id, return_ty, return_ty_span)
+        };
+
+        lints::check(tcx, &body, def_id);
+
+        let mut body = BodyAndCache::new(body);
+        body.ensure_predecessors();
+        body
+    })
+}
+
+///////////////////////////////////////////////////////////////////////////
+// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
+
+fn liberated_closure_env_ty(
+    tcx: TyCtxt<'_>,
+    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_def_id, closure_substs) = match closure_ty.kind {
+        ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs),
+        _ => bug!("closure expr does not have closure type: {:?}", closure_ty),
+    };
+
+    let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap();
+    tcx.liberate_late_bound_regions(closure_def_id, &closure_env_ty)
+}
+
+#[derive(Debug, PartialEq, Eq)]
+enum BlockFrame {
+    /// Evaluation is currently within a statement.
+    ///
+    /// Examples include:
+    /// 1. `EXPR;`
+    /// 2. `let _ = EXPR;`
+    /// 3. `let x = EXPR;`
+    Statement {
+        /// If true, then statement discards result from evaluating
+        /// the expression (such as examples 1 and 2 above).
+        ignores_expr_result: bool,
+    },
+
+    /// Evaluation is currently within the tail expression of a block.
+    ///
+    /// Example: `{ STMT_1; STMT_2; EXPR }`
+    TailExpr {
+        /// If true, then the surrounding context of the block ignores
+        /// the result of evaluating the block's tail expression.
+        ///
+        /// Example: `let _ = { STMT_1; EXPR };`
+        tail_result_is_ignored: bool,
+    },
+
+    /// Generic mark meaning that the block occurred as a subexpression
+    /// where the result might be used.
+    ///
+    /// Examples: `foo(EXPR)`, `match EXPR { ... }`
+    SubExpr,
+}
+
+impl BlockFrame {
+    fn is_tail_expr(&self) -> bool {
+        match *self {
+            BlockFrame::TailExpr { .. } => true,
+
+            BlockFrame::Statement { .. } | BlockFrame::SubExpr => false,
+        }
+    }
+    fn is_statement(&self) -> bool {
+        match *self {
+            BlockFrame::Statement { .. } => true,
+
+            BlockFrame::TailExpr { .. } | BlockFrame::SubExpr => false,
+        }
+    }
+}
+
+#[derive(Debug)]
+struct BlockContext(Vec<BlockFrame>);
+
+struct Builder<'a, 'tcx> {
+    hir: Cx<'a, 'tcx>,
+    cfg: CFG<'tcx>,
+
+    fn_span: Span,
+    arg_count: usize,
+    generator_kind: Option<GeneratorKind>,
+
+    /// The current set of scopes, updated as we traverse;
+    /// see the `scope` module for more details.
+    scopes: scope::Scopes<'tcx>,
+
+    /// The block-context: each time we build the code within an hair::Block,
+    /// we push a frame here tracking whether we are building a statement or
+    /// if we are pushing the tail expression of the block. This is used to
+    /// embed information in generated temps about whether they were created
+    /// for a block tail expression or not.
+    ///
+    /// It would be great if we could fold this into `self.scopes`
+    /// somehow, but right now I think that is very tightly tied to
+    /// the code generation in ways that we cannot (or should not)
+    /// start just throwing new entries onto that vector in order to
+    /// distinguish the context of EXPR1 from the context of EXPR2 in
+    /// `{ STMTS; EXPR1 } + EXPR2`.
+    block_context: BlockContext,
+
+    /// The current unsafe block in scope, even if it is hidden by
+    /// a `PushUnsafeBlock`.
+    unpushed_unsafe: Safety,
+
+    /// The number of `push_unsafe_block` levels in scope.
+    push_unsafe_count: usize,
+
+    /// The vector of all scopes that we have created thus far;
+    /// we track this for debuginfo later.
+    source_scopes: IndexVec<SourceScope, SourceScopeData>,
+    source_scope: SourceScope,
+
+    /// The guard-context: each time we build the guard expression for
+    /// a match arm, we push onto this stack, and then pop when we
+    /// finish building it.
+    guard_context: Vec<GuardFrame>,
+
+    /// Maps `HirId`s of variable bindings to the `Local`s created for them.
+    /// (A match binding can have two locals; the 2nd is for the arm's guard.)
+    var_indices: HirIdMap<LocalsForNode>,
+    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+    canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
+    upvar_mutbls: Vec<Mutability>,
+    unit_temp: Option<Place<'tcx>>,
+
+    var_debug_info: Vec<VarDebugInfo<'tcx>>,
+
+    /// Cached block with the `RESUME` terminator; this is created
+    /// when first set of cleanups are built.
+    cached_resume_block: Option<BasicBlock>,
+    /// Cached block with the `RETURN` terminator.
+    cached_return_block: Option<BasicBlock>,
+    /// Cached block with the `UNREACHABLE` terminator.
+    cached_unreachable_block: Option<BasicBlock>,
+}
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool {
+        self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
+    }
+
+    fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local {
+        self.var_indices[&id].local_id(for_guard)
+    }
+}
+
+impl BlockContext {
+    fn new() -> Self {
+        BlockContext(vec![])
+    }
+    fn push(&mut self, bf: BlockFrame) {
+        self.0.push(bf);
+    }
+    fn pop(&mut self) -> Option<BlockFrame> {
+        self.0.pop()
+    }
+
+    /// Traverses the frames on the `BlockContext`, searching for either
+    /// the first block-tail expression frame with no intervening
+    /// statement frame.
+    ///
+    /// Notably, this skips over `SubExpr` frames; this method is
+    /// meant to be used in the context of understanding the
+    /// relationship of a temp (created within some complicated
+    /// expression) with its containing expression, and whether the
+    /// value of that *containing expression* (not the temp!) is
+    /// ignored.
+    fn currently_in_block_tail(&self) -> Option<BlockTailInfo> {
+        for bf in self.0.iter().rev() {
+            match bf {
+                BlockFrame::SubExpr => continue,
+                BlockFrame::Statement { .. } => break,
+                &BlockFrame::TailExpr { tail_result_is_ignored } => {
+                    return Some(BlockTailInfo { tail_result_is_ignored });
+                }
+            }
+        }
+
+        return None;
+    }
+
+    /// Looks at the topmost frame on the BlockContext and reports
+    /// whether its one that would discard a block tail result.
+    ///
+    /// Unlike `currently_within_ignored_tail_expression`, this does
+    /// *not* skip over `SubExpr` frames: here, we want to know
+    /// whether the block result itself is discarded.
+    fn currently_ignores_tail_results(&self) -> bool {
+        match self.0.last() {
+            // no context: conservatively assume result is read
+            None => false,
+
+            // sub-expression: block result feeds into some computation
+            Some(BlockFrame::SubExpr) => false,
+
+            // otherwise: use accumulated is_ignored state.
+            Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored })
+            | Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored,
+        }
+    }
+}
+
+#[derive(Debug)]
+enum LocalsForNode {
+    /// In the usual case, a `HirId` for an identifier maps to at most
+    /// one `Local` declaration.
+    One(Local),
+
+    /// The exceptional case is identifiers in a match arm's pattern
+    /// that are referenced in a guard of that match arm. For these,
+    /// we have `2` Locals.
+    ///
+    /// * `for_arm_body` is the Local used in the arm body (which is
+    ///   just like the `One` case above),
+    ///
+    /// * `ref_for_guard` is the Local used in the arm's guard (which
+    ///   is a reference to a temp that is an alias of
+    ///   `for_arm_body`).
+    ForGuard { ref_for_guard: Local, for_arm_body: Local },
+}
+
+#[derive(Debug)]
+struct GuardFrameLocal {
+    id: hir::HirId,
+}
+
+impl GuardFrameLocal {
+    fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self {
+        GuardFrameLocal { id: id }
+    }
+}
+
+#[derive(Debug)]
+struct GuardFrame {
+    /// These are the id's of names that are bound by patterns of the
+    /// arm of *this* guard.
+    ///
+    /// (Frames higher up the stack will have the id's bound in arms
+    /// further out, such as in a case like:
+    ///
+    /// match E1 {
+    ///      P1(id1) if (... (match E2 { P2(id2) if ... => B2 })) => B1,
+    /// }
+    ///
+    /// here, when building for FIXME.
+    locals: Vec<GuardFrameLocal>,
+}
+
+/// `ForGuard` indicates whether we are talking about:
+///   1. The variable for use outside of guard expressions, or
+///   2. The temp that holds reference to (1.), which is actually what the
+///      guard expressions see.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum ForGuard {
+    RefWithinGuard,
+    OutsideGuard,
+}
+
+impl LocalsForNode {
+    fn local_id(&self, for_guard: ForGuard) -> Local {
+        match (self, for_guard) {
+            (&LocalsForNode::One(local_id), ForGuard::OutsideGuard)
+            | (
+                &LocalsForNode::ForGuard { ref_for_guard: local_id, .. },
+                ForGuard::RefWithinGuard,
+            )
+            | (&LocalsForNode::ForGuard { for_arm_body: local_id, .. }, ForGuard::OutsideGuard) => {
+                local_id
+            }
+
+            (&LocalsForNode::One(_), ForGuard::RefWithinGuard) => {
+                bug!("anything with one local should never be within a guard.")
+            }
+        }
+    }
+}
+
+struct CFG<'tcx> {
+    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+}
+
+rustc_index::newtype_index! {
+    struct ScopeId { .. }
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// The `BlockAnd` "monad" packages up the new basic block along with a
+/// produced value (sometimes just unit, of course). The `unpack!`
+/// macro (and methods below) makes working with `BlockAnd` much more
+/// convenient.
+
+#[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
+struct BlockAnd<T>(BasicBlock, T);
+
+trait BlockAndExtension {
+    fn and<T>(self, v: T) -> BlockAnd<T>;
+    fn unit(self) -> BlockAnd<()>;
+}
+
+impl BlockAndExtension for BasicBlock {
+    fn and<T>(self, v: T) -> BlockAnd<T> {
+        BlockAnd(self, v)
+    }
+
+    fn unit(self) -> BlockAnd<()> {
+        BlockAnd(self, ())
+    }
+}
+
+/// Update a block pointer and return the value.
+/// Use it like `let x = unpack!(block = self.foo(block, foo))`.
+macro_rules! unpack {
+    ($x:ident = $c:expr) => {{
+        let BlockAnd(b, v) = $c;
+        $x = b;
+        v
+    }};
+
+    ($c:expr) => {{
+        let BlockAnd(b, ()) = $c;
+        b
+    }};
+}
+
+fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, _abi: Abi) -> bool {
+    // Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
+    let attrs = &tcx.get_attrs(fn_def_id);
+    let unwind_attr = attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs);
+
+    // We never unwind, so it's not relevant to stop an unwind.
+    if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
+        return false;
+    }
+
+    // We cannot add landing pads, so don't add one.
+    if tcx.sess.no_landing_pads() {
+        return false;
+    }
+
+    // This is a special case: some functions have a C abi but are meant to
+    // unwind anyway. Don't stop them.
+    match unwind_attr {
+        None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)`
+        Some(UnwindAttr::Allowed) => false,
+        Some(UnwindAttr::Aborts) => true,
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+/// the main entry point for building MIR for a function
+
+struct ArgInfo<'tcx>(
+    Ty<'tcx>,
+    Option<Span>,
+    Option<&'tcx hir::Param<'tcx>>,
+    Option<ImplicitSelfKind>,
+);
+
+fn construct_fn<'a, 'tcx, A>(
+    hir: Cx<'a, 'tcx>,
+    fn_id: hir::HirId,
+    arguments: A,
+    safety: Safety,
+    abi: Abi,
+    return_ty: Ty<'tcx>,
+    return_ty_span: Span,
+    body: &'tcx hir::Body<'tcx>,
+) -> Body<'tcx>
+where
+    A: Iterator<Item = ArgInfo<'tcx>>,
+{
+    let arguments: Vec<_> = arguments.collect();
+
+    let tcx = hir.tcx();
+    let tcx_hir = tcx.hir();
+    let span = tcx_hir.span(fn_id);
+
+    let fn_def_id = tcx_hir.local_def_id(fn_id);
+
+    let mut builder = Builder::new(
+        hir,
+        span,
+        arguments.len(),
+        safety,
+        return_ty,
+        return_ty_span,
+        body.generator_kind,
+    );
+
+    let call_site_scope =
+        region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite };
+    let arg_scope =
+        region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Arguments };
+    let mut block = START_BLOCK;
+    let source_info = builder.source_info(span);
+    let call_site_s = (call_site_scope, source_info);
+    unpack!(
+        block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
+            if should_abort_on_panic(tcx, fn_def_id, abi) {
+                builder.schedule_abort();
+            }
+
+            let arg_scope_s = (arg_scope, source_info);
+            // `return_block` is called when we evaluate a `return` expression, so
+            // we just use `START_BLOCK` here.
+            unpack!(
+                block = builder.in_breakable_scope(
+                    None,
+                    START_BLOCK,
+                    Place::return_place(),
+                    |builder| {
+                        builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
+                            builder.args_and_body(
+                                block,
+                                fn_def_id,
+                                &arguments,
+                                arg_scope,
+                                &body.value,
+                            )
+                        })
+                    },
+                )
+            );
+            // Attribute epilogue to function's closing brace
+            let fn_end = span.shrink_to_hi();
+            let source_info = builder.source_info(fn_end);
+            let return_block = builder.return_block();
+            builder.cfg.goto(block, source_info, return_block);
+            builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
+            // Attribute any unreachable codepaths to the function's closing brace
+            if let Some(unreachable_block) = builder.cached_unreachable_block {
+                builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable);
+            }
+            return_block.unit()
+        })
+    );
+    assert_eq!(block, builder.return_block());
+
+    let mut spread_arg = None;
+    if abi == Abi::RustCall {
+        // RustCall pseudo-ABI untuples the last argument.
+        spread_arg = Some(Local::new(arguments.len()));
+    }
+    debug!("fn_id {:?} has attrs {:?}", fn_def_id, tcx.get_attrs(fn_def_id));
+
+    let mut body = builder.finish();
+    body.spread_arg = spread_arg;
+    body
+}
+
+fn construct_const<'a, 'tcx>(
+    hir: Cx<'a, 'tcx>,
+    body_id: hir::BodyId,
+    const_ty: Ty<'tcx>,
+    const_ty_span: Span,
+) -> Body<'tcx> {
+    let tcx = hir.tcx();
+    let owner_id = tcx.hir().body_owner(body_id);
+    let span = tcx.hir().span(owner_id);
+    let mut builder = Builder::new(hir, span, 0, Safety::Safe, const_ty, const_ty_span, None);
+
+    let mut block = START_BLOCK;
+    let ast_expr = &tcx.hir().body(body_id).value;
+    let expr = builder.hir.mirror(ast_expr);
+    unpack!(block = builder.into_expr(&Place::return_place(), block, expr));
+
+    let source_info = builder.source_info(span);
+    builder.cfg.terminate(block, source_info, TerminatorKind::Return);
+
+    // Constants can't `return` so a return block should not be created.
+    assert_eq!(builder.cached_return_block, None);
+
+    // Constants may be match expressions in which case an unreachable block may
+    // be created, so terminate it properly.
+    if let Some(unreachable_block) = builder.cached_unreachable_block {
+        builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable);
+    }
+
+    builder.finish()
+}
+
+fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> {
+    let owner_id = hir.tcx().hir().body_owner(body_id);
+    let span = hir.tcx().hir().span(owner_id);
+    let ty = hir.tcx().types.err;
+    let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, None);
+    let source_info = builder.source_info(span);
+    builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
+    builder.finish()
+}
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    fn new(
+        hir: Cx<'a, 'tcx>,
+        span: Span,
+        arg_count: usize,
+        safety: Safety,
+        return_ty: Ty<'tcx>,
+        return_span: Span,
+        generator_kind: Option<GeneratorKind>,
+    ) -> Builder<'a, 'tcx> {
+        let lint_level = LintLevel::Explicit(hir.root_lint_level);
+        let mut builder = Builder {
+            hir,
+            cfg: CFG { basic_blocks: IndexVec::new() },
+            fn_span: span,
+            arg_count,
+            generator_kind,
+            scopes: Default::default(),
+            block_context: BlockContext::new(),
+            source_scopes: IndexVec::new(),
+            source_scope: OUTERMOST_SOURCE_SCOPE,
+            guard_context: vec![],
+            push_unsafe_count: 0,
+            unpushed_unsafe: safety,
+            local_decls: IndexVec::from_elem_n(
+                LocalDecl::new_return_place(return_ty, return_span),
+                1,
+            ),
+            canonical_user_type_annotations: IndexVec::new(),
+            upvar_mutbls: vec![],
+            var_indices: Default::default(),
+            unit_temp: None,
+            var_debug_info: vec![],
+            cached_resume_block: None,
+            cached_return_block: None,
+            cached_unreachable_block: None,
+        };
+
+        assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
+        assert_eq!(
+            builder.new_source_scope(span, lint_level, Some(safety)),
+            OUTERMOST_SOURCE_SCOPE
+        );
+        builder.source_scopes[OUTERMOST_SOURCE_SCOPE].parent_scope = None;
+
+        builder
+    }
+
+    fn finish(self) -> Body<'tcx> {
+        for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
+            if block.terminator.is_none() {
+                span_bug!(self.fn_span, "no terminator on block {:?}", index);
+            }
+        }
+
+        Body::new(
+            self.cfg.basic_blocks,
+            self.source_scopes,
+            self.local_decls,
+            self.canonical_user_type_annotations,
+            self.arg_count,
+            self.var_debug_info,
+            self.fn_span,
+            self.hir.control_flow_destroyed(),
+            self.generator_kind,
+        )
+    }
+
+    fn args_and_body(
+        &mut self,
+        mut block: BasicBlock,
+        fn_def_id: DefId,
+        arguments: &[ArgInfo<'tcx>],
+        argument_scope: region::Scope,
+        ast_body: &'tcx hir::Expr<'tcx>,
+    ) -> BlockAnd<()> {
+        // Allocate locals for the function arguments
+        for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
+            let source_info = SourceInfo {
+                scope: OUTERMOST_SOURCE_SCOPE,
+                span: arg_opt.map_or(self.fn_span, |arg| arg.pat.span),
+            };
+            let arg_local = self.local_decls.push(LocalDecl {
+                mutability: Mutability::Mut,
+                ty,
+                user_ty: UserTypeProjections::none(),
+                source_info,
+                internal: false,
+                local_info: LocalInfo::Other,
+                is_block_tail: None,
+            });
+
+            // If this is a simple binding pattern, give debuginfo a nice name.
+            if let Some(arg) = arg_opt {
+                if let Some(ident) = arg.pat.simple_ident() {
+                    self.var_debug_info.push(VarDebugInfo {
+                        name: ident.name,
+                        source_info,
+                        place: arg_local.into(),
+                    });
+                }
+            }
+        }
+
+        let tcx = self.hir.tcx();
+        let tcx_hir = tcx.hir();
+        let hir_tables = self.hir.tables();
+
+        // In analyze_closure() in upvar.rs we gathered a list of upvars used by a
+        // closure and we stored in a map called upvar_list in TypeckTables indexed
+        // 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.upvar_list.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;
+            if let ty::Ref(_, ty, _) = closure_ty.kind {
+                closure_env_projs.push(ProjectionElem::Deref);
+                closure_ty = ty;
+            }
+            let (def_id, upvar_substs) = match closure_ty.kind {
+                ty::Closure(def_id, substs) => (def_id, ty::UpvarSubsts::Closure(substs)),
+                ty::Generator(def_id, substs, _) => (def_id, ty::UpvarSubsts::Generator(substs)),
+                _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty),
+            };
+            let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
+            let upvars_with_tys = upvars.iter().zip(upvar_tys);
+            self.upvar_mutbls = upvars_with_tys
+                .enumerate()
+                .map(|(i, ((&var_id, &upvar_id), ty))| {
+                    let capture = hir_tables.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) {
+                                Some(ty::BindByValue(hir::Mutability::Mut)) => {
+                                    mutability = Mutability::Mut;
+                                }
+                                Some(_) => mutability = Mutability::Not,
+                                _ => {}
+                            }
+                        }
+                    }
+
+                    let mut projs = closure_env_projs.clone();
+                    projs.push(ProjectionElem::Field(Field::new(i), ty));
+                    match capture {
+                        ty::UpvarCapture::ByValue => {}
+                        ty::UpvarCapture::ByRef(..) => {
+                            projs.push(ProjectionElem::Deref);
+                        }
+                    };
+
+                    self.var_debug_info.push(VarDebugInfo {
+                        name,
+                        source_info: SourceInfo {
+                            scope: OUTERMOST_SOURCE_SCOPE,
+                            span: tcx_hir.span(var_id),
+                        },
+                        place: Place {
+                            local: closure_env_arg.into(),
+                            projection: tcx.intern_place_elems(&projs),
+                        },
+                    });
+
+                    mutability
+                })
+                .collect();
+        }
+
+        let mut scope = None;
+        // Bind the argument patterns
+        for (index, arg_info) in arguments.iter().enumerate() {
+            // Function arguments always get the first Local indices after the return place
+            let local = Local::new(index + 1);
+            let place = Place::from(local);
+            let &ArgInfo(_, opt_ty_info, arg_opt, ref self_binding) = arg_info;
+
+            // Make sure we drop (parts of) the argument even when not matched on.
+            self.schedule_drop(
+                arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span),
+                argument_scope,
+                local,
+                DropKind::Value,
+            );
+
+            if let Some(arg) = arg_opt {
+                let pattern = self.hir.pattern_from_hir(&arg.pat);
+                let original_source_scope = self.source_scope;
+                let span = pattern.span;
+                self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
+                match *pattern.kind {
+                    // Don't introduce extra copies for simple bindings
+                    PatKind::Binding {
+                        mutability,
+                        var,
+                        mode: BindingMode::ByValue,
+                        subpattern: None,
+                        ..
+                    } => {
+                        self.local_decls[local].mutability = mutability;
+                        self.local_decls[local].source_info.scope = self.source_scope;
+                        self.local_decls[local].local_info = if let Some(kind) = self_binding {
+                            LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))
+                        } else {
+                            let binding_mode = ty::BindingMode::BindByValue(mutability.into());
+                            LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+                                VarBindingForm {
+                                    binding_mode,
+                                    opt_ty_info,
+                                    opt_match_place: Some((Some(place.clone()), span)),
+                                    pat_span: span,
+                                },
+                            )))
+                        };
+                        self.var_indices.insert(var, LocalsForNode::One(local));
+                    }
+                    _ => {
+                        scope = self.declare_bindings(
+                            scope,
+                            ast_body.span,
+                            &pattern,
+                            matches::ArmHasGuard(false),
+                            Some((Some(&place), span)),
+                        );
+                        unpack!(block = self.place_into_pattern(block, pattern, &place, false));
+                    }
+                }
+                self.source_scope = original_source_scope;
+            }
+        }
+
+        // Enter the argument pattern bindings source scope, if it exists.
+        if let Some(source_scope) = scope {
+            self.source_scope = source_scope;
+        }
+
+        let body = self.hir.mirror(ast_body);
+        self.into(&Place::return_place(), block, body)
+    }
+
+    fn set_correct_source_scope_for_arg(
+        &mut self,
+        arg_hir_id: hir::HirId,
+        original_source_scope: SourceScope,
+        pattern_span: Span,
+    ) {
+        let tcx = self.hir.tcx();
+        let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir.root_lint_level);
+        let parent_root = tcx.maybe_lint_level_root_bounded(
+            self.source_scopes[original_source_scope]
+                .local_data
+                .as_ref()
+                .assert_crate_local()
+                .lint_root,
+            self.hir.root_lint_level,
+        );
+        if current_root != parent_root {
+            self.source_scope =
+                self.new_source_scope(pattern_span, LintLevel::Explicit(current_root), None);
+        }
+    }
+
+    fn get_unit_temp(&mut self) -> Place<'tcx> {
+        match self.unit_temp {
+            Some(ref tmp) => tmp.clone(),
+            None => {
+                let ty = self.hir.unit_ty();
+                let fn_span = self.fn_span;
+                let tmp = self.temp(ty, fn_span);
+                self.unit_temp = Some(tmp.clone());
+                tmp
+            }
+        }
+    }
+
+    fn return_block(&mut self) -> BasicBlock {
+        match self.cached_return_block {
+            Some(rb) => rb,
+            None => {
+                let rb = self.cfg.start_new_block();
+                self.cached_return_block = Some(rb);
+                rb
+            }
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Builder methods are broken up into modules, depending on what kind
+// of thing is being lowered. Note that they use the `unpack` macro
+// above extensively.
+
+mod block;
+mod cfg;
+mod expr;
+mod into;
+mod matches;
+mod misc;
+mod scope;
diff --git a/src/librustc_mir_build/build/scope.rs b/src/librustc_mir_build/build/scope.rs
new file mode 100644 (file)
index 0000000..d994b87
--- /dev/null
@@ -0,0 +1,1313 @@
+/*!
+Managing the scope stack. The scopes are tied to lexical scopes, so as
+we descend the HAIR, we push a scope on the stack, build its
+contents, and then pop it off. Every scope is named by a
+`region::Scope`.
+
+### SEME Regions
+
+When pushing a new scope, we record the current point in the graph (a
+basic block); this marks the entry to the scope. We then generate more
+stuff in the control-flow graph. Whenever the scope is exited, either
+via a `break` or `return` or just by fallthrough, that marks an exit
+from the scope. Each lexical scope thus corresponds to a single-entry,
+multiple-exit (SEME) region in the control-flow graph.
+
+For now, we keep a mapping from each `region::Scope` to its
+corresponding SEME region for later reference (see caveat in next
+paragraph). This is because region scopes are tied to
+them. Eventually, when we shift to non-lexical lifetimes, there should
+be no need to remember this mapping.
+
+### Not so SEME Regions
+
+In the course of building matches, it sometimes happens that certain code
+(namely guards) gets executed multiple times. This means that the scope lexical
+scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
+mapping is from one scope to a vector of SEME regions.
+
+Also in matches, the scopes assigned to arms are not even SEME regions! Each
+arm has a single region with one entry for each pattern. We manually
+manipulate the scheduled drops in this scope to avoid dropping things multiple
+times, although drop elaboration would clean this up for value drops.
+
+### Drops
+
+The primary purpose for scopes is to insert drops: while building
+the contents, we also accumulate places that need to be dropped upon
+exit from each scope. This is done by calling `schedule_drop`. Once a
+drop is scheduled, whenever we branch out we will insert drops of all
+those places onto the outgoing edge. Note that we don't know the full
+set of scheduled drops up front, and so whenever we exit from the
+scope we only drop the values scheduled thus far. For example, consider
+the scope S corresponding to this loop:
+
+```
+# let cond = true;
+loop {
+    let x = ..;
+    if cond { break; }
+    let y = ..;
+}
+```
+
+When processing the `let x`, we will add one drop to the scope for
+`x`.  The break will then insert a drop for `x`. When we process `let
+y`, we will add another drop (in fact, to a subscope, but let's ignore
+that for now); any later drops would also drop `y`.
+
+### Early exit
+
+There are numerous "normal" ways to early exit a scope: `break`,
+`continue`, `return` (panics are handled separately). Whenever an
+early exit occurs, the method `exit_scope` is called. It is given the
+current point in execution where the early exit occurs, as well as the
+scope you want to branch to (note that all early exits from to some
+other enclosing scope). `exit_scope` will record this exit point and
+also add all drops.
+
+Panics are handled in a similar fashion, except that a panic always
+returns out to the `DIVERGE_BLOCK`. To trigger a panic, simply call
+`panic(p)` with the current point `p`. Or else you can call
+`diverge_cleanup`, which will produce a block that you can branch to
+which does the appropriate cleanup and then diverges. `panic(p)`
+simply calls `diverge_cleanup()` and adds an edge from `p` to the
+result.
+
+### Loop scopes
+
+In addition to the normal scope stack, we track a loop scope stack
+that contains only loops. It tracks where a `break` and `continue`
+should go to.
+
+*/
+
+use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
+use crate::hair::{Expr, ExprRef, LintLevel};
+use rustc::middle::region;
+use rustc::mir::*;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_hir::GeneratorKind;
+use rustc_span::{Span, DUMMY_SP};
+use std::collections::hash_map::Entry;
+use std::mem;
+
+#[derive(Debug)]
+struct Scope {
+    /// The source scope this scope was created in.
+    source_scope: SourceScope,
+
+    /// the region span of this scope within source code.
+    region_scope: region::Scope,
+
+    /// the span of that region_scope
+    region_scope_span: Span,
+
+    /// set of places to drop when exiting this scope. This starts
+    /// out empty but grows as variables are declared during the
+    /// building process. This is a stack, so we always drop from the
+    /// end of the vector (top of the stack) first.
+    drops: Vec<DropData>,
+
+    moved_locals: Vec<Local>,
+
+    /// The cache for drop chain on “normal” exit into a particular BasicBlock.
+    cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>,
+
+    /// The cache for drop chain on "generator drop" exit.
+    cached_generator_drop: Option<BasicBlock>,
+
+    /// The cache for drop chain on "unwind" exit.
+    cached_unwind: CachedBlock,
+}
+
+#[derive(Debug, Default)]
+crate struct Scopes<'tcx> {
+    scopes: Vec<Scope>,
+    /// The current set of breakable scopes. See module comment for more details.
+    breakable_scopes: Vec<BreakableScope<'tcx>>,
+}
+
+#[derive(Debug)]
+struct DropData {
+    /// span where drop obligation was incurred (typically where place was declared)
+    span: Span,
+
+    /// local to drop
+    local: Local,
+
+    /// Whether this is a value Drop or a StorageDead.
+    kind: DropKind,
+
+    /// The cached blocks for unwinds.
+    cached_block: CachedBlock,
+}
+
+#[derive(Debug, Default, Clone, Copy)]
+struct CachedBlock {
+    /// The cached block for the cleanups-on-diverge path. This block
+    /// contains code to run the current drop and all the preceding
+    /// drops (i.e., those having lower index in Drop’s Scope drop
+    /// array)
+    unwind: Option<BasicBlock>,
+
+    /// The cached block for unwinds during cleanups-on-generator-drop path
+    ///
+    /// This is split from the standard unwind path here to prevent drop
+    /// elaboration from creating drop flags that would have to be captured
+    /// by the generator. I'm not sure how important this optimization is,
+    /// but it is here.
+    generator_drop: Option<BasicBlock>,
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) enum DropKind {
+    Value,
+    Storage,
+}
+
+#[derive(Clone, Debug)]
+struct BreakableScope<'tcx> {
+    /// Region scope of the loop
+    region_scope: region::Scope,
+    /// Where the body of the loop begins. `None` if block
+    continue_block: Option<BasicBlock>,
+    /// Block to branch into when the loop or block terminates (either by being
+    /// `break`-en out from, or by having its condition to become false)
+    break_block: BasicBlock,
+    /// The destination of the loop/block expression itself (i.e., where to put
+    /// the result of a `break` expression)
+    break_destination: Place<'tcx>,
+}
+
+/// The target of an expression that breaks out of a scope
+#[derive(Clone, Copy, Debug)]
+crate enum BreakableTarget {
+    Continue(region::Scope),
+    Break(region::Scope),
+    Return,
+}
+
+impl CachedBlock {
+    fn invalidate(&mut self) {
+        *self = CachedBlock::default();
+    }
+
+    fn get(&self, generator_drop: bool) -> Option<BasicBlock> {
+        if generator_drop { self.generator_drop } else { self.unwind }
+    }
+
+    fn ref_mut(&mut self, generator_drop: bool) -> &mut Option<BasicBlock> {
+        if generator_drop { &mut self.generator_drop } else { &mut self.unwind }
+    }
+}
+
+impl Scope {
+    /// Invalidates all the cached blocks in the scope.
+    ///
+    /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
+    /// larger extent of code.
+    ///
+    /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`.
+    /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
+    /// top-of-scope (as opposed to dependent scopes).
+    fn invalidate_cache(
+        &mut self,
+        storage_only: bool,
+        generator_kind: Option<GeneratorKind>,
+        this_scope_only: bool,
+    ) {
+        // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
+        // with lots of `try!`?
+
+        // cached exits drop storage and refer to the top-of-scope
+        self.cached_exits.clear();
+
+        // the current generator drop and unwind refer to top-of-scope
+        self.cached_generator_drop = None;
+
+        let ignore_unwinds = storage_only && generator_kind.is_none();
+        if !ignore_unwinds {
+            self.cached_unwind.invalidate();
+        }
+
+        if !ignore_unwinds && !this_scope_only {
+            for drop_data in &mut self.drops {
+                drop_data.cached_block.invalidate();
+            }
+        }
+    }
+
+    /// Given a span and this scope's source scope, make a SourceInfo.
+    fn source_info(&self, span: Span) -> SourceInfo {
+        SourceInfo { span, scope: self.source_scope }
+    }
+
+    /// Whether there's anything to do for the cleanup path, that is,
+    /// when unwinding through this scope. This includes destructors,
+    /// but not StorageDead statements, which don't get emitted at all
+    /// for unwinding, for several reasons:
+    ///  * clang doesn't emit llvm.lifetime.end for C++ unwinding
+    ///  * LLVM's memory dependency analysis can't handle it atm
+    ///  * polluting the cleanup MIR with StorageDead creates
+    ///    landing pads even though there's no actual destructors
+    ///  * freeing up stack space has no effect during unwinding
+    /// Note that for generators we do emit StorageDeads, for the
+    /// use of optimizations in the MIR generator transform.
+    fn needs_cleanup(&self) -> bool {
+        self.drops.iter().any(|drop| match drop.kind {
+            DropKind::Value => true,
+            DropKind::Storage => false,
+        })
+    }
+}
+
+impl<'tcx> Scopes<'tcx> {
+    fn len(&self) -> usize {
+        self.scopes.len()
+    }
+
+    fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) {
+        debug!("push_scope({:?})", region_scope);
+        self.scopes.push(Scope {
+            source_scope: vis_scope,
+            region_scope: region_scope.0,
+            region_scope_span: region_scope.1.span,
+            drops: vec![],
+            moved_locals: vec![],
+            cached_generator_drop: None,
+            cached_exits: Default::default(),
+            cached_unwind: CachedBlock::default(),
+        });
+    }
+
+    fn pop_scope(
+        &mut self,
+        region_scope: (region::Scope, SourceInfo),
+    ) -> (Scope, Option<BasicBlock>) {
+        let scope = self.scopes.pop().unwrap();
+        assert_eq!(scope.region_scope, region_scope.0);
+        let unwind_to =
+            self.scopes.last().and_then(|next_scope| next_scope.cached_unwind.get(false));
+        (scope, unwind_to)
+    }
+
+    fn may_panic(&self, scope_count: usize) -> bool {
+        let len = self.len();
+        self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup())
+    }
+
+    /// Finds the breakable scope for a given label. This is used for
+    /// resolving `return`, `break` and `continue`.
+    fn find_breakable_scope(
+        &self,
+        span: Span,
+        target: BreakableTarget,
+    ) -> (BasicBlock, region::Scope, Option<Place<'tcx>>) {
+        let get_scope = |scope: region::Scope| {
+            // find the loop-scope by its `region::Scope`.
+            self.breakable_scopes
+                .iter()
+                .rfind(|breakable_scope| breakable_scope.region_scope == scope)
+                .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
+        };
+        match target {
+            BreakableTarget::Return => {
+                let scope = &self.breakable_scopes[0];
+                if scope.break_destination != Place::return_place() {
+                    span_bug!(span, "`return` in item with no return scope");
+                }
+                (scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
+            }
+            BreakableTarget::Break(scope) => {
+                let scope = get_scope(scope);
+                (scope.break_block, scope.region_scope, Some(scope.break_destination.clone()))
+            }
+            BreakableTarget::Continue(scope) => {
+                let scope = get_scope(scope);
+                let continue_block = scope
+                    .continue_block
+                    .unwrap_or_else(|| span_bug!(span, "missing `continue` block"));
+                (continue_block, scope.region_scope, None)
+            }
+        }
+    }
+
+    fn num_scopes_above(&self, region_scope: region::Scope, span: Span) -> usize {
+        let scope_count = self
+            .scopes
+            .iter()
+            .rev()
+            .position(|scope| scope.region_scope == region_scope)
+            .unwrap_or_else(|| span_bug!(span, "region_scope {:?} does not enclose", region_scope));
+        let len = self.len();
+        assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
+        scope_count
+    }
+
+    fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
+        self.scopes.iter_mut().rev()
+    }
+
+    fn top_scopes(&mut self, count: usize) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
+        let len = self.len();
+        self.scopes[len - count..].iter_mut()
+    }
+
+    /// Returns the topmost active scope, which is known to be alive until
+    /// the next scope expression.
+    pub(super) fn topmost(&self) -> region::Scope {
+        self.scopes.last().expect("topmost_scope: no scopes present").region_scope
+    }
+
+    fn source_info(&self, index: usize, span: Span) -> SourceInfo {
+        self.scopes[self.len() - index].source_info(span)
+    }
+}
+
+impl<'a, 'tcx> Builder<'a, 'tcx> {
+    // Adding and removing scopes
+    // ==========================
+    //  Start a breakable scope, which tracks where `continue`, `break` and
+    //  `return` should branch to.
+    crate fn in_breakable_scope<F, R>(
+        &mut self,
+        loop_block: Option<BasicBlock>,
+        break_block: BasicBlock,
+        break_destination: Place<'tcx>,
+        f: F,
+    ) -> R
+    where
+        F: FnOnce(&mut Builder<'a, 'tcx>) -> R,
+    {
+        let region_scope = self.scopes.topmost();
+        let scope = BreakableScope {
+            region_scope,
+            continue_block: loop_block,
+            break_block,
+            break_destination,
+        };
+        self.scopes.breakable_scopes.push(scope);
+        let res = f(self);
+        let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
+        assert!(breakable_scope.region_scope == region_scope);
+        res
+    }
+
+    crate fn in_opt_scope<F, R>(
+        &mut self,
+        opt_scope: Option<(region::Scope, SourceInfo)>,
+        f: F,
+    ) -> BlockAnd<R>
+    where
+        F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
+    {
+        debug!("in_opt_scope(opt_scope={:?})", opt_scope);
+        if let Some(region_scope) = opt_scope {
+            self.push_scope(region_scope);
+        }
+        let mut block;
+        let rv = unpack!(block = f(self));
+        if let Some(region_scope) = opt_scope {
+            unpack!(block = self.pop_scope(region_scope, block));
+        }
+        debug!("in_scope: exiting opt_scope={:?} block={:?}", opt_scope, block);
+        block.and(rv)
+    }
+
+    /// Convenience wrapper that pushes a scope and then executes `f`
+    /// to build its contents, popping the scope afterwards.
+    crate fn in_scope<F, R>(
+        &mut self,
+        region_scope: (region::Scope, SourceInfo),
+        lint_level: LintLevel,
+        f: F,
+    ) -> BlockAnd<R>
+    where
+        F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
+    {
+        debug!("in_scope(region_scope={:?})", region_scope);
+        let source_scope = self.source_scope;
+        let tcx = self.hir.tcx();
+        if let LintLevel::Explicit(current_hir_id) = lint_level {
+            // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
+            // to avoid adding Hir dependences on our parents.
+            // We estimate the true lint roots here to avoid creating a lot of source scopes.
+
+            let parent_root = tcx.maybe_lint_level_root_bounded(
+                self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root,
+                self.hir.root_lint_level,
+            );
+            let current_root =
+                tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir.root_lint_level);
+
+            if parent_root != current_root {
+                self.source_scope = self.new_source_scope(
+                    region_scope.1.span,
+                    LintLevel::Explicit(current_root),
+                    None,
+                );
+            }
+        }
+        self.push_scope(region_scope);
+        let mut block;
+        let rv = unpack!(block = f(self));
+        unpack!(block = self.pop_scope(region_scope, block));
+        self.source_scope = source_scope;
+        debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
+        block.and(rv)
+    }
+
+    /// Push a scope onto the stack. You can then build code in this
+    /// scope and call `pop_scope` afterwards. Note that these two
+    /// calls must be paired; using `in_scope` as a convenience
+    /// wrapper maybe preferable.
+    crate fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) {
+        self.scopes.push_scope(region_scope, self.source_scope);
+    }
+
+    /// Pops a scope, which should have region scope `region_scope`,
+    /// adding any drops onto the end of `block` that are needed.
+    /// This must match 1-to-1 with `push_scope`.
+    crate fn pop_scope(
+        &mut self,
+        region_scope: (region::Scope, SourceInfo),
+        mut block: BasicBlock,
+    ) -> BlockAnd<()> {
+        debug!("pop_scope({:?}, {:?})", region_scope, block);
+        // If we are emitting a `drop` statement, we need to have the cached
+        // diverge cleanup pads ready in case that drop panics.
+        if self.scopes.may_panic(1) {
+            self.diverge_cleanup();
+        }
+        let (scope, unwind_to) = self.scopes.pop_scope(region_scope);
+        let unwind_to = unwind_to.unwrap_or_else(|| self.resume_block());
+
+        unpack!(
+            block = build_scope_drops(
+                &mut self.cfg,
+                self.generator_kind,
+                &scope,
+                block,
+                unwind_to,
+                self.arg_count,
+                false, // not generator
+                false, // not unwind path
+            )
+        );
+
+        block.unit()
+    }
+
+    crate fn break_scope(
+        &mut self,
+        mut block: BasicBlock,
+        value: Option<ExprRef<'tcx>>,
+        scope: BreakableTarget,
+        source_info: SourceInfo,
+    ) -> BlockAnd<()> {
+        let (mut target_block, region_scope, destination) =
+            self.scopes.find_breakable_scope(source_info.span, scope);
+        if let BreakableTarget::Return = scope {
+            // We call this now, rather than when we start lowering the
+            // function so that the return block doesn't precede the entire
+            // rest of the CFG. Some passes and LLVM prefer blocks to be in
+            // approximately CFG order.
+            target_block = self.return_block();
+        }
+        if let Some(destination) = destination {
+            if let Some(value) = value {
+                debug!("stmt_expr Break val block_context.push(SubExpr)");
+                self.block_context.push(BlockFrame::SubExpr);
+                unpack!(block = self.into(&destination, block, value));
+                self.block_context.pop();
+            } else {
+                self.cfg.push_assign_unit(block, source_info, &destination)
+            }
+        } else {
+            assert!(value.is_none(), "`return` and `break` should have a destination");
+        }
+        self.exit_scope(source_info.span, region_scope, block, target_block);
+        self.cfg.start_new_block().unit()
+    }
+
+    /// Branch out of `block` to `target`, exiting all scopes up to
+    /// and including `region_scope`. This will insert whatever drops are
+    /// needed. See module comment for details.
+    crate fn exit_scope(
+        &mut self,
+        span: Span,
+        region_scope: region::Scope,
+        mut block: BasicBlock,
+        target: BasicBlock,
+    ) {
+        debug!(
+            "exit_scope(region_scope={:?}, block={:?}, target={:?})",
+            region_scope, block, target
+        );
+        let scope_count = self.scopes.num_scopes_above(region_scope, span);
+
+        // If we are emitting a `drop` statement, we need to have the cached
+        // diverge cleanup pads ready in case that drop panics.
+        let may_panic = self.scopes.may_panic(scope_count);
+        if may_panic {
+            self.diverge_cleanup();
+        }
+
+        let mut scopes = self.scopes.top_scopes(scope_count + 1).rev();
+        let mut scope = scopes.next().unwrap();
+        for next_scope in scopes {
+            if scope.drops.is_empty() {
+                scope = next_scope;
+                continue;
+            }
+            let source_info = scope.source_info(span);
+            block = match scope.cached_exits.entry((target, region_scope)) {
+                Entry::Occupied(e) => {
+                    self.cfg.goto(block, source_info, *e.get());
+                    return;
+                }
+                Entry::Vacant(v) => {
+                    let b = self.cfg.start_new_block();
+                    self.cfg.goto(block, source_info, b);
+                    v.insert(b);
+                    b
+                }
+            };
+
+            let unwind_to = next_scope.cached_unwind.get(false).unwrap_or_else(|| {
+                debug_assert!(!may_panic, "cached block not present?");
+                START_BLOCK
+            });
+
+            unpack!(
+                block = build_scope_drops(
+                    &mut self.cfg,
+                    self.generator_kind,
+                    scope,
+                    block,
+                    unwind_to,
+                    self.arg_count,
+                    false, // not generator
+                    false, // not unwind path
+                )
+            );
+
+            scope = next_scope;
+        }
+
+        self.cfg.goto(block, self.scopes.source_info(scope_count, span), target);
+    }
+
+    /// Creates a path that performs all required cleanup for dropping a generator.
+    ///
+    /// This path terminates in GeneratorDrop. Returns the start of the path.
+    /// None indicates there’s no cleanup to do at this point.
+    crate fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
+        // Fill in the cache for unwinds
+        self.diverge_cleanup_gen(true);
+
+        let src_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
+        let resume_block = self.resume_block();
+        let mut scopes = self.scopes.iter_mut().peekable();
+        let mut block = self.cfg.start_new_block();
+        let result = block;
+
+        while let Some(scope) = scopes.next() {
+            block = if let Some(b) = scope.cached_generator_drop {
+                self.cfg.goto(block, src_info, b);
+                return Some(result);
+            } else {
+                let b = self.cfg.start_new_block();
+                scope.cached_generator_drop = Some(b);
+                self.cfg.goto(block, src_info, b);
+                b
+            };
+
+            let unwind_to = scopes
+                .peek()
+                .as_ref()
+                .map(|scope| {
+                    scope
+                        .cached_unwind
+                        .get(true)
+                        .unwrap_or_else(|| span_bug!(src_info.span, "cached block not present?"))
+                })
+                .unwrap_or(resume_block);
+
+            unpack!(
+                block = build_scope_drops(
+                    &mut self.cfg,
+                    self.generator_kind,
+                    scope,
+                    block,
+                    unwind_to,
+                    self.arg_count,
+                    true, // is generator
+                    true, // is cached path
+                )
+            );
+        }
+
+        self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
+
+        Some(result)
+    }
+
+    /// Creates a new source scope, nested in the current one.
+    crate fn new_source_scope(
+        &mut self,
+        span: Span,
+        lint_level: LintLevel,
+        safety: Option<Safety>,
+    ) -> SourceScope {
+        let parent = self.source_scope;
+        debug!(
+            "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
+            span,
+            lint_level,
+            safety,
+            parent,
+            self.source_scopes.get(parent)
+        );
+        let scope_local_data = SourceScopeLocalData {
+            lint_root: if let LintLevel::Explicit(lint_root) = lint_level {
+                lint_root
+            } else {
+                self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root
+            },
+            safety: safety.unwrap_or_else(|| {
+                self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety
+            }),
+        };
+        self.source_scopes.push(SourceScopeData {
+            span,
+            parent_scope: Some(parent),
+            local_data: ClearCrossCrate::Set(scope_local_data),
+        })
+    }
+
+    /// Given a span and the current source scope, make a SourceInfo.
+    crate fn source_info(&self, span: Span) -> SourceInfo {
+        SourceInfo { span, scope: self.source_scope }
+    }
+
+    // Finding scopes
+    // ==============
+    /// Returns the scope that we should use as the lifetime of an
+    /// operand. Basically, an operand must live until it is consumed.
+    /// This is similar to, but not quite the same as, the temporary
+    /// scope (which can be larger or smaller).
+    ///
+    /// Consider:
+    ///
+    ///     let x = foo(bar(X, Y));
+    ///
+    /// We wish to pop the storage for X and Y after `bar()` is
+    /// called, not after the whole `let` is completed.
+    ///
+    /// As another example, if the second argument diverges:
+    ///
+    ///     foo(Box::new(2), panic!())
+    ///
+    /// We would allocate the box but then free it on the unwinding
+    /// path; we would also emit a free on the 'success' path from
+    /// panic, but that will turn out to be removed as dead-code.
+    ///
+    /// When building statics/constants, returns `None` since
+    /// intermediate values do not have to be dropped in that case.
+    crate fn local_scope(&self) -> Option<region::Scope> {
+        match self.hir.body_owner_kind {
+            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) =>
+            // No need to free storage in this context.
+            {
+                None
+            }
+            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()),
+        }
+    }
+
+    // Schedule an abort block - this is used for some ABIs that cannot unwind
+    crate fn schedule_abort(&mut self) -> BasicBlock {
+        let source_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
+        let abortblk = self.cfg.start_new_cleanup_block();
+        self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort);
+        self.cached_resume_block = Some(abortblk);
+        abortblk
+    }
+
+    // Scheduling drops
+    // ================
+    crate fn schedule_drop_storage_and_value(
+        &mut self,
+        span: Span,
+        region_scope: region::Scope,
+        local: Local,
+    ) {
+        self.schedule_drop(span, region_scope, local, DropKind::Storage);
+        self.schedule_drop(span, region_scope, local, DropKind::Value);
+    }
+
+    /// Indicates that `place` should be dropped on exit from
+    /// `region_scope`.
+    ///
+    /// When called with `DropKind::Storage`, `place` should be a local
+    /// with an index higher than the current `self.arg_count`.
+    crate fn schedule_drop(
+        &mut self,
+        span: Span,
+        region_scope: region::Scope,
+        local: Local,
+        drop_kind: DropKind,
+    ) {
+        let needs_drop = match drop_kind {
+            DropKind::Value => {
+                if !self.hir.needs_drop(self.local_decls[local].ty) {
+                    return;
+                }
+                true
+            }
+            DropKind::Storage => {
+                if local.index() <= self.arg_count {
+                    span_bug!(
+                        span,
+                        "`schedule_drop` called with local {:?} and arg_count {}",
+                        local,
+                        self.arg_count,
+                    )
+                }
+                false
+            }
+        };
+
+        for scope in self.scopes.iter_mut() {
+            let this_scope = scope.region_scope == region_scope;
+            // When building drops, we try to cache chains of drops in such a way so these drops
+            // could be reused by the drops which would branch into the cached (already built)
+            // blocks.  This, however, means that whenever we add a drop into a scope which already
+            // had some blocks built (and thus, cached) for it, we must invalidate all caches which
+            // might branch into the scope which had a drop just added to it. This is necessary,
+            // because otherwise some other code might use the cache to branch into already built
+            // chain of drops, essentially ignoring the newly added drop.
+            //
+            // For example consider there’s two scopes with a drop in each. These are built and
+            // thus the caches are filled:
+            //
+            // +--------------------------------------------------------+
+            // | +---------------------------------+                    |
+            // | | +--------+     +-------------+  |  +---------------+ |
+            // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
+            // | | +--------+     +-------------+  |  +---------------+ |
+            // | +------------|outer_scope cache|--+                    |
+            // +------------------------------|middle_scope cache|------+
+            //
+            // Now, a new, inner-most scope is added along with a new drop into both inner-most and
+            // outer-most scopes:
+            //
+            // +------------------------------------------------------------+
+            // | +----------------------------------+                       |
+            // | | +--------+      +-------------+  |   +---------------+   | +-------------+
+            // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
+            // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
+            // | |             +-+ +-------------+  |                       |
+            // | +---|invalid outer_scope cache|----+                       |
+            // +----=----------------|invalid middle_scope cache|-----------+
+            //
+            // If, when adding `drop(new)` we do not invalidate the cached blocks for both
+            // outer_scope and middle_scope, then, when building drops for the inner (right-most)
+            // scope, the old, cached blocks, without `drop(new)` will get used, producing the
+            // wrong results.
+            //
+            // The cache and its invalidation for unwind branch is somewhat special. The cache is
+            // per-drop, rather than per scope, which has a several different implications. Adding
+            // a new drop into a scope will not invalidate cached blocks of the prior drops in the
+            // scope. That is true, because none of the already existing drops will have an edge
+            // into a block with the newly added drop.
+            //
+            // Note that this code iterates scopes from the inner-most to the outer-most,
+            // invalidating caches of each scope visited. This way bare minimum of the
+            // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
+            // cache of outer scope stays intact.
+            scope.invalidate_cache(!needs_drop, self.generator_kind, this_scope);
+            if this_scope {
+                let region_scope_span =
+                    region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree);
+                // Attribute scope exit drops to scope's closing brace.
+                let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span);
+
+                scope.drops.push(DropData {
+                    span: scope_end,
+                    local,
+                    kind: drop_kind,
+                    cached_block: CachedBlock::default(),
+                });
+                return;
+            }
+        }
+        span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
+    }
+
+    /// Indicates that the "local operand" stored in `local` is
+    /// *moved* at some point during execution (see `local_scope` for
+    /// more information about what a "local operand" is -- in short,
+    /// it's an intermediate operand created as part of preparing some
+    /// MIR instruction). We use this information to suppress
+    /// redundant drops on the non-unwind paths. This results in less
+    /// MIR, but also avoids spurious borrow check errors
+    /// (c.f. #64391).
+    ///
+    /// Example: when compiling the call to `foo` here:
+    ///
+    /// ```rust
+    /// foo(bar(), ...)
+    /// ```
+    ///
+    /// we would evaluate `bar()` to an operand `_X`. We would also
+    /// schedule `_X` to be dropped when the expression scope for
+    /// `foo(bar())` is exited. This is relevant, for example, if the
+    /// later arguments should unwind (it would ensure that `_X` gets
+    /// dropped). However, if no unwind occurs, then `_X` will be
+    /// unconditionally consumed by the `call`:
+    ///
+    /// ```
+    /// bb {
+    ///   ...
+    ///   _R = CALL(foo, _X, ...)
+    /// }
+    /// ```
+    ///
+    /// However, `_X` is still registered to be dropped, and so if we
+    /// do nothing else, we would generate a `DROP(_X)` that occurs
+    /// after the call. This will later be optimized out by the
+    /// drop-elaboation code, but in the meantime it can lead to
+    /// spurious borrow-check errors -- the problem, ironically, is
+    /// not the `DROP(_X)` itself, but the (spurious) unwind pathways
+    /// that it creates. See #64391 for an example.
+    crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
+        let scope = match self.local_scope() {
+            None => {
+                // if there is no local scope, operands won't be dropped anyway
+                return;
+            }
+
+            Some(local_scope) => self
+                .scopes
+                .iter_mut()
+                .find(|scope| scope.region_scope == local_scope)
+                .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)),
+        };
+
+        // look for moves of a local variable, like `MOVE(_X)`
+        let locals_moved = operands.iter().flat_map(|operand| match operand {
+            Operand::Copy(_) | Operand::Constant(_) => None,
+            Operand::Move(place) => place.as_local(),
+        });
+
+        for local in locals_moved {
+            // check if we have a Drop for this operand and -- if so
+            // -- add it to the list of moved operands. Note that this
+            // local might not have been an operand created for this
+            // call, it could come from other places too.
+            if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) {
+                scope.moved_locals.push(local);
+            }
+        }
+    }
+
+    // Other
+    // =====
+    /// Branch based on a boolean condition.
+    ///
+    /// This is a special case because the temporary for the condition needs to
+    /// be dropped on both the true and the false arm.
+    crate fn test_bool(
+        &mut self,
+        mut block: BasicBlock,
+        condition: Expr<'tcx>,
+        source_info: SourceInfo,
+    ) -> (BasicBlock, BasicBlock) {
+        let cond = unpack!(block = self.as_local_operand(block, condition));
+        let true_block = self.cfg.start_new_block();
+        let false_block = self.cfg.start_new_block();
+        let term = TerminatorKind::if_(self.hir.tcx(), cond.clone(), true_block, false_block);
+        self.cfg.terminate(block, source_info, term);
+
+        match cond {
+            // Don't try to drop a constant
+            Operand::Constant(_) => (),
+            // If constants and statics, we don't generate StorageLive for this
+            // temporary, so don't try to generate StorageDead for it either.
+            _ if self.local_scope().is_none() => (),
+            Operand::Copy(place) | Operand::Move(place) => {
+                if let Some(cond_temp) = place.as_local() {
+                    // Manually drop the condition on both branches.
+                    let top_scope = self.scopes.scopes.last_mut().unwrap();
+                    let top_drop_data = top_scope.drops.pop().unwrap();
+
+                    match top_drop_data.kind {
+                        DropKind::Value { .. } => {
+                            bug!("Drop scheduled on top of condition variable")
+                        }
+                        DropKind::Storage => {
+                            let source_info = top_scope.source_info(top_drop_data.span);
+                            let local = top_drop_data.local;
+                            assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
+                            self.cfg.push(
+                                true_block,
+                                Statement { source_info, kind: StatementKind::StorageDead(local) },
+                            );
+                            self.cfg.push(
+                                false_block,
+                                Statement { source_info, kind: StatementKind::StorageDead(local) },
+                            );
+                        }
+                    }
+
+                    top_scope.invalidate_cache(true, self.generator_kind, true);
+                } else {
+                    bug!("Expected as_local_operand to produce a temporary");
+                }
+            }
+        }
+
+        (true_block, false_block)
+    }
+
+    /// Creates a path that performs all required cleanup for unwinding.
+    ///
+    /// This path terminates in Resume. Returns the start of the path.
+    /// See module comment for more details.
+    crate fn diverge_cleanup(&mut self) -> BasicBlock {
+        self.diverge_cleanup_gen(false)
+    }
+
+    fn resume_block(&mut self) -> BasicBlock {
+        if let Some(target) = self.cached_resume_block {
+            target
+        } else {
+            let resumeblk = self.cfg.start_new_cleanup_block();
+            self.cfg.terminate(
+                resumeblk,
+                SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span: self.fn_span },
+                TerminatorKind::Resume,
+            );
+            self.cached_resume_block = Some(resumeblk);
+            resumeblk
+        }
+    }
+
+    fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
+        // Build up the drops in **reverse** order. The end result will
+        // look like:
+        //
+        //    scopes[n] -> scopes[n-1] -> ... -> scopes[0]
+        //
+        // However, we build this in **reverse order**. That is, we
+        // process scopes[0], then scopes[1], etc, pointing each one at
+        // the result generates from the one before. Along the way, we
+        // store caches. If everything is cached, we'll just walk right
+        // to left reading the cached results but never created anything.
+
+        // Find the last cached block
+        debug!("diverge_cleanup_gen(self.scopes = {:?})", self.scopes);
+        let cached_cleanup = self.scopes.iter_mut().enumerate().find_map(|(idx, ref scope)| {
+            let cached_block = scope.cached_unwind.get(generator_drop)?;
+            Some((cached_block, idx))
+        });
+        let (mut target, first_uncached) =
+            cached_cleanup.unwrap_or_else(|| (self.resume_block(), self.scopes.len()));
+
+        for scope in self.scopes.top_scopes(first_uncached) {
+            target = build_diverge_scope(
+                &mut self.cfg,
+                scope.region_scope_span,
+                scope,
+                target,
+                generator_drop,
+                self.generator_kind,
+            );
+        }
+
+        target
+    }
+
+    /// Utility function for *non*-scope code to build their own drops
+    crate fn build_drop_and_replace(
+        &mut self,
+        block: BasicBlock,
+        span: Span,
+        location: Place<'tcx>,
+        value: Operand<'tcx>,
+    ) -> BlockAnd<()> {
+        let source_info = self.source_info(span);
+        let next_target = self.cfg.start_new_block();
+        let diverge_target = self.diverge_cleanup();
+        self.cfg.terminate(
+            block,
+            source_info,
+            TerminatorKind::DropAndReplace {
+                location,
+                value,
+                target: next_target,
+                unwind: Some(diverge_target),
+            },
+        );
+        next_target.unit()
+    }
+
+    /// Creates an Assert terminator and return the success block.
+    /// If the boolean condition operand is not the expected value,
+    /// a runtime panic will be caused with the given message.
+    crate fn assert(
+        &mut self,
+        block: BasicBlock,
+        cond: Operand<'tcx>,
+        expected: bool,
+        msg: AssertMessage<'tcx>,
+        span: Span,
+    ) -> BasicBlock {
+        let source_info = self.source_info(span);
+
+        let success_block = self.cfg.start_new_block();
+        let cleanup = self.diverge_cleanup();
+
+        self.cfg.terminate(
+            block,
+            source_info,
+            TerminatorKind::Assert {
+                cond,
+                expected,
+                msg,
+                target: success_block,
+                cleanup: Some(cleanup),
+            },
+        );
+
+        success_block
+    }
+
+    // `match` arm scopes
+    // ==================
+    /// Unschedules any drops in the top scope.
+    ///
+    /// This is only needed for `match` arm scopes, because they have one
+    /// entrance per pattern, but only one exit.
+    pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) {
+        let top_scope = self.scopes.scopes.last_mut().unwrap();
+
+        assert_eq!(top_scope.region_scope, region_scope);
+
+        top_scope.drops.clear();
+        top_scope.invalidate_cache(false, self.generator_kind, true);
+    }
+}
+
+/// Builds drops for pop_scope and exit_scope.
+fn build_scope_drops<'tcx>(
+    cfg: &mut CFG<'tcx>,
+    generator_kind: Option<GeneratorKind>,
+    scope: &Scope,
+    mut block: BasicBlock,
+    last_unwind_to: BasicBlock,
+    arg_count: usize,
+    generator_drop: bool,
+    is_cached_path: bool,
+) -> BlockAnd<()> {
+    debug!("build_scope_drops({:?} -> {:?})", block, scope);
+
+    // Build up the drops in evaluation order. The end result will
+    // look like:
+    //
+    // [SDs, drops[n]] --..> [SDs, drop[1]] -> [SDs, drop[0]] -> [[SDs]]
+    //               |                    |                 |
+    //               :                    |                 |
+    //                                    V                 V
+    // [drop[n]] -...-> [drop[1]] ------> [drop[0]] ------> [last_unwind_to]
+    //
+    // The horizontal arrows represent the execution path when the drops return
+    // successfully. The downwards arrows represent the execution path when the
+    // drops panic (panicking while unwinding will abort, so there's no need for
+    // another set of arrows).
+    //
+    // For generators, we unwind from a drop on a local to its StorageDead
+    // statement. For other functions we don't worry about StorageDead. The
+    // drops for the unwind path should have already been generated by
+    // `diverge_cleanup_gen`.
+
+    for drop_idx in (0..scope.drops.len()).rev() {
+        let drop_data = &scope.drops[drop_idx];
+        let source_info = scope.source_info(drop_data.span);
+        let local = drop_data.local;
+
+        match drop_data.kind {
+            DropKind::Value => {
+                // If the operand has been moved, and we are not on an unwind
+                // path, then don't generate the drop. (We only take this into
+                // account for non-unwind paths so as not to disturb the
+                // caching mechanism.)
+                if !is_cached_path && scope.moved_locals.iter().any(|&o| o == local) {
+                    continue;
+                }
+
+                let unwind_to = get_unwind_to(scope, generator_kind, drop_idx, generator_drop)
+                    .unwrap_or(last_unwind_to);
+
+                let next = cfg.start_new_block();
+                cfg.terminate(
+                    block,
+                    source_info,
+                    TerminatorKind::Drop {
+                        location: local.into(),
+                        target: next,
+                        unwind: Some(unwind_to),
+                    },
+                );
+                block = next;
+            }
+            DropKind::Storage => {
+                // Only temps and vars need their storage dead.
+                assert!(local.index() > arg_count);
+                cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) });
+            }
+        }
+    }
+    block.unit()
+}
+
+fn get_unwind_to(
+    scope: &Scope,
+    generator_kind: Option<GeneratorKind>,
+    unwind_from: usize,
+    generator_drop: bool,
+) -> Option<BasicBlock> {
+    for drop_idx in (0..unwind_from).rev() {
+        let drop_data = &scope.drops[drop_idx];
+        match (generator_kind, &drop_data.kind) {
+            (Some(_), DropKind::Storage) => {
+                return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
+                    span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
+                }));
+            }
+            (None, DropKind::Value) => {
+                return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
+                    span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
+                }));
+            }
+            _ => (),
+        }
+    }
+    None
+}
+
+fn build_diverge_scope<'tcx>(
+    cfg: &mut CFG<'tcx>,
+    span: Span,
+    scope: &mut Scope,
+    mut target: BasicBlock,
+    generator_drop: bool,
+    generator_kind: Option<GeneratorKind>,
+) -> BasicBlock {
+    // Build up the drops in **reverse** order. The end result will
+    // look like:
+    //
+    //    [drops[n]] -...-> [drops[0]] -> [target]
+    //
+    // The code in this function reads from right to left. At each
+    // point, we check for cached blocks representing the
+    // remainder. If everything is cached, we'll just walk right to
+    // left reading the cached results but never create anything.
+
+    let source_scope = scope.source_scope;
+    let source_info = |span| SourceInfo { span, scope: source_scope };
+
+    // We keep track of StorageDead statements to prepend to our current block
+    // and store them here, in reverse order.
+    let mut storage_deads = vec![];
+
+    let mut target_built_by_us = false;
+
+    // Build up the drops. Here we iterate the vector in
+    // *forward* order, so that we generate drops[0] first (right to
+    // left in diagram above).
+    debug!("build_diverge_scope({:?})", scope.drops);
+    for (j, drop_data) in scope.drops.iter_mut().enumerate() {
+        debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data);
+        // Only full value drops are emitted in the diverging path,
+        // not StorageDead, except in the case of generators.
+        //
+        // Note: This may not actually be what we desire (are we
+        // "freeing" stack storage as we unwind, or merely observing a
+        // frozen stack)? In particular, the intent may have been to
+        // match the behavior of clang, but on inspection eddyb says
+        // this is not what clang does.
+        match drop_data.kind {
+            DropKind::Storage if generator_kind.is_some() => {
+                storage_deads.push(Statement {
+                    source_info: source_info(drop_data.span),
+                    kind: StatementKind::StorageDead(drop_data.local),
+                });
+                if !target_built_by_us {
+                    // We cannot add statements to an existing block, so we create a new
+                    // block for our StorageDead statements.
+                    let block = cfg.start_new_cleanup_block();
+                    let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope };
+                    cfg.goto(block, source_info, target);
+                    target = block;
+                    target_built_by_us = true;
+                }
+                *drop_data.cached_block.ref_mut(generator_drop) = Some(target);
+            }
+            DropKind::Storage => {}
+            DropKind::Value => {
+                let cached_block = drop_data.cached_block.ref_mut(generator_drop);
+                target = if let Some(cached_block) = *cached_block {
+                    storage_deads.clear();
+                    target_built_by_us = false;
+                    cached_block
+                } else {
+                    push_storage_deads(cfg, target, &mut storage_deads);
+                    let block = cfg.start_new_cleanup_block();
+                    cfg.terminate(
+                        block,
+                        source_info(drop_data.span),
+                        TerminatorKind::Drop {
+                            location: drop_data.local.into(),
+                            target,
+                            unwind: None,
+                        },
+                    );
+                    *cached_block = Some(block);
+                    target_built_by_us = true;
+                    block
+                };
+            }
+        };
+    }
+    push_storage_deads(cfg, target, &mut storage_deads);
+    *scope.cached_unwind.ref_mut(generator_drop) = Some(target);
+
+    assert!(storage_deads.is_empty());
+    debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
+
+    target
+}
+
+fn push_storage_deads<'tcx>(
+    cfg: &mut CFG<'tcx>,
+    target: BasicBlock,
+    storage_deads: &mut Vec<Statement<'tcx>>,
+) {
+    if storage_deads.is_empty() {
+        return;
+    }
+    let statements = &mut cfg.block_data_mut(target).statements;
+    storage_deads.reverse();
+    debug!(
+        "push_storage_deads({:?}), storage_deads={:?}, statements={:?}",
+        target, storage_deads, statements
+    );
+    storage_deads.append(statements);
+    mem::swap(statements, storage_deads);
+    assert!(storage_deads.is_empty());
+}
diff --git a/src/librustc_mir_build/hair/constant.rs b/src/librustc_mir_build/hair/constant.rs
new file mode 100644 (file)
index 0000000..a4bedfa
--- /dev/null
@@ -0,0 +1,89 @@
+use rustc::mir::interpret::{ConstValue, Scalar};
+use rustc::ty::{self, layout::Size, ParamEnv, Ty, TyCtxt};
+use rustc_span::symbol::Symbol;
+use syntax::ast;
+
+#[derive(PartialEq)]
+crate enum LitToConstError {
+    UnparseableFloat,
+    Reported,
+}
+
+crate fn lit_to_const<'tcx>(
+    lit: &'tcx ast::LitKind,
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    neg: bool,
+) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
+    use syntax::ast::*;
+
+    let trunc = |n| {
+        let param_ty = ParamEnv::reveal_all().and(ty);
+        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
+        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
+        let result = truncate(n, width);
+        trace!("trunc result: {}", result);
+        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
+    };
+
+    use rustc::mir::interpret::*;
+    let lit = match *lit {
+        LitKind::Str(ref s, _) => {
+            let s = s.as_str();
+            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
+            let allocation = tcx.intern_const_alloc(allocation);
+            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
+        }
+        LitKind::ByteStr(ref data) => {
+            let id = tcx.allocate_bytes(data);
+            ConstValue::Scalar(Scalar::Ptr(id.into()))
+        }
+        LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))),
+        LitKind::Int(n, _) if neg => {
+            let n = n as i128;
+            let n = n.overflowing_neg().0;
+            trunc(n as u128)?
+        }
+        LitKind::Int(n, _) => trunc(n)?,
+        LitKind::Float(n, _) => {
+            let fty = match ty.kind {
+                ty::Float(fty) => fty,
+                _ => bug!(),
+            };
+            parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
+        }
+        LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
+        LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
+        LitKind::Err(_) => unreachable!(),
+    };
+    Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(lit), ty }))
+}
+
+fn parse_float<'tcx>(num: Symbol, fty: ast::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
+    let num = num.as_str();
+    use rustc_apfloat::ieee::{Double, Single};
+    let scalar = match fty {
+        ast::FloatTy::F32 => {
+            num.parse::<f32>().map_err(|_| ())?;
+            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
+                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
+            });
+            if neg {
+                f = -f;
+            }
+            Scalar::from_f32(f)
+        }
+        ast::FloatTy::F64 => {
+            num.parse::<f64>().map_err(|_| ())?;
+            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
+                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
+            });
+            if neg {
+                f = -f;
+            }
+            Scalar::from_f64(f)
+        }
+    };
+
+    Ok(ConstValue::Scalar(scalar))
+}
diff --git a/src/librustc_mir_build/hair/cx/block.rs b/src/librustc_mir_build/hair/cx/block.rs
new file mode 100644 (file)
index 0000000..a883b84
--- /dev/null
@@ -0,0 +1,117 @@
+use crate::hair::cx::to_ref::ToRef;
+use crate::hair::cx::Cx;
+use crate::hair::{self, *};
+
+use rustc::middle::region;
+use rustc::ty;
+use rustc_hir as hir;
+
+use rustc_index::vec::Idx;
+
+impl<'tcx> Mirror<'tcx> for &'tcx hir::Block<'tcx> {
+    type Output = Block<'tcx>;
+
+    fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
+        // We have to eagerly lower the "spine" of the statements
+        // in order to get the lexical scoping correctly.
+        let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts);
+        let opt_destruction_scope =
+            cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id);
+        Block {
+            targeted_by_break: self.targeted_by_break,
+            region_scope: region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node },
+            opt_destruction_scope,
+            span: self.span,
+            stmts,
+            expr: self.expr.to_ref(),
+            safety_mode: match self.rules {
+                hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
+                hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(self.hir_id),
+                hir::BlockCheckMode::PushUnsafeBlock(..) => BlockSafety::PushUnsafe,
+                hir::BlockCheckMode::PopUnsafeBlock(..) => BlockSafety::PopUnsafe,
+            },
+        }
+    }
+}
+
+fn mirror_stmts<'a, 'tcx>(
+    cx: &mut Cx<'a, 'tcx>,
+    block_id: hir::ItemLocalId,
+    stmts: &'tcx [hir::Stmt<'tcx>],
+) -> Vec<StmtRef<'tcx>> {
+    let mut result = vec![];
+    for (index, stmt) in stmts.iter().enumerate() {
+        let hir_id = stmt.hir_id;
+        let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id);
+        match stmt.kind {
+            hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
+                result.push(StmtRef::Mirror(Box::new(Stmt {
+                    kind: StmtKind::Expr {
+                        scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node },
+                        expr: expr.to_ref(),
+                    },
+                    opt_destruction_scope: opt_dxn_ext,
+                })))
+            }
+            hir::StmtKind::Item(..) => {
+                // ignore for purposes of the MIR
+            }
+            hir::StmtKind::Local(ref local) => {
+                let remainder_scope = region::Scope {
+                    id: block_id,
+                    data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
+                };
+
+                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) {
+                        debug!("mirror_stmts: user_ty={:?}", user_ty);
+                        pattern = Pat {
+                            ty: pattern.ty,
+                            span: pattern.span,
+                            kind: Box::new(PatKind::AscribeUserType {
+                                ascription: hair::pattern::Ascription {
+                                    user_ty: PatTyProj::from_user_type(user_ty),
+                                    user_ty_span: ty.span,
+                                    variance: ty::Variance::Covariant,
+                                },
+                                subpattern: pattern,
+                            }),
+                        };
+                    }
+                }
+
+                result.push(StmtRef::Mirror(Box::new(Stmt {
+                    kind: StmtKind::Let {
+                        remainder_scope: remainder_scope,
+                        init_scope: region::Scope {
+                            id: hir_id.local_id,
+                            data: region::ScopeData::Node,
+                        },
+                        pattern,
+                        initializer: local.init.to_ref(),
+                        lint_level: LintLevel::Explicit(local.hir_id),
+                    },
+                    opt_destruction_scope: opt_dxn_ext,
+                })));
+            }
+        }
+    }
+    return result;
+}
+
+crate fn to_expr_ref<'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 temp_lifetime = cx.region_scope_tree.temporary_scope(block.hir_id.local_id);
+    let expr = Expr {
+        ty: block_ty,
+        temp_lifetime,
+        span: block.span,
+        kind: ExprKind::Block { body: block },
+    };
+    expr.to_ref()
+}
diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs
new file mode 100644 (file)
index 0000000..97e7181
--- /dev/null
@@ -0,0 +1,1020 @@
+use crate::hair::cx::block;
+use crate::hair::cx::to_ref::ToRef;
+use crate::hair::cx::Cx;
+use crate::hair::util::UserAnnotatedTyHelpers;
+use crate::hair::*;
+use rustc::mir::interpret::{ErrorHandled, Scalar};
+use rustc::mir::BorrowKind;
+use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast};
+use rustc::ty::subst::{InternalSubsts, SubstsRef};
+use rustc::ty::{self, AdtKind, Ty};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::def_id::LocalDefId;
+use rustc_index::vec::Idx;
+use rustc_span::Span;
+
+impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr<'tcx> {
+    type Output = Expr<'tcx>;
+
+    fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
+        let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id);
+        let expr_scope = region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node };
+
+        debug!("Expr::make_mirror(): id={}, span={:?}", self.hir_id, self.span);
+
+        let mut expr = make_mirror_unadjusted(cx, self);
+
+        // Now apply adjustments, if any.
+        for adjustment in cx.tables().expr_adjustments(self) {
+            debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
+            expr = apply_adjustment(cx, self, expr, adjustment);
+        }
+
+        // Next, wrap this up in the expr's scope.
+        expr = Expr {
+            temp_lifetime,
+            ty: expr.ty,
+            span: self.span,
+            kind: ExprKind::Scope {
+                region_scope: expr_scope,
+                value: expr.to_ref(),
+                lint_level: LintLevel::Explicit(self.hir_id),
+            },
+        };
+
+        // Finally, create a destruction scope, if any.
+        if let Some(region_scope) = cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id)
+        {
+            expr = Expr {
+                temp_lifetime,
+                ty: expr.ty,
+                span: self.span,
+                kind: ExprKind::Scope {
+                    region_scope,
+                    value: expr.to_ref(),
+                    lint_level: LintLevel::Inherited,
+                },
+            };
+        }
+
+        // OK, all done!
+        expr
+    }
+}
+
+fn apply_adjustment<'a, 'tcx>(
+    cx: &mut Cx<'a, 'tcx>,
+    hir_expr: &'tcx hir::Expr<'tcx>,
+    mut expr: Expr<'tcx>,
+    adjustment: &Adjustment<'tcx>,
+) -> Expr<'tcx> {
+    let Expr { temp_lifetime, mut span, .. } = expr;
+
+    // Adjust the span from the block, to the last expression of the
+    // block. This is a better span when returning a mutable reference
+    // with too short a lifetime. The error message will use the span
+    // from the assignment to the return place, which should only point
+    // at the returned value, not the entire function body.
+    //
+    // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 {
+    //      x
+    //   // ^ error message points at this expression.
+    // }
+    let mut adjust_span = |expr: &mut Expr<'tcx>| {
+        if let ExprKind::Block { body } = expr.kind {
+            if let Some(ref last_expr) = body.expr {
+                span = last_expr.span;
+                expr.span = span;
+            }
+        }
+    };
+
+    let kind = match adjustment.kind {
+        Adjust::Pointer(PointerCast::Unsize) => {
+            adjust_span(&mut expr);
+            ExprKind::Pointer { cast: PointerCast::Unsize, source: expr.to_ref() }
+        }
+        Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: expr.to_ref() },
+        Adjust::NeverToAny => ExprKind::NeverToAny { source: expr.to_ref() },
+        Adjust::Deref(None) => {
+            adjust_span(&mut expr);
+            ExprKind::Deref { arg: expr.to_ref() }
+        }
+        Adjust::Deref(Some(deref)) => {
+            // We don't need to do call adjust_span here since
+            // deref coercions always start with a built-in deref.
+            let call = deref.method_call(cx.tcx(), expr.ty);
+
+            expr = Expr {
+                temp_lifetime,
+                ty: cx.tcx.mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }),
+                span,
+                kind: ExprKind::Borrow {
+                    borrow_kind: deref.mutbl.to_borrow_kind(),
+                    arg: expr.to_ref(),
+                },
+            };
+
+            overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
+        }
+        Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
+            ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
+        }
+        Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
+            ExprKind::AddressOf { mutability, arg: expr.to_ref() }
+        }
+    };
+
+    Expr { temp_lifetime, ty: adjustment.target, span, kind }
+}
+
+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 temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+
+    let kind = match expr.kind {
+        // Here comes the interesting stuff:
+        hir::ExprKind::MethodCall(_, method_span, ref args) => {
+            // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
+            let expr = method_callee(cx, expr, method_span, None);
+            let args = args.iter().map(|e| e.to_ref()).collect();
+            ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true }
+        }
+
+        hir::ExprKind::Call(ref fun, ref args) => {
+            if cx.tables().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
+                // callee-object as expr parameter.
+
+                // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
+
+                let method = method_callee(cx, expr, fun.span, None);
+
+                let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
+                let tupled_args = Expr {
+                    ty: cx.tcx.mk_tup(arg_tys),
+                    temp_lifetime,
+                    span: expr.span,
+                    kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
+                };
+
+                ExprKind::Call {
+                    ty: method.ty,
+                    fun: method.to_ref(),
+                    args: vec![fun.to_ref(), tupled_args.to_ref()],
+                    from_hir_call: true,
+                }
+            } else {
+                let adt_data =
+                    if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind {
+                        // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
+                        expr_ty.ty_adt_def().and_then(|adt_def| match path.res {
+                            Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
+                                Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
+                            }
+                            Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))),
+                            _ => None,
+                        })
+                    } else {
+                        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 user_ty =
+                        user_provided_types.get(fun.hir_id).map(|u_ty| *u_ty).map(|mut u_ty| {
+                            if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
+                                *did = adt_def.did;
+                            }
+                            u_ty
+                        });
+                    debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
+
+                    let field_refs = args
+                        .iter()
+                        .enumerate()
+                        .map(|(idx, e)| FieldExprRef { name: Field::new(idx), expr: e.to_ref() })
+                        .collect();
+                    ExprKind::Adt {
+                        adt_def,
+                        substs,
+                        variant_index: index,
+                        fields: field_refs,
+                        user_ty,
+                        base: None,
+                    }
+                } else {
+                    ExprKind::Call {
+                        ty: cx.tables().node_type(fun.hir_id),
+                        fun: fun.to_ref(),
+                        args: args.to_ref(),
+                        from_hir_call: true,
+                    }
+                }
+            }
+        }
+
+        hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => {
+            ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: arg.to_ref() }
+        }
+
+        hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
+            ExprKind::AddressOf { mutability, arg: arg.to_ref() }
+        }
+
+        hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk },
+
+        hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
+            ExprKind::Assign { lhs: lhs.to_ref(), rhs: rhs.to_ref() }
+        }
+
+        hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+            if cx.tables().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() }
+            }
+        }
+
+        hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
+            literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
+            user_ty: None,
+        },
+
+        hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
+            } else {
+                // FIXME overflow
+                match (op.node, cx.constness) {
+                    // Destroy control flow if `#![feature(const_if_match)]` is not enabled.
+                    (hir::BinOpKind::And, hir::Constness::Const)
+                        if !cx.tcx.features().const_if_match =>
+                    {
+                        cx.control_flow_destroyed.push((op.span, "`&&` operator".into()));
+                        ExprKind::Binary { op: BinOp::BitAnd, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
+                    }
+                    (hir::BinOpKind::Or, hir::Constness::Const)
+                        if !cx.tcx.features().const_if_match =>
+                    {
+                        cx.control_flow_destroyed.push((op.span, "`||` operator".into()));
+                        ExprKind::Binary { op: BinOp::BitOr, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
+                    }
+
+                    (hir::BinOpKind::And, _) => ExprKind::LogicalOp {
+                        op: LogicalOp::And,
+                        lhs: lhs.to_ref(),
+                        rhs: rhs.to_ref(),
+                    },
+                    (hir::BinOpKind::Or, _) => ExprKind::LogicalOp {
+                        op: LogicalOp::Or,
+                        lhs: lhs.to_ref(),
+                        rhs: rhs.to_ref(),
+                    },
+
+                    _ => {
+                        let op = bin_op(op.node);
+                        ExprKind::Binary { op, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
+                    }
+                }
+            }
+        }
+
+        hir::ExprKind::Index(ref lhs, ref index) => {
+            if cx.tables().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() }
+            }
+        }
+
+        hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
+            if cx.tables().is_method_call(expr) {
+                overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()])
+            } else {
+                ExprKind::Deref { arg: arg.to_ref() }
+            }
+        }
+
+        hir::ExprKind::Unary(hir::UnOp::UnNot, ref arg) => {
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![arg.to_ref()])
+            } else {
+                ExprKind::Unary { op: UnOp::Not, arg: arg.to_ref() }
+            }
+        }
+
+        hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => {
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![arg.to_ref()])
+            } else {
+                if let hir::ExprKind::Lit(ref lit) = arg.kind {
+                    ExprKind::Literal {
+                        literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
+                        user_ty: None,
+                    }
+                } else {
+                    ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() }
+                }
+            }
+        }
+
+        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_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
+                    debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
+                    ExprKind::Adt {
+                        adt_def: adt,
+                        variant_index: VariantIdx::new(0),
+                        substs,
+                        user_ty,
+                        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(),
+                        }),
+                    }
+                }
+                AdtKind::Enum => {
+                    let res = cx.tables().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_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
+                            debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
+                            ExprKind::Adt {
+                                adt_def: adt,
+                                variant_index: index,
+                                substs,
+                                user_ty,
+                                fields: field_refs(cx, fields),
+                                base: None,
+                            }
+                        }
+                        _ => {
+                            span_bug!(expr.span, "unexpected res: {:?}", res);
+                        }
+                    }
+                }
+            },
+            _ => {
+                span_bug!(expr.span, "unexpected type for struct literal: {:?}", expr_ty);
+            }
+        },
+
+        hir::ExprKind::Closure(..) => {
+            let closure_ty = cx.tables().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) => {
+                    (def_id, UpvarSubsts::Generator(substs), Some(movability))
+                }
+                _ => {
+                    span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
+                }
+            };
+            let upvars = cx
+                .tcx
+                .upvars(def_id)
+                .iter()
+                .flat_map(|upvars| upvars.iter())
+                .zip(substs.upvar_tys(def_id, cx.tcx))
+                .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty))
+                .collect();
+            ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
+        }
+
+        hir::ExprKind::Path(ref qpath) => {
+            let res = cx.tables().qpath_res(qpath, expr.hir_id);
+            convert_path_expr(cx, expr, res)
+        }
+
+        hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
+            asm: &asm.inner,
+            outputs: asm.outputs_exprs.to_ref(),
+            inputs: asm.inputs_exprs.to_ref(),
+        },
+
+        // Now comes the rote stuff:
+        hir::ExprKind::Repeat(ref v, ref count) => {
+            let def_id = cx.tcx.hir().local_def_id(count.hir_id);
+            let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
+            let span = cx.tcx.def_span(def_id);
+            let count =
+                match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, None, Some(span)) {
+                    Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
+                    Err(ErrorHandled::Reported) => 0,
+                    Err(ErrorHandled::TooGeneric) => {
+                        let span = cx.tcx.def_span(def_id);
+                        cx.tcx
+                            .sess
+                            .span_err(span, "array lengths can't depend on generic parameters");
+                        0
+                    }
+                };
+
+            ExprKind::Repeat { value: v.to_ref(), count }
+        }
+        hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.to_ref() },
+        hir::ExprKind::Break(dest, ref value) => match dest.target_id {
+            Ok(target_id) => ExprKind::Break {
+                label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
+                value: value.to_ref(),
+            },
+            Err(err) => bug!("invalid loop id for break: {}", err),
+        },
+        hir::ExprKind::Continue(dest) => match dest.target_id {
+            Ok(loop_id) => ExprKind::Continue {
+                label: region::Scope { id: loop_id.local_id, data: region::ScopeData::Node },
+            },
+            Err(err) => bug!("invalid loop id for continue: {}", err),
+        },
+        hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
+            scrutinee: discr.to_ref(),
+            arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
+        },
+        hir::ExprKind::Loop(ref body, _, _) => {
+            ExprKind::Loop { body: block::to_expr_ref(cx, body) }
+        }
+        hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
+            lhs: source.to_ref(),
+            name: Field::new(cx.tcx.field_index(expr.hir_id, cx.tables)),
+        },
+        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_ty = user_provided_types.get(cast_ty.hir_id);
+
+            debug!(
+                "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
+                expr, cast_ty.hir_id, user_ty,
+            );
+
+            // 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) {
+                // Convert the lexpr to a vexpr.
+                ExprKind::Use { source: source.to_ref() }
+            } else if cx.tables().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.
+                ExprKind::Pointer { source: source.to_ref(), cast: PointerCast::ArrayToPointer }
+            } else {
+                // check whether this is casting an enum variant discriminant
+                // to prevent cycles, we refer to the discriminant initializer
+                // which is always an integer and thus doesn't need to know the
+                // enum's layout (or its tag type) to compute it during const eval
+                // Example:
+                // enum Foo {
+                //     A,
+                //     B = A as isize + 4,
+                // }
+                // 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 {
+                            Res::Def(
+                                DefKind::Ctor(CtorOf::Variant, CtorKind::Const),
+                                variant_ctor_id,
+                            ) => {
+                                let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
+                                let (d, o) = adt_def.discriminant_def_for_variant(idx);
+                                use rustc::ty::util::IntTypeExt;
+                                let ty = adt_def.repr.discr_type();
+                                let ty = ty.to_ty(cx.tcx());
+                                Some((d, o, ty))
+                            }
+                            _ => None,
+                        },
+                    )
+                } else {
+                    None
+                };
+
+                let source = if let Some((did, offset, var_ty)) = var {
+                    let mk_const = |literal| {
+                        Expr {
+                            temp_lifetime,
+                            ty: var_ty,
+                            span: expr.span,
+                            kind: ExprKind::Literal { literal, user_ty: None },
+                        }
+                        .to_ref()
+                    };
+                    let offset = mk_const(ty::Const::from_bits(
+                        cx.tcx,
+                        offset as u128,
+                        cx.param_env.and(var_ty),
+                    ));
+                    match did {
+                        Some(did) => {
+                            // in case we are offsetting from a computed discriminant
+                            // and not the beginning of discriminants (which is always `0`)
+                            let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
+                            let lhs = mk_const(cx.tcx().mk_const(ty::Const {
+                                val: ty::ConstKind::Unevaluated(did, substs, None),
+                                ty: var_ty,
+                            }));
+                            let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
+                            Expr { temp_lifetime, ty: var_ty, span: expr.span, kind: bin }.to_ref()
+                        }
+                        None => offset,
+                    }
+                } else {
+                    source.to_ref()
+                };
+
+                ExprKind::Cast { source }
+            };
+
+            if let Some(user_ty) = user_ty {
+                // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
+                //       inefficient, revisit this when performance becomes an issue.
+                let cast_expr = Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: cast };
+                debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
+
+                ExprKind::ValueTypeAscription {
+                    source: cast_expr.to_ref(),
+                    user_ty: Some(*user_ty),
+                }
+            } else {
+                cast
+            }
+        }
+        hir::ExprKind::Type(ref source, ref ty) => {
+            let user_provided_types = cx.tables.user_provided_types();
+            let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty);
+            debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
+            if source.is_syntactic_place_expr() {
+                ExprKind::PlaceTypeAscription { source: source.to_ref(), user_ty }
+            } else {
+                ExprKind::ValueTypeAscription { source: source.to_ref(), user_ty }
+            }
+        }
+        hir::ExprKind::DropTemps(ref source) => ExprKind::Use { source: source.to_ref() },
+        hir::ExprKind::Box(ref value) => ExprKind::Box { value: value.to_ref() },
+        hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() },
+        hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
+
+        hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: v.to_ref() },
+        hir::ExprKind::Err => unreachable!(),
+    };
+
+    Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
+}
+
+fn user_substs_applied_to_res<'tcx>(
+    cx: &mut Cx<'_, 'tcx>,
+    hir_id: hir::HirId,
+    res: Res,
+) -> Option<ty::CanonicalUserType<'tcx>> {
+    debug!("user_substs_applied_to_res: res={:?}", res);
+    let user_provided_type = match res {
+        // A reference to something callable -- e.g., a fn, method, or
+        // a tuple-struct or tuple-variant. This has the type of a
+        // `Fn` but with the user-given substitutions.
+        Res::Def(DefKind::Fn, _)
+        | Res::Def(DefKind::Method, _)
+        | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
+        | Res::Def(DefKind::Const, _)
+        | Res::Def(DefKind::AssocConst, _) => {
+            cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty)
+        }
+
+        // A unit struct/variant which is used as a value (e.g.,
+        // `None`). This has the type of the enum/struct that defines
+        // this variant -- but with the substitutions given by the
+        // user.
+        Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
+            cx.user_substs_applied_to_ty_of_hir_id(hir_id)
+        }
+
+        // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
+        Res::SelfCtor(_) => cx.user_substs_applied_to_ty_of_hir_id(hir_id),
+
+        _ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
+    };
+    debug!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type);
+    user_provided_type
+}
+
+fn method_callee<'a, 'tcx>(
+    cx: &mut Cx<'a, 'tcx>,
+    expr: &hir::Expr<'_>,
+    span: Span,
+    overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
+) -> Expr<'tcx> {
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+    let (def_id, substs, user_ty) = match overloaded_callee {
+        Some((def_id, substs)) => (def_id, substs, None),
+        None => {
+            let (kind, def_id) = cx
+                .tables()
+                .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)
+        }
+    };
+    let ty = cx.tcx().mk_fn_def(def_id, substs);
+    Expr {
+        temp_lifetime,
+        ty,
+        span,
+        kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx(), ty), user_ty },
+    }
+}
+
+trait ToBorrowKind {
+    fn to_borrow_kind(&self) -> BorrowKind;
+}
+
+impl ToBorrowKind for AutoBorrowMutability {
+    fn to_borrow_kind(&self) -> BorrowKind {
+        use rustc::ty::adjustment::AllowTwoPhase;
+        match *self {
+            AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut {
+                allow_two_phase_borrow: match allow_two_phase_borrow {
+                    AllowTwoPhase::Yes => true,
+                    AllowTwoPhase::No => false,
+                },
+            },
+            AutoBorrowMutability::Not => BorrowKind::Shared,
+        }
+    }
+}
+
+impl ToBorrowKind for hir::Mutability {
+    fn to_borrow_kind(&self) -> BorrowKind {
+        match *self {
+            hir::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
+            hir::Mutability::Not => BorrowKind::Shared,
+        }
+    }
+}
+
+fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> {
+    Arm {
+        pattern: cx.pattern_from_hir(&arm.pat),
+        guard: match arm.guard {
+            Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())),
+            _ => None,
+        },
+        body: arm.body.to_ref(),
+        lint_level: LintLevel::Explicit(arm.hir_id),
+        scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
+        span: arm.span,
+    }
+}
+
+fn convert_path_expr<'a, 'tcx>(
+    cx: &mut Cx<'a, 'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    res: Res,
+) -> ExprKind<'tcx> {
+    let substs = cx.tables().node_substs(expr.hir_id);
+    match res {
+        // A regular function, constructor function or a constant.
+        Res::Def(DefKind::Fn, _)
+        | Res::Def(DefKind::Method, _)
+        | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
+        | Res::SelfCtor(..) => {
+            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)),
+                user_ty,
+            }
+        }
+
+        Res::Def(DefKind::ConstParam, def_id) => {
+            let hir_id = cx.tcx.hir().as_local_hir_id(def_id).unwrap();
+            let item_id = cx.tcx.hir().get_parent_node(hir_id);
+            let item_def_id = cx.tcx.hir().local_def_id(item_id);
+            let generics = cx.tcx.generics_of(item_def_id);
+            let local_def_id = cx.tcx.hir().local_def_id(hir_id);
+            let index = generics.param_def_id_to_index[&local_def_id];
+            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) }),
+                user_ty: None,
+            }
+        }
+
+        Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
+            let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
+            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),
+                }),
+                user_ty,
+            }
+        }
+
+        Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => {
+            let user_provided_types = cx.tables.user_provided_types();
+            let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
+            debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
+            let ty = cx.tables().node_type(expr.hir_id);
+            match ty.kind {
+                // A unit struct/variant which is used as a value.
+                // We return a completely different ExprKind here to account for this special case.
+                ty::Adt(adt_def, substs) => ExprKind::Adt {
+                    adt_def,
+                    variant_index: adt_def.variant_index_with_ctor_id(def_id),
+                    substs,
+                    user_ty: user_provided_type,
+                    fields: vec![],
+                    base: None,
+                },
+                _ => bug!("unexpected ty: {:?}", ty),
+            }
+        }
+
+        // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
+        // a constant reference (or constant raw pointer for `static mut`) in MIR
+        Res::Def(DefKind::Static, id) => {
+            let ty = cx.tcx.static_ptr_ty(id);
+            let ptr = cx.tcx.alloc_map.lock().create_static_alloc(id);
+            let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+            ExprKind::Deref {
+                arg: Expr {
+                    ty,
+                    temp_lifetime,
+                    span: expr.span,
+                    kind: ExprKind::StaticRef {
+                        literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty),
+                        def_id: id,
+                    },
+                }
+                .to_ref(),
+            }
+        }
+
+        Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id),
+
+        _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
+    }
+}
+
+fn convert_var<'tcx>(
+    cx: &mut Cx<'_, 'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    var_hir_id: hir::HirId,
+) -> ExprKind<'tcx> {
+    let upvar_index = cx
+        .tables()
+        .upvar_list
+        .get(&cx.body_owner)
+        .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
+
+    debug!(
+        "convert_var({:?}): upvar_index={:?}, body_owner={:?}",
+        var_hir_id, upvar_index, cx.body_owner
+    );
+
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+
+    match upvar_index {
+        None => ExprKind::VarRef { id: var_hir_id },
+
+        Some(upvar_index) => {
+            let closure_def_id = cx.body_owner;
+            let upvar_id = ty::UpvarId {
+                var_path: ty::UpvarPath { hir_id: var_hir_id },
+                closure_expr_id: LocalDefId::from_def_id(closure_def_id),
+            };
+            let var_ty = cx.tables().node_type(var_hir_id);
+
+            // FIXME free regions in closures are not right
+            let closure_ty = cx
+                .tables()
+                .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
+            // signature will be &self or &mut self and hence will
+            // have a bound region with number 0
+            let region = ty::ReFree(ty::FreeRegion {
+                scope: closure_def_id,
+                bound_region: ty::BoundRegion::BrAnon(0),
+            });
+            let region = cx.tcx.mk_region(region);
+
+            let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind {
+                match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() {
+                    ty::ClosureKind::Fn => {
+                        let ref_closure_ty = cx.tcx.mk_ref(
+                            region,
+                            ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Not },
+                        );
+                        Expr {
+                            ty: closure_ty,
+                            temp_lifetime,
+                            span: expr.span,
+                            kind: ExprKind::Deref {
+                                arg: Expr {
+                                    ty: ref_closure_ty,
+                                    temp_lifetime,
+                                    span: expr.span,
+                                    kind: ExprKind::SelfRef,
+                                }
+                                .to_ref(),
+                            },
+                        }
+                    }
+                    ty::ClosureKind::FnMut => {
+                        let ref_closure_ty = cx.tcx.mk_ref(
+                            region,
+                            ty::TypeAndMut { ty: closure_ty, mutbl: hir::Mutability::Mut },
+                        );
+                        Expr {
+                            ty: closure_ty,
+                            temp_lifetime,
+                            span: expr.span,
+                            kind: ExprKind::Deref {
+                                arg: Expr {
+                                    ty: ref_closure_ty,
+                                    temp_lifetime,
+                                    span: expr.span,
+                                    kind: ExprKind::SelfRef,
+                                }
+                                .to_ref(),
+                            },
+                        }
+                    }
+                    ty::ClosureKind::FnOnce => Expr {
+                        ty: closure_ty,
+                        temp_lifetime,
+                        span: expr.span,
+                        kind: ExprKind::SelfRef,
+                    },
+                }
+            } else {
+                Expr { ty: closure_ty, temp_lifetime, span: expr.span, kind: ExprKind::SelfRef }
+            };
+
+            // at this point we have `self.n`, which loads up the upvar
+            let field_kind =
+                ExprKind::Field { lhs: self_expr.to_ref(), name: Field::new(upvar_index) };
+
+            // ...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) {
+                ty::UpvarCapture::ByValue => field_kind,
+                ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref {
+                    arg: Expr {
+                        temp_lifetime,
+                        ty: cx.tcx.mk_ref(
+                            borrow.region,
+                            ty::TypeAndMut { ty: var_ty, mutbl: borrow.kind.to_mutbl_lossy() },
+                        ),
+                        span: expr.span,
+                        kind: field_kind,
+                    }
+                    .to_ref(),
+                },
+            }
+        }
+    }
+}
+
+fn bin_op(op: hir::BinOpKind) -> BinOp {
+    match op {
+        hir::BinOpKind::Add => BinOp::Add,
+        hir::BinOpKind::Sub => BinOp::Sub,
+        hir::BinOpKind::Mul => BinOp::Mul,
+        hir::BinOpKind::Div => BinOp::Div,
+        hir::BinOpKind::Rem => BinOp::Rem,
+        hir::BinOpKind::BitXor => BinOp::BitXor,
+        hir::BinOpKind::BitAnd => BinOp::BitAnd,
+        hir::BinOpKind::BitOr => BinOp::BitOr,
+        hir::BinOpKind::Shl => BinOp::Shl,
+        hir::BinOpKind::Shr => BinOp::Shr,
+        hir::BinOpKind::Eq => BinOp::Eq,
+        hir::BinOpKind::Lt => BinOp::Lt,
+        hir::BinOpKind::Le => BinOp::Le,
+        hir::BinOpKind::Ne => BinOp::Ne,
+        hir::BinOpKind::Ge => BinOp::Ge,
+        hir::BinOpKind::Gt => BinOp::Gt,
+        _ => bug!("no equivalent for ast binop {:?}", op),
+    }
+}
+
+fn overloaded_operator<'a, 'tcx>(
+    cx: &mut Cx<'a, 'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    args: Vec<ExprRef<'tcx>>,
+) -> ExprKind<'tcx> {
+    let fun = method_callee(cx, expr, expr.span, None);
+    ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false }
+}
+
+fn overloaded_place<'a, 'tcx>(
+    cx: &mut Cx<'a, 'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    place_ty: Ty<'tcx>,
+    overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
+    args: Vec<ExprRef<'tcx>>,
+) -> ExprKind<'tcx> {
+    // For an overloaded *x or x[y] expression of type T, the method
+    // call returns an &T and we must add the deref so that the types
+    // 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::Mirror(ref e) => e.ty,
+    };
+
+    // Reconstruct the output assuming it's a reference with the
+    // same region and mutability as the receiver. This holds for
+    // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
+    let (region, mutbl) = match recv_ty.kind {
+        ty::Ref(region, _, mutbl) => (region, mutbl),
+        _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"),
+    };
+    let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
+
+    // construct the complete expression `foo()` for the overloaded call,
+    // which will yield the &T type
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+    let fun = method_callee(cx, expr, expr.span, overloaded_callee);
+    let ref_expr = Expr {
+        temp_lifetime,
+        ty: ref_ty,
+        span: expr.span,
+        kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false },
+    };
+
+    // construct and return a deref wrapper `*foo()`
+    ExprKind::Deref { arg: ref_expr.to_ref() }
+}
+
+fn capture_upvar<'tcx>(
+    cx: &mut Cx<'_, 'tcx>,
+    closure_expr: &'tcx hir::Expr<'tcx>,
+    var_hir_id: hir::HirId,
+    upvar_ty: Ty<'tcx>,
+) -> ExprRef<'tcx> {
+    let upvar_id = ty::UpvarId {
+        var_path: ty::UpvarPath { hir_id: var_hir_id },
+        closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id).to_local(),
+    };
+    let upvar_capture = cx.tables().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 captured_var = Expr {
+        temp_lifetime,
+        ty: var_ty,
+        span: closure_expr.span,
+        kind: convert_var(cx, closure_expr, var_hir_id),
+    };
+    match upvar_capture {
+        ty::UpvarCapture::ByValue => captured_var.to_ref(),
+        ty::UpvarCapture::ByRef(upvar_borrow) => {
+            let borrow_kind = match upvar_borrow.kind {
+                ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
+                ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
+                ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
+            };
+            Expr {
+                temp_lifetime,
+                ty: upvar_ty,
+                span: closure_expr.span,
+                kind: ExprKind::Borrow { borrow_kind, arg: captured_var.to_ref() },
+            }
+            .to_ref()
+        }
+    }
+}
+
+/// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExprRef.
+fn field_refs<'a, 'tcx>(
+    cx: &mut Cx<'a, 'tcx>,
+    fields: &'tcx [hir::Field<'tcx>],
+) -> Vec<FieldExprRef<'tcx>> {
+    fields
+        .iter()
+        .map(|field| FieldExprRef {
+            name: Field::new(cx.tcx.field_index(field.hir_id, cx.tables)),
+            expr: field.expr.to_ref(),
+        })
+        .collect()
+}
diff --git a/src/librustc_mir_build/hair/cx/mod.rs b/src/librustc_mir_build/hair/cx/mod.rs
new file mode 100644 (file)
index 0000000..5fc9a1e
--- /dev/null
@@ -0,0 +1,220 @@
+//! This module contains the fcuntaiontliy 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.
+
+use crate::hair::util::UserAnnotatedTyHelpers;
+use crate::hair::*;
+
+use crate::hair::constant::{lit_to_const, LitToConstError};
+use rustc::infer::InferCtxt;
+use rustc::middle::region;
+use rustc::ty::layout::VariantIdx;
+use rustc::ty::subst::Subst;
+use rustc::ty::subst::{GenericArg, InternalSubsts};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::Node;
+use rustc_index::vec::Idx;
+use rustc_span::symbol::{sym, Symbol};
+use syntax::ast;
+use syntax::attr;
+
+#[derive(Clone)]
+crate struct Cx<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    infcx: &'a InferCtxt<'a, 'tcx>,
+
+    crate root_lint_level: hir::HirId,
+    crate param_env: ty::ParamEnv<'tcx>,
+
+    /// Identity `InternalSubsts` for use with const-evaluation.
+    crate identity_substs: &'tcx InternalSubsts<'tcx>,
+
+    crate region_scope_tree: &'tcx region::ScopeTree,
+    crate tables: &'a ty::TypeckTables<'tcx>,
+
+    /// This is `Constness::Const` if we are compiling a `static`,
+    /// `const`, or the body of a `const fn`.
+    constness: hir::Constness,
+
+    /// The `DefId` of the owner of this body.
+    body_owner: DefId,
+
+    /// What kind of body is being compiled.
+    crate body_owner_kind: hir::BodyOwnerKind,
+
+    /// Whether this constant/function needs overflow checks.
+    check_overflow: bool,
+
+    /// See field with the same name on `mir::Body`.
+    control_flow_destroyed: Vec<(Span, String)>,
+}
+
+impl<'a, 'tcx> Cx<'a, 'tcx> {
+    crate fn new(infcx: &'a InferCtxt<'a, 'tcx>, 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 body_owner_kind = tcx.hir().body_owner_kind(src_id);
+
+        let constness = match body_owner_kind {
+            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
+            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
+        };
+
+        let attrs = tcx.hir().attrs(src_id);
+
+        // Some functions always have overflow checks enabled,
+        // however, they may not get codegen'd, depending on
+        // the settings for the crate they are codegened in.
+        let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
+
+        // Respect -C overflow-checks.
+        check_overflow |= tcx.sess.overflow_checks();
+
+        // Constants always need overflow checks.
+        check_overflow |= constness == hir::Constness::Const;
+
+        Cx {
+            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),
+            region_scope_tree: tcx.region_scope_tree(src_def_id),
+            tables,
+            constness,
+            body_owner: src_def_id,
+            body_owner_kind,
+            check_overflow,
+            control_flow_destroyed: Vec::new(),
+        }
+    }
+
+    crate fn control_flow_destroyed(self) -> Vec<(Span, String)> {
+        self.control_flow_destroyed
+    }
+}
+
+impl<'a, 'tcx> Cx<'a, 'tcx> {
+    /// Normalizes `ast` into the appropriate "mirror" type.
+    crate fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
+        ast.make_mirror(self)
+    }
+
+    crate fn usize_ty(&mut self) -> Ty<'tcx> {
+        self.tcx.types.usize
+    }
+
+    crate fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
+        ty::Const::from_usize(self.tcx, value)
+    }
+
+    crate fn bool_ty(&mut self) -> Ty<'tcx> {
+        self.tcx.types.bool
+    }
+
+    crate fn unit_ty(&mut self) -> Ty<'tcx> {
+        self.tcx.mk_unit()
+    }
+
+    crate fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
+        ty::Const::from_bool(self.tcx, true)
+    }
+
+    crate fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
+        ty::Const::from_bool(self.tcx, false)
+    }
+
+    crate fn const_eval_literal(
+        &mut self,
+        lit: &'tcx ast::LitKind,
+        ty: Ty<'tcx>,
+        sp: Span,
+        neg: bool,
+    ) -> &'tcx ty::Const<'tcx> {
+        trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
+
+        match lit_to_const(lit, self.tcx, ty, neg) {
+            Ok(c) => c,
+            Err(LitToConstError::UnparseableFloat) => {
+                // FIXME(#31407) this is only necessary because float parsing is buggy
+                self.tcx.sess.span_err(sp, "could not evaluate float literal (see issue #31407)");
+                // create a dummy value and continue compiling
+                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
+            }
+            Err(LitToConstError::Reported) => {
+                // create a dummy value and continue compiling
+                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
+            }
+        }
+    }
+
+    crate fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
+        let p = match self.tcx.hir().get(p.hir_id) {
+            Node::Pat(p) | Node::Binding(p) => p,
+            node => bug!("pattern became {:?}", node),
+        };
+        Pat::from_hir(self.tcx, self.param_env, self.tables(), p)
+    }
+
+    crate fn trait_method(
+        &mut self,
+        trait_def_id: DefId,
+        method_name: Symbol,
+        self_ty: Ty<'tcx>,
+        params: &[GenericArg<'tcx>],
+    ) -> &'tcx ty::Const<'tcx> {
+        let substs = self.tcx.mk_substs_trait(self_ty, params);
+        for item in self.tcx.associated_items(trait_def_id) {
+            // The unhygienic comparison here is acceptable because this is only
+            // used on known traits.
+            if item.kind == ty::AssocKind::Method && item.ident.name == method_name {
+                let method_ty = self.tcx.type_of(item.def_id);
+                let method_ty = method_ty.subst(self.tcx, substs);
+                return ty::Const::zero_sized(self.tcx, method_ty);
+            }
+        }
+
+        bug!("found no method `{}` in `{:?}`", method_name, trait_def_id);
+    }
+
+    crate fn all_fields(&mut self, adt_def: &ty::AdtDef, variant_index: VariantIdx) -> Vec<Field> {
+        (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect()
+    }
+
+    crate fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
+        ty.needs_drop(self.tcx, self.param_env)
+    }
+
+    crate fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    crate fn tables(&self) -> &'a ty::TypeckTables<'tcx> {
+        self.tables
+    }
+
+    crate fn check_overflow(&self) -> bool {
+        self.check_overflow
+    }
+
+    crate fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
+        self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
+    }
+}
+
+impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx()
+    }
+
+    fn tables(&self) -> &ty::TypeckTables<'tcx> {
+        self.tables()
+    }
+}
+
+mod block;
+mod expr;
+mod to_ref;
diff --git a/src/librustc_mir_build/hair/cx/to_ref.rs b/src/librustc_mir_build/hair/cx/to_ref.rs
new file mode 100644 (file)
index 0000000..6cf8122
--- /dev/null
@@ -0,0 +1,65 @@
+use crate::hair::*;
+
+use rustc_hir as hir;
+
+crate trait ToRef {
+    type Output;
+    fn to_ref(self) -> Self::Output;
+}
+
+impl<'tcx> ToRef for &'tcx hir::Expr<'tcx> {
+    type Output = ExprRef<'tcx>;
+
+    fn to_ref(self) -> ExprRef<'tcx> {
+        ExprRef::Hair(self)
+    }
+}
+
+impl<'tcx> ToRef for &'tcx &'tcx hir::Expr<'tcx> {
+    type Output = ExprRef<'tcx>;
+
+    fn to_ref(self) -> ExprRef<'tcx> {
+        ExprRef::Hair(&**self)
+    }
+}
+
+impl<'tcx> ToRef for Expr<'tcx> {
+    type Output = ExprRef<'tcx>;
+
+    fn to_ref(self) -> ExprRef<'tcx> {
+        ExprRef::Mirror(Box::new(self))
+    }
+}
+
+impl<'tcx, T, U> ToRef for &'tcx Option<T>
+where
+    &'tcx T: ToRef<Output = U>,
+{
+    type Output = Option<U>;
+
+    fn to_ref(self) -> Option<U> {
+        self.as_ref().map(|expr| expr.to_ref())
+    }
+}
+
+impl<'tcx, T, U> ToRef for &'tcx Vec<T>
+where
+    &'tcx T: ToRef<Output = U>,
+{
+    type Output = Vec<U>;
+
+    fn to_ref(self) -> Vec<U> {
+        self.iter().map(|expr| expr.to_ref()).collect()
+    }
+}
+
+impl<'tcx, T, U> ToRef for &'tcx [T]
+where
+    &'tcx T: ToRef<Output = U>,
+{
+    type Output = Vec<U>;
+
+    fn to_ref(self) -> Vec<U> {
+        self.iter().map(|expr| expr.to_ref()).collect()
+    }
+}
diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs
new file mode 100644 (file)
index 0000000..3257f28
--- /dev/null
@@ -0,0 +1,413 @@
+//! The MIR is built from some high-level abstract IR
+//! (HAIR). This section defines the HAIR along with a trait for
+//! accessing it. The intention is to allow MIR construction to be
+//! unit-tested and separated from the Rust source and compiler data
+//! structures.
+
+use self::cx::Cx;
+use rustc::infer::canonical::Canonical;
+use rustc::middle::region;
+use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
+use rustc::ty::adjustment::PointerCast;
+use rustc::ty::layout::VariantIdx;
+use rustc::ty::subst::SubstsRef;
+use rustc::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::Span;
+
+mod constant;
+crate mod cx;
+
+crate mod pattern;
+crate use self::pattern::PatTyProj;
+crate use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange};
+
+mod util;
+
+#[derive(Copy, Clone, Debug)]
+crate enum LintLevel {
+    Inherited,
+    Explicit(hir::HirId),
+}
+
+#[derive(Clone, Debug)]
+crate struct Block<'tcx> {
+    crate targeted_by_break: bool,
+    crate region_scope: region::Scope,
+    crate opt_destruction_scope: Option<region::Scope>,
+    crate span: Span,
+    crate stmts: Vec<StmtRef<'tcx>>,
+    crate expr: Option<ExprRef<'tcx>>,
+    crate safety_mode: BlockSafety,
+}
+
+#[derive(Copy, Clone, Debug)]
+crate enum BlockSafety {
+    Safe,
+    ExplicitUnsafe(hir::HirId),
+    PushUnsafe,
+    PopUnsafe,
+}
+
+#[derive(Clone, Debug)]
+crate enum StmtRef<'tcx> {
+    Mirror(Box<Stmt<'tcx>>),
+}
+
+#[derive(Clone, Debug)]
+crate struct Stmt<'tcx> {
+    crate kind: StmtKind<'tcx>,
+    crate opt_destruction_scope: Option<region::Scope>,
+}
+
+#[derive(Clone, Debug)]
+crate enum StmtKind<'tcx> {
+    Expr {
+        /// scope for this statement; may be used as lifetime of temporaries
+        scope: region::Scope,
+
+        /// expression being evaluated in this statement
+        expr: ExprRef<'tcx>,
+    },
+
+    Let {
+        /// scope for variables bound in this let; covers this and
+        /// remaining statements in block
+        remainder_scope: region::Scope,
+
+        /// scope for the initialization itself; might be used as
+        /// lifetime of temporaries
+        init_scope: region::Scope,
+
+        /// `let <PAT> = ...`
+        ///
+        /// if a type is included, it is added as an ascription pattern
+        pattern: Pat<'tcx>,
+
+        /// let pat: ty = <INIT> ...
+        initializer: Option<ExprRef<'tcx>>,
+
+        /// the lint level for this let-statement
+        lint_level: LintLevel,
+    },
+}
+
+// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Expr<'_>, 168);
+
+/// The Hair trait implementor lowers their expressions (`&'tcx H::Expr`)
+/// into instances of this `Expr` enum. This lowering can be done
+/// basically as lazily or as eagerly as desired: every recursive
+/// reference to an expression in this enum is an `ExprRef<'tcx>`, which
+/// may in turn be another instance of this enum (boxed), or else an
+/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
+/// short-lived. They are created by `Hair::to_expr`, analyzed and
+/// converted into MIR, and then discarded.
+///
+/// If you compare `Expr` to the full compiler AST, you will see it is
+/// a good bit simpler. In fact, a number of the more straight-forward
+/// MIR simplifications are already done in the impl of `Hair`. For
+/// example, method calls and overloaded operators are absent: they are
+/// expected to be converted into `Expr::Call` instances.
+#[derive(Clone, Debug)]
+crate struct Expr<'tcx> {
+    /// type of this expression
+    crate ty: Ty<'tcx>,
+
+    /// lifetime of this expression if it should be spilled into a
+    /// temporary; should be None only if in a constant context
+    crate temp_lifetime: Option<region::Scope>,
+
+    /// span of the expression in the source
+    crate span: Span,
+
+    /// kind of expression
+    crate kind: ExprKind<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+crate enum ExprKind<'tcx> {
+    Scope {
+        region_scope: region::Scope,
+        lint_level: LintLevel,
+        value: ExprRef<'tcx>,
+    },
+    Box {
+        value: ExprRef<'tcx>,
+    },
+    Call {
+        ty: Ty<'tcx>,
+        fun: ExprRef<'tcx>,
+        args: Vec<ExprRef<'tcx>>,
+        // Whether this is from a call in HIR, rather than from an overloaded
+        // operator. True for overloaded function call.
+        from_hir_call: bool,
+    },
+    Deref {
+        arg: ExprRef<'tcx>,
+    }, // NOT overloaded!
+    Binary {
+        op: BinOp,
+        lhs: ExprRef<'tcx>,
+        rhs: ExprRef<'tcx>,
+    }, // NOT overloaded!
+    LogicalOp {
+        op: LogicalOp,
+        lhs: ExprRef<'tcx>,
+        rhs: ExprRef<'tcx>,
+    }, // NOT overloaded!
+    // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
+    Unary {
+        op: UnOp,
+        arg: ExprRef<'tcx>,
+    }, // NOT overloaded!
+    Cast {
+        source: ExprRef<'tcx>,
+    },
+    Use {
+        source: ExprRef<'tcx>,
+    }, // Use a lexpr to get a vexpr.
+    NeverToAny {
+        source: ExprRef<'tcx>,
+    },
+    Pointer {
+        cast: PointerCast,
+        source: ExprRef<'tcx>,
+    },
+    Loop {
+        body: ExprRef<'tcx>,
+    },
+    Match {
+        scrutinee: ExprRef<'tcx>,
+        arms: Vec<Arm<'tcx>>,
+    },
+    Block {
+        body: &'tcx hir::Block<'tcx>,
+    },
+    Assign {
+        lhs: ExprRef<'tcx>,
+        rhs: ExprRef<'tcx>,
+    },
+    AssignOp {
+        op: BinOp,
+        lhs: ExprRef<'tcx>,
+        rhs: ExprRef<'tcx>,
+    },
+    Field {
+        lhs: ExprRef<'tcx>,
+        name: Field,
+    },
+    Index {
+        lhs: ExprRef<'tcx>,
+        index: ExprRef<'tcx>,
+    },
+    VarRef {
+        id: hir::HirId,
+    },
+    /// first argument, used for self in a closure
+    SelfRef,
+    Borrow {
+        borrow_kind: BorrowKind,
+        arg: ExprRef<'tcx>,
+    },
+    /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
+    AddressOf {
+        mutability: hir::Mutability,
+        arg: ExprRef<'tcx>,
+    },
+    Break {
+        label: region::Scope,
+        value: Option<ExprRef<'tcx>>,
+    },
+    Continue {
+        label: region::Scope,
+    },
+    Return {
+        value: Option<ExprRef<'tcx>>,
+    },
+    Repeat {
+        value: ExprRef<'tcx>,
+        count: u64,
+    },
+    Array {
+        fields: Vec<ExprRef<'tcx>>,
+    },
+    Tuple {
+        fields: Vec<ExprRef<'tcx>>,
+    },
+    Adt {
+        adt_def: &'tcx AdtDef,
+        variant_index: VariantIdx,
+        substs: SubstsRef<'tcx>,
+
+        /// Optional user-given substs: for something like `let x =
+        /// Bar::<T> { ... }`.
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+
+        fields: Vec<FieldExprRef<'tcx>>,
+        base: Option<FruInfo<'tcx>>,
+    },
+    PlaceTypeAscription {
+        source: ExprRef<'tcx>,
+        /// Type that the user gave to this expression
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+    },
+    ValueTypeAscription {
+        source: ExprRef<'tcx>,
+        /// Type that the user gave to this expression
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+    },
+    Closure {
+        closure_id: DefId,
+        substs: UpvarSubsts<'tcx>,
+        upvars: Vec<ExprRef<'tcx>>,
+        movability: Option<hir::Movability>,
+    },
+    Literal {
+        literal: &'tcx Const<'tcx>,
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+    },
+    /// A literal containing the address of a `static`.
+    ///
+    /// This is only distinguished from `Literal` so that we can register some
+    /// info for diagnostics.
+    StaticRef {
+        literal: &'tcx Const<'tcx>,
+        def_id: DefId,
+    },
+    InlineAsm {
+        asm: &'tcx hir::InlineAsmInner,
+        outputs: Vec<ExprRef<'tcx>>,
+        inputs: Vec<ExprRef<'tcx>>,
+    },
+    Yield {
+        value: ExprRef<'tcx>,
+    },
+}
+
+#[derive(Clone, Debug)]
+crate enum ExprRef<'tcx> {
+    Hair(&'tcx hir::Expr<'tcx>),
+    Mirror(Box<Expr<'tcx>>),
+}
+
+#[derive(Clone, Debug)]
+crate struct FieldExprRef<'tcx> {
+    crate name: Field,
+    crate expr: ExprRef<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+crate struct FruInfo<'tcx> {
+    crate base: ExprRef<'tcx>,
+    crate field_types: Vec<Ty<'tcx>>,
+}
+
+#[derive(Clone, Debug)]
+crate struct Arm<'tcx> {
+    crate pattern: Pat<'tcx>,
+    crate guard: Option<Guard<'tcx>>,
+    crate body: ExprRef<'tcx>,
+    crate lint_level: LintLevel,
+    crate scope: region::Scope,
+    crate span: Span,
+}
+
+impl<'tcx> Arm<'tcx> {
+    // HACK(or_patterns; Centril | dlrobertson): Remove this and
+    // correctly handle each case in which this method is used.
+    crate fn top_pats_hack(&self) -> &[Pat<'tcx>] {
+        match &*self.pattern.kind {
+            PatKind::Or { pats } => pats,
+            _ => std::slice::from_ref(&self.pattern),
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+crate enum Guard<'tcx> {
+    If(ExprRef<'tcx>),
+}
+
+#[derive(Copy, Clone, Debug)]
+crate enum LogicalOp {
+    And,
+    Or,
+}
+
+impl<'tcx> ExprRef<'tcx> {
+    crate fn span(&self) -> Span {
+        match self {
+            ExprRef::Hair(expr) => expr.span,
+            ExprRef::Mirror(expr) => expr.span,
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// The Mirror trait
+
+/// "Mirroring" is the process of converting from a HIR type into one
+/// of the HAIR types defined in this file. This is basically a "on
+/// the fly" desugaring step that hides a lot of the messiness in the
+/// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
+/// `Expr<'tcx>`.
+///
+/// Mirroring is gradual: when you mirror an outer expression like `e1
+/// + e2`, the references to the inner expressions `e1` and `e2` are
+/// `ExprRef<'tcx>` instances, and they may or may not be eagerly
+/// mirrored. This allows a single AST node from the compiler to
+/// expand into one or more Hair nodes, which lets the Hair nodes be
+/// simpler.
+crate trait Mirror<'tcx> {
+    type Output;
+
+    fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output;
+}
+
+impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
+    type Output = Expr<'tcx>;
+
+    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
+        self
+    }
+}
+
+impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
+    type Output = Expr<'tcx>;
+
+    fn make_mirror(self, hir: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
+        match self {
+            ExprRef::Hair(h) => h.make_mirror(hir),
+            ExprRef::Mirror(m) => *m,
+        }
+    }
+}
+
+impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
+    type Output = Stmt<'tcx>;
+
+    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
+        self
+    }
+}
+
+impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
+    type Output = Stmt<'tcx>;
+
+    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
+        match self {
+            StmtRef::Mirror(m) => *m,
+        }
+    }
+}
+
+impl<'tcx> Mirror<'tcx> for Block<'tcx> {
+    type Output = Block<'tcx>;
+
+    fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
+        self
+    }
+}
diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
new file mode 100644 (file)
index 0000000..8fcaa1e
--- /dev/null
@@ -0,0 +1,2495 @@
+/// Note: most tests relevant to this file can be found (at the time of writing)
+/// in src/tests/ui/pattern/usefulness.
+///
+/// This file includes the logic for exhaustiveness and usefulness checking for
+/// pattern-matching. Specifically, given a list of patterns for a type, we can
+/// tell whether:
+/// (a) the patterns cover every possible constructor for the type [exhaustiveness]
+/// (b) each pattern is necessary [usefulness]
+///
+/// The algorithm implemented here is a modified version of the one described in:
+/// http://moscova.inria.fr/~maranget/papers/warn/index.html
+/// However, to save future implementors from reading the original paper, we
+/// summarise the algorithm here to hopefully save time and be a little clearer
+/// (without being so rigorous).
+///
+/// The core of the algorithm revolves about a "usefulness" check. In particular, we
+/// are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
+/// a matrix). `U(P, p)` represents whether, given an existing list of patterns
+/// `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously-
+/// uncovered values of the type).
+///
+/// If we have this predicate, then we can easily compute both exhaustiveness of an
+/// entire set of patterns and the individual usefulness of each one.
+/// (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard
+/// match doesn't increase the number of values we're matching)
+/// (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a
+/// pattern to those that have come before it doesn't increase the number of values
+/// we're matching).
+///
+/// During the course of the algorithm, the rows of the matrix won't just be individual patterns,
+/// but rather partially-deconstructed patterns in the form of a list of patterns. The paper
+/// calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
+/// new pattern `p`.
+///
+/// For example, say we have the following:
+/// ```
+///     // x: (Option<bool>, Result<()>)
+///     match x {
+///         (Some(true), _) => {}
+///         (None, Err(())) => {}
+///         (None, Err(_)) => {}
+///     }
+/// ```
+/// Here, the matrix `P` starts as:
+/// [
+///     [(Some(true), _)],
+///     [(None, Err(()))],
+///     [(None, Err(_))],
+/// ]
+/// We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
+/// `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
+/// all the values it covers are already covered by row 2.
+///
+/// A list of patterns can be thought of as a stack, because we are mainly interested in the top of
+/// the stack at any given point, and we can pop or apply constructors to get new pattern-stacks.
+/// To match the paper, the top of the stack is at the beginning / on the left.
+///
+/// There are two important operations on pattern-stacks necessary to understand the algorithm:
+///     1. We can pop a given constructor off the top of a stack. This operation is called
+///        `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
+///        `None`) and `p` a pattern-stack.
+///        If the pattern on top of the stack can cover `c`, this removes the constructor and
+///        pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
+///        Otherwise the pattern-stack is discarded.
+///        This essentially filters those pattern-stacks whose top covers the constructor `c` and
+///        discards the others.
+///
+///        For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
+///        pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
+///        `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
+///        nothing back.
+///
+///        This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
+///        on top of the stack, and we have four cases:
+///             1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
+///                  push onto the stack the arguments of this constructor, and return the result:
+///                     r_1, .., r_a, p_2, .., p_n
+///             1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
+///                  return nothing.
+///             1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
+///                  arguments (its arity), and return the resulting stack:
+///                     _, .., _, p_2, .., p_n
+///             1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
+///                  stack:
+///                     S(c, (r_1, p_2, .., p_n))
+///                     S(c, (r_2, p_2, .., p_n))
+///
+///     2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
+///        a pattern-stack.
+///        This is used when we know there are missing constructor cases, but there might be
+///        existing wildcard patterns, so to check the usefulness of the matrix, we have to check
+///        all its *other* components.
+///
+///        It is computed as follows. We look at the pattern `p_1` on top of the stack,
+///        and we have three cases:
+///             1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
+///             1.2. `p_1 = _`. We return the rest of the stack:
+///                     p_2, .., p_n
+///             1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
+///               stack.
+///                     D((r_1, p_2, .., p_n))
+///                     D((r_2, p_2, .., p_n))
+///
+///     Note that the OR-patterns are not always used directly in Rust, but are used to derive the
+///     exhaustive integer matching rules, so they're written here for posterity.
+///
+/// Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
+/// working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
+/// the given constructor, and popping a wildcard keeps those rows that start with a wildcard.
+///
+///
+/// The algorithm for computing `U`
+/// -------------------------------
+/// The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
+/// That means we're going to check the components from left-to-right, so the algorithm
+/// operates principally on the first component of the matrix and new pattern-stack `p`.
+/// This algorithm is realised in the `is_useful` function.
+///
+/// Base case. (`n = 0`, i.e., an empty tuple pattern)
+///     - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`),
+///       then `U(P, p)` is false.
+///     - Otherwise, `P` must be empty, so `U(P, p)` is true.
+///
+/// Inductive step. (`n > 0`, i.e., whether there's at least one column
+///                  [which may then be expanded into further columns later])
+///     We're going to match on the top of the new pattern-stack, `p_1`.
+///         - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
+///           Then, the usefulness of `p_1` can be reduced to whether it is useful when
+///           we ignore all the patterns in the first column of `P` that involve other constructors.
+///           This is where `S(c, P)` comes in:
+///           `U(P, p) := U(S(c, P), S(c, p))`
+///           This special case is handled in `is_useful_specialized`.
+///
+///           For example, if `P` is:
+///           [
+///               [Some(true), _],
+///               [None, 0],
+///           ]
+///           and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
+///           matches values that row 2 doesn't. For row 1 however, we need to dig into the
+///           arguments of `Some` to know whether some new value is covered. So we compute
+///           `U([[true, _]], [false, 0])`.
+///
+///         - If `p_1 == _`, then we look at the list of constructors that appear in the first
+///               component of the rows of `P`:
+///             + If there are some constructors that aren't present, then we might think that the
+///               wildcard `_` is useful, since it covers those constructors that weren't covered
+///               before.
+///               That's almost correct, but only works if there were no wildcards in those first
+///               components. So we need to check that `p` is useful with respect to the rows that
+///               start with a wildcard, if there are any. This is where `D` comes in:
+///               `U(P, p) := U(D(P), D(p))`
+///
+///               For example, if `P` is:
+///               [
+///                   [_, true, _],
+///                   [None, false, 1],
+///               ]
+///               and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
+///               only had row 2, we'd know that `p` is useful. However row 1 starts with a
+///               wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
+///
+///             + Otherwise, all possible constructors (for the relevant type) are present. In this
+///               case we must check whether the wildcard pattern covers any unmatched value. For
+///               that, we can think of the `_` pattern as a big OR-pattern that covers all
+///               possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
+///               example. The wildcard pattern is useful in this case if it is useful when
+///               specialized to one of the possible constructors. So we compute:
+///               `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
+///
+///               For example, if `P` is:
+///               [
+///                   [Some(true), _],
+///                   [None, false],
+///               ]
+///               and `p` is [_, false], both `None` and `Some` constructors appear in the first
+///               components of `P`. We will therefore try popping both constructors in turn: we
+///               compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]],
+///               [false]) for the `None` constructor. The first case returns true, so we know that
+///               `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
+///               before.
+///
+///         - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
+///           `U(P, p) := U(P, (r_1, p_2, .., p_n))
+///                    || U(P, (r_2, p_2, .., p_n))`
+///
+/// Modifications to the algorithm
+/// ------------------------------
+/// The algorithm in the paper doesn't cover some of the special cases that arise in Rust, for
+/// example uninhabited types and variable-length slice patterns. These are drawn attention to
+/// throughout the code below. I'll make a quick note here about how exhaustive integer matching is
+/// accounted for, though.
+///
+/// Exhaustive integer matching
+/// ---------------------------
+/// An integer type can be thought of as a (huge) sum type: 1 | 2 | 3 | ...
+/// So to support exhaustive integer matching, we can make use of the logic in the paper for
+/// OR-patterns. However, we obviously can't just treat ranges x..=y as individual sums, because
+/// they are likely gigantic. So we instead treat ranges as constructors of the integers. This means
+/// that we have a constructor *of* constructors (the integers themselves). We then need to work
+/// through all the inductive step rules above, deriving how the ranges would be treated as
+/// OR-patterns, and making sure that they're treated in the same way even when they're ranges.
+/// There are really only four special cases here:
+/// - When we match on a constructor that's actually a range, we have to treat it as if we would
+///   an OR-pattern.
+///     + It turns out that we can simply extend the case for single-value patterns in
+///      `specialize` to either be *equal* to a value constructor, or *contained within* a range
+///      constructor.
+///     + When the pattern itself is a range, you just want to tell whether any of the values in
+///       the pattern range coincide with values in the constructor range, which is precisely
+///       intersection.
+///   Since when encountering a range pattern for a value constructor, we also use inclusion, it
+///   means that whenever the constructor is a value/range and the pattern is also a value/range,
+///   we can simply use intersection to test usefulness.
+/// - When we're testing for usefulness of a pattern and the pattern's first component is a
+///   wildcard.
+///     + If all the constructors appear in the matrix, we have a slight complication. By default,
+///       the behaviour (i.e., a disjunction over specialised matrices for each constructor) is
+///       invalid, because we want a disjunction over every *integer* in each range, not just a
+///       disjunction over every range. This is a bit more tricky to deal with: essentially we need
+///       to form equivalence classes of subranges of the constructor range for which the behaviour
+///       of the matrix `P` and new pattern `p` are the same. This is described in more
+///       detail in `split_grouped_constructors`.
+///     + If some constructors are missing from the matrix, it turns out we don't need to do
+///       anything special (because we know none of the integers are actually wildcards: i.e., we
+///       can't span wildcards using ranges).
+use self::Constructor::*;
+use self::SliceKind::*;
+use self::Usefulness::*;
+use self::WitnessPreference::*;
+
+use rustc_data_structures::captures::Captures;
+use rustc_index::vec::Idx;
+
+use super::{compare_const_vals, PatternFoldable, PatternFolder};
+use super::{FieldPat, Pat, PatKind, PatRange};
+
+use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
+use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{HirId, RangeEnd};
+
+use rustc::lint;
+use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
+use rustc::mir::Field;
+use rustc::util::common::ErrorReported;
+
+use rustc_span::{Span, DUMMY_SP};
+use syntax::attr::{SignedInt, UnsignedInt};
+
+use arena::TypedArena;
+
+use smallvec::{smallvec, SmallVec};
+use std::borrow::Cow;
+use std::cmp::{self, max, min, Ordering};
+use std::convert::TryInto;
+use std::fmt;
+use std::iter::{FromIterator, IntoIterator};
+use std::ops::RangeInclusive;
+use std::u128;
+
+crate fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
+    LiteralExpander { tcx: cx.tcx, param_env: cx.param_env }.fold_pattern(&pat)
+}
+
+struct LiteralExpander<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> LiteralExpander<'tcx> {
+    /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice.
+    ///
+    /// `crty` and `rty` can differ because you can use array constants in the presence of slice
+    /// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
+    /// the array to a slice in that case.
+    fn fold_const_value_deref(
+        &mut self,
+        val: ConstValue<'tcx>,
+        // the pattern's pointee type
+        rty: Ty<'tcx>,
+        // the constant's pointee type
+        crty: Ty<'tcx>,
+    ) -> ConstValue<'tcx> {
+        debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
+        match (val, &crty.kind, &rty.kind) {
+            // the easy case, deref a reference
+            (ConstValue::Scalar(p), x, y) if x == y => {
+                match p {
+                    Scalar::Ptr(p) => {
+                        let alloc = self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id);
+                        ConstValue::ByRef { alloc, offset: p.offset }
+                    }
+                    Scalar::Raw { .. } => {
+                        let layout = self.tcx.layout_of(self.param_env.and(rty)).unwrap();
+                        if layout.is_zst() {
+                            // Deref of a reference to a ZST is a nop.
+                            ConstValue::Scalar(Scalar::zst())
+                        } else {
+                            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;`
+                            bug!("cannot deref {:#?}, {} -> {}", val, crty, rty);
+                        }
+                    }
+                }
+            }
+            // unsize array to slice if pattern is array but match value or other patterns are slice
+            (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
+                assert_eq!(t, u);
+                ConstValue::Slice {
+                    data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
+                    start: p.offset.bytes().try_into().unwrap(),
+                    end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(),
+                }
+            }
+            // fat pointers stay the same
+            (ConstValue::Slice { .. }, _, _)
+            | (_, ty::Slice(_), ty::Slice(_))
+            | (_, ty::Str, ty::Str) => val,
+            // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
+            _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
+        }
+    }
+}
+
+impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> {
+    fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
+        debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind, pat.kind);
+        match (&pat.ty.kind, &*pat.kind) {
+            (
+                &ty::Ref(_, rty, _),
+                &PatKind::Constant {
+                    value:
+                        Const {
+                            val: ty::ConstKind::Value(val),
+                            ty: ty::TyS { kind: ty::Ref(_, crty, _), .. },
+                        },
+                },
+            ) => Pat {
+                ty: pat.ty,
+                span: pat.span,
+                kind: box PatKind::Deref {
+                    subpattern: Pat {
+                        ty: rty,
+                        span: pat.span,
+                        kind: box PatKind::Constant {
+                            value: self.tcx.mk_const(Const {
+                                val: ty::ConstKind::Value(
+                                    self.fold_const_value_deref(*val, rty, crty),
+                                ),
+                                ty: rty,
+                            }),
+                        },
+                    },
+                },
+            },
+
+            (
+                &ty::Ref(_, rty, _),
+                &PatKind::Constant {
+                    value: Const { val, ty: ty::TyS { kind: ty::Ref(_, crty, _), .. } },
+                },
+            ) => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
+
+            (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self),
+            (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self),
+            _ => pat.super_fold_with(self),
+        }
+    }
+}
+
+impl<'tcx> Pat<'tcx> {
+    pub(super) fn is_wildcard(&self) -> bool {
+        match *self.kind {
+            PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true,
+            _ => false,
+        }
+    }
+}
+
+/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
+/// works well.
+#[derive(Debug, Clone)]
+crate struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>);
+
+impl<'p, 'tcx> PatStack<'p, 'tcx> {
+    crate fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
+        PatStack(smallvec![pat])
+    }
+
+    fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
+        PatStack(vec)
+    }
+
+    fn from_slice(s: &[&'p Pat<'tcx>]) -> Self {
+        PatStack(SmallVec::from_slice(s))
+    }
+
+    fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    fn head(&self) -> &'p Pat<'tcx> {
+        self.0[0]
+    }
+
+    fn to_tail(&self) -> Self {
+        PatStack::from_slice(&self.0[1..])
+    }
+
+    fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
+        self.0.iter().map(|p| *p)
+    }
+
+    // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
+    fn expand_or_pat(&self) -> Option<Vec<Self>> {
+        if self.is_empty() {
+            None
+        } else if let PatKind::Or { pats } = &*self.head().kind {
+            Some(
+                pats.iter()
+                    .map(|pat| {
+                        let mut new_patstack = PatStack::from_pattern(pat);
+                        new_patstack.0.extend_from_slice(&self.0[1..]);
+                        new_patstack
+                    })
+                    .collect(),
+            )
+        } else {
+            None
+        }
+    }
+
+    /// This computes `D(self)`. See top of the file for explanations.
+    fn specialize_wildcard(&self) -> Option<Self> {
+        if self.head().is_wildcard() { Some(self.to_tail()) } else { None }
+    }
+
+    /// This computes `S(constructor, self)`. See top of the file for explanations.
+    fn specialize_constructor(
+        &self,
+        cx: &mut MatchCheckCtxt<'p, 'tcx>,
+        constructor: &Constructor<'tcx>,
+        ctor_wild_subpatterns: &'p [Pat<'tcx>],
+    ) -> Option<PatStack<'p, 'tcx>> {
+        let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
+        new_heads.map(|mut new_head| {
+            new_head.0.extend_from_slice(&self.0[1..]);
+            new_head
+        })
+    }
+}
+
+impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
+    fn default() -> Self {
+        PatStack(smallvec![])
+    }
+}
+
+impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
+    fn from_iter<T>(iter: T) -> Self
+    where
+        T: IntoIterator<Item = &'p Pat<'tcx>>,
+    {
+        PatStack(iter.into_iter().collect())
+    }
+}
+
+/// A 2D matrix.
+#[derive(Clone)]
+crate struct Matrix<'p, 'tcx>(Vec<PatStack<'p, 'tcx>>);
+
+impl<'p, 'tcx> Matrix<'p, 'tcx> {
+    crate fn empty() -> Self {
+        Matrix(vec![])
+    }
+
+    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
+    crate fn push(&mut self, row: PatStack<'p, 'tcx>) {
+        if let Some(rows) = row.expand_or_pat() {
+            self.0.extend(rows);
+        } else {
+            self.0.push(row);
+        }
+    }
+
+    /// Iterate over the first component of each row
+    fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
+        self.0.iter().map(|r| r.head())
+    }
+
+    /// This computes `D(self)`. See top of the file for explanations.
+    fn specialize_wildcard(&self) -> Self {
+        self.0.iter().filter_map(|r| r.specialize_wildcard()).collect()
+    }
+
+    /// This computes `S(constructor, self)`. See top of the file for explanations.
+    fn specialize_constructor(
+        &self,
+        cx: &mut MatchCheckCtxt<'p, 'tcx>,
+        constructor: &Constructor<'tcx>,
+        ctor_wild_subpatterns: &'p [Pat<'tcx>],
+    ) -> Matrix<'p, 'tcx> {
+        self.0
+            .iter()
+            .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
+            .collect()
+    }
+}
+
+/// Pretty-printer for matrices of patterns, example:
+/// +++++++++++++++++++++++++++++
+/// + _     + []                +
+/// +++++++++++++++++++++++++++++
+/// + true  + [First]           +
+/// +++++++++++++++++++++++++++++
+/// + true  + [Second(true)]    +
+/// +++++++++++++++++++++++++++++
+/// + false + [_]               +
+/// +++++++++++++++++++++++++++++
+/// + _     + [_, _, tail @ ..] +
+/// +++++++++++++++++++++++++++++
+impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "\n")?;
+
+        let &Matrix(ref m) = self;
+        let pretty_printed_matrix: Vec<Vec<String>> =
+            m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect();
+
+        let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
+        assert!(m.iter().all(|row| row.len() == column_count));
+        let column_widths: Vec<usize> = (0..column_count)
+            .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0))
+            .collect();
+
+        let total_width = column_widths.iter().cloned().sum::<usize>() + column_count * 3 + 1;
+        let br = "+".repeat(total_width);
+        write!(f, "{}\n", br)?;
+        for row in pretty_printed_matrix {
+            write!(f, "+")?;
+            for (column, pat_str) in row.into_iter().enumerate() {
+                write!(f, " ")?;
+                write!(f, "{:1$}", pat_str, column_widths[column])?;
+                write!(f, " +")?;
+            }
+            write!(f, "\n")?;
+            write!(f, "{}\n", br)?;
+        }
+        Ok(())
+    }
+}
+
+impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
+    fn from_iter<T>(iter: T) -> Self
+    where
+        T: IntoIterator<Item = PatStack<'p, 'tcx>>,
+    {
+        let mut matrix = Matrix::empty();
+        for x in iter {
+            // Using `push` ensures we correctly expand or-patterns.
+            matrix.push(x);
+        }
+        matrix
+    }
+}
+
+crate struct MatchCheckCtxt<'a, 'tcx> {
+    crate tcx: TyCtxt<'tcx>,
+    /// The module in which the match occurs. This is necessary for
+    /// checking inhabited-ness of types because whether a type is (visibly)
+    /// inhabited can depend on whether it was defined in the current module or
+    /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
+    /// outside it's module and should not be matchable with an empty match
+    /// statement.
+    crate module: DefId,
+    param_env: ty::ParamEnv<'tcx>,
+    crate pattern_arena: &'a TypedArena<Pat<'tcx>>,
+}
+
+impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
+    crate fn create_and_enter<F, R>(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        module: DefId,
+        f: F,
+    ) -> R
+    where
+        F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
+    {
+        let pattern_arena = TypedArena::default();
+
+        f(MatchCheckCtxt { tcx, param_env, module, pattern_arena: &pattern_arena })
+    }
+
+    fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
+        if self.tcx.features().exhaustive_patterns {
+            self.tcx.is_ty_uninhabited_from(self.module, ty)
+        } else {
+            false
+        }
+    }
+
+    // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
+    crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
+        match ty.kind {
+            ty::Adt(def, ..) => {
+                def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
+            }
+            _ => false,
+        }
+    }
+
+    // Returns whether the given variant is from another crate and has its fields declared
+    // `#[non_exhaustive]`.
+    fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool {
+        match ty.kind {
+            ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(),
+            _ => false,
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum SliceKind {
+    /// Patterns of length `n` (`[x, y]`).
+    FixedLen(u64),
+    /// Patterns using the `..` notation (`[x, .., y]`).
+    /// Captures any array constructor of `length >= i + j`.
+    /// In the case where `array_len` is `Some(_)`,
+    /// this indicates that we only care about the first `i` and the last `j` values of the array,
+    /// and everything in between is a wildcard `_`.
+    VarLen(u64, u64),
+}
+
+impl SliceKind {
+    fn arity(self) -> u64 {
+        match self {
+            FixedLen(length) => length,
+            VarLen(prefix, suffix) => prefix + suffix,
+        }
+    }
+
+    /// Whether this pattern includes patterns of length `other_len`.
+    fn covers_length(self, other_len: u64) -> bool {
+        match self {
+            FixedLen(len) => len == other_len,
+            VarLen(prefix, suffix) => prefix + suffix <= other_len,
+        }
+    }
+
+    /// Returns a collection of slices that spans the values covered by `self`, subtracted by the
+    /// values covered by `other`: i.e., `self \ other` (in set notation).
+    fn subtract(self, other: Self) -> SmallVec<[Self; 1]> {
+        // Remember, `VarLen(i, j)` covers the union of `FixedLen` from `i + j` to infinity.
+        // Naming: we remove the "neg" constructors from the "pos" ones.
+        match self {
+            FixedLen(pos_len) => {
+                if other.covers_length(pos_len) {
+                    smallvec![]
+                } else {
+                    smallvec![self]
+                }
+            }
+            VarLen(pos_prefix, pos_suffix) => {
+                let pos_len = pos_prefix + pos_suffix;
+                match other {
+                    FixedLen(neg_len) => {
+                        if neg_len < pos_len {
+                            smallvec![self]
+                        } else {
+                            (pos_len..neg_len)
+                                .map(FixedLen)
+                                // We know that `neg_len + 1 >= pos_len >= pos_suffix`.
+                                .chain(Some(VarLen(neg_len + 1 - pos_suffix, pos_suffix)))
+                                .collect()
+                        }
+                    }
+                    VarLen(neg_prefix, neg_suffix) => {
+                        let neg_len = neg_prefix + neg_suffix;
+                        if neg_len <= pos_len {
+                            smallvec![]
+                        } else {
+                            (pos_len..neg_len).map(FixedLen).collect()
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// A constructor for array and slice patterns.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+struct Slice {
+    /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`.
+    array_len: Option<u64>,
+    /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`.
+    kind: SliceKind,
+}
+
+impl Slice {
+    /// Returns what patterns this constructor covers: either fixed-length patterns or
+    /// variable-length patterns.
+    fn pattern_kind(self) -> SliceKind {
+        match self {
+            Slice { array_len: Some(len), kind: VarLen(prefix, suffix) }
+                if prefix + suffix == len =>
+            {
+                FixedLen(len)
+            }
+            _ => self.kind,
+        }
+    }
+
+    /// Returns what values this constructor covers: either values of only one given length, or
+    /// values of length above a given length.
+    /// This is different from `pattern_kind()` because in some cases the pattern only takes into
+    /// account a subset of the entries of the array, but still only captures values of a given
+    /// length.
+    fn value_kind(self) -> SliceKind {
+        match self {
+            Slice { array_len: Some(len), kind: VarLen(_, _) } => FixedLen(len),
+            _ => self.kind,
+        }
+    }
+
+    fn arity(self) -> u64 {
+        self.pattern_kind().arity()
+    }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+enum Constructor<'tcx> {
+    /// The constructor of all patterns that don't vary by constructor,
+    /// e.g., struct patterns and fixed-length arrays.
+    Single,
+    /// Enum variants.
+    Variant(DefId),
+    /// Literal values.
+    ConstantValue(&'tcx ty::Const<'tcx>),
+    /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
+    IntRange(IntRange<'tcx>),
+    /// Ranges of floating-point literal values (`2.0..=5.2`).
+    FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+    /// Array and slice patterns.
+    Slice(Slice),
+    /// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
+    NonExhaustive,
+}
+
+impl<'tcx> Constructor<'tcx> {
+    fn is_slice(&self) -> bool {
+        match self {
+            Slice(_) => true,
+            _ => false,
+        }
+    }
+
+    fn variant_index_for_adt<'a>(
+        &self,
+        cx: &MatchCheckCtxt<'a, 'tcx>,
+        adt: &'tcx ty::AdtDef,
+    ) -> VariantIdx {
+        match *self {
+            Variant(id) => adt.variant_index_with_id(id),
+            Single => {
+                assert!(!adt.is_enum());
+                VariantIdx::new(0)
+            }
+            ConstantValue(c) => cx.tcx.destructure_const(cx.param_env.and(c)).variant,
+            _ => bug!("bad constructor {:?} for adt {:?}", self, adt),
+        }
+    }
+
+    // Returns the set of constructors covered by `self` but not by
+    // anything in `other_ctors`.
+    fn subtract_ctors(&self, other_ctors: &Vec<Constructor<'tcx>>) -> Vec<Constructor<'tcx>> {
+        if other_ctors.is_empty() {
+            return vec![self.clone()];
+        }
+
+        match self {
+            // Those constructors can only match themselves.
+            Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
+                if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] }
+            }
+            &Slice(slice) => {
+                let mut other_slices = other_ctors
+                    .iter()
+                    .filter_map(|c: &Constructor<'_>| match c {
+                        Slice(slice) => Some(*slice),
+                        // FIXME(oli-obk): implement `deref` for `ConstValue`
+                        ConstantValue(..) => None,
+                        _ => bug!("bad slice pattern constructor {:?}", c),
+                    })
+                    .map(Slice::value_kind);
+
+                match slice.value_kind() {
+                    FixedLen(self_len) => {
+                        if other_slices.any(|other_slice| other_slice.covers_length(self_len)) {
+                            vec![]
+                        } else {
+                            vec![Slice(slice)]
+                        }
+                    }
+                    kind @ VarLen(..) => {
+                        let mut remaining_slices = vec![kind];
+
+                        // For each used slice, subtract from the current set of slices.
+                        for other_slice in other_slices {
+                            remaining_slices = remaining_slices
+                                .into_iter()
+                                .flat_map(|remaining_slice| remaining_slice.subtract(other_slice))
+                                .collect();
+
+                            // If the constructors that have been considered so far already cover
+                            // the entire range of `self`, no need to look at more constructors.
+                            if remaining_slices.is_empty() {
+                                break;
+                            }
+                        }
+
+                        remaining_slices
+                            .into_iter()
+                            .map(|kind| Slice { array_len: slice.array_len, kind })
+                            .map(Slice)
+                            .collect()
+                    }
+                }
+            }
+            IntRange(self_range) => {
+                let mut remaining_ranges = vec![self_range.clone()];
+                for other_ctor in other_ctors {
+                    if let IntRange(other_range) = other_ctor {
+                        if other_range == self_range {
+                            // If the `self` range appears directly in a `match` arm, we can
+                            // eliminate it straight away.
+                            remaining_ranges = vec![];
+                        } else {
+                            // Otherwise explicitely compute the remaining ranges.
+                            remaining_ranges = other_range.subtract_from(remaining_ranges);
+                        }
+
+                        // If the ranges that have been considered so far already cover the entire
+                        // range of values, we can return early.
+                        if remaining_ranges.is_empty() {
+                            break;
+                        }
+                    }
+                }
+
+                // Convert the ranges back into constructors.
+                remaining_ranges.into_iter().map(IntRange).collect()
+            }
+            // This constructor is never covered by anything else
+            NonExhaustive => vec![NonExhaustive],
+        }
+    }
+
+    /// This returns one wildcard pattern for each argument to this constructor.
+    ///
+    /// This must be consistent with `apply`, `specialize_one_pattern`, and `arity`.
+    fn wildcard_subpatterns<'a>(
+        &self,
+        cx: &MatchCheckCtxt<'a, 'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Vec<Pat<'tcx>> {
+        debug!("wildcard_subpatterns({:#?}, {:?})", self, ty);
+
+        match self {
+            Single | Variant(_) => match ty.kind {
+                ty::Tuple(ref fs) => {
+                    fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect()
+                }
+                ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)],
+                ty::Adt(adt, substs) => {
+                    if adt.is_box() {
+                        // Use T as the sub pattern type of Box<T>.
+                        vec![Pat::wildcard_from_ty(substs.type_at(0))]
+                    } else {
+                        let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
+                        let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant);
+                        variant
+                            .fields
+                            .iter()
+                            .map(|field| {
+                                let is_visible = adt.is_enum()
+                                    || field.vis.is_accessible_from(cx.module, cx.tcx);
+                                let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs));
+                                match (is_visible, is_non_exhaustive, is_uninhabited) {
+                                    // Treat all uninhabited types in non-exhaustive variants as
+                                    // `TyErr`.
+                                    (_, true, true) => cx.tcx.types.err,
+                                    // Treat all non-visible fields as `TyErr`. They can't appear
+                                    // in any other pattern from this match (because they are
+                                    // private), so their type does not matter - but we don't want
+                                    // to know they are uninhabited.
+                                    (false, ..) => cx.tcx.types.err,
+                                    (true, ..) => {
+                                        let ty = field.ty(cx.tcx, substs);
+                                        match ty.kind {
+                                            // If the field type returned is an array of an unknown
+                                            // size return an TyErr.
+                                            ty::Array(_, len)
+                                                if len
+                                                    .try_eval_usize(cx.tcx, cx.param_env)
+                                                    .is_none() =>
+                                            {
+                                                cx.tcx.types.err
+                                            }
+                                            _ => ty,
+                                        }
+                                    }
+                                }
+                            })
+                            .map(Pat::wildcard_from_ty)
+                            .collect()
+                    }
+                }
+                _ => vec![],
+            },
+            Slice(_) => match ty.kind {
+                ty::Slice(ty) | ty::Array(ty, _) => {
+                    let arity = self.arity(cx, ty);
+                    (0..arity).map(|_| Pat::wildcard_from_ty(ty)).collect()
+                }
+                _ => bug!("bad slice pattern {:?} {:?}", self, ty),
+            },
+            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => vec![],
+        }
+    }
+
+    /// This computes the arity of a constructor. The arity of a constructor
+    /// is how many subpattern patterns of that constructor should be expanded to.
+    ///
+    /// For instance, a tuple pattern `(_, 42, Some([]))` has the arity of 3.
+    /// A struct pattern's arity is the number of fields it contains, etc.
+    ///
+    /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `apply`.
+    fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 {
+        debug!("Constructor::arity({:#?}, {:?})", self, ty);
+        match self {
+            Single | Variant(_) => match ty.kind {
+                ty::Tuple(ref fs) => fs.len() as u64,
+                ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
+                ty::Ref(..) => 1,
+                ty::Adt(adt, _) => {
+                    adt.variants[self.variant_index_for_adt(cx, adt)].fields.len() as u64
+                }
+                _ => 0,
+            },
+            Slice(slice) => slice.arity(),
+            ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => 0,
+        }
+    }
+
+    /// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
+    /// must have as many elements as this constructor's arity.
+    ///
+    /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `arity`.
+    ///
+    /// Examples:
+    /// `self`: `Constructor::Single`
+    /// `ty`: `(u32, u32, u32)`
+    /// `pats`: `[10, 20, _]`
+    /// returns `(10, 20, _)`
+    ///
+    /// `self`: `Constructor::Variant(Option::Some)`
+    /// `ty`: `Option<bool>`
+    /// `pats`: `[false]`
+    /// returns `Some(false)`
+    fn apply<'a>(
+        &self,
+        cx: &MatchCheckCtxt<'a, 'tcx>,
+        ty: Ty<'tcx>,
+        pats: impl IntoIterator<Item = Pat<'tcx>>,
+    ) -> Pat<'tcx> {
+        let mut subpatterns = pats.into_iter();
+
+        let pat = match self {
+            Single | Variant(_) => match ty.kind {
+                ty::Adt(..) | ty::Tuple(..) => {
+                    let subpatterns = subpatterns
+                        .enumerate()
+                        .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+                        .collect();
+
+                    if let ty::Adt(adt, substs) = ty.kind {
+                        if adt.is_enum() {
+                            PatKind::Variant {
+                                adt_def: adt,
+                                substs,
+                                variant_index: self.variant_index_for_adt(cx, adt),
+                                subpatterns,
+                            }
+                        } else {
+                            PatKind::Leaf { subpatterns }
+                        }
+                    } else {
+                        PatKind::Leaf { subpatterns }
+                    }
+                }
+                ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() },
+                ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
+                _ => PatKind::Wild,
+            },
+            Slice(slice) => match slice.pattern_kind() {
+                FixedLen(_) => {
+                    PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
+                }
+                VarLen(prefix, _) => {
+                    let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect();
+                    if slice.array_len.is_some() {
+                        // Improves diagnostics a bit: if the type is a known-size array, instead
+                        // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
+                        // This is incorrect if the size is not known, since `[_, ..]` captures
+                        // arrays of lengths `>= 1` whereas `[..]` captures any length.
+                        while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() {
+                            prefix.pop();
+                        }
+                    }
+                    let suffix: Vec<_> = if slice.array_len.is_some() {
+                        // Same as above.
+                        subpatterns.skip_while(Pat::is_wildcard).collect()
+                    } else {
+                        subpatterns.collect()
+                    };
+                    let wild = Pat::wildcard_from_ty(ty);
+                    PatKind::Slice { prefix, slice: Some(wild), suffix }
+                }
+            },
+            &ConstantValue(value) => PatKind::Constant { value },
+            &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
+            IntRange(range) => return range.to_pat(cx.tcx),
+            NonExhaustive => PatKind::Wild,
+        };
+
+        Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
+    }
+
+    /// Like `apply`, but where all the subpatterns are wildcards `_`.
+    fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
+        let subpatterns = self.wildcard_subpatterns(cx, ty).into_iter().rev();
+        self.apply(cx, ty, subpatterns)
+    }
+}
+
+#[derive(Clone, Debug)]
+crate enum Usefulness<'tcx, 'p> {
+    /// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns.
+    Useful(Vec<&'p Pat<'tcx>>),
+    /// Carries a list of witnesses of non-exhaustiveness.
+    UsefulWithWitness(Vec<Witness<'tcx>>),
+    NotUseful,
+}
+
+impl<'tcx, 'p> Usefulness<'tcx, 'p> {
+    fn new_useful(preference: WitnessPreference) -> Self {
+        match preference {
+            ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
+            LeaveOutWitness => Useful(vec![]),
+        }
+    }
+
+    fn is_useful(&self) -> bool {
+        match *self {
+            NotUseful => false,
+            _ => true,
+        }
+    }
+
+    fn apply_constructor(
+        self,
+        cx: &MatchCheckCtxt<'_, 'tcx>,
+        ctor: &Constructor<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Self {
+        match self {
+            UsefulWithWitness(witnesses) => UsefulWithWitness(
+                witnesses
+                    .into_iter()
+                    .map(|witness| witness.apply_constructor(cx, &ctor, ty))
+                    .collect(),
+            ),
+            x => x,
+        }
+    }
+
+    fn apply_wildcard(self, ty: Ty<'tcx>) -> Self {
+        match self {
+            UsefulWithWitness(witnesses) => {
+                let wild = Pat::wildcard_from_ty(ty);
+                UsefulWithWitness(
+                    witnesses
+                        .into_iter()
+                        .map(|mut witness| {
+                            witness.0.push(wild.clone());
+                            witness
+                        })
+                        .collect(),
+                )
+            }
+            x => x,
+        }
+    }
+
+    fn apply_missing_ctors(
+        self,
+        cx: &MatchCheckCtxt<'_, 'tcx>,
+        ty: Ty<'tcx>,
+        missing_ctors: &MissingConstructors<'tcx>,
+    ) -> Self {
+        match self {
+            UsefulWithWitness(witnesses) => {
+                let new_patterns: Vec<_> =
+                    missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, ty)).collect();
+                // Add the new patterns to each witness
+                UsefulWithWitness(
+                    witnesses
+                        .into_iter()
+                        .flat_map(|witness| {
+                            new_patterns.iter().map(move |pat| {
+                                let mut witness = witness.clone();
+                                witness.0.push(pat.clone());
+                                witness
+                            })
+                        })
+                        .collect(),
+                )
+            }
+            x => x,
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+crate enum WitnessPreference {
+    ConstructWitness,
+    LeaveOutWitness,
+}
+
+#[derive(Copy, Clone, Debug)]
+struct PatCtxt<'tcx> {
+    ty: Ty<'tcx>,
+    span: Span,
+}
+
+/// A witness of non-exhaustiveness for error reporting, represented
+/// as a list of patterns (in reverse order of construction) with
+/// wildcards inside to represent elements that can take any inhabitant
+/// of the type as a value.
+///
+/// A witness against a list of patterns should have the same types
+/// and length as the pattern matched against. Because Rust `match`
+/// is always against a single pattern, at the end the witness will
+/// have length 1, but in the middle of the algorithm, it can contain
+/// multiple patterns.
+///
+/// For example, if we are constructing a witness for the match against
+/// ```
+/// struct Pair(Option<(u32, u32)>, bool);
+///
+/// match (p: Pair) {
+///    Pair(None, _) => {}
+///    Pair(_, false) => {}
+/// }
+/// ```
+///
+/// We'll perform the following steps:
+/// 1. Start with an empty witness
+///     `Witness(vec![])`
+/// 2. Push a witness `Some(_)` against the `None`
+///     `Witness(vec![Some(_)])`
+/// 3. Push a witness `true` against the `false`
+///     `Witness(vec![Some(_), true])`
+/// 4. Apply the `Pair` constructor to the witnesses
+///     `Witness(vec![Pair(Some(_), true)])`
+///
+/// The final `Pair(Some(_), true)` is then the resulting witness.
+#[derive(Clone, Debug)]
+crate struct Witness<'tcx>(Vec<Pat<'tcx>>);
+
+impl<'tcx> Witness<'tcx> {
+    crate fn single_pattern(self) -> Pat<'tcx> {
+        assert_eq!(self.0.len(), 1);
+        self.0.into_iter().next().unwrap()
+    }
+
+    /// Constructs a partial witness for a pattern given a list of
+    /// patterns expanded by the specialization step.
+    ///
+    /// When a pattern P is discovered to be useful, this function is used bottom-up
+    /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset
+    /// of values, V, where each value in that set is not covered by any previously
+    /// used patterns and is covered by the pattern P'. Examples:
+    ///
+    /// left_ty: tuple of 3 elements
+    /// pats: [10, 20, _]           => (10, 20, _)
+    ///
+    /// left_ty: struct X { a: (bool, &'static str), b: usize}
+    /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
+    fn apply_constructor<'a>(
+        mut self,
+        cx: &MatchCheckCtxt<'a, 'tcx>,
+        ctor: &Constructor<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Self {
+        let arity = ctor.arity(cx, ty);
+        let pat = {
+            let len = self.0.len() as u64;
+            let pats = self.0.drain((len - arity) as usize..).rev();
+            ctor.apply(cx, ty, pats)
+        };
+
+        self.0.push(pat);
+
+        self
+    }
+}
+
+/// This determines the set of all possible constructors of a pattern matching
+/// values of type `left_ty`. For vectors, this would normally be an infinite set
+/// but is instead bounded by the maximum fixed length of slice patterns in
+/// the column of patterns being analyzed.
+///
+/// We make sure to omit constructors that are statically impossible. E.g., for
+/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
+/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
+/// `cx.is_uninhabited()`).
+fn all_constructors<'a, 'tcx>(
+    cx: &mut MatchCheckCtxt<'a, 'tcx>,
+    pcx: PatCtxt<'tcx>,
+) -> Vec<Constructor<'tcx>> {
+    debug!("all_constructors({:?})", pcx.ty);
+    let make_range = |start, end| {
+        IntRange(
+            // `unwrap()` is ok because we know the type is an integer.
+            IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included, pcx.span)
+                .unwrap(),
+        )
+    };
+    match pcx.ty.kind {
+        ty::Bool => {
+            [true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect()
+        }
+        ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
+            let len = len.eval_usize(cx.tcx, cx.param_env);
+            if len != 0 && cx.is_uninhabited(sub_ty) {
+                vec![]
+            } else {
+                vec![Slice(Slice { array_len: Some(len), kind: VarLen(0, 0) })]
+            }
+        }
+        // Treat arrays of a constant but unknown length like slices.
+        ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => {
+            let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
+            vec![Slice(Slice { array_len: None, kind })]
+        }
+        ty::Adt(def, substs) if def.is_enum() => {
+            let ctors: Vec<_> = if cx.tcx.features().exhaustive_patterns {
+                // If `exhaustive_patterns` is enabled, we exclude variants known to be
+                // uninhabited.
+                def.variants
+                    .iter()
+                    .filter(|v| {
+                        !v.uninhabited_from(cx.tcx, substs, def.adt_kind())
+                            .contains(cx.tcx, cx.module)
+                    })
+                    .map(|v| Variant(v.def_id))
+                    .collect()
+            } else {
+                def.variants.iter().map(|v| Variant(v.def_id)).collect()
+            };
+
+            // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
+            // additional "unknown" constructor.
+            // There is no point in enumerating all possible variants, because the user can't
+            // actually match against them all themselves. So we always return only the fictitious
+            // constructor.
+            // E.g., in an example like:
+            // ```
+            //     let err: io::ErrorKind = ...;
+            //     match err {
+            //         io::ErrorKind::NotFound => {},
+            //     }
+            // ```
+            // we don't want to show every possible IO error, but instead have only `_` as the
+            // witness.
+            let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
+
+            // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
+            // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
+            // an empty match will still be considered exhaustive because that case is handled
+            // separately in `check_match`.
+            let is_secretly_empty =
+                def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns;
+
+            if is_secretly_empty || is_declared_nonexhaustive { vec![NonExhaustive] } else { ctors }
+        }
+        ty::Char => {
+            vec![
+                // The valid Unicode Scalar Value ranges.
+                make_range('\u{0000}' as u128, '\u{D7FF}' as u128),
+                make_range('\u{E000}' as u128, '\u{10FFFF}' as u128),
+            ]
+        }
+        ty::Int(_) | ty::Uint(_)
+            if pcx.ty.is_ptr_sized_integral()
+                && !cx.tcx.features().precise_pointer_size_matching =>
+        {
+            // `usize`/`isize` are not allowed to be matched exhaustively unless the
+            // `precise_pointer_size_matching` feature is enabled. So we treat those types like
+            // `#[non_exhaustive]` enums by returning a special unmatcheable constructor.
+            vec![NonExhaustive]
+        }
+        ty::Int(ity) => {
+            let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
+            let min = 1u128 << (bits - 1);
+            let max = min - 1;
+            vec![make_range(min, max)]
+        }
+        ty::Uint(uty) => {
+            let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
+            let max = truncate(u128::max_value(), size);
+            vec![make_range(0, max)]
+        }
+        _ => {
+            if cx.is_uninhabited(pcx.ty) {
+                vec![]
+            } else {
+                vec![Single]
+            }
+        }
+    }
+}
+
+/// An inclusive interval, used for precise integer exhaustiveness checking.
+/// `IntRange`s always store a contiguous range. This means that values are
+/// encoded such that `0` encodes the minimum value for the integer,
+/// regardless of the signedness.
+/// For example, the pattern `-128..=127i8` is encoded as `0..=255`.
+/// This makes comparisons and arithmetic on interval endpoints much more
+/// straightforward. See `signed_bias` for details.
+///
+/// `IntRange` is never used to encode an empty range or a "range" that wraps
+/// around the (offset) space: i.e., `range.lo <= range.hi`.
+#[derive(Clone, Debug)]
+struct IntRange<'tcx> {
+    range: RangeInclusive<u128>,
+    ty: Ty<'tcx>,
+    span: Span,
+}
+
+impl<'tcx> IntRange<'tcx> {
+    #[inline]
+    fn is_integral(ty: Ty<'_>) -> bool {
+        match ty.kind {
+            ty::Char | ty::Int(_) | ty::Uint(_) => true,
+            _ => false,
+        }
+    }
+
+    fn is_singleton(&self) -> bool {
+        self.range.start() == self.range.end()
+    }
+
+    fn boundaries(&self) -> (u128, u128) {
+        (*self.range.start(), *self.range.end())
+    }
+
+    /// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching` feature
+    /// is enabled.
+    fn treat_exhaustively(&self, tcx: TyCtxt<'tcx>) -> bool {
+        !self.ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching
+    }
+
+    #[inline]
+    fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
+        match ty.kind {
+            ty::Char => Some((Size::from_bytes(4), 0)),
+            ty::Int(ity) => {
+                let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+                Some((size, 1u128 << (size.bits() as u128 - 1)))
+            }
+            ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)),
+            _ => None,
+        }
+    }
+
+    #[inline]
+    fn from_const(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        value: &Const<'tcx>,
+        span: Span,
+    ) -> Option<IntRange<'tcx>> {
+        if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
+            let ty = value.ty;
+            let val = if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, size })) =
+                value.val
+            {
+                // For this specific pattern we can skip a lot of effort and go
+                // straight to the result, after doing a bit of checking. (We
+                // could remove this branch and just use the next branch, which
+                // is more general but much slower.)
+                Scalar::<()>::check_raw(data, size, target_size);
+                data
+            } else if let Some(val) = value.try_eval_bits(tcx, param_env, ty) {
+                // This is a more general form of the previous branch.
+                val
+            } else {
+                return None;
+            };
+            let val = val ^ bias;
+            Some(IntRange { range: val..=val, ty, span })
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn from_range(
+        tcx: TyCtxt<'tcx>,
+        lo: u128,
+        hi: u128,
+        ty: Ty<'tcx>,
+        end: &RangeEnd,
+        span: Span,
+    ) -> Option<IntRange<'tcx>> {
+        if Self::is_integral(ty) {
+            // Perform a shift if the underlying types are signed,
+            // which makes the interval arithmetic simpler.
+            let bias = IntRange::signed_bias(tcx, ty);
+            let (lo, hi) = (lo ^ bias, hi ^ bias);
+            let offset = (*end == RangeEnd::Excluded) as u128;
+            if lo > hi || (lo == hi && *end == RangeEnd::Excluded) {
+                // This should have been caught earlier by E0030.
+                bug!("malformed range pattern: {}..={}", lo, (hi - offset));
+            }
+            Some(IntRange { range: lo..=(hi - offset), ty, span })
+        } else {
+            None
+        }
+    }
+
+    fn from_pat(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        pat: &Pat<'tcx>,
+    ) -> Option<IntRange<'tcx>> {
+        match pat_constructor(tcx, param_env, pat)? {
+            IntRange(range) => Some(range),
+            _ => None,
+        }
+    }
+
+    // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
+    fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 {
+        match ty.kind {
+            ty::Int(ity) => {
+                let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
+                1u128 << (bits - 1)
+            }
+            _ => 0,
+        }
+    }
+
+    /// Returns a collection of ranges that spans the values covered by `ranges`, subtracted
+    /// by the values covered by `self`: i.e., `ranges \ self` (in set notation).
+    fn subtract_from(&self, ranges: Vec<IntRange<'tcx>>) -> Vec<IntRange<'tcx>> {
+        let mut remaining_ranges = vec![];
+        let ty = self.ty;
+        let span = self.span;
+        let (lo, hi) = self.boundaries();
+        for subrange in ranges {
+            let (subrange_lo, subrange_hi) = subrange.range.into_inner();
+            if lo > subrange_hi || subrange_lo > hi {
+                // The pattern doesn't intersect with the subrange at all,
+                // so the subrange remains untouched.
+                remaining_ranges.push(IntRange { range: subrange_lo..=subrange_hi, ty, span });
+            } else {
+                if lo > subrange_lo {
+                    // The pattern intersects an upper section of the
+                    // subrange, so a lower section will remain.
+                    remaining_ranges.push(IntRange { range: subrange_lo..=(lo - 1), ty, span });
+                }
+                if hi < subrange_hi {
+                    // The pattern intersects a lower section of the
+                    // subrange, so an upper section will remain.
+                    remaining_ranges.push(IntRange { range: (hi + 1)..=subrange_hi, ty, span });
+                }
+            }
+        }
+        remaining_ranges
+    }
+
+    fn is_subrange(&self, other: &Self) -> bool {
+        other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
+    }
+
+    fn intersection(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Option<Self> {
+        let ty = self.ty;
+        let (lo, hi) = self.boundaries();
+        let (other_lo, other_hi) = other.boundaries();
+        if self.treat_exhaustively(tcx) {
+            if lo <= other_hi && other_lo <= hi {
+                let span = other.span;
+                Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span })
+            } else {
+                None
+            }
+        } else {
+            // If the range should not be treated exhaustively, fallback to checking for inclusion.
+            if self.is_subrange(other) { Some(self.clone()) } else { None }
+        }
+    }
+
+    fn suspicious_intersection(&self, other: &Self) -> bool {
+        // `false` in the following cases:
+        // 1     ----      // 1  ----------   // 1 ----        // 1       ----
+        // 2  ----------   // 2     ----      // 2       ----  // 2 ----
+        //
+        // The following are currently `false`, but could be `true` in the future (#64007):
+        // 1 ---------       // 1     ---------
+        // 2     ----------  // 2 ----------
+        //
+        // `true` in the following cases:
+        // 1 -------          // 1       -------
+        // 2       --------   // 2 -------
+        let (lo, hi) = self.boundaries();
+        let (other_lo, other_hi) = other.boundaries();
+        (lo == other_hi || hi == other_lo)
+    }
+
+    fn to_pat(&self, tcx: TyCtxt<'tcx>) -> Pat<'tcx> {
+        let (lo, hi) = self.boundaries();
+
+        let bias = IntRange::signed_bias(tcx, self.ty);
+        let (lo, hi) = (lo ^ bias, hi ^ bias);
+
+        let ty = ty::ParamEnv::empty().and(self.ty);
+        let lo_const = ty::Const::from_bits(tcx, lo, ty);
+        let hi_const = ty::Const::from_bits(tcx, hi, ty);
+
+        let kind = if lo == hi {
+            PatKind::Constant { value: lo_const }
+        } else {
+            PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
+        };
+
+        // This is a brand new pattern, so we don't reuse `self.span`.
+        Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(kind) }
+    }
+}
+
+/// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
+impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
+    fn eq(&self, other: &Self) -> bool {
+        self.range == other.range && self.ty == other.ty
+    }
+}
+
+// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
+struct MissingConstructors<'tcx> {
+    all_ctors: Vec<Constructor<'tcx>>,
+    used_ctors: Vec<Constructor<'tcx>>,
+}
+
+impl<'tcx> MissingConstructors<'tcx> {
+    fn new(all_ctors: Vec<Constructor<'tcx>>, used_ctors: Vec<Constructor<'tcx>>) -> Self {
+        MissingConstructors { all_ctors, used_ctors }
+    }
+
+    fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
+        (self.all_ctors, self.used_ctors)
+    }
+
+    fn is_empty(&self) -> bool {
+        self.iter().next().is_none()
+    }
+    /// Whether this contains all the constructors for the given type or only a
+    /// subset.
+    fn all_ctors_are_missing(&self) -> bool {
+        self.used_ctors.is_empty()
+    }
+
+    /// Iterate over all_ctors \ used_ctors
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Constructor<'tcx>> + Captures<'a> {
+        self.all_ctors.iter().flat_map(move |req_ctor| req_ctor.subtract_ctors(&self.used_ctors))
+    }
+}
+
+impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let ctors: Vec<_> = self.iter().collect();
+        write!(f, "{:?}", ctors)
+    }
+}
+
+/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
+/// The algorithm from the paper has been modified to correctly handle empty
+/// types. The changes are:
+///   (0) We don't exit early if the pattern matrix has zero rows. We just
+///       continue to recurse over columns.
+///   (1) all_constructors will only return constructors that are statically
+///       possible. E.g., it will only return `Ok` for `Result<T, !>`.
+///
+/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
+/// to a set of such vectors `m` - this is defined as there being a set of
+/// inputs that will match `v` but not any of the sets in `m`.
+///
+/// All the patterns at each column of the `matrix ++ v` matrix must
+/// have the same type, except that wildcard (PatKind::Wild) patterns
+/// with type `TyErr` are also allowed, even if the "type of the column"
+/// is not `TyErr`. That is used to represent private fields, as using their
+/// real type would assert that they are inhabited.
+///
+/// This is used both for reachability checking (if a pattern isn't useful in
+/// relation to preceding patterns, it is not reachable) and exhaustiveness
+/// checking (if a wildcard pattern is useful in relation to a matrix, the
+/// matrix isn't exhaustive).
+crate fn is_useful<'p, 'tcx>(
+    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+    matrix: &Matrix<'p, 'tcx>,
+    v: &PatStack<'p, 'tcx>,
+    witness_preference: WitnessPreference,
+    hir_id: HirId,
+    is_top_level: bool,
+) -> Usefulness<'tcx, 'p> {
+    let &Matrix(ref rows) = matrix;
+    debug!("is_useful({:#?}, {:#?})", matrix, v);
+
+    // The base case. We are pattern-matching on () and the return value is
+    // based on whether our matrix has a row or not.
+    // NOTE: This could potentially be optimized by checking rows.is_empty()
+    // first and then, if v is non-empty, the return value is based on whether
+    // the type of the tuple we're checking is inhabited or not.
+    if v.is_empty() {
+        return if rows.is_empty() {
+            Usefulness::new_useful(witness_preference)
+        } else {
+            NotUseful
+        };
+    };
+
+    assert!(rows.iter().all(|r| r.len() == v.len()));
+
+    // If the first pattern is an or-pattern, expand it.
+    if let Some(vs) = v.expand_or_pat() {
+        // We need to push the already-seen patterns into the matrix in order to detect redundant
+        // branches like `Some(_) | Some(0)`. We also keep track of the unreachable subpatterns.
+        let mut matrix = matrix.clone();
+        let mut unreachable_pats = Vec::new();
+        let mut any_is_useful = false;
+        for v in vs {
+            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
+            match res {
+                Useful(pats) => {
+                    any_is_useful = true;
+                    unreachable_pats.extend(pats);
+                }
+                NotUseful => unreachable_pats.push(v.head()),
+                UsefulWithWitness(_) => {
+                    bug!("Encountered or-pat in `v` during exhaustiveness checking")
+                }
+            }
+            matrix.push(v);
+        }
+        return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
+    }
+
+    let (ty, span) = matrix
+        .heads()
+        .map(|r| (r.ty, r.span))
+        .find(|(ty, _)| !ty.references_error())
+        .unwrap_or((v.head().ty, v.head().span));
+    let pcx = PatCtxt {
+        // TyErr is used to represent the type of wildcard patterns matching
+        // against inaccessible (private) fields of structs, so that we won't
+        // be able to observe whether the types of the struct's fields are
+        // inhabited.
+        //
+        // If the field is truly inaccessible, then all the patterns
+        // matching against it must be wildcard patterns, so its type
+        // does not matter.
+        //
+        // However, if we are matching against non-wildcard patterns, we
+        // need to know the real type of the field so we can specialize
+        // against it. This primarily occurs through constants - they
+        // can include contents for fields that are inaccessible at the
+        // location of the match. In that case, the field's type is
+        // inhabited - by the constant - so we can just use it.
+        //
+        // FIXME: this might lead to "unstable" behavior with macro hygiene
+        // introducing uninhabited patterns for inaccessible fields. We
+        // need to figure out how to model that.
+        ty,
+        span,
+    };
+
+    debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
+
+    if let Some(constructor) = pat_constructor(cx.tcx, cx.param_env, v.head()) {
+        debug!("is_useful - expanding constructor: {:#?}", constructor);
+        split_grouped_constructors(
+            cx.tcx,
+            cx.param_env,
+            pcx,
+            vec![constructor],
+            matrix,
+            pcx.span,
+            Some(hir_id),
+        )
+        .into_iter()
+        .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
+        .find(|result| result.is_useful())
+        .unwrap_or(NotUseful)
+    } else {
+        debug!("is_useful - expanding wildcard");
+
+        let used_ctors: Vec<Constructor<'_>> =
+            matrix.heads().filter_map(|p| pat_constructor(cx.tcx, cx.param_env, p)).collect();
+        debug!("used_ctors = {:#?}", used_ctors);
+        // `all_ctors` are all the constructors for the given type, which
+        // should all be represented (or caught with the wild pattern `_`).
+        let all_ctors = all_constructors(cx, pcx);
+        debug!("all_ctors = {:#?}", all_ctors);
+
+        // `missing_ctors` is the set of constructors from the same type as the
+        // first column of `matrix` that are matched only by wildcard patterns
+        // from the first column.
+        //
+        // Therefore, if there is some pattern that is unmatched by `matrix`,
+        // it will still be unmatched if the first constructor is replaced by
+        // any of the constructors in `missing_ctors`
+
+        // Missing constructors are those that are not matched by any non-wildcard patterns in the
+        // current column. We only fully construct them on-demand, because they're rarely used and
+        // can be big.
+        let missing_ctors = MissingConstructors::new(all_ctors, used_ctors);
+
+        debug!("missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
+
+        if missing_ctors.is_empty() {
+            let (all_ctors, _) = missing_ctors.into_inner();
+            split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None)
+                .into_iter()
+                .map(|c| {
+                    is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id)
+                })
+                .find(|result| result.is_useful())
+                .unwrap_or(NotUseful)
+        } else {
+            let matrix = matrix.specialize_wildcard();
+            let v = v.to_tail();
+            let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
+
+            // In this case, there's at least one "free"
+            // constructor that is only matched against by
+            // wildcard patterns.
+            //
+            // There are 2 ways we can report a witness here.
+            // Commonly, we can report all the "free"
+            // constructors as witnesses, e.g., if we have:
+            //
+            // ```
+            //     enum Direction { N, S, E, W }
+            //     let Direction::N = ...;
+            // ```
+            //
+            // we can report 3 witnesses: `S`, `E`, and `W`.
+            //
+            // However, there is a case where we don't want
+            // to do this and instead report a single `_` witness:
+            // if the user didn't actually specify a constructor
+            // in this arm, e.g., in
+            // ```
+            //     let x: (Direction, Direction, bool) = ...;
+            //     let (_, _, false) = x;
+            // ```
+            // we don't want to show all 16 possible witnesses
+            // `(<direction-1>, <direction-2>, true)` - we are
+            // satisfied with `(_, _, true)`. In this case,
+            // `used_ctors` is empty.
+            // The exception is: if we are at the top-level, for example in an empty match, we
+            // sometimes prefer reporting the list of constructors instead of just `_`.
+            let report_ctors_rather_than_wildcard = is_top_level && !IntRange::is_integral(pcx.ty);
+            if missing_ctors.all_ctors_are_missing() && !report_ctors_rather_than_wildcard {
+                // All constructors are unused. Add a wild pattern
+                // rather than each individual constructor.
+                usefulness.apply_wildcard(pcx.ty)
+            } else {
+                // Construct for each missing constructor a "wild" version of this
+                // constructor, that matches everything that can be built with
+                // it. For example, if `ctor` is a `Constructor::Variant` for
+                // `Option::Some`, we get the pattern `Some(_)`.
+                usefulness.apply_missing_ctors(cx, pcx.ty, &missing_ctors)
+            }
+        }
+    }
+}
+
+/// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied
+/// to the specialised version of both the pattern matrix `P` and the new pattern `q`.
+fn is_useful_specialized<'p, 'tcx>(
+    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+    matrix: &Matrix<'p, 'tcx>,
+    v: &PatStack<'p, 'tcx>,
+    ctor: Constructor<'tcx>,
+    lty: Ty<'tcx>,
+    witness_preference: WitnessPreference,
+    hir_id: HirId,
+) -> Usefulness<'tcx, 'p> {
+    debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
+
+    let ctor_wild_subpatterns =
+        cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
+    let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
+    v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
+        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false))
+        .map(|u| u.apply_constructor(cx, &ctor, lty))
+        .unwrap_or(NotUseful)
+}
+
+/// Determines the constructor that the given pattern can be specialized to.
+/// Returns `None` in case of a catch-all, which can't be specialized.
+fn pat_constructor<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    pat: &Pat<'tcx>,
+) -> Option<Constructor<'tcx>> {
+    match *pat.kind {
+        PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
+        PatKind::Binding { .. } | PatKind::Wild => None,
+        PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(Single),
+        PatKind::Variant { adt_def, variant_index, .. } => {
+            Some(Variant(adt_def.variants[variant_index].def_id))
+        }
+        PatKind::Constant { value } => {
+            if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
+                Some(IntRange(int_range))
+            } else {
+                match (value.val, &value.ty.kind) {
+                    (_, ty::Array(_, n)) => {
+                        let len = n.eval_usize(tcx, param_env);
+                        Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) }))
+                    }
+                    (ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => {
+                        let len = (end - start) as u64;
+                        Some(Slice(Slice { array_len: None, kind: FixedLen(len) }))
+                    }
+                    // FIXME(oli-obk): implement `deref` for `ConstValue`
+                    // (ty::ConstKind::Value(ConstValue::ByRef { .. }), ty::Slice(_)) => { ... }
+                    _ => Some(ConstantValue(value)),
+                }
+            }
+        }
+        PatKind::Range(PatRange { lo, hi, end }) => {
+            let ty = lo.ty;
+            if let Some(int_range) = IntRange::from_range(
+                tcx,
+                lo.eval_bits(tcx, param_env, lo.ty),
+                hi.eval_bits(tcx, param_env, hi.ty),
+                ty,
+                &end,
+                pat.span,
+            ) {
+                Some(IntRange(int_range))
+            } else {
+                Some(FloatRange(lo, hi, end))
+            }
+        }
+        PatKind::Array { ref prefix, ref slice, ref suffix }
+        | PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+            let array_len = match pat.ty.kind {
+                ty::Array(_, length) => Some(length.eval_usize(tcx, param_env)),
+                ty::Slice(_) => None,
+                _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
+            };
+            let prefix = prefix.len() as u64;
+            let suffix = suffix.len() as u64;
+            let kind =
+                if slice.is_some() { VarLen(prefix, suffix) } else { FixedLen(prefix + suffix) };
+            Some(Slice(Slice { array_len, kind }))
+        }
+        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
+    }
+}
+
+// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
+// meaning all other types will compare unequal and thus equal patterns often do not cause the
+// second pattern to lint about unreachable match arms.
+fn slice_pat_covered_by_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    _span: Span,
+    const_val: &'tcx ty::Const<'tcx>,
+    prefix: &[Pat<'tcx>],
+    slice: &Option<Pat<'tcx>>,
+    suffix: &[Pat<'tcx>],
+    param_env: ty::ParamEnv<'tcx>,
+) -> Result<bool, ErrorReported> {
+    let const_val_val = if let ty::ConstKind::Value(val) = const_val.val {
+        val
+    } else {
+        bug!(
+            "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
+            const_val,
+            prefix,
+            slice,
+            suffix,
+        )
+    };
+
+    let data: &[u8] = match (const_val_val, &const_val.ty.kind) {
+        (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => {
+            assert_eq!(*t, tcx.types.u8);
+            let n = n.eval_usize(tcx, param_env);
+            let ptr = Pointer::new(AllocId(0), offset);
+            alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
+        }
+        (ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
+            assert_eq!(*t, tcx.types.u8);
+            let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64));
+            data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap()
+        }
+        // FIXME(oli-obk): create a way to extract fat pointers from ByRef
+        (_, ty::Slice(_)) => return Ok(false),
+        _ => bug!(
+            "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
+            const_val,
+            prefix,
+            slice,
+            suffix,
+        ),
+    };
+
+    let pat_len = prefix.len() + suffix.len();
+    if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
+        return Ok(false);
+    }
+
+    for (ch, pat) in data[..prefix.len()]
+        .iter()
+        .zip(prefix)
+        .chain(data[data.len() - suffix.len()..].iter().zip(suffix))
+    {
+        match pat.kind {
+            box PatKind::Constant { value } => {
+                let b = value.eval_bits(tcx, param_env, pat.ty);
+                assert_eq!(b as u8 as u128, b);
+                if b as u8 != *ch {
+                    return Ok(false);
+                }
+            }
+            _ => {}
+        }
+    }
+
+    Ok(true)
+}
+
+/// For exhaustive integer matching, some constructors are grouped within other constructors
+/// (namely integer typed values are grouped within ranges). However, when specialising these
+/// constructors, we want to be specialising for the underlying constructors (the integers), not
+/// the groups (the ranges). Thus we need to split the groups up. Splitting them up naïvely would
+/// mean creating a separate constructor for every single value in the range, which is clearly
+/// impractical. However, observe that for some ranges of integers, the specialisation will be
+/// identical across all values in that range (i.e., there are equivalence classes of ranges of
+/// constructors based on their `is_useful_specialized` outcome). These classes are grouped by
+/// the patterns that apply to them (in the matrix `P`). We can split the range whenever the
+/// patterns that apply to that range (specifically: the patterns that *intersect* with that range)
+/// change.
+/// Our solution, therefore, is to split the range constructor into subranges at every single point
+/// the group of intersecting patterns changes (using the method described below).
+/// And voilà! We're testing precisely those ranges that we need to, without any exhaustive matching
+/// on actual integers. The nice thing about this is that the number of subranges is linear in the
+/// number of rows in the matrix (i.e., the number of cases in the `match` statement), so we don't
+/// need to be worried about matching over gargantuan ranges.
+///
+/// Essentially, given the first column of a matrix representing ranges, looking like the following:
+///
+/// |------|  |----------| |-------|    ||
+///    |-------| |-------|            |----| ||
+///       |---------|
+///
+/// We split the ranges up into equivalence classes so the ranges are no longer overlapping:
+///
+/// |--|--|||-||||--||---|||-------|  |-|||| ||
+///
+/// The logic for determining how to split the ranges is fairly straightforward: we calculate
+/// boundaries for each interval range, sort them, then create constructors for each new interval
+/// between every pair of boundary points. (This essentially sums up to performing the intuitive
+/// merging operation depicted above.)
+///
+/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
+/// ranges that case.
+///
+/// This also splits variable-length slices into fixed-length slices.
+fn split_grouped_constructors<'p, 'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    pcx: PatCtxt<'tcx>,
+    ctors: Vec<Constructor<'tcx>>,
+    matrix: &Matrix<'p, 'tcx>,
+    span: Span,
+    hir_id: Option<HirId>,
+) -> Vec<Constructor<'tcx>> {
+    let ty = pcx.ty;
+    let mut split_ctors = Vec::with_capacity(ctors.len());
+    debug!("split_grouped_constructors({:#?}, {:#?})", matrix, ctors);
+
+    for ctor in ctors.into_iter() {
+        match ctor {
+            IntRange(ctor_range) if ctor_range.treat_exhaustively(tcx) => {
+                // Fast-track if the range is trivial. In particular, don't do the overlapping
+                // ranges check.
+                if ctor_range.is_singleton() {
+                    split_ctors.push(IntRange(ctor_range));
+                    continue;
+                }
+
+                /// Represents a border between 2 integers. Because the intervals spanning borders
+                /// must be able to cover every integer, we need to be able to represent
+                /// 2^128 + 1 such borders.
+                #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
+                enum Border {
+                    JustBefore(u128),
+                    AfterMax,
+                }
+
+                // A function for extracting the borders of an integer interval.
+                fn range_borders(r: IntRange<'_>) -> impl Iterator<Item = Border> {
+                    let (lo, hi) = r.range.into_inner();
+                    let from = Border::JustBefore(lo);
+                    let to = match hi.checked_add(1) {
+                        Some(m) => Border::JustBefore(m),
+                        None => Border::AfterMax,
+                    };
+                    vec![from, to].into_iter()
+                }
+
+                // Collect the span and range of all the intersecting ranges to lint on likely
+                // incorrect range patterns. (#63987)
+                let mut overlaps = vec![];
+                // `borders` is the set of borders between equivalence classes: each equivalence
+                // class lies between 2 borders.
+                let row_borders = matrix
+                    .0
+                    .iter()
+                    .flat_map(|row| {
+                        IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len()))
+                    })
+                    .flat_map(|(range, row_len)| {
+                        let intersection = ctor_range.intersection(tcx, &range);
+                        let should_lint = ctor_range.suspicious_intersection(&range);
+                        if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
+                            // FIXME: for now, only check for overlapping ranges on simple range
+                            // patterns. Otherwise with the current logic the following is detected
+                            // as overlapping:
+                            //   match (10u8, true) {
+                            //    (0 ..= 125, false) => {}
+                            //    (126 ..= 255, false) => {}
+                            //    (0 ..= 255, true) => {}
+                            //  }
+                            overlaps.push(range.clone());
+                        }
+                        intersection
+                    })
+                    .flat_map(|range| range_borders(range));
+                let ctor_borders = range_borders(ctor_range.clone());
+                let mut borders: Vec<_> = row_borders.chain(ctor_borders).collect();
+                borders.sort_unstable();
+
+                lint_overlapping_patterns(tcx, hir_id, ctor_range, ty, overlaps);
+
+                // We're going to iterate through every adjacent pair of borders, making sure that
+                // each represents an interval of nonnegative length, and convert each such
+                // interval into a constructor.
+                split_ctors.extend(
+                    borders
+                        .windows(2)
+                        .filter_map(|window| match (window[0], window[1]) {
+                            (Border::JustBefore(n), Border::JustBefore(m)) => {
+                                if n < m {
+                                    Some(IntRange { range: n..=(m - 1), ty, span })
+                                } else {
+                                    None
+                                }
+                            }
+                            (Border::JustBefore(n), Border::AfterMax) => {
+                                Some(IntRange { range: n..=u128::MAX, ty, span })
+                            }
+                            (Border::AfterMax, _) => None,
+                        })
+                        .map(IntRange),
+                );
+            }
+            Slice(Slice { array_len, kind: VarLen(self_prefix, self_suffix) }) => {
+                // The exhaustiveness-checking paper does not include any details on
+                // checking variable-length slice patterns. However, they are matched
+                // by an infinite collection of fixed-length array patterns.
+                //
+                // Checking the infinite set directly would take an infinite amount
+                // of time. However, it turns out that for each finite set of
+                // patterns `P`, all sufficiently large array lengths are equivalent:
+                //
+                // Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
+                // to exactly the subset `Pₜ` of `P` can be transformed to a slice
+                // `sₘ` for each sufficiently-large length `m` that applies to exactly
+                // the same subset of `P`.
+                //
+                // Because of that, each witness for reachability-checking from one
+                // of the sufficiently-large lengths can be transformed to an
+                // equally-valid witness from any other length, so we only have
+                // to check slice lengths from the "minimal sufficiently-large length"
+                // and below.
+                //
+                // Note that the fact that there is a *single* `sₘ` for each `m`
+                // not depending on the specific pattern in `P` is important: if
+                // you look at the pair of patterns
+                //     `[true, ..]`
+                //     `[.., false]`
+                // Then any slice of length ≥1 that matches one of these two
+                // patterns can be trivially turned to a slice of any
+                // other length ≥1 that matches them and vice-versa - for
+                // but the slice from length 2 `[false, true]` that matches neither
+                // of these patterns can't be turned to a slice from length 1 that
+                // matches neither of these patterns, so we have to consider
+                // slices from length 2 there.
+                //
+                // Now, to see that that length exists and find it, observe that slice
+                // patterns are either "fixed-length" patterns (`[_, _, _]`) or
+                // "variable-length" patterns (`[_, .., _]`).
+                //
+                // For fixed-length patterns, all slices with lengths *longer* than
+                // the pattern's length have the same outcome (of not matching), so
+                // as long as `L` is greater than the pattern's length we can pick
+                // any `sₘ` from that length and get the same result.
+                //
+                // For variable-length patterns, the situation is more complicated,
+                // because as seen above the precise value of `sₘ` matters.
+                //
+                // However, for each variable-length pattern `p` with a prefix of length
+                // `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
+                // `slₚ` elements are examined.
+                //
+                // Therefore, as long as `L` is positive (to avoid concerns about empty
+                // types), all elements after the maximum prefix length and before
+                // the maximum suffix length are not examined by any variable-length
+                // pattern, and therefore can be added/removed without affecting
+                // them - creating equivalent patterns from any sufficiently-large
+                // length.
+                //
+                // Of course, if fixed-length patterns exist, we must be sure
+                // that our length is large enough to miss them all, so
+                // we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
+                //
+                // for example, with the above pair of patterns, all elements
+                // but the first and last can be added/removed, so any
+                // witness of length ≥2 (say, `[false, false, true]`) can be
+                // turned to a witness from any other length ≥2.
+
+                let mut max_prefix_len = self_prefix;
+                let mut max_suffix_len = self_suffix;
+                let mut max_fixed_len = 0;
+
+                let head_ctors =
+                    matrix.heads().filter_map(|pat| pat_constructor(tcx, param_env, pat));
+                for ctor in head_ctors {
+                    match ctor {
+                        Slice(slice) => match slice.pattern_kind() {
+                            FixedLen(len) => {
+                                max_fixed_len = cmp::max(max_fixed_len, len);
+                            }
+                            VarLen(prefix, suffix) => {
+                                max_prefix_len = cmp::max(max_prefix_len, prefix);
+                                max_suffix_len = cmp::max(max_suffix_len, suffix);
+                            }
+                        },
+                        _ => {}
+                    }
+                }
+
+                // For diagnostics, we keep the prefix and suffix lengths separate, so in the case
+                // where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly,
+                // so that `L = max_prefix_len + max_suffix_len`.
+                if max_fixed_len + 1 >= max_prefix_len + max_suffix_len {
+                    // The subtraction can't overflow thanks to the above check.
+                    // The new `max_prefix_len` is also guaranteed to be larger than its previous
+                    // value.
+                    max_prefix_len = max_fixed_len + 1 - max_suffix_len;
+                }
+
+                match array_len {
+                    Some(len) => {
+                        let kind = if max_prefix_len + max_suffix_len < len {
+                            VarLen(max_prefix_len, max_suffix_len)
+                        } else {
+                            FixedLen(len)
+                        };
+                        split_ctors.push(Slice(Slice { array_len, kind }));
+                    }
+                    None => {
+                        // `ctor` originally covered the range `(self_prefix +
+                        // self_suffix..infinity)`. We now split it into two: lengths smaller than
+                        // `max_prefix_len + max_suffix_len` are treated independently as
+                        // fixed-lengths slices, and lengths above are captured by a final VarLen
+                        // constructor.
+                        split_ctors.extend(
+                            (self_prefix + self_suffix..max_prefix_len + max_suffix_len)
+                                .map(|len| Slice(Slice { array_len, kind: FixedLen(len) })),
+                        );
+                        split_ctors.push(Slice(Slice {
+                            array_len,
+                            kind: VarLen(max_prefix_len, max_suffix_len),
+                        }));
+                    }
+                }
+            }
+            // Any other constructor can be used unchanged.
+            _ => split_ctors.push(ctor),
+        }
+    }
+
+    debug!("split_grouped_constructors(..)={:#?}", split_ctors);
+    split_ctors
+}
+
+fn lint_overlapping_patterns<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hir_id: Option<HirId>,
+    ctor_range: IntRange<'tcx>,
+    ty: Ty<'tcx>,
+    overlaps: Vec<IntRange<'tcx>>,
+) {
+    if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
+        let mut err = tcx.struct_span_lint_hir(
+            lint::builtin::OVERLAPPING_PATTERNS,
+            hir_id,
+            ctor_range.span,
+            "multiple patterns covering the same range",
+        );
+        err.span_label(ctor_range.span, "overlapping patterns");
+        for int_range in overlaps {
+            // Use the real type for user display of the ranges:
+            err.span_label(
+                int_range.span,
+                &format!(
+                    "this range overlaps on `{}`",
+                    IntRange { range: int_range.range, ty, span: DUMMY_SP }.to_pat(tcx),
+                ),
+            );
+        }
+        err.emit();
+    }
+}
+
+fn constructor_covered_by_range<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ctor: &Constructor<'tcx>,
+    pat: &Pat<'tcx>,
+) -> Option<()> {
+    if let Single = ctor {
+        return Some(());
+    }
+
+    let (pat_from, pat_to, pat_end, ty) = match *pat.kind {
+        PatKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
+        PatKind::Range(PatRange { lo, hi, end }) => (lo, hi, end, lo.ty),
+        _ => bug!("`constructor_covered_by_range` called with {:?}", pat),
+    };
+    let (ctor_from, ctor_to, ctor_end) = match *ctor {
+        ConstantValue(value) => (value, value, RangeEnd::Included),
+        FloatRange(from, to, ctor_end) => (from, to, ctor_end),
+        _ => bug!("`constructor_covered_by_range` called with {:?}", ctor),
+    };
+    trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, pat_from, pat_to, ty);
+
+    let to = compare_const_vals(tcx, ctor_to, pat_to, param_env, ty)?;
+    let from = compare_const_vals(tcx, ctor_from, pat_from, param_env, ty)?;
+    let intersects = (from == Ordering::Greater || from == Ordering::Equal)
+        && (to == Ordering::Less || (pat_end == ctor_end && to == Ordering::Equal));
+    if intersects { Some(()) } else { None }
+}
+
+fn patterns_for_variant<'p, 'tcx>(
+    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+    subpatterns: &'p [FieldPat<'tcx>],
+    ctor_wild_subpatterns: &'p [Pat<'tcx>],
+    is_non_exhaustive: bool,
+) -> PatStack<'p, 'tcx> {
+    let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect();
+
+    for subpat in subpatterns {
+        if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
+            result[subpat.field.index()] = &subpat.pattern;
+        }
+    }
+
+    debug!(
+        "patterns_for_variant({:#?}, {:#?}) = {:#?}",
+        subpatterns, ctor_wild_subpatterns, result
+    );
+    PatStack::from_vec(result)
+}
+
+/// This is the main specialization step. It expands the pattern
+/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
+/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
+/// Returns `None` if the pattern does not have the given constructor.
+///
+/// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
+/// different patterns.
+/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
+/// fields filled with wild patterns.
+fn specialize_one_pattern<'p, 'tcx>(
+    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+    pat: &'p Pat<'tcx>,
+    constructor: &Constructor<'tcx>,
+    ctor_wild_subpatterns: &'p [Pat<'tcx>],
+) -> Option<PatStack<'p, 'tcx>> {
+    if let NonExhaustive = constructor {
+        // Only a wildcard pattern can match the special extra constructor
+        return if pat.is_wildcard() { Some(PatStack::default()) } else { None };
+    }
+
+    let result = match *pat.kind {
+        PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
+
+        PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()),
+
+        PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
+            let ref variant = adt_def.variants[variant_index];
+            let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant);
+            Some(Variant(variant.def_id))
+                .filter(|variant_constructor| variant_constructor == constructor)
+                .map(|_| {
+                    patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, is_non_exhaustive)
+                })
+        }
+
+        PatKind::Leaf { ref subpatterns } => {
+            Some(patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, false))
+        }
+
+        PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
+
+        PatKind::Constant { value } if constructor.is_slice() => {
+            // We extract an `Option` for the pointer because slices of zero
+            // elements don't necessarily point to memory, they are usually
+            // just integers. The only time they should be pointing to memory
+            // is when they are subslices of nonzero slices.
+            let (alloc, offset, n, ty) = match value.ty.kind {
+                ty::Array(t, n) => {
+                    let n = n.eval_usize(cx.tcx, cx.param_env);
+                    // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce,
+                    // the result would be exactly what we early return here.
+                    if n == 0 {
+                        if ctor_wild_subpatterns.len() as u64 == 0 {
+                            return Some(PatStack::from_slice(&[]));
+                        } else {
+                            return None;
+                        }
+                    }
+                    match value.val {
+                        ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
+                            (Cow::Borrowed(alloc), offset, n, t)
+                        }
+                        _ => span_bug!(pat.span, "array pattern is {:?}", value,),
+                    }
+                }
+                ty::Slice(t) => {
+                    match value.val {
+                        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
+                            let offset = Size::from_bytes(start as u64);
+                            let n = (end - start) as u64;
+                            (Cow::Borrowed(data), offset, n, t)
+                        }
+                        ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
+                            // FIXME(oli-obk): implement `deref` for `ConstValue`
+                            return None;
+                        }
+                        _ => span_bug!(
+                            pat.span,
+                            "slice pattern constant must be scalar pair but is {:?}",
+                            value,
+                        ),
+                    }
+                }
+                _ => span_bug!(
+                    pat.span,
+                    "unexpected const-val {:?} with ctor {:?}",
+                    value,
+                    constructor,
+                ),
+            };
+            if ctor_wild_subpatterns.len() as u64 == n {
+                // convert a constant slice/array pattern to a list of patterns.
+                let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
+                let ptr = Pointer::new(AllocId(0), offset);
+                (0..n)
+                    .map(|i| {
+                        let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
+                        let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
+                        let scalar = scalar.not_undef().ok()?;
+                        let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
+                        let pattern =
+                            Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
+                        Some(&*cx.pattern_arena.alloc(pattern))
+                    })
+                    .collect()
+            } else {
+                None
+            }
+        }
+
+        PatKind::Constant { .. } | PatKind::Range { .. } => {
+            // If the constructor is a:
+            // - Single value: add a row if the pattern contains the constructor.
+            // - Range: add a row if the constructor intersects the pattern.
+            if let IntRange(ctor) = constructor {
+                match IntRange::from_pat(cx.tcx, cx.param_env, pat) {
+                    Some(pat) => ctor.intersection(cx.tcx, &pat).map(|_| {
+                        // Constructor splitting should ensure that all intersections we encounter
+                        // are actually inclusions.
+                        assert!(ctor.is_subrange(&pat));
+                        PatStack::default()
+                    }),
+                    _ => None,
+                }
+            } else {
+                // Fallback for non-ranges and ranges that involve
+                // floating-point numbers, which are not conveniently handled
+                // by `IntRange`. For these cases, the constructor may not be a
+                // range so intersection actually devolves into being covered
+                // by the pattern.
+                constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat)
+                    .map(|()| PatStack::default())
+            }
+        }
+
+        PatKind::Array { ref prefix, ref slice, ref suffix }
+        | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
+            Slice(_) => {
+                let pat_len = prefix.len() + suffix.len();
+                if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
+                    if slice_count == 0 || slice.is_some() {
+                        Some(
+                            prefix
+                                .iter()
+                                .chain(
+                                    ctor_wild_subpatterns
+                                        .iter()
+                                        .skip(prefix.len())
+                                        .take(slice_count)
+                                        .chain(suffix.iter()),
+                                )
+                                .collect(),
+                        )
+                    } else {
+                        None
+                    }
+                } else {
+                    None
+                }
+            }
+            ConstantValue(cv) => {
+                match slice_pat_covered_by_const(
+                    cx.tcx,
+                    pat.span,
+                    cv,
+                    prefix,
+                    slice,
+                    suffix,
+                    cx.param_env,
+                ) {
+                    Ok(true) => Some(PatStack::default()),
+                    Ok(false) => None,
+                    Err(ErrorReported) => None,
+                }
+            }
+            _ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
+        },
+
+        PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
+    };
+    debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
+
+    result
+}
diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs
new file mode 100644 (file)
index 0000000..84d57a8
--- /dev/null
@@ -0,0 +1,755 @@
+use super::_match::Usefulness::*;
+use super::_match::WitnessPreference::*;
+use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack};
+
+use super::{PatCtxt, PatKind, PatternError};
+
+use rustc::hir::map::Map;
+use rustc::lint;
+use rustc::session::parse::feature_err;
+use rustc::session::Session;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc_error_codes::*;
+use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_hir as hir;
+use rustc_hir::def::*;
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::{HirId, Pat};
+use rustc_span::symbol::sym;
+use rustc_span::{MultiSpan, Span};
+use syntax::ast::Mutability;
+
+use std::slice;
+
+crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
+    let body_id = match tcx.hir().as_local_hir_id(def_id) {
+        None => return,
+        Some(id) => tcx.hir().body_owned_by(id),
+    };
+
+    let mut visitor =
+        MatchVisitor { tcx, tables: tcx.body_tables(body_id), param_env: tcx.param_env(def_id) };
+    visitor.visit_body(tcx.hir().body(body_id));
+}
+
+fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> {
+    struct_span_err!(sess, sp, E0004, "{}", &error_message)
+}
+
+struct MatchVisitor<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    tables: &'a ty::TypeckTables<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+        intravisit::walk_expr(self, ex);
+
+        if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.kind {
+            self.check_match(scrut, arms, source);
+        }
+    }
+
+    fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) {
+        intravisit::walk_local(self, loc);
+
+        let (msg, sp) = match loc.source {
+            hir::LocalSource::Normal => ("local binding", Some(loc.span)),
+            hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
+            hir::LocalSource::AsyncFn => ("async fn binding", None),
+            hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
+        };
+        self.check_irrefutable(&loc.pat, msg, sp);
+
+        // Check legality of move bindings and `@` patterns.
+        self.check_patterns(false, &loc.pat);
+    }
+
+    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
+        intravisit::walk_body(self, body);
+
+        for param in body.params {
+            self.check_irrefutable(&param.pat, "function argument", None);
+            self.check_patterns(false, &param.pat);
+        }
+    }
+}
+
+impl PatCtxt<'_, '_> {
+    fn report_inlining_errors(&self, pat_span: Span) {
+        for error in &self.errors {
+            match *error {
+                PatternError::StaticInPattern(span) => {
+                    self.span_e0158(span, "statics cannot be referenced in patterns")
+                }
+                PatternError::AssocConstInPattern(span) => {
+                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
+                }
+                PatternError::FloatBug => {
+                    // FIXME(#31407) this is only necessary because float parsing is buggy
+                    ::rustc::mir::interpret::struct_error(
+                        self.tcx.at(pat_span),
+                        "could not evaluate float literal (see issue #31407)",
+                    )
+                    .emit();
+                }
+                PatternError::NonConstPath(span) => {
+                    ::rustc::mir::interpret::struct_error(
+                        self.tcx.at(span),
+                        "runtime values cannot be referenced in patterns",
+                    )
+                    .emit();
+                }
+            }
+        }
+    }
+
+    fn span_e0158(&self, span: Span, text: &str) {
+        struct_span_err!(self.tcx.sess, span, E0158, "{}", text).emit();
+    }
+}
+
+impl<'tcx> MatchVisitor<'_, 'tcx> {
+    fn check_patterns(&mut self, has_guard: bool, pat: &Pat<'_>) {
+        check_legality_of_move_bindings(self, has_guard, pat);
+        check_borrow_conflicts_in_at_patterns(self, pat);
+        if !self.tcx.features().bindings_after_at {
+            check_legality_of_bindings_in_at_patterns(self, pat);
+        }
+    }
+
+    fn check_match(
+        &mut self,
+        scrut: &hir::Expr<'_>,
+        arms: &'tcx [hir::Arm<'tcx>],
+        source: hir::MatchSource,
+    ) {
+        for arm in arms {
+            // First, check legality of move bindings.
+            self.check_patterns(arm.guard.is_some(), &arm.pat);
+
+            // Second, perform some lints.
+            check_for_bindings_named_same_as_variants(self, &arm.pat);
+        }
+
+        let module = self.tcx.hir().get_module_parent(scrut.hir_id);
+        MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
+            let mut have_errors = false;
+
+            let inlined_arms: Vec<_> = arms
+                .iter()
+                .map(|arm| {
+                    let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
+                    patcx.include_lint_checks();
+                    let pattern = patcx.lower_pattern(&arm.pat);
+                    let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
+                    if !patcx.errors.is_empty() {
+                        patcx.report_inlining_errors(arm.pat.span);
+                        have_errors = true;
+                    }
+                    (pattern, &*arm.pat, arm.guard.is_some())
+                })
+                .collect();
+
+            // Bail out early if inlining failed.
+            if have_errors {
+                return;
+            }
+
+            // Fourth, check for unreachable arms.
+            let matrix = check_arms(cx, &inlined_arms, source);
+
+            // Fifth, check if the match is exhaustive.
+            let scrut_ty = self.tables.node_type(scrut.hir_id);
+            // 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 is_empty_match = inlined_arms.is_empty();
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
+        })
+    }
+
+    fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
+        let module = self.tcx.hir().get_module_parent(pat.hir_id);
+        MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
+            let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
+            patcx.include_lint_checks();
+            let pattern = patcx.lower_pattern(pat);
+            let pattern_ty = pattern.ty;
+            let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
+            let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
+
+            let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
+                Ok(_) => return,
+                Err(err) => err,
+            };
+
+            let joined_patterns = joined_uncovered_patterns(&witnesses);
+            let mut err = struct_span_err!(
+                self.tcx.sess,
+                pat.span,
+                E0005,
+                "refutable pattern in {}: {} not covered",
+                origin,
+                joined_patterns
+            );
+            let suggest_if_let = match &pat.kind {
+                hir::PatKind::Path(hir::QPath::Resolved(None, path))
+                    if path.segments.len() == 1 && path.segments[0].args.is_none() =>
+                {
+                    const_not_var(&mut err, cx.tcx, pat, path);
+                    false
+                }
+                _ => {
+                    err.span_label(
+                        pat.span,
+                        pattern_not_covered_label(&witnesses, &joined_patterns),
+                    );
+                    true
+                }
+            };
+
+            if let (Some(span), true) = (sp, suggest_if_let) {
+                err.note(
+                    "`let` bindings require an \"irrefutable pattern\", like a `struct` or \
+                     an `enum` with only one variant",
+                );
+                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                    err.span_suggestion(
+                        span,
+                        "you might want to use `if let` to ignore the variant that isn't matched",
+                        format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
+                        Applicability::HasPlaceholders,
+                    );
+                }
+                err.note(
+                    "for more information, visit \
+                     https://doc.rust-lang.org/book/ch18-02-refutability.html",
+                );
+            }
+
+            adt_defined_here(cx, &mut err, pattern_ty, &witnesses);
+            err.emit();
+        });
+    }
+}
+
+/// A path pattern was interpreted as a constant, not a new variable.
+/// This caused an irrefutable match failure in e.g. `let`.
+fn const_not_var(
+    err: &mut DiagnosticBuilder<'_>,
+    tcx: TyCtxt<'_>,
+    pat: &Pat<'_>,
+    path: &hir::Path<'_>,
+) {
+    let descr = path.res.descr();
+    err.span_label(
+        pat.span,
+        format!("interpreted as {} {} pattern, not a new variable", path.res.article(), descr,),
+    );
+
+    err.span_suggestion(
+        pat.span,
+        "introduce a variable instead",
+        format!("{}_var", path.segments[0].ident).to_lowercase(),
+        // Cannot use `MachineApplicable` as it's not really *always* correct
+        // because there may be such an identifier in scope or the user maybe
+        // really wanted to match against the constant. This is quite unlikely however.
+        Applicability::MaybeIncorrect,
+    );
+
+    if let Some(span) = tcx.hir().res_span(path.res) {
+        err.span_label(span, format!("{} defined here", descr));
+    }
+}
+
+fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
+    pat.walk_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)
+            {
+                let pat_ty = cx.tables.pat_ty(p).peel_refs();
+                if let ty::Adt(edef, _) = pat_ty.kind {
+                    if edef.is_enum()
+                        && edef.variants.iter().any(|variant| {
+                            variant.ident == ident && variant.ctor_kind == CtorKind::Const
+                        })
+                    {
+                        let ty_path = cx.tcx.def_path_str(edef.did);
+                        cx.tcx
+                            .struct_span_lint_hir(
+                                lint::builtin::BINDINGS_WITH_VARIANT_NAME,
+                                p.hir_id,
+                                p.span,
+                                &format!(
+                                    "pattern binding `{}` is named the same as one \
+                                    of the variants of the type `{}`",
+                                    ident, ty_path
+                                ),
+                            )
+                            .code(error_code!(E0170))
+                            .span_suggestion(
+                                p.span,
+                                "to match on the variant, qualify the path",
+                                format!("{}::{}", ty_path, ident),
+                                Applicability::MachineApplicable,
+                            )
+                            .emit();
+                    }
+                }
+            }
+        }
+    });
+}
+
+/// Checks for common cases of "catchall" patterns that may not be intended as such.
+fn pat_is_catchall(pat: &Pat<'_>) -> bool {
+    match pat.kind {
+        hir::PatKind::Binding(.., None) => true,
+        hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
+        hir::PatKind::Ref(ref s, _) => pat_is_catchall(s),
+        hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)),
+        _ => false,
+    }
+}
+
+/// Check for unreachable patterns.
+fn check_arms<'p, 'tcx>(
+    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+    arms: &[(&'p super::Pat<'tcx>, &hir::Pat<'_>, bool)],
+    source: hir::MatchSource,
+) -> Matrix<'p, 'tcx> {
+    let mut seen = Matrix::empty();
+    let mut catchall = None;
+    for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
+        let v = PatStack::from_pattern(pat);
+
+        match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
+            NotUseful => {
+                match source {
+                    hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
+
+                    hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
+                        // check which arm we're on.
+                        match arm_index {
+                            // The arm with the user-specified pattern.
+                            0 => {
+                                cx.tcx.lint_hir(
+                                    lint::builtin::UNREACHABLE_PATTERNS,
+                                    hir_pat.hir_id,
+                                    pat.span,
+                                    "unreachable pattern",
+                                );
+                            }
+                            // The arm with the wildcard pattern.
+                            1 => {
+                                let msg = match source {
+                                    hir::MatchSource::IfLetDesugar { .. } => {
+                                        "irrefutable if-let pattern"
+                                    }
+                                    hir::MatchSource::WhileLetDesugar => {
+                                        "irrefutable while-let pattern"
+                                    }
+                                    _ => bug!(),
+                                };
+                                cx.tcx.lint_hir(
+                                    lint::builtin::IRREFUTABLE_LET_PATTERNS,
+                                    hir_pat.hir_id,
+                                    pat.span,
+                                    msg,
+                                );
+                            }
+                            _ => bug!(),
+                        }
+                    }
+
+                    hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
+                        let mut err = cx.tcx.struct_span_lint_hir(
+                            lint::builtin::UNREACHABLE_PATTERNS,
+                            hir_pat.hir_id,
+                            pat.span,
+                            "unreachable pattern",
+                        );
+                        // if we had a catchall pattern, hint at that
+                        if let Some(catchall) = catchall {
+                            err.span_label(pat.span, "unreachable pattern");
+                            err.span_label(catchall, "matches any value");
+                        }
+                        err.emit();
+                    }
+
+                    // Unreachable patterns in try and await expressions occur when one of
+                    // the arms are an uninhabited type. Which is OK.
+                    hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
+                }
+            }
+            Useful(unreachable_subpatterns) => {
+                for pat in unreachable_subpatterns {
+                    cx.tcx.lint_hir(
+                        lint::builtin::UNREACHABLE_PATTERNS,
+                        hir_pat.hir_id,
+                        pat.span,
+                        "unreachable pattern",
+                    );
+                }
+            }
+            UsefulWithWitness(_) => bug!(),
+        }
+        if !has_guard {
+            seen.push(v);
+            if catchall.is_none() && pat_is_catchall(hir_pat) {
+                catchall = Some(pat.span);
+            }
+        }
+    }
+    seen
+}
+
+fn check_not_useful<'p, 'tcx>(
+    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+    ty: Ty<'tcx>,
+    matrix: &Matrix<'p, 'tcx>,
+    hir_id: HirId,
+) -> Result<(), Vec<super::Pat<'tcx>>> {
+    let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
+    let v = PatStack::from_pattern(wild_pattern);
+    match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) {
+        NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
+        UsefulWithWitness(pats) => Err(if pats.is_empty() {
+            bug!("Exhaustiveness check returned no witnesses")
+        } else {
+            pats.into_iter().map(|w| w.single_pattern()).collect()
+        }),
+        Useful(_) => bug!(),
+    }
+}
+
+fn check_exhaustive<'p, 'tcx>(
+    cx: &mut MatchCheckCtxt<'p, 'tcx>,
+    scrut_ty: Ty<'tcx>,
+    sp: Span,
+    matrix: &Matrix<'p, 'tcx>,
+    hir_id: HirId,
+    is_empty_match: bool,
+) {
+    // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by
+    // `is_useful` to exhaustively match uninhabited types, so we manually check here.
+    if is_empty_match && !cx.tcx.features().exhaustive_patterns {
+        let scrutinee_is_visibly_uninhabited = match scrut_ty.kind {
+            ty::Never => true,
+            ty::Adt(def, _) => {
+                def.is_enum()
+                    && def.variants.is_empty()
+                    && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
+            }
+            _ => false,
+        };
+        if scrutinee_is_visibly_uninhabited {
+            // If the type *is* uninhabited, an empty match is vacuously exhaustive.
+            return;
+        }
+    }
+
+    let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
+        Ok(_) => return,
+        Err(err) => err,
+    };
+
+    let non_empty_enum = match scrut_ty.kind {
+        ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
+        _ => false,
+    };
+    // In the case of an empty match, replace the '`_` not covered' diagnostic with something more
+    // informative.
+    let mut err;
+    if is_empty_match && !non_empty_enum {
+        err = create_e0004(
+            cx.tcx.sess,
+            sp,
+            format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
+        );
+    } else {
+        let joined_patterns = joined_uncovered_patterns(&witnesses);
+        err = create_e0004(
+            cx.tcx.sess,
+            sp,
+            format!("non-exhaustive patterns: {} not covered", joined_patterns),
+        );
+        err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+    };
+
+    adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
+    err.help(
+        "ensure that all possible cases are being handled, \
+         possibly by adding wildcards or more match arms",
+    );
+    err.emit();
+}
+
+fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String {
+    const LIMIT: usize = 3;
+    match witnesses {
+        [] => bug!(),
+        [witness] => format!("`{}`", witness),
+        [head @ .., tail] if head.len() < LIMIT => {
+            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
+            format!("`{}` and `{}`", head.join("`, `"), tail)
+        }
+        _ => {
+            let (head, tail) = witnesses.split_at(LIMIT);
+            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
+            format!("`{}` and {} more", head.join("`, `"), tail.len())
+        }
+    }
+}
+
+fn pattern_not_covered_label(witnesses: &[super::Pat<'_>], joined_patterns: &str) -> String {
+    format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns)
+}
+
+/// Point at the definition of non-covered `enum` variants.
+fn adt_defined_here(
+    cx: &MatchCheckCtxt<'_, '_>,
+    err: &mut DiagnosticBuilder<'_>,
+    ty: Ty<'_>,
+    witnesses: &[super::Pat<'_>],
+) {
+    let ty = ty.peel_refs();
+    if let ty::Adt(def, _) = ty.kind {
+        if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
+            err.span_label(sp, format!("`{}` defined here", ty));
+        }
+
+        if witnesses.len() < 4 {
+            for sp in maybe_point_at_variant(ty, &witnesses) {
+                err.span_label(sp, "not covered");
+            }
+        }
+    }
+}
+
+fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec<Span> {
+    let mut covered = vec![];
+    if let ty::Adt(def, _) = ty.kind {
+        // Don't point at variants that have already been covered due to other patterns to avoid
+        // visual clutter.
+        for pattern in patterns {
+            use PatKind::{AscribeUserType, Deref, Leaf, Or, Variant};
+            match &*pattern.kind {
+                AscribeUserType { subpattern, .. } | Deref { subpattern } => {
+                    covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern)));
+                }
+                Variant { adt_def, variant_index, subpatterns, .. } if adt_def.did == def.did => {
+                    let sp = def.variants[*variant_index].ident.span;
+                    if covered.contains(&sp) {
+                        continue;
+                    }
+                    covered.push(sp);
+
+                    let pats = subpatterns
+                        .iter()
+                        .map(|field_pattern| field_pattern.pattern.clone())
+                        .collect::<Box<[_]>>();
+                    covered.extend(maybe_point_at_variant(ty, &pats));
+                }
+                Leaf { subpatterns } => {
+                    let pats = subpatterns
+                        .iter()
+                        .map(|field_pattern| field_pattern.pattern.clone())
+                        .collect::<Box<[_]>>();
+                    covered.extend(maybe_point_at_variant(ty, &pats));
+                }
+                Or { pats } => {
+                    let pats = pats.iter().cloned().collect::<Box<[_]>>();
+                    covered.extend(maybe_point_at_variant(ty, &pats));
+                }
+                _ => {}
+            }
+        }
+    }
+    covered
+}
+
+/// 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;
+
+    // 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) {
+            by_ref_spans.push(span);
+        }
+    });
+
+    // Find bad by-move spans:
+    let by_move_spans = &mut Vec::new();
+    let mut check_move = |p: &Pat<'_>, sub: Option<&Pat<'_>>| {
+        // Check legality of moving out of the enum.
+        //
+        // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't.
+        if sub.map_or(false, |p| p.contains_bindings()) {
+            struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings")
+                .span_label(p.span, "binds an already bound by-move value by moving it")
+                .emit();
+        } else if !has_guard && !by_ref_spans.is_empty() {
+            by_move_spans.push(p.span);
+        }
+    };
+    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) {
+                let pat_ty = tables.node_type(p.hir_id);
+                if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) {
+                    check_move(p, sub.as_deref());
+                }
+            }
+        }
+    });
+
+    // Found some bad by-move spans, error!
+    if !by_move_spans.is_empty() {
+        let mut err = struct_span_err!(
+            sess,
+            MultiSpan::from_spans(by_move_spans.clone()),
+            E0009,
+            "cannot bind by-move and by-ref in the same pattern",
+        );
+        for span in by_ref_spans.iter() {
+            err.span_label(*span, "by-ref pattern here");
+        }
+        for span in by_move_spans.iter() {
+            err.span_label(*span, "by-move pattern here");
+        }
+        err.emit();
+    }
+}
+
+/// Check that there are no borrow conflicts in `binding @ subpat` patterns.
+///
+/// For example, this would reject:
+/// - `ref x @ Some(ref mut y)`,
+/// - `ref mut x @ Some(ref y)`
+/// - `ref mut x @ Some(ref mut y)`.
+///
+/// This analysis is *not* subsumed by NLL.
+fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
+    let tab = cx.tables;
+    let sess = cx.tcx.sess;
+    // Get the mutability of `p` if it's by-ref.
+    let extract_binding_mut = |hir_id, span| match tab.extract_binding_mode(sess, hir_id, span)? {
+        ty::BindByValue(_) => None,
+        ty::BindByReference(m) => Some(m),
+    };
+    pat.walk_always(|pat| {
+        // Extract `sub` in `binding @ sub`.
+        let (name, sub) = match &pat.kind {
+            hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub),
+            _ => return,
+        };
+
+        // Extract the mutability.
+        let mut_outer = match extract_binding_mut(pat.hir_id, pat.span) {
+            None => return,
+            Some(m) => m,
+        };
+
+        // We now have `ref $mut_outer binding @ sub` (semantically).
+        // Recurse into each binding in `sub` and find mutability conflicts.
+        let mut conflicts_mut_mut = Vec::new();
+        let mut conflicts_mut_ref = Vec::new();
+        sub.each_binding(|_, hir_id, span, _| {
+            if let Some(mut_inner) = extract_binding_mut(hir_id, span) {
+                match (mut_outer, mut_inner) {
+                    (Mutability::Not, Mutability::Not) => {}
+                    (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push(span),
+                    _ => conflicts_mut_ref.push(span),
+                }
+            }
+        });
+
+        // Report errors if any.
+        let binding_span = pat.span.with_hi(name.span.hi());
+        if !conflicts_mut_mut.is_empty() {
+            // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
+            let msg = &format!("cannot borrow `{}` as mutable more than once at a time", name);
+            let mut err = sess.struct_span_err(pat.span, msg);
+            err.span_label(binding_span, "first mutable borrow occurs here");
+            for sp in conflicts_mut_mut {
+                err.span_label(sp, "another mutable borrow occurs here");
+            }
+            for sp in conflicts_mut_ref {
+                err.span_label(sp, "also borrowed as immutable here");
+            }
+            err.emit();
+        } else if !conflicts_mut_ref.is_empty() {
+            // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
+            let (primary, also) = match mut_outer {
+                Mutability::Mut => ("mutable", "immutable"),
+                Mutability::Not => ("immutable", "mutable"),
+            };
+            let msg = &format!(
+                "cannot borrow `{}` as {} because it is also borrowed as {}",
+                name, also, primary,
+            );
+            let mut err = sess.struct_span_err(pat.span, msg);
+            err.span_label(binding_span, &format!("{} borrow occurs here", primary));
+            for sp in conflicts_mut_ref {
+                err.span_label(sp, &format!("{} borrow occurs here", also));
+            }
+            err.emit();
+        }
+    });
+}
+
+/// Forbids bindings in `@` patterns. This used to be is necessary for memory safety,
+/// because of the way rvalues were handled in the borrow check. (See issue #14587.)
+fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
+    AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat);
+
+    struct AtBindingPatternVisitor<'a, 'b, 'tcx> {
+        cx: &'a MatchVisitor<'b, 'tcx>,
+        bindings_allowed: bool,
+    }
+
+    impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> {
+        type Map = Map<'v>;
+
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
+            NestedVisitorMap::None
+        }
+
+        fn visit_pat(&mut self, pat: &Pat<'_>) {
+            match pat.kind {
+                hir::PatKind::Binding(.., ref subpat) => {
+                    if !self.bindings_allowed {
+                        feature_err(
+                            &self.cx.tcx.sess.parse_sess,
+                            sym::bindings_after_at,
+                            pat.span,
+                            "pattern bindings after an `@` are unstable",
+                        )
+                        .emit();
+                    }
+
+                    if subpat.is_some() {
+                        let bindings_were_allowed = self.bindings_allowed;
+                        self.bindings_allowed = false;
+                        intravisit::walk_pat(self, pat);
+                        self.bindings_allowed = bindings_were_allowed;
+                    }
+                }
+                _ => intravisit::walk_pat(self, pat),
+            }
+        }
+    }
+}
diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs
new file mode 100644 (file)
index 0000000..a21a0ee
--- /dev/null
@@ -0,0 +1,263 @@
+use rustc::infer::InferCtxt;
+use rustc::lint;
+use rustc::mir::Field;
+use rustc::traits::predicate_for_trait_def;
+use rustc::traits::{self, ObligationCause, PredicateObligation};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc_hir as hir;
+
+use rustc_index::vec::Idx;
+
+use rustc_span::Span;
+
+use std::cell::Cell;
+
+use super::{FieldPat, Pat, PatCtxt, PatKind};
+
+impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
+    /// Converts an evaluated constant to a pattern (if possible).
+    /// This means aggregate values (like structs and enums) are converted
+    /// to a pattern that matches the value (as if you'd compared via structural equality).
+    pub(super) fn const_to_pat(
+        &self,
+        cv: &'tcx ty::Const<'tcx>,
+        id: hir::HirId,
+        span: Span,
+    ) -> Pat<'tcx> {
+        debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
+        debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
+
+        self.tcx.infer_ctxt().enter(|infcx| {
+            let mut convert = ConstToPat::new(self, id, span, infcx);
+            convert.to_pat(cv)
+        })
+    }
+}
+
+struct ConstToPat<'a, 'tcx> {
+    id: hir::HirId,
+    span: Span,
+    param_env: ty::ParamEnv<'tcx>,
+
+    // This tracks if we signal some hard error for a given const value, so that
+    // we will not subsequently issue an irrelevant lint for the same const
+    // value.
+    saw_const_match_error: Cell<bool>,
+
+    // inference context used for checking `T: Structural` bounds.
+    infcx: InferCtxt<'a, 'tcx>,
+
+    include_lint_checks: bool,
+}
+
+impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
+    fn new(
+        pat_ctxt: &PatCtxt<'_, 'tcx>,
+        id: hir::HirId,
+        span: Span,
+        infcx: InferCtxt<'a, 'tcx>,
+    ) -> Self {
+        ConstToPat {
+            id,
+            span,
+            infcx,
+            param_env: pat_ctxt.param_env,
+            include_lint_checks: pat_ctxt.include_lint_checks,
+            saw_const_match_error: Cell::new(false),
+        }
+    }
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn search_for_structural_match_violation(
+        &self,
+        ty: Ty<'tcx>,
+    ) -> Option<traits::NonStructuralMatchTy<'tcx>> {
+        traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty)
+    }
+
+    fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
+        traits::type_marked_structural(self.id, self.span, &self.infcx, ty)
+    }
+
+    fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
+        // This method is just a wrapper handling a validity check; the heavy lifting is
+        // performed by the recursive `recur` method, which is not meant to be
+        // invoked except by this method.
+        //
+        // once indirect_structural_match is a full fledged error, this
+        // level of indirection can be eliminated
+
+        let inlined_const_as_pat = self.recur(cv);
+
+        if self.include_lint_checks && !self.saw_const_match_error.get() {
+            // If we were able to successfully convert the const to some pat,
+            // double-check that all types in the const implement `Structural`.
+
+            let structural = self.search_for_structural_match_violation(cv.ty);
+            debug!(
+                "search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
+                cv.ty, structural
+            );
+            if let Some(non_sm_ty) = structural {
+                let adt_def = match non_sm_ty {
+                    traits::NonStructuralMatchTy::Adt(adt_def) => adt_def,
+                    traits::NonStructuralMatchTy::Param => {
+                        bug!("use of constant whose type is a parameter inside a pattern")
+                    }
+                };
+                let path = self.tcx().def_path_str(adt_def.did);
+                let msg = format!(
+                    "to use a constant of type `{}` in a pattern, \
+                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                    path, path,
+                );
+
+                // double-check there even *is* a semantic `PartialEq` to dispatch to.
+                //
+                // (If there isn't, then we can safely issue a hard
+                // error, because that's never worked, due to compiler
+                // using `PartialEq::eq` in this scenario in the past.)
+                //
+                // Note: To fix rust-lang/rust#65466, one could lift this check
+                // *before* any structural-match checking, and unconditionally error
+                // if `PartialEq` is not implemented. However, that breaks stable
+                // code at the moment, because types like `for <'a> fn(&'a ())` do
+                // not *yet* implement `PartialEq`. So for now we leave this here.
+                let ty_is_partial_eq: bool = {
+                    let partial_eq_trait_id = self.tcx().lang_items().eq_trait().unwrap();
+                    let obligation: PredicateObligation<'_> = predicate_for_trait_def(
+                        self.tcx(),
+                        self.param_env,
+                        ObligationCause::misc(self.span, self.id),
+                        partial_eq_trait_id,
+                        0,
+                        cv.ty,
+                        &[],
+                    );
+                    // FIXME: should this call a `predicate_must_hold` variant instead?
+                    self.infcx.predicate_may_hold(&obligation)
+                };
+
+                if !ty_is_partial_eq {
+                    // span_fatal avoids ICE from resolution of non-existent method (rare case).
+                    self.tcx().sess.span_fatal(self.span, &msg);
+                } else {
+                    self.tcx().lint_hir(
+                        lint::builtin::INDIRECT_STRUCTURAL_MATCH,
+                        self.id,
+                        self.span,
+                        &msg,
+                    );
+                }
+            }
+        }
+
+        inlined_const_as_pat
+    }
+
+    // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
+    fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
+        let id = self.id;
+        let span = self.span;
+        let tcx = self.tcx();
+        let param_env = self.param_env;
+
+        let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| {
+            vals.iter()
+                .enumerate()
+                .map(|(idx, val)| {
+                    let field = Field::new(idx);
+                    FieldPat { field, pattern: self.recur(val) }
+                })
+                .collect()
+        };
+
+        let kind = match cv.ty.kind {
+            ty::Float(_) => {
+                tcx.lint_hir(
+                    ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+                    id,
+                    span,
+                    "floating-point types cannot be used in patterns",
+                );
+                PatKind::Constant { value: cv }
+            }
+            ty::Adt(adt_def, _) if adt_def.is_union() => {
+                // Matching on union fields is unsafe, we can't hide it in constants
+                self.saw_const_match_error.set(true);
+                tcx.sess.span_err(span, "cannot use unions in constant patterns");
+                PatKind::Wild
+            }
+            // keep old code until future-compat upgraded to errors.
+            ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => {
+                debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty);
+                let path = tcx.def_path_str(adt_def.did);
+                let msg = format!(
+                    "to use a constant of type `{}` in a pattern, \
+                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                    path, path,
+                );
+                self.saw_const_match_error.set(true);
+                tcx.sess.span_err(span, &msg);
+                PatKind::Wild
+            }
+            // keep old code until future-compat upgraded to errors.
+            ty::Ref(_, adt_ty @ ty::TyS { kind: ty::Adt(_, _), .. }, _)
+                if !self.type_marked_structural(adt_ty) =>
+            {
+                let adt_def =
+                    if let ty::Adt(adt_def, _) = adt_ty.kind { adt_def } else { unreachable!() };
+
+                debug!(
+                    "adt_def {:?} has !type_marked_structural for adt_ty: {:?}",
+                    adt_def, adt_ty
+                );
+
+                // HACK(estebank): Side-step ICE #53708, but anything other than erroring here
+                // would be wrong. Returnging `PatKind::Wild` is not technically correct.
+                let path = tcx.def_path_str(adt_def.did);
+                let msg = format!(
+                    "to use a constant of type `{}` in a pattern, \
+                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                    path, path,
+                );
+                self.saw_const_match_error.set(true);
+                tcx.sess.span_err(span, &msg);
+                PatKind::Wild
+            }
+            ty::Adt(adt_def, substs) if adt_def.is_enum() => {
+                let destructured = tcx.destructure_const(param_env.and(cv));
+                PatKind::Variant {
+                    adt_def,
+                    substs,
+                    variant_index: destructured.variant,
+                    subpatterns: field_pats(destructured.fields),
+                }
+            }
+            ty::Adt(_, _) => {
+                let destructured = tcx.destructure_const(param_env.and(cv));
+                PatKind::Leaf { subpatterns: field_pats(destructured.fields) }
+            }
+            ty::Tuple(_) => {
+                let destructured = tcx.destructure_const(param_env.and(cv));
+                PatKind::Leaf { subpatterns: field_pats(destructured.fields) }
+            }
+            ty::Array(..) => PatKind::Array {
+                prefix: tcx
+                    .destructure_const(param_env.and(cv))
+                    .fields
+                    .iter()
+                    .map(|val| self.recur(val))
+                    .collect(),
+                slice: None,
+                suffix: Vec::new(),
+            },
+            _ => PatKind::Constant { value: cv },
+        };
+
+        Pat { span, ty: cv.ty, kind: Box::new(kind) }
+    }
+}
diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs
new file mode 100644 (file)
index 0000000..9e00c4e
--- /dev/null
@@ -0,0 +1,1071 @@
+//! Validation of patterns/matches.
+
+mod _match;
+mod check_match;
+mod const_to_pat;
+
+pub(crate) use self::check_match::check_match;
+
+use crate::hair::constant::*;
+use crate::hair::util::UserAnnotatedTyHelpers;
+
+use rustc::mir::interpret::{get_slice_bytes, sign_extend, ConstValue, ErrorHandled};
+use rustc::mir::UserTypeProjection;
+use rustc::mir::{BorrowKind, Field, Mutability};
+use rustc::ty::layout::VariantIdx;
+use rustc::ty::subst::{GenericArg, SubstsRef};
+use rustc::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
+use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::pat_util::EnumerateAndAdjustIterator;
+use rustc_hir::RangeEnd;
+use rustc_index::vec::Idx;
+use rustc_span::{Span, DUMMY_SP};
+use syntax::ast;
+
+use std::cmp::Ordering;
+use std::fmt;
+
+use rustc_error_codes::*;
+
+#[derive(Clone, Debug)]
+crate enum PatternError {
+    AssocConstInPattern(Span),
+    StaticInPattern(Span),
+    FloatBug,
+    NonConstPath(Span),
+}
+
+#[derive(Copy, Clone, Debug)]
+crate enum BindingMode {
+    ByValue,
+    ByRef(BorrowKind),
+}
+
+#[derive(Clone, Debug)]
+crate struct FieldPat<'tcx> {
+    crate field: Field,
+    crate pattern: Pat<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+crate struct Pat<'tcx> {
+    crate ty: Ty<'tcx>,
+    crate span: Span,
+    crate kind: Box<PatKind<'tcx>>,
+}
+
+impl<'tcx> Pat<'tcx> {
+    pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
+        Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+crate struct PatTyProj<'tcx> {
+    crate user_ty: CanonicalUserType<'tcx>,
+}
+
+impl<'tcx> PatTyProj<'tcx> {
+    pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
+        Self { user_ty: user_annotation }
+    }
+
+    pub(crate) fn user_ty(
+        self,
+        annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
+        inferred_ty: Ty<'tcx>,
+        span: Span,
+    ) -> UserTypeProjection {
+        UserTypeProjection {
+            base: annotations.push(CanonicalUserTypeAnnotation {
+                span,
+                user_ty: self.user_ty,
+                inferred_ty,
+            }),
+            projs: Vec::new(),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+crate struct Ascription<'tcx> {
+    crate user_ty: PatTyProj<'tcx>,
+    /// Variance to use when relating the type `user_ty` to the **type of the value being
+    /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
+    /// have a type that is some subtype of the ascribed type.
+    ///
+    /// Note that this variance does not apply for any bindings within subpatterns. The type
+    /// assigned to those bindings must be exactly equal to the `user_ty` given here.
+    ///
+    /// The only place where this field is not `Covariant` is when matching constants, where
+    /// we currently use `Contravariant` -- this is because the constant type just needs to
+    /// be "comparable" to the type of the input value. So, for example:
+    ///
+    /// ```text
+    /// match x { "foo" => .. }
+    /// ```
+    ///
+    /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
+    /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
+    /// of the old type-check for now. See #57280 for details.
+    crate variance: ty::Variance,
+    crate user_ty_span: Span,
+}
+
+#[derive(Clone, Debug)]
+crate enum PatKind<'tcx> {
+    Wild,
+
+    AscribeUserType {
+        ascription: Ascription<'tcx>,
+        subpattern: Pat<'tcx>,
+    },
+
+    /// `x`, `ref x`, `x @ P`, etc.
+    Binding {
+        mutability: Mutability,
+        name: ast::Name,
+        mode: BindingMode,
+        var: hir::HirId,
+        ty: Ty<'tcx>,
+        subpattern: Option<Pat<'tcx>>,
+    },
+
+    /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
+    /// multiple variants.
+    Variant {
+        adt_def: &'tcx AdtDef,
+        substs: SubstsRef<'tcx>,
+        variant_index: VariantIdx,
+        subpatterns: Vec<FieldPat<'tcx>>,
+    },
+
+    /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
+    /// a single variant.
+    Leaf {
+        subpatterns: Vec<FieldPat<'tcx>>,
+    },
+
+    /// `box P`, `&P`, `&mut P`, etc.
+    Deref {
+        subpattern: Pat<'tcx>,
+    },
+
+    Constant {
+        value: &'tcx ty::Const<'tcx>,
+    },
+
+    Range(PatRange<'tcx>),
+
+    /// Matches against a slice, checking the length and extracting elements.
+    /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
+    /// e.g., `&[ref xs @ ..]`.
+    Slice {
+        prefix: Vec<Pat<'tcx>>,
+        slice: Option<Pat<'tcx>>,
+        suffix: Vec<Pat<'tcx>>,
+    },
+
+    /// Fixed match against an array; irrefutable.
+    Array {
+        prefix: Vec<Pat<'tcx>>,
+        slice: Option<Pat<'tcx>>,
+        suffix: Vec<Pat<'tcx>>,
+    },
+
+    /// An or-pattern, e.g. `p | q`.
+    /// Invariant: `pats.len() >= 2`.
+    Or {
+        pats: Vec<Pat<'tcx>>,
+    },
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+crate struct PatRange<'tcx> {
+    crate lo: &'tcx ty::Const<'tcx>,
+    crate hi: &'tcx ty::Const<'tcx>,
+    crate end: RangeEnd,
+}
+
+impl<'tcx> fmt::Display for Pat<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Printing lists is a chore.
+        let mut first = true;
+        let mut start_or_continue = |s| {
+            if first {
+                first = false;
+                ""
+            } else {
+                s
+            }
+        };
+        let mut start_or_comma = || start_or_continue(", ");
+
+        match *self.kind {
+            PatKind::Wild => write!(f, "_"),
+            PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
+            PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
+                let is_mut = match mode {
+                    BindingMode::ByValue => mutability == Mutability::Mut,
+                    BindingMode::ByRef(bk) => {
+                        write!(f, "ref ")?;
+                        match bk {
+                            BorrowKind::Mut { .. } => true,
+                            _ => false,
+                        }
+                    }
+                };
+                if is_mut {
+                    write!(f, "mut ")?;
+                }
+                write!(f, "{}", name)?;
+                if let Some(ref subpattern) = *subpattern {
+                    write!(f, " @ {}", subpattern)?;
+                }
+                Ok(())
+            }
+            PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
+                let variant = match *self.kind {
+                    PatKind::Variant { adt_def, variant_index, .. } => {
+                        Some(&adt_def.variants[variant_index])
+                    }
+                    _ => {
+                        if let ty::Adt(adt, _) = self.ty.kind {
+                            if !adt.is_enum() {
+                                Some(&adt.variants[VariantIdx::new(0)])
+                            } else {
+                                None
+                            }
+                        } else {
+                            None
+                        }
+                    }
+                };
+
+                if let Some(variant) = variant {
+                    write!(f, "{}", variant.ident)?;
+
+                    // Only for Adt we can have `S {...}`,
+                    // which we handle separately here.
+                    if variant.ctor_kind == CtorKind::Fictive {
+                        write!(f, " {{ ")?;
+
+                        let mut printed = 0;
+                        for p in subpatterns {
+                            if let PatKind::Wild = *p.pattern.kind {
+                                continue;
+                            }
+                            let name = variant.fields[p.field.index()].ident;
+                            write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
+                            printed += 1;
+                        }
+
+                        if printed < variant.fields.len() {
+                            write!(f, "{}..", start_or_comma())?;
+                        }
+
+                        return write!(f, " }}");
+                    }
+                }
+
+                let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
+                if num_fields != 0 || variant.is_none() {
+                    write!(f, "(")?;
+                    for i in 0..num_fields {
+                        write!(f, "{}", start_or_comma())?;
+
+                        // Common case: the field is where we expect it.
+                        if let Some(p) = subpatterns.get(i) {
+                            if p.field.index() == i {
+                                write!(f, "{}", p.pattern)?;
+                                continue;
+                            }
+                        }
+
+                        // Otherwise, we have to go looking for it.
+                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+                            write!(f, "{}", p.pattern)?;
+                        } else {
+                            write!(f, "_")?;
+                        }
+                    }
+                    write!(f, ")")?;
+                }
+
+                Ok(())
+            }
+            PatKind::Deref { ref subpattern } => {
+                match self.ty.kind {
+                    ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
+                    ty::Ref(_, _, mutbl) => {
+                        write!(f, "&{}", mutbl.prefix_str())?;
+                    }
+                    _ => bug!("{} is a bad Deref pattern type", self.ty),
+                }
+                write!(f, "{}", subpattern)
+            }
+            PatKind::Constant { value } => write!(f, "{}", value),
+            PatKind::Range(PatRange { lo, hi, end }) => {
+                write!(f, "{}", lo)?;
+                write!(f, "{}", end)?;
+                write!(f, "{}", hi)
+            }
+            PatKind::Slice { ref prefix, ref slice, ref suffix }
+            | PatKind::Array { ref prefix, ref slice, ref suffix } => {
+                write!(f, "[")?;
+                for p in prefix {
+                    write!(f, "{}{}", start_or_comma(), p)?;
+                }
+                if let Some(ref slice) = *slice {
+                    write!(f, "{}", start_or_comma())?;
+                    match *slice.kind {
+                        PatKind::Wild => {}
+                        _ => write!(f, "{}", slice)?,
+                    }
+                    write!(f, "..")?;
+                }
+                for p in suffix {
+                    write!(f, "{}{}", start_or_comma(), p)?;
+                }
+                write!(f, "]")
+            }
+            PatKind::Or { ref pats } => {
+                for pat in pats {
+                    write!(f, "{}{}", start_or_continue(" | "), pat)?;
+                }
+                Ok(())
+            }
+        }
+    }
+}
+
+crate struct PatCtxt<'a, 'tcx> {
+    crate tcx: TyCtxt<'tcx>,
+    crate param_env: ty::ParamEnv<'tcx>,
+    crate tables: &'a ty::TypeckTables<'tcx>,
+    crate errors: Vec<PatternError>,
+    include_lint_checks: bool,
+}
+
+impl<'a, 'tcx> Pat<'tcx> {
+    crate fn from_hir(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        tables: &'a ty::TypeckTables<'tcx>,
+        pat: &'tcx hir::Pat<'tcx>,
+    ) -> Self {
+        let mut pcx = PatCtxt::new(tcx, param_env, tables);
+        let result = pcx.lower_pattern(pat);
+        if !pcx.errors.is_empty() {
+            let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
+            tcx.sess.delay_span_bug(pat.span, &msg);
+        }
+        debug!("Pat::from_hir({:?}) = {:?}", pat, result);
+        result
+    }
+}
+
+impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
+    crate fn new(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        tables: &'a ty::TypeckTables<'tcx>,
+    ) -> Self {
+        PatCtxt { tcx, param_env, tables, errors: vec![], include_lint_checks: false }
+    }
+
+    crate fn include_lint_checks(&mut self) -> &mut Self {
+        self.include_lint_checks = true;
+        self
+    }
+
+    crate fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
+        // pattern has the type that results *after* dereferencing. For example, in this code:
+        //
+        // ```
+        // match &&Some(0i32) {
+        //     Some(n) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
+        // determined in rustc_typeck::check::match). The adjustments would be
+        //
+        // `vec![&&Option<i32>, &Option<i32>]`.
+        //
+        // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
+        // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
+        // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
+        // gets the least-dereferenced type).
+        let unadjusted_pat = self.lower_pattern_unadjusted(pat);
+        self.tables.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);
+                Pat {
+                    span: pat.span,
+                    ty: ref_ty,
+                    kind: Box::new(PatKind::Deref { subpattern: pat }),
+                }
+            },
+        )
+    }
+
+    fn lower_range_expr(
+        &mut self,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) {
+        match self.lower_lit(expr) {
+            PatKind::AscribeUserType { ascription, subpattern: Pat { kind: box kind, .. } } => {
+                (kind, Some(ascription))
+            }
+            kind => (kind, None),
+        }
+    }
+
+    fn lower_pattern_range(
+        &mut self,
+        ty: Ty<'tcx>,
+        lo: &'tcx ty::Const<'tcx>,
+        hi: &'tcx ty::Const<'tcx>,
+        end: RangeEnd,
+        span: Span,
+    ) -> PatKind<'tcx> {
+        assert_eq!(lo.ty, ty);
+        assert_eq!(hi.ty, ty);
+        let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
+        match (end, cmp) {
+            // `x..y` where `x < y`.
+            // Non-empty because the range includes at least `x`.
+            (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+            // `x..y` where `x >= y`. The range is empty => error.
+            (RangeEnd::Excluded, _) => {
+                struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0579,
+                    "lower range bound must be less than upper"
+                )
+                .emit();
+                PatKind::Wild
+            }
+            // `x..=y` where `x == y`.
+            (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
+            // `x..=y` where `x < y`.
+            (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+            // `x..=y` where `x > y` hence the range is empty => error.
+            (RangeEnd::Included, _) => {
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0030,
+                    "lower range bound must be less than or equal to upper"
+                );
+                err.span_label(span, "lower bound larger than upper bound");
+                if self.tcx.sess.teach(&err.get_code().unwrap()) {
+                    err.note(
+                        "When matching against a range, the compiler \
+                              verifies that the range is non-empty. Range \
+                              patterns include both end-points, so this is \
+                              equivalent to requiring the start of the range \
+                              to be less than or equal to the end of the range.",
+                    );
+                }
+                err.emit();
+                PatKind::Wild
+            }
+        }
+    }
+
+    fn normalize_range_pattern_ends(
+        &self,
+        ty: Ty<'tcx>,
+        lo: Option<&PatKind<'tcx>>,
+        hi: Option<&PatKind<'tcx>>,
+    ) -> Option<(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>)> {
+        match (lo, hi) {
+            (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
+                Some((lo, hi))
+            }
+            (Some(PatKind::Constant { value: lo }), None) => {
+                Some((lo, ty.numeric_max_val(self.tcx)?))
+            }
+            (None, Some(PatKind::Constant { value: hi })) => {
+                Some((ty.numeric_min_val(self.tcx)?, hi))
+            }
+            _ => None,
+        }
+    }
+
+    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+        let mut ty = self.tables.node_type(pat.hir_id);
+
+        if let ty::Error = ty.kind {
+            // Avoid ICEs (e.g., #50577 and #50585).
+            return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
+        }
+
+        let kind = match pat.kind {
+            hir::PatKind::Wild => PatKind::Wild,
+
+            hir::PatKind::Lit(ref value) => self.lower_lit(value),
+
+            hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
+                let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
+                let lo_span = lo_expr.map_or(pat.span, |e| e.span);
+                let lo = lo_expr.map(|e| self.lower_range_expr(e));
+                let hi = hi_expr.map(|e| self.lower_range_expr(e));
+
+                let (lp, hp) = (lo.as_ref().map(|x| &x.0), hi.as_ref().map(|x| &x.0));
+                let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) {
+                    Some((lc, hc)) => self.lower_pattern_range(ty, lc, hc, end, lo_span),
+                    None => {
+                        let msg = &format!(
+                            "found bad range pattern `{:?}` outside of error recovery",
+                            (&lo, &hi),
+                        );
+                        self.tcx.sess.delay_span_bug(pat.span, msg);
+                        PatKind::Wild
+                    }
+                };
+
+                // If we are handling a range with associated constants (e.g.
+                // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
+                // constants somewhere. Have them on the range pattern.
+                for end in &[lo, hi] {
+                    if let Some((_, Some(ascription))) = end {
+                        let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) };
+                        kind = PatKind::AscribeUserType { ascription: *ascription, subpattern };
+                    }
+                }
+
+                kind
+            }
+
+            hir::PatKind::Path(ref qpath) => {
+                return self.lower_path(qpath, pat.hir_id, pat.span);
+            }
+
+            hir::PatKind::Ref(ref subpattern, _) | hir::PatKind::Box(ref subpattern) => {
+                PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
+            }
+
+            hir::PatKind::Slice(ref prefix, ref slice, ref suffix) => {
+                self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
+            }
+
+            hir::PatKind::Tuple(ref pats, ddpos) => {
+                let tys = match ty.kind {
+                    ty::Tuple(ref tys) => tys,
+                    _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty),
+                };
+                let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos);
+                PatKind::Leaf { subpatterns }
+            }
+
+            hir::PatKind::Binding(_, id, ident, ref sub) => {
+                let bm =
+                    *self.tables.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) => (
+                        Mutability::Not,
+                        BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }),
+                    ),
+                    ty::BindByReference(hir::Mutability::Not) => {
+                        (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared))
+                    }
+                };
+
+                // A ref x pattern is the same node used for x, and as such it has
+                // x's type, which is &T, where we want T (the type being matched).
+                let var_ty = ty;
+                if let ty::BindByReference(_) = bm {
+                    if let ty::Ref(_, rty, _) = ty.kind {
+                        ty = rty;
+                    } else {
+                        bug!("`ref {}` has wrong type {}", ident, ty);
+                    }
+                };
+
+                PatKind::Binding {
+                    mutability,
+                    mode,
+                    name: ident.name,
+                    var: id,
+                    ty: var_ty,
+                    subpattern: self.lower_opt_pattern(sub),
+                }
+            }
+
+            hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => {
+                let res = self.tables.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),
+                };
+                let variant_def = adt_def.variant_of_res(res);
+                let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
+                self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
+            }
+
+            hir::PatKind::Struct(ref qpath, ref fields, _) => {
+                let res = self.tables.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)),
+                        pattern: self.lower_pattern(&field.pat),
+                    })
+                    .collect();
+
+                self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
+            }
+
+            hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
+        };
+
+        Pat { span: pat.span, ty, kind: Box::new(kind) }
+    }
+
+    fn lower_tuple_subpats(
+        &mut self,
+        pats: &'tcx [&'tcx hir::Pat<'tcx>],
+        expected_len: usize,
+        gap_pos: Option<usize>,
+    ) -> Vec<FieldPat<'tcx>> {
+        pats.iter()
+            .enumerate_and_adjust(expected_len, gap_pos)
+            .map(|(i, subpattern)| FieldPat {
+                field: Field::new(i),
+                pattern: self.lower_pattern(subpattern),
+            })
+            .collect()
+    }
+
+    fn lower_patterns(&mut self, pats: &'tcx [&'tcx hir::Pat<'tcx>]) -> Vec<Pat<'tcx>> {
+        pats.iter().map(|p| self.lower_pattern(p)).collect()
+    }
+
+    fn lower_opt_pattern(&mut self, pat: &'tcx Option<&'tcx hir::Pat<'tcx>>) -> Option<Pat<'tcx>> {
+        pat.as_ref().map(|p| self.lower_pattern(p))
+    }
+
+    fn slice_or_array_pattern(
+        &mut self,
+        span: Span,
+        ty: Ty<'tcx>,
+        prefix: &'tcx [&'tcx hir::Pat<'tcx>],
+        slice: &'tcx Option<&'tcx hir::Pat<'tcx>>,
+        suffix: &'tcx [&'tcx hir::Pat<'tcx>],
+    ) -> PatKind<'tcx> {
+        let prefix = self.lower_patterns(prefix);
+        let slice = self.lower_opt_pattern(slice);
+        let suffix = self.lower_patterns(suffix);
+        match ty.kind {
+            // Matching a slice, `[T]`.
+            ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
+            // Fixed-length array, `[T; len]`.
+            ty::Array(_, len) => {
+                let len = len.eval_usize(self.tcx, self.param_env);
+                assert!(len >= prefix.len() as u64 + suffix.len() as u64);
+                PatKind::Array { prefix, slice, suffix }
+            }
+            _ => span_bug!(span, "bad slice pattern type {:?}", ty),
+        }
+    }
+
+    fn lower_variant_or_leaf(
+        &mut self,
+        res: Res,
+        hir_id: hir::HirId,
+        span: Span,
+        ty: Ty<'tcx>,
+        subpatterns: Vec<FieldPat<'tcx>>,
+    ) -> PatKind<'tcx> {
+        let res = match res {
+            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
+                let variant_id = self.tcx.parent(variant_ctor_id).unwrap();
+                Res::Def(DefKind::Variant, variant_id)
+            }
+            res => res,
+        };
+
+        let mut kind = match res {
+            Res::Def(DefKind::Variant, variant_id) => {
+                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let adt_def = self.tcx.adt_def(enum_id);
+                if adt_def.is_enum() {
+                    let substs = match ty.kind {
+                        ty::Adt(_, substs) | ty::FnDef(_, substs) => substs,
+                        ty::Error => {
+                            // Avoid ICE (#50585)
+                            return PatKind::Wild;
+                        }
+                        _ => bug!("inappropriate type for def: {:?}", ty),
+                    };
+                    PatKind::Variant {
+                        adt_def,
+                        substs,
+                        variant_index: adt_def.variant_index_with_id(variant_id),
+                        subpatterns,
+                    }
+                } else {
+                    PatKind::Leaf { subpatterns }
+                }
+            }
+
+            Res::Def(DefKind::Struct, _)
+            | Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
+            | Res::Def(DefKind::Union, _)
+            | Res::Def(DefKind::TyAlias, _)
+            | Res::Def(DefKind::AssocTy, _)
+            | Res::SelfTy(..)
+            | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
+
+            _ => {
+                self.errors.push(PatternError::NonConstPath(span));
+                PatKind::Wild
+            }
+        };
+
+        if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
+            debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
+            kind = PatKind::AscribeUserType {
+                subpattern: Pat { span, ty, kind: Box::new(kind) },
+                ascription: Ascription {
+                    user_ty: PatTyProj::from_user_type(user_ty),
+                    user_ty_span: span,
+                    variance: ty::Variance::Covariant,
+                },
+            };
+        }
+
+        kind
+    }
+
+    /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
+    /// 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 is_associated_const = match res {
+            Res::Def(DefKind::AssocConst, _) => true,
+            _ => false,
+        };
+        let kind = match res {
+            Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
+                let substs = self.tables.node_substs(id);
+                // Use `Reveal::All` here because patterns are always monomorphic even if their function isn't.
+                match self.tcx.const_eval_resolve(
+                    self.param_env.with_reveal_all(),
+                    def_id,
+                    substs,
+                    None,
+                    Some(span),
+                ) {
+                    Ok(value) => {
+                        let pattern = self.const_to_pat(value, id, span);
+                        if !is_associated_const {
+                            return pattern;
+                        }
+
+                        let user_provided_types = self.tables().user_provided_types();
+                        return if let Some(u_ty) = user_provided_types.get(id) {
+                            let user_ty = PatTyProj::from_user_type(*u_ty);
+                            Pat {
+                                span,
+                                kind: Box::new(PatKind::AscribeUserType {
+                                    subpattern: pattern,
+                                    ascription: Ascription {
+                                        /// Note that use `Contravariant` here. See the
+                                        /// `variance` field documentation for details.
+                                        variance: ty::Variance::Contravariant,
+                                        user_ty,
+                                        user_ty_span: span,
+                                    },
+                                }),
+                                ty: value.ty,
+                            }
+                        } else {
+                            pattern
+                        };
+                    }
+                    Err(ErrorHandled::TooGeneric) => {
+                        self.errors.push(if is_associated_const {
+                            PatternError::AssocConstInPattern(span)
+                        } else {
+                            PatternError::StaticInPattern(span)
+                        });
+                        PatKind::Wild
+                    }
+                    Err(_) => {
+                        self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+                        PatKind::Wild
+                    }
+                }
+            }
+            _ => self.lower_variant_or_leaf(res, id, span, ty, vec![]),
+        };
+
+        Pat { span, ty, kind: Box::new(kind) }
+    }
+
+    /// Converts literals, paths and negation of literals to patterns.
+    /// The special case for negation exists to allow things like `-128_i8`
+    /// which would overflow if we tried to evaluate `128_i8` and then negate
+    /// afterwards.
+    fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
+        match expr.kind {
+            hir::ExprKind::Lit(ref lit) => {
+                let ty = self.tables.expr_ty(expr);
+                match lit_to_const(&lit.node, self.tcx, ty, false) {
+                    Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
+                    Err(LitToConstError::UnparseableFloat) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatKind::Wild
+                    }
+                    Err(LitToConstError::Reported) => PatKind::Wild,
+                }
+            }
+            hir::ExprKind::Path(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
+            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
+                let ty = self.tables.expr_ty(expr);
+                let lit = match expr.kind {
+                    hir::ExprKind::Lit(ref lit) => lit,
+                    _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+                };
+                match lit_to_const(&lit.node, self.tcx, ty, true) {
+                    Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
+                    Err(LitToConstError::UnparseableFloat) => {
+                        self.errors.push(PatternError::FloatBug);
+                        PatKind::Wild
+                    }
+                    Err(LitToConstError::Reported) => PatKind::Wild,
+                }
+            }
+            _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+        }
+    }
+}
+
+impl<'tcx> UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn tables(&self) -> &ty::TypeckTables<'tcx> {
+        self.tables
+    }
+}
+
+crate trait PatternFoldable<'tcx>: Sized {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.super_fold_with(folder)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
+}
+
+crate trait PatternFolder<'tcx>: Sized {
+    fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> {
+        pattern.super_fold_with(self)
+    }
+
+    fn fold_pattern_kind(&mut self, kind: &PatKind<'tcx>) -> PatKind<'tcx> {
+        kind.super_fold_with(self)
+    }
+}
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let content: T = (**self).fold_with(folder);
+        box content
+    }
+}
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.iter().map(|t| t.fold_with(folder)).collect()
+    }
+}
+
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        self.as_ref().map(|t| t.fold_with(folder))
+    }
+}
+
+macro_rules! CloneImpls {
+    (<$lt_tcx:tt> $($ty:ty),+) => {
+        $(
+            impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
+                fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
+                    Clone::clone(self)
+                }
+            }
+        )+
+    }
+}
+
+CloneImpls! { <'tcx>
+    Span, Field, Mutability, ast::Name, hir::HirId, usize, ty::Const<'tcx>,
+    Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef,
+    SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
+    UserTypeProjection, PatTyProj<'tcx>
+}
+
+impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> {
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) }
+    }
+}
+
+impl<'tcx> PatternFoldable<'tcx> for Pat<'tcx> {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_pattern(self)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        Pat {
+            ty: self.ty.fold_with(folder),
+            span: self.span.fold_with(folder),
+            kind: self.kind.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
+    fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_pattern_kind(self)
+    }
+
+    fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        match *self {
+            PatKind::Wild => PatKind::Wild,
+            PatKind::AscribeUserType {
+                ref subpattern,
+                ascription: Ascription { variance, ref user_ty, user_ty_span },
+            } => PatKind::AscribeUserType {
+                subpattern: subpattern.fold_with(folder),
+                ascription: Ascription {
+                    user_ty: user_ty.fold_with(folder),
+                    variance,
+                    user_ty_span,
+                },
+            },
+            PatKind::Binding { mutability, name, mode, var, ty, ref subpattern } => {
+                PatKind::Binding {
+                    mutability: mutability.fold_with(folder),
+                    name: name.fold_with(folder),
+                    mode: mode.fold_with(folder),
+                    var: var.fold_with(folder),
+                    ty: ty.fold_with(folder),
+                    subpattern: subpattern.fold_with(folder),
+                }
+            }
+            PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
+                PatKind::Variant {
+                    adt_def: adt_def.fold_with(folder),
+                    substs: substs.fold_with(folder),
+                    variant_index,
+                    subpatterns: subpatterns.fold_with(folder),
+                }
+            }
+            PatKind::Leaf { ref subpatterns } => {
+                PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) }
+            }
+            PatKind::Deref { ref subpattern } => {
+                PatKind::Deref { subpattern: subpattern.fold_with(folder) }
+            }
+            PatKind::Constant { value } => PatKind::Constant { value },
+            PatKind::Range(range) => PatKind::Range(range),
+            PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
+                prefix: prefix.fold_with(folder),
+                slice: slice.fold_with(folder),
+                suffix: suffix.fold_with(folder),
+            },
+            PatKind::Array { ref prefix, ref slice, ref suffix } => PatKind::Array {
+                prefix: prefix.fold_with(folder),
+                slice: slice.fold_with(folder),
+                suffix: suffix.fold_with(folder),
+            },
+            PatKind::Or { ref pats } => PatKind::Or { pats: pats.fold_with(folder) },
+        }
+    }
+}
+
+crate fn compare_const_vals<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    a: &'tcx ty::Const<'tcx>,
+    b: &'tcx ty::Const<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<Ordering> {
+    trace!("compare_const_vals: {:?}, {:?}", a, b);
+
+    let from_bool = |v: bool| v.then_some(Ordering::Equal);
+
+    let fallback = || from_bool(a == b);
+
+    // Use the fallback if any type differs
+    if a.ty != b.ty || a.ty != ty {
+        return fallback();
+    }
+
+    // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
+    // are just integer addresses).
+    if a.val == b.val {
+        return from_bool(true);
+    }
+
+    let a_bits = a.try_eval_bits(tcx, param_env, ty);
+    let b_bits = b.try_eval_bits(tcx, param_env, ty);
+
+    if let (Some(a), Some(b)) = (a_bits, b_bits) {
+        use ::rustc_apfloat::Float;
+        return match ty.kind {
+            ty::Float(ast::FloatTy::F32) => {
+                let l = ::rustc_apfloat::ieee::Single::from_bits(a);
+                let r = ::rustc_apfloat::ieee::Single::from_bits(b);
+                l.partial_cmp(&r)
+            }
+            ty::Float(ast::FloatTy::F64) => {
+                let l = ::rustc_apfloat::ieee::Double::from_bits(a);
+                let r = ::rustc_apfloat::ieee::Double::from_bits(b);
+                l.partial_cmp(&r)
+            }
+            ty::Int(ity) => {
+                use rustc::ty::layout::{Integer, IntegerExt};
+                use syntax::attr::SignedInt;
+                let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+                let a = sign_extend(a, size);
+                let b = sign_extend(b, size);
+                Some((a as i128).cmp(&(b as i128)))
+            }
+            _ => Some(a.cmp(&b)),
+        };
+    }
+
+    if let ty::Str = ty.kind {
+        match (a.val, b.val) {
+            (
+                ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }),
+                ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }),
+            ) => {
+                let a_bytes = get_slice_bytes(&tcx, a_val);
+                let b_bytes = get_slice_bytes(&tcx, b_val);
+                return from_bool(a_bytes == b_bytes);
+            }
+            _ => (),
+        }
+    }
+
+    fallback()
+}
diff --git a/src/librustc_mir_build/hair/util.rs b/src/librustc_mir_build/hair/util.rs
new file mode 100644 (file)
index 0000000..c27844e
--- /dev/null
@@ -0,0 +1,31 @@
+use rustc::ty::{self, CanonicalUserType, TyCtxt, UserType};
+use rustc_hir as hir;
+
+crate trait UserAnnotatedTyHelpers<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx>;
+
+    fn tables(&self) -> &ty::TypeckTables<'tcx>;
+
+    /// Looks up the type associated with this hir-id and applies the
+    /// user-given substitutions; the hir-id must map to a suitable
+    /// type.
+    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 mut user_ty = *user_provided_types.get(hir_id)?;
+        debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty);
+        let ty = self.tables().node_type(hir_id);
+        match ty.kind {
+            ty::Adt(adt_def, ..) => {
+                if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value {
+                    *did = adt_def.did;
+                }
+                Some(user_ty)
+            }
+            ty::FnDef(..) => Some(user_ty),
+            _ => bug!("ty: {:?} should not have user provided type {:?} recorded ", ty, user_ty),
+        }
+    }
+}
diff --git a/src/librustc_mir_build/lib.rs b/src/librustc_mir_build/lib.rs
new file mode 100644 (file)
index 0000000..96032a7
--- /dev/null
@@ -0,0 +1,26 @@
+//! Construction of MIR from HIR.
+//!
+//! This crate also contains the match exhaustiveness and usefulness checking.
+
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(crate_visibility_modifier)]
+#![feature(slice_patterns)]
+#![feature(bool_to_option)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate rustc;
+
+mod build;
+mod hair;
+mod lints;
+
+use rustc::ty::query::Providers;
+
+pub fn provide(providers: &mut Providers<'_>) {
+    providers.check_match = hair::pattern::check_match;
+    providers.mir_built = build::mir_built;
+}
diff --git a/src/librustc_mir_build/lints.rs b/src/librustc_mir_build/lints.rs
new file mode 100644 (file)
index 0000000..4244e1b
--- /dev/null
@@ -0,0 +1,141 @@
+use rustc::hir::map::blocks::FnLikeNode;
+use rustc::lint::builtin::UNCONDITIONAL_RECURSION;
+use rustc::mir::{self, Body, TerminatorKind};
+use rustc::ty::subst::InternalSubsts;
+use rustc::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_index::bit_set::BitSet;
+
+crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId) {
+    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+
+    if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
+        check_fn_for_unconditional_recursion(tcx, fn_like_node.kind(), body, def_id);
+    }
+}
+
+fn check_fn_for_unconditional_recursion<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_kind: FnKind<'_>,
+    body: &Body<'tcx>,
+    def_id: DefId,
+) {
+    if let FnKind::Closure(_) = fn_kind {
+        // closures can't recur, so they don't matter.
+        return;
+    }
+
+    //FIXME(#54444) rewrite this lint to use the dataflow framework
+
+    // Walk through this function (say `f`) looking to see if
+    // every possible path references itself, i.e., the function is
+    // called recursively unconditionally. This is done by trying
+    // to find a path from the entry node to the exit node that
+    // *doesn't* call `f` by traversing from the entry while
+    // pretending that calls of `f` are sinks (i.e., ignoring any
+    // exit edges from them).
+    //
+    // NB. this has an edge case with non-returning statements,
+    // like `loop {}` or `panic!()`: control flow never reaches
+    // the exit node through these, so one can have a function
+    // that never actually calls itself but is still picked up by
+    // this lint:
+    //
+    //     fn f(cond: bool) {
+    //         if !cond { panic!() } // could come from `assert!(cond)`
+    //         f(false)
+    //     }
+    //
+    // In general, functions of that form may be able to call
+    // itself a finite number of times and then diverge. The lint
+    // considers this to be an error for two reasons, (a) it is
+    // easier to implement, and (b) it seems rare to actually want
+    // to have behaviour like the above, rather than
+    // e.g., accidentally recursing after an assert.
+
+    let basic_blocks = body.basic_blocks();
+    let mut reachable_without_self_call_queue = vec![mir::START_BLOCK];
+    let mut reached_exit_without_self_call = false;
+    let mut self_call_locations = vec![];
+    let mut visited = BitSet::new_empty(basic_blocks.len());
+
+    let param_env = tcx.param_env(def_id);
+    let trait_substs_count = match tcx.opt_associated_item(def_id) {
+        Some(AssocItem { container: AssocItemContainer::TraitContainer(trait_def_id), .. }) => {
+            tcx.generics_of(trait_def_id).count()
+        }
+        _ => 0,
+    };
+    let caller_substs = &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count];
+
+    while let Some(bb) = reachable_without_self_call_queue.pop() {
+        if !visited.insert(bb) {
+            //already done
+            continue;
+        }
+
+        let block = &basic_blocks[bb];
+
+        if let Some(ref terminator) = block.terminator {
+            match terminator.kind {
+                TerminatorKind::Call { ref func, .. } => {
+                    let func_ty = func.ty(body, tcx);
+
+                    if let ty::FnDef(fn_def_id, substs) = func_ty.kind {
+                        let (call_fn_id, call_substs) = if let Some(instance) =
+                            Instance::resolve(tcx, param_env, fn_def_id, substs)
+                        {
+                            (instance.def_id(), instance.substs)
+                        } else {
+                            (fn_def_id, substs)
+                        };
+
+                        let is_self_call = call_fn_id == def_id
+                            && &call_substs[..caller_substs.len()] == caller_substs;
+
+                        if is_self_call {
+                            self_call_locations.push(terminator.source_info);
+
+                            //this is a self call so we shouldn't explore
+                            //further down this path
+                            continue;
+                        }
+                    }
+                }
+                TerminatorKind::Abort | TerminatorKind::Return => {
+                    //found a path!
+                    reached_exit_without_self_call = true;
+                    break;
+                }
+                _ => {}
+            }
+
+            for successor in terminator.successors() {
+                reachable_without_self_call_queue.push(*successor);
+            }
+        }
+    }
+
+    // Check the number of self calls because a function that
+    // doesn't return (e.g., calls a `-> !` function or `loop { /*
+    // no break */ }`) shouldn't be linted unless it actually
+    // recurs.
+    if !reached_exit_without_self_call && !self_call_locations.is_empty() {
+        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+        let sp = tcx.sess.source_map().def_span(tcx.hir().span(hir_id));
+        let mut db = tcx.struct_span_lint_hir(
+            UNCONDITIONAL_RECURSION,
+            hir_id,
+            sp,
+            "function cannot return without recursing",
+        );
+        db.span_label(sp, "cannot return without recursing");
+        // offer some help to the programmer.
+        for location in &self_call_locations {
+            db.span_label(location.span, "recursive call site");
+        }
+        db.help("a `loop` may express intention better if this is on purpose");
+        db.emit();
+    }
+}
diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml
deleted file mode 100644 (file)
index bda4078..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-build = "build.rs"
-name = "rustc_msan"
-version = "0.0.0"
-edition = "2018"
-
-[lib]
-name = "rustc_msan"
-path = "lib.rs"
-test = false
-
-[build-dependencies]
-build_helper = { path = "../build_helper" }
-cmake = "0.1.38"
-
-[dependencies]
-alloc = { path = "../liballoc" }
-core = { path = "../libcore" }
-compiler_builtins = "0.1.0"
diff --git a/src/librustc_msan/build.rs b/src/librustc_msan/build.rs
deleted file mode 100644 (file)
index dc08d51..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-use build_helper::sanitizer_lib_boilerplate;
-use std::env;
-
-use cmake::Config;
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
-    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
-        return;
-    }
-    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
-        build_helper::restore_library_path();
-
-        let (native, target) = match sanitizer_lib_boilerplate("msan") {
-            Ok(native) => native,
-            _ => return,
-        };
-
-        Config::new(&native.src_dir)
-            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
-            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
-            .define("COMPILER_RT_BUILD_XRAY", "OFF")
-            .define("LLVM_CONFIG_PATH", llvm_config)
-            .out_dir(&native.out_dir)
-            .build_target(&target)
-            .build();
-    }
-    println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
-}
diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs
deleted file mode 100644 (file)
index bdbc154..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#![sanitizer_runtime]
-#![feature(nll)]
-#![feature(sanitizer_runtime)]
-#![feature(staged_api)]
-#![no_std]
-#![unstable(
-    feature = "sanitizer_runtime_lib",
-    reason = "internal implementation detail of sanitizers",
-    issue = "none"
-)]
index d41d89902efcd6135c17cceb37c5f7dec51de3f3..aa159c55ff2846ed68784580de6b32b46334bcf2 100644 (file)
@@ -18,6 +18,7 @@ rustc_lexer = { path = "../librustc_lexer" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_error_codes = { path = "../librustc_error_codes" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
 syntax = { path = "../libsyntax" }
 unicode-normalization = "0.1.11"
index f2ffd9470ed7601908ae67a145307a6e31329e40..8467acc759c2b5cd25e93d1c047df0349d3b2121 100644 (file)
@@ -9,18 +9,22 @@
 //! [#64197]: https://github.com/rust-lang/rust/issues/64197
 
 use crate::{parse_in, validate_attr};
-use rustc_errors::Applicability;
-use rustc_feature::Features;
-use rustc_span::edition::Edition;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_error_codes::*;
+use rustc_errors::{error_code, struct_span_err, Applicability, Handler};
+use rustc_feature::{Feature, Features, State as FeatureState};
+use rustc_feature::{
+    ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
+};
+use rustc_span::edition::{Edition, ALL_EDITIONS};
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::{Span, DUMMY_SP};
 use syntax::ast::{self, AttrItem, Attribute, MetaItem};
 use syntax::attr;
 use syntax::attr::HasAttrs;
-use syntax::feature_gate::{feature_err, get_features};
 use syntax::mut_visit::*;
 use syntax::ptr::P;
-use syntax::sess::ParseSess;
+use syntax::sess::{feature_err, ParseSess};
 use syntax::util::map_in_place::MapInPlace;
 
 use smallvec::SmallVec;
@@ -31,6 +35,172 @@ pub struct StripUnconfigured<'a> {
     pub features: Option<&'a Features>,
 }
 
+fn get_features(
+    span_handler: &Handler,
+    krate_attrs: &[ast::Attribute],
+    crate_edition: Edition,
+    allow_features: &Option<Vec<String>>,
+) -> Features {
+    fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
+        let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
+        err.span_label(span, "feature has been removed");
+        if let Some(reason) = reason {
+            err.note(reason);
+        }
+        err.emit();
+    }
+
+    fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> {
+        ACTIVE_FEATURES.iter().filter(move |feature| {
+            if let Some(feature_edition) = feature.edition {
+                feature_edition <= edition
+            } else {
+                false
+            }
+        })
+    }
+
+    let mut features = Features::default();
+    let mut edition_enabled_features = FxHashMap::default();
+
+    for &edition in ALL_EDITIONS {
+        if edition <= crate_edition {
+            // The `crate_edition` implies its respective umbrella feature-gate
+            // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
+            edition_enabled_features.insert(edition.feature_name(), edition);
+        }
+    }
+
+    for feature in active_features_up_to(crate_edition) {
+        feature.set(&mut features, DUMMY_SP);
+        edition_enabled_features.insert(feature.name, crate_edition);
+    }
+
+    // Process the edition umbrella feature-gates first, to ensure
+    // `edition_enabled_features` is completed before it's queried.
+    for attr in krate_attrs {
+        if !attr.check_name(sym::feature) {
+            continue;
+        }
+
+        let list = match attr.meta_item_list() {
+            Some(list) => list,
+            None => continue,
+        };
+
+        for mi in list {
+            if !mi.is_word() {
+                continue;
+            }
+
+            let name = mi.name_or_empty();
+
+            let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
+            if let Some(edition) = edition {
+                if edition <= crate_edition {
+                    continue;
+                }
+
+                for feature in active_features_up_to(edition) {
+                    // FIXME(Manishearth) there is currently no way to set
+                    // lib features by edition
+                    feature.set(&mut features, DUMMY_SP);
+                    edition_enabled_features.insert(feature.name, edition);
+                }
+            }
+        }
+    }
+
+    for attr in krate_attrs {
+        if !attr.check_name(sym::feature) {
+            continue;
+        }
+
+        let list = match attr.meta_item_list() {
+            Some(list) => list,
+            None => continue,
+        };
+
+        let bad_input = |span| {
+            struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
+        };
+
+        for mi in list {
+            let name = match mi.ident() {
+                Some(ident) if mi.is_word() => ident.name,
+                Some(ident) => {
+                    bad_input(mi.span())
+                        .span_suggestion(
+                            mi.span(),
+                            "expected just one word",
+                            format!("{}", ident.name),
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
+                    continue;
+                }
+                None => {
+                    bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
+                    continue;
+                }
+            };
+
+            if let Some(edition) = edition_enabled_features.get(&name) {
+                let msg =
+                    &format!("the feature `{}` is included in the Rust {} edition", name, edition);
+                span_handler.struct_span_warn_with_code(mi.span(), msg, error_code!(E0705)).emit();
+                continue;
+            }
+
+            if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
+                // Handled in the separate loop above.
+                continue;
+            }
+
+            let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
+            let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
+            if let Some(Feature { state, .. }) = removed.or(stable_removed) {
+                if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } =
+                    state
+                {
+                    feature_removed(span_handler, mi.span(), *reason);
+                    continue;
+                }
+            }
+
+            if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
+                let since = Some(Symbol::intern(since));
+                features.declared_lang_features.push((name, mi.span(), since));
+                continue;
+            }
+
+            if let Some(allowed) = allow_features.as_ref() {
+                if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
+                    struct_span_err!(
+                        span_handler,
+                        mi.span(),
+                        E0725,
+                        "the feature `{}` is not in the list of allowed features",
+                        name
+                    )
+                    .emit();
+                    continue;
+                }
+            }
+
+            if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
+                f.set(&mut features, mi.span());
+                features.declared_lang_features.push((name, mi.span(), None));
+                continue;
+            }
+
+            features.declared_lib_features.push((name, mi.span()));
+        }
+    }
+
+    features
+}
+
 // `cfg_attr`-process the crate's attributes and compute the crate's features.
 pub fn features(
     mut krate: ast::Crate,
index 151c63a49b57c497af98398cd44cf43fd94c33d4..88762dabd8a290610742fa8f3b0341e4a512f406 100644 (file)
@@ -3,11 +3,10 @@
 use std::iter::once;
 use std::ops::Range;
 
+use rustc_errors::{Applicability, Handler};
 use rustc_lexer::unescape::{EscapeError, Mode};
 use rustc_span::{BytePos, Span};
 
-use syntax::errors::{Applicability, Handler};
-
 pub(crate) fn emit_unescape_error(
     handler: &Handler,
     // interior part of the literal, without quotes
index 94785e9eff3a59300e16e13ca144e3e673dad617..6a18c63017ed6cce86d937470f4ac42fece74c47 100644 (file)
@@ -2,7 +2,9 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_error_codes::*;
-use rustc_errors::{self, pluralize, Applicability, DiagnosticBuilder, Handler, PResult};
+use rustc_errors::{pluralize, struct_span_err};
+use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::kw;
 use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
 use syntax::ast::{
@@ -11,7 +13,6 @@
 use syntax::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
 use syntax::print::pprust;
 use syntax::ptr::P;
-use syntax::struct_span_err;
 use syntax::token::{self, token_can_begin_expr, TokenKind};
 use syntax::util::parser::AssocOp;
 
@@ -51,7 +52,6 @@ pub enum Error {
         secondary_path: String,
     },
     UselessDocComment,
-    InclusiveRangeWithNoEnd,
 }
 
 impl Error {
@@ -102,11 +102,6 @@ fn span_err(self, sp: impl Into<MultiSpan>, handler: &Handler) -> DiagnosticBuil
                 );
                 err
             }
-            Error::InclusiveRangeWithNoEnd => {
-                let mut err = struct_span_err!(handler, sp, E0586, "inclusive range with no end",);
-                err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)");
-                err
-            }
         }
     }
 }
@@ -265,10 +260,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
             };
             (
                 format!("expected one of {}, found {}", expect, actual),
-                (
-                    self.sess.source_map().next_point(self.prev_span),
-                    format!("expected one of {}", short_expect),
-                ),
+                (self.prev_span.shrink_to_hi(), format!("expected one of {}", short_expect)),
             )
         } else if expected.is_empty() {
             (
@@ -278,7 +270,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
         } else {
             (
                 format!("expected {}, found {}", expect, actual),
-                (self.sess.source_map().next_point(self.prev_span), format!("expected {}", expect)),
+                (self.prev_span.shrink_to_hi(), format!("expected {}", expect)),
             )
         };
         self.last_unexpected_token_span = Some(self.token.span);
@@ -500,6 +492,58 @@ pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, en
         }
     }
 
+    /// Check to see if a pair of chained operators looks like an attempt at chained comparison,
+    /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
+    /// parenthesising the leftmost comparison.
+    fn attempt_chained_comparison_suggestion(
+        &mut self,
+        err: &mut DiagnosticBuilder<'_>,
+        inner_op: &Expr,
+        outer_op: &Spanned<AssocOp>,
+    ) {
+        if let ExprKind::Binary(op, ref l1, ref r1) = inner_op.kind {
+            match (op.node, &outer_op.node) {
+                // `x < y < z` and friends.
+                (BinOpKind::Lt, AssocOp::Less) | (BinOpKind::Lt, AssocOp::LessEqual) |
+                (BinOpKind::Le, AssocOp::LessEqual) | (BinOpKind::Le, AssocOp::Less) |
+                // `x > y > z` and friends.
+                (BinOpKind::Gt, AssocOp::Greater) | (BinOpKind::Gt, AssocOp::GreaterEqual) |
+                (BinOpKind::Ge, AssocOp::GreaterEqual) | (BinOpKind::Ge, AssocOp::Greater) => {
+                    let expr_to_str = |e: &Expr| {
+                        self.span_to_snippet(e.span)
+                            .unwrap_or_else(|_| pprust::expr_to_string(&e))
+                    };
+                    err.span_suggestion(
+                        inner_op.span.to(outer_op.span),
+                        "split the comparison into two...",
+                        format!(
+                            "{} {} {} && {} {}",
+                            expr_to_str(&l1),
+                            op.node.to_string(),
+                            expr_to_str(&r1),
+                            expr_to_str(&r1),
+                            outer_op.node.to_ast_binop().unwrap().to_string(),
+                        ),
+                        Applicability::MaybeIncorrect,
+                    );
+                    err.span_suggestion(
+                        inner_op.span.to(outer_op.span),
+                        "...or parenthesize one of the comparisons",
+                        format!(
+                            "({} {} {}) {}",
+                            expr_to_str(&l1),
+                            op.node.to_string(),
+                            expr_to_str(&r1),
+                            outer_op.node.to_ast_binop().unwrap().to_string(),
+                        ),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => {}
+            }
+        }
+    }
+
     /// Produces an error if comparison operators are chained (RFC #558).
     /// We only need to check the LHS, not the RHS, because all comparison ops have same
     /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`).
@@ -515,27 +559,31 @@ pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, en
     ///           /   \
     ///     inner_op   r2
     ///        /  \
-    ///     l1    r1
+    ///      l1    r1
     pub(super) fn check_no_chained_comparison(
         &mut self,
-        lhs: &Expr,
-        outer_op: &AssocOp,
+        inner_op: &Expr,
+        outer_op: &Spanned<AssocOp>,
     ) -> PResult<'a, Option<P<Expr>>> {
         debug_assert!(
-            outer_op.is_comparison(),
+            outer_op.node.is_comparison(),
             "check_no_chained_comparison: {:?} is not comparison",
-            outer_op,
+            outer_op.node,
         );
 
         let mk_err_expr =
             |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new())));
 
-        match lhs.kind {
+        match inner_op.kind {
             ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
                 // Respan to include both operators.
                 let op_span = op.span.to(self.prev_span);
-                let mut err = self
-                    .struct_span_err(op_span, "chained comparison operators require parentheses");
+                let mut err =
+                    self.struct_span_err(op_span, "comparison operators cannot be chained");
+
+                // If it looks like a genuine attempt to chain operators (as opposed to a
+                // misformatted turbofish, for instance), suggest a correct form.
+                self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
 
                 let suggest = |err: &mut DiagnosticBuilder<'_>| {
                     err.span_suggestion_verbose(
@@ -547,12 +595,12 @@ pub(super) fn check_no_chained_comparison(
                 };
 
                 if op.node == BinOpKind::Lt &&
-                    *outer_op == AssocOp::Less ||  // Include `<` to provide this recommendation
-                    *outer_op == AssocOp::Greater
+                    outer_op.node == AssocOp::Less ||  // Include `<` to provide this recommendation
+                    outer_op.node == AssocOp::Greater
                 // even in a case like the following:
                 {
                     //     Foo<Bar<Baz<Qux, ()>>>
-                    if *outer_op == AssocOp::Less {
+                    if outer_op.node == AssocOp::Less {
                         let snapshot = self.clone();
                         self.bump();
                         // So far we have parsed `foo<bar<`, consume the rest of the type args.
@@ -584,7 +632,7 @@ pub(super) fn check_no_chained_comparison(
                                 // FIXME: actually check that the two expressions in the binop are
                                 // paths and resynthesize new fn call expression instead of using
                                 // `ExprKind::Err` placeholder.
-                                mk_err_expr(self, lhs.span.to(self.prev_span))
+                                mk_err_expr(self, inner_op.span.to(self.prev_span))
                             }
                             Err(mut expr_err) => {
                                 expr_err.cancel();
@@ -606,7 +654,7 @@ pub(super) fn check_no_chained_comparison(
                                 // FIXME: actually check that the two expressions in the binop are
                                 // paths and resynthesize new fn call expression instead of using
                                 // `ExprKind::Err` placeholder.
-                                mk_err_expr(self, lhs.span.to(self.prev_span))
+                                mk_err_expr(self, inner_op.span.to(self.prev_span))
                             }
                         }
                     } else {
@@ -809,7 +857,7 @@ pub(super) fn unexpected_try_recover(
             _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span),
             // EOF, don't want to point at the following char, but rather the last token.
             (token::Eof, None) => (self.prev_span, self.token.span),
-            _ => (self.sess.source_map().next_point(self.prev_span), self.token.span),
+            _ => (self.prev_span.shrink_to_hi(), self.token.span),
         };
         let msg = format!(
             "expected `{}`, found {}",
@@ -1132,7 +1180,7 @@ pub(super) fn recover_closing_delimiter(
                     err.span_label(sp, "unclosed delimiter");
                 }
                 err.span_suggestion_short(
-                    self.sess.source_map().next_point(self.prev_span),
+                    self.prev_span.shrink_to_hi(),
                     &format!("{} may belong here", delim.to_string()),
                     delim.to_string(),
                     Applicability::MaybeIncorrect,
index 90f15375aec428b3b6ebdd06d4c560efbcba1c9a..098c8355ab94498b3eacf626da50beffb3610573 100644 (file)
@@ -1,11 +1,10 @@
-use super::diagnostics::Error;
 use super::pat::{GateOr, PARAM_EXPECTED};
 use super::{BlockMode, Parser, PathStyle, PrevTokenKind, Restrictions, TokenType};
 use super::{SemiColonMode, SeqSep, TokenExpectType};
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
 use rustc_errors::{Applicability, PResult};
-use rustc_span::source_map::{self, Span};
+use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::mem;
 use syntax::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, DUMMY_NODE_ID};
@@ -181,17 +180,17 @@ pub(super) fn parse_assoc_expr_with(
             };
 
             let cur_op_span = self.token.span;
-            let restrictions = if op.is_assign_like() {
+            let restrictions = if op.node.is_assign_like() {
                 self.restrictions & Restrictions::NO_STRUCT_LITERAL
             } else {
                 self.restrictions
             };
-            let prec = op.precedence();
+            let prec = op.node.precedence();
             if prec < min_prec {
                 break;
             }
             // Check for deprecated `...` syntax
-            if self.token == token::DotDotDot && op == AssocOp::DotDotEq {
+            if self.token == token::DotDotDot && op.node == AssocOp::DotDotEq {
                 self.err_dotdotdot_syntax(self.token.span);
             }
 
@@ -200,11 +199,12 @@ pub(super) fn parse_assoc_expr_with(
             }
 
             self.bump();
-            if op.is_comparison() {
+            if op.node.is_comparison() {
                 if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
                     return Ok(expr);
                 }
             }
+            let op = op.node;
             // Special cases:
             if op == AssocOp::As {
                 lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
@@ -298,7 +298,7 @@ pub(super) fn parse_assoc_expr_with(
     }
 
     fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
-        match (self.expr_is_complete(lhs), self.check_assoc_op()) {
+        match (self.expr_is_complete(lhs), self.check_assoc_op().map(|op| op.node)) {
             // Semi-statement forms are odd:
             // See https://github.com/rust-lang/rust/issues/29071
             (true, None) => false,
@@ -343,19 +343,22 @@ fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
     /// The method does not advance the current token.
     ///
     /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
-    fn check_assoc_op(&self) -> Option<AssocOp> {
-        match (AssocOp::from_token(&self.token), &self.token.kind) {
-            (op @ Some(_), _) => op,
-            (None, token::Ident(sym::and, false)) => {
-                self.error_bad_logical_op("and", "&&", "conjunction");
-                Some(AssocOp::LAnd)
-            }
-            (None, token::Ident(sym::or, false)) => {
-                self.error_bad_logical_op("or", "||", "disjunction");
-                Some(AssocOp::LOr)
-            }
-            _ => None,
-        }
+    fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
+        Some(Spanned {
+            node: match (AssocOp::from_token(&self.token), &self.token.kind) {
+                (Some(op), _) => op,
+                (None, token::Ident(sym::and, false)) => {
+                    self.error_bad_logical_op("and", "&&", "conjunction");
+                    AssocOp::LAnd
+                }
+                (None, token::Ident(sym::or, false)) => {
+                    self.error_bad_logical_op("or", "||", "disjunction");
+                    AssocOp::LOr
+                }
+                _ => return None,
+            },
+            span: self.token.span,
+        })
     }
 
     /// Error on `and` and `or` suggesting `&&` and `||` respectively.
@@ -1646,7 +1649,7 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
                             //   |      |
                             //   |      parsed until here as `"y" & X`
                             err.span_suggestion_short(
-                                cm.next_point(arm_start_span),
+                                arm_start_span.shrink_to_hi(),
                                 "missing a comma here to end this `match` arm",
                                 ",".to_owned(),
                                 Applicability::MachineApplicable,
@@ -1967,7 +1970,8 @@ fn mk_range(
         limits: RangeLimits,
     ) -> PResult<'a, ExprKind> {
         if end.is_none() && limits == RangeLimits::Closed {
-            Err(self.span_fatal_err(self.token.span, Error::InclusiveRangeWithNoEnd))
+            self.error_inclusive_range_with_no_end(self.prev_span);
+            Ok(ExprKind::Err)
         } else {
             Ok(ExprKind::Range(start, end, limits))
         }
index 1b816e2b90da964cf83a580e8c744e195a292544..075583711f5d3e8f9b129364cd1a0f9143327557 100644 (file)
@@ -156,7 +156,7 @@ pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
             self.expect_gt()?;
             (params, span_lo.to(self.prev_span))
         } else {
-            (vec![], self.prev_span.between(self.token.span))
+            (vec![], self.prev_span.shrink_to_hi())
         };
         Ok(ast::Generics {
             params,
index a05bc48981efe4446c5d31ccbec59c28df43ceac..d4756dff49a9d8cd6ac4ebb5f1b4486b0d29ea85 100644 (file)
@@ -4,8 +4,8 @@
 use crate::maybe_whole;
 
 use rustc_error_codes::*;
-use rustc_errors::{Applicability, DiagnosticBuilder, PResult, StashKey};
-use rustc_span::source_map::{self, respan, Span};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
+use rustc_span::source_map::{self, respan, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::BytePos;
 use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
@@ -16,7 +16,6 @@
 use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind};
 use syntax::print::pprust;
 use syntax::ptr::P;
-use syntax::struct_span_err;
 use syntax::token;
 use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
 
@@ -141,7 +140,7 @@ fn parse_item_implementation(
                     self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span));
                 }
                 let ext = self.parse_extern()?;
-                self.bump(); // `fn`
+                self.expect_keyword(kw::Fn)?;
 
                 let header = FnHeader {
                     unsafety,
@@ -543,10 +542,11 @@ fn missing_assoc_item_kind_err(
     ///    impl<'a, T> TYPE { /* impl items */ }
     ///    impl<'a, T> TRAIT for TYPE { /* impl items */ }
     ///    impl<'a, T> !TRAIT for TYPE { /* impl items */ }
+    ///    impl<'a, T> const TRAIT for TYPE { /* impl items */ }
     ///
     /// We actually parse slightly more relaxed grammar for better error reporting and recovery.
-    ///     `impl` GENERICS `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}`
-    ///     `impl` GENERICS `!`? TYPE (`where` PREDICATES)? `{` BODY `}`
+    ///   `impl` GENERICS `const`? `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}`
+    ///   `impl` GENERICS `const`? `!`? TYPE (`where` PREDICATES)? `{` BODY `}`
     fn parse_item_impl(
         &mut self,
         unsafety: Unsafety,
@@ -556,7 +556,19 @@ fn parse_item_impl(
         let mut generics = if self.choose_generics_over_qpath() {
             self.parse_generics()?
         } else {
-            Generics::default()
+            let mut generics = Generics::default();
+            // impl A for B {}
+            //    /\ this is where `generics.span` should point when there are no type params.
+            generics.span = self.prev_span.shrink_to_hi();
+            generics
+        };
+
+        let constness = if self.eat_keyword(kw::Const) {
+            let span = self.prev_span;
+            self.sess.gated_spans.gate(sym::const_trait_impl, span);
+            Some(respan(span, Constness::Const))
+        } else {
+            None
         };
 
         // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
@@ -619,7 +631,8 @@ fn parse_item_impl(
                         err_path(ty_first.span)
                     }
                 };
-                let trait_ref = TraitRef { path, ref_id: ty_first.id };
+                let constness = constness.map(|c| c.node);
+                let trait_ref = TraitRef { path, constness, ref_id: ty_first.id };
 
                 ItemKind::Impl(
                     unsafety,
@@ -632,6 +645,13 @@ fn parse_item_impl(
                 )
             }
             None => {
+                // Reject `impl const Type {}` here
+                if let Some(Spanned { node: Constness::Const, span }) = constness {
+                    self.struct_span_err(span, "`const` cannot modify an inherent impl")
+                        .help("only a trait impl can be `const`")
+                        .emit();
+                }
+
                 // impl Type
                 ItemKind::Impl(
                     unsafety,
@@ -1490,7 +1510,7 @@ fn parse_single_struct_field(
                 }
             }
             _ => {
-                let sp = self.sess.source_map().next_point(self.prev_span);
+                let sp = self.prev_span.shrink_to_hi();
                 let mut err = self.struct_span_err(
                     sp,
                     &format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
@@ -1629,7 +1649,7 @@ fn report_invalid_macro_expansion_item(&self) {
             // it's safe to peel off one character only when it has the close delim
             self.prev_span.with_lo(self.prev_span.hi() - BytePos(1))
         } else {
-            self.sess.source_map().next_point(self.prev_span)
+            self.prev_span.shrink_to_hi()
         };
 
         self.struct_span_err(
@@ -1645,7 +1665,7 @@ fn report_invalid_macro_expansion_item(&self) {
             Applicability::MaybeIncorrect,
         )
         .span_suggestion(
-            self.sess.source_map().next_point(self.prev_span),
+            self.prev_span.shrink_to_hi(),
             "add a semicolon",
             ';'.to_string(),
             Applicability::MaybeIncorrect,
index a2fa335cf72e2f30ed3c0d7f535fb79cfbfe2cd3..1368230168e07ef5a8f0faabdf7ca7f85e95c0ed 100644 (file)
@@ -2,6 +2,7 @@
 mod expr;
 mod item;
 mod module;
+pub use module::{ModulePath, ModulePathSuccess};
 mod pat;
 mod path;
 mod ty;
@@ -15,7 +16,7 @@
 use crate::{Directory, DirectoryOwnership};
 
 use log::debug;
-use rustc_errors::{Applicability, DiagnosticBuilder, FatalError, PResult};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
 use rustc_span::source_map::respan;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
@@ -24,7 +25,6 @@
 use syntax::print::pprust;
 use syntax::ptr::P;
 use syntax::sess::ParseSess;
-use syntax::struct_span_err;
 use syntax::token::{self, DelimToken, Token, TokenKind};
 use syntax::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint};
 use syntax::util::comments::{doc_comment_style, strip_doc_comment_decoration};
@@ -118,7 +118,8 @@ pub struct Parser<'a> {
     /// Used to determine the path to externally loaded source files.
     pub(super) directory: Directory<'a>,
     /// `true` to parse sub-modules in other files.
-    pub(super) recurse_into_file_modules: bool,
+    // Public for rustfmt usage.
+    pub recurse_into_file_modules: bool,
     /// Name of the root module this parser originated from. If `None`, then the
     /// name is not known. This does not change while the parser is descending
     /// into modules, and sub-parsers have new values for this name.
@@ -127,7 +128,8 @@ pub struct Parser<'a> {
     token_cursor: TokenCursor,
     desugar_doc_comments: bool,
     /// `true` we should configure out of line modules as we parse.
-    cfg_mods: bool,
+    // Public for rustfmt usage.
+    pub cfg_mods: bool,
     /// This field is used to keep track of how many left angle brackets we have seen. This is
     /// required in order to detect extra leading left angle brackets (`<` characters) and error
     /// appropriately.
@@ -484,7 +486,8 @@ pub fn expect_one_of(
         }
     }
 
-    fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
+    // Public for rustfmt usage.
+    pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
         self.parse_ident_common(true)
     }
 
@@ -541,7 +544,8 @@ fn check_keyword(&mut self, kw: Symbol) -> bool {
 
     /// If the next token is the given keyword, eats it and returns `true`.
     /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
-    fn eat_keyword(&mut self, kw: Symbol) -> bool {
+    // Public for rustfmt usage.
+    pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
         if self.check_keyword(kw) {
             self.bump();
             true
@@ -766,7 +770,7 @@ fn parse_seq_to_before_tokens<T>(
                             break;
                         }
                         Err(mut expect_err) => {
-                            let sp = self.sess.source_map().next_point(self.prev_span);
+                            let sp = self.prev_span.shrink_to_hi();
                             let token_str = pprust::token_kind_to_string(t);
 
                             // Attempt to keep parsing if it was a similar separator.
index 3254ab5b46325e7815e72662ecba685a995def67..6ce94d3c6793ce2fc04989e05e94038d58961d50 100644 (file)
 use std::path::{self, Path, PathBuf};
 
 /// Information about the path to a module.
-pub(super) struct ModulePath {
+// Public for rustfmt usage.
+pub struct ModulePath {
     name: String,
     path_exists: bool,
     pub result: Result<ModulePathSuccess, Error>,
 }
 
-pub(super) struct ModulePathSuccess {
+// Public for rustfmt usage.
+pub struct ModulePathSuccess {
     pub path: PathBuf,
     pub directory_ownership: DirectoryOwnership,
 }
@@ -177,7 +179,8 @@ fn submod_path(
         }
     }
 
-    pub(super) fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
+    // Public for rustfmt usage.
+    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
         if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) {
             let s = s.as_str();
 
@@ -194,7 +197,8 @@ pub(super) fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Opt
     }
 
     /// Returns a path to a module.
-    pub(super) fn default_submod_path(
+    // Public for rustfmt usage.
+    pub fn default_submod_path(
         id: ast::Ident,
         relative: Option<ast::Ident>,
         dir_path: &Path,
index bf7f5735f134b12f4b235e312291b5b1dbdc1096..0c2cfc20daf0fd1b8043badf7bb27337d81d6646 100644 (file)
@@ -1,6 +1,6 @@
 use super::{Parser, PathStyle};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
-use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult};
 use rustc_span::source_map::{respan, Span, Spanned};
 use rustc_span::symbol::{kw, sym};
 use syntax::ast::{self, AttrVec, Attribute, FieldPat, Mac, Pat, PatKind, RangeEnd, RangeSyntax};
@@ -281,91 +281,73 @@ fn parse_pat_with_range_pat(
         maybe_whole!(self, NtPat, |x| x);
 
         let lo = self.token.span;
-        let pat = match self.token.kind {
-            token::BinOp(token::And) | token::AndAnd => self.parse_pat_deref(expected)?,
-            token::OpenDelim(token::Paren) => self.parse_pat_tuple_or_parens()?,
-            token::OpenDelim(token::Bracket) => {
-                // Parse `[pat, pat,...]` as a slice pattern.
-                let (pats, _) =
-                    self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat_with_or_inner())?;
-                PatKind::Slice(pats)
-            }
-            token::DotDot => {
-                self.bump();
-                if self.is_pat_range_end_start() {
-                    // Parse `..42` for recovery.
-                    self.parse_pat_range_to(RangeEnd::Excluded, "..")?
-                } else {
-                    // A rest pattern `..`.
-                    PatKind::Rest
-                }
-            }
-            token::DotDotEq => {
-                // Parse `..=42` for recovery.
-                self.bump();
-                self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?
-            }
-            token::DotDotDot => {
-                // Parse `...42` for recovery.
-                self.bump();
-                self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?
+
+        let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
+            self.parse_pat_deref(expected)?
+        } else if self.check(&token::OpenDelim(token::Paren)) {
+            self.parse_pat_tuple_or_parens()?
+        } else if self.check(&token::OpenDelim(token::Bracket)) {
+            // Parse `[pat, pat,...]` as a slice pattern.
+            let (pats, _) =
+                self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat_with_or_inner())?;
+            PatKind::Slice(pats)
+        } else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) {
+            // A rest pattern `..`.
+            self.bump(); // `..`
+            PatKind::Rest
+        } else if let Some(form) = self.parse_range_end() {
+            self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`.
+        } else if self.eat_keyword(kw::Underscore) {
+            // Parse _
+            PatKind::Wild
+        } else if self.eat_keyword(kw::Mut) {
+            self.parse_pat_ident_mut()?
+        } else if self.eat_keyword(kw::Ref) {
+            // Parse ref ident @ pat / ref mut ident @ pat
+            let mutbl = self.parse_mutability();
+            self.parse_pat_ident(BindingMode::ByRef(mutbl))?
+        } else if self.eat_keyword(kw::Box) {
+            // Parse `box pat`
+            let pat = self.parse_pat_with_range_pat(false, None)?;
+            self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_span));
+            PatKind::Box(pat)
+        } else if self.can_be_ident_pat() {
+            // Parse `ident @ pat`
+            // This can give false positives and parse nullary enums,
+            // they are dealt with later in resolve.
+            self.parse_pat_ident(BindingMode::ByValue(Mutability::Not))?
+        } else if self.is_start_of_pat_with_path() {
+            // Parse pattern starting with a path
+            let (qself, path) = if self.eat_lt() {
+                // Parse a qualified path
+                let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+                (Some(qself), path)
+            } else {
+                // Parse an unqualified path
+                (None, self.parse_path(PathStyle::Expr)?)
+            };
+            let span = lo.to(self.prev_span);
+
+            if qself.is_none() && self.check(&token::Not) {
+                self.parse_pat_mac_invoc(path)?
+            } else if let Some(form) = self.parse_range_end() {
+                let begin = self.mk_expr(span, ExprKind::Path(qself, path), AttrVec::new());
+                self.parse_pat_range_begin_with(begin, form)?
+            } else if self.check(&token::OpenDelim(token::Brace)) {
+                self.parse_pat_struct(qself, path)?
+            } else if self.check(&token::OpenDelim(token::Paren)) {
+                self.parse_pat_tuple_struct(qself, path)?
+            } else {
+                PatKind::Path(qself, path)
             }
-            // At this point, token != `&`, `&&`, `(`, `[`, `..`, `..=`, or `...`.
-            _ => {
-                if self.eat_keyword(kw::Underscore) {
-                    // Parse _
-                    PatKind::Wild
-                } else if self.eat_keyword(kw::Mut) {
-                    self.parse_pat_ident_mut()?
-                } else if self.eat_keyword(kw::Ref) {
-                    // Parse ref ident @ pat / ref mut ident @ pat
-                    let mutbl = self.parse_mutability();
-                    self.parse_pat_ident(BindingMode::ByRef(mutbl))?
-                } else if self.eat_keyword(kw::Box) {
-                    // Parse `box pat`
-                    let pat = self.parse_pat_with_range_pat(false, None)?;
-                    self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_span));
-                    PatKind::Box(pat)
-                } else if self.can_be_ident_pat() {
-                    // Parse `ident @ pat`
-                    // This can give false positives and parse nullary enums,
-                    // they are dealt with later in resolve.
-                    self.parse_pat_ident(BindingMode::ByValue(Mutability::Not))?
-                } else if self.is_start_of_pat_with_path() {
-                    // Parse pattern starting with a path
-                    let (qself, path) = if self.eat_lt() {
-                        // Parse a qualified path
-                        let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
-                        (Some(qself), path)
-                    } else {
-                        // Parse an unqualified path
-                        (None, self.parse_path(PathStyle::Expr)?)
-                    };
-                    match self.token.kind {
-                        token::Not if qself.is_none() => self.parse_pat_mac_invoc(path)?,
-                        token::DotDotDot | token::DotDotEq | token::DotDot => {
-                            self.parse_pat_range_starting_with_path(lo, qself, path)?
-                        }
-                        token::OpenDelim(token::Brace) => self.parse_pat_struct(qself, path)?,
-                        token::OpenDelim(token::Paren) => {
-                            self.parse_pat_tuple_struct(qself, path)?
-                        }
-                        _ => PatKind::Path(qself, path),
-                    }
-                } else {
-                    // Try to parse everything else as literal with optional minus
-                    match self.parse_literal_maybe_minus() {
-                        Ok(begin)
-                            if self.check(&token::DotDot)
-                                || self.check(&token::DotDotEq)
-                                || self.check(&token::DotDotDot) =>
-                        {
-                            self.parse_pat_range_starting_with_lit(begin)?
-                        }
-                        Ok(begin) => PatKind::Lit(begin),
-                        Err(err) => return self.fatal_unexpected_non_pat(err, expected),
-                    }
-                }
+        } else {
+            // Try to parse everything else as literal with optional minus
+            match self.parse_literal_maybe_minus() {
+                Ok(begin) => match self.parse_range_end() {
+                    Some(form) => self.parse_pat_range_begin_with(begin, form)?,
+                    None => PatKind::Lit(begin),
+                },
+                Err(err) => return self.fatal_unexpected_non_pat(err, expected),
             }
         };
 
@@ -374,7 +356,7 @@ fn parse_pat_with_range_pat(
         let pat = self.recover_intersection_pat(pat)?;
 
         if !allow_range_pat {
-            self.ban_pat_range_if_ambiguous(&pat)?
+            self.ban_pat_range_if_ambiguous(&pat)
         }
 
         Ok(pat)
@@ -441,26 +423,25 @@ fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
     }
 
     /// Ban a range pattern if it has an ambiguous interpretation.
-    fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> {
+    fn ban_pat_range_if_ambiguous(&self, pat: &Pat) {
         match pat.kind {
             PatKind::Range(
                 ..,
                 Spanned { node: RangeEnd::Included(RangeSyntax::DotDotDot), .. },
-            ) => return Ok(()),
+            ) => return,
             PatKind::Range(..) => {}
-            _ => return Ok(()),
+            _ => return,
         }
 
-        let mut err =
-            self.struct_span_err(pat.span, "the range pattern here has ambiguous interpretation");
-        err.span_suggestion(
-            pat.span,
-            "add parentheses to clarify the precedence",
-            format!("({})", pprust::pat_to_string(&pat)),
-            // "ambiguous interpretation" implies that we have to be guessing
-            Applicability::MaybeIncorrect,
-        );
-        Err(err)
+        self.struct_span_err(pat.span, "the range pattern here has ambiguous interpretation")
+            .span_suggestion(
+                pat.span,
+                "add parentheses to clarify the precedence",
+                format!("({})", pprust::pat_to_string(&pat)),
+                // "ambiguous interpretation" implies that we have to be guessing
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
     }
 
     /// Parse `&pat` / `&mut pat`.
@@ -618,51 +599,6 @@ fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
         Ok(PatKind::Mac(mac))
     }
 
-    fn excluded_range_end(&self, span: Span) -> RangeEnd {
-        self.sess.gated_spans.gate(sym::exclusive_range_pattern, span);
-        RangeEnd::Excluded
-    }
-
-    /// Parse a range pattern `$path $form $end?` where `$form = ".." | "..." | "..=" ;`.
-    /// The `$path` has already been parsed and the next token is the `$form`.
-    fn parse_pat_range_starting_with_path(
-        &mut self,
-        lo: Span,
-        qself: Option<QSelf>,
-        path: Path,
-    ) -> PResult<'a, PatKind> {
-        let (end_kind, form) = match self.token.kind {
-            token::DotDot => (self.excluded_range_end(self.token.span), ".."),
-            token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
-            token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
-            _ => panic!("can only parse `..`/`...`/`..=` for ranges (checked above)"),
-        };
-        let op_span = self.token.span;
-        // Parse range
-        let span = lo.to(self.prev_span);
-        let begin = self.mk_expr(span, ExprKind::Path(qself, path), AttrVec::new());
-        self.bump();
-        let end = self.parse_pat_range_end_opt(&begin, form)?;
-        Ok(PatKind::Range(begin, end, respan(op_span, end_kind)))
-    }
-
-    /// Parse a range pattern `$literal $form $end?` where `$form = ".." | "..." | "..=" ;`.
-    /// The `$path` has already been parsed and the next token is the `$form`.
-    fn parse_pat_range_starting_with_lit(&mut self, begin: P<Expr>) -> PResult<'a, PatKind> {
-        let op_span = self.token.span;
-        let (end_kind, form) = if self.eat(&token::DotDotDot) {
-            (RangeEnd::Included(RangeSyntax::DotDotDot), "...")
-        } else if self.eat(&token::DotDotEq) {
-            (RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
-        } else if self.eat(&token::DotDot) {
-            (self.excluded_range_end(op_span), "..")
-        } else {
-            panic!("impossible case: we already matched on a range-operator token")
-        };
-        let end = self.parse_pat_range_end_opt(&begin, form)?;
-        Ok(PatKind::Range(begin, end, respan(op_span, end_kind)))
-    }
-
     fn fatal_unexpected_non_pat(
         &mut self,
         mut err: DiagnosticBuilder<'a>,
@@ -684,57 +620,86 @@ fn fatal_unexpected_non_pat(
         Err(err)
     }
 
-    /// Is the current token suitable as the start of a range patterns end?
-    fn is_pat_range_end_start(&self) -> bool {
-        self.token.is_path_start() // e.g. `MY_CONST`;
-            || self.token == token::Dot // e.g. `.5` for recovery;
-            || self.token.can_begin_literal_or_bool() // e.g. `42`.
-            || self.token.is_whole_expr()
-    }
-
-    /// Parse a range-to pattern, e.g. `..X` and `..=X` for recovery.
-    fn parse_pat_range_to(&mut self, re: RangeEnd, form: &str) -> PResult<'a, PatKind> {
-        let lo = self.prev_span;
-        let end = self.parse_pat_range_end()?;
-        let range_span = lo.to(end.span);
-        let begin = self.mk_expr(range_span, ExprKind::Err, AttrVec::new());
-
-        self.struct_span_err(range_span, &format!("`{}X` range patterns are not supported", form))
-            .span_suggestion(
-                range_span,
-                "try using the minimum value for the type",
-                format!("MIN{}{}", form, pprust::expr_to_string(&end)),
-                Applicability::HasPlaceholders,
-            )
-            .emit();
-
-        Ok(PatKind::Range(begin, end, respan(lo, re)))
+    /// Parses the range pattern end form `".." | "..." | "..=" ;`.
+    fn parse_range_end(&mut self) -> Option<Spanned<RangeEnd>> {
+        let re = if self.eat(&token::DotDotDot) {
+            RangeEnd::Included(RangeSyntax::DotDotDot)
+        } else if self.eat(&token::DotDotEq) {
+            RangeEnd::Included(RangeSyntax::DotDotEq)
+        } else if self.eat(&token::DotDot) {
+            self.sess.gated_spans.gate(sym::exclusive_range_pattern, self.prev_span);
+            RangeEnd::Excluded
+        } else {
+            return None;
+        };
+        Some(respan(self.prev_span, re))
     }
 
-    /// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern  or recover
-    /// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively.
-    fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> {
-        if self.is_pat_range_end_start() {
+    /// Parse a range pattern `$begin $form $end?` where `$form = ".." | "..." | "..=" ;`.
+    /// `$begin $form` has already been parsed.
+    fn parse_pat_range_begin_with(
+        &mut self,
+        begin: P<Expr>,
+        re: Spanned<RangeEnd>,
+    ) -> PResult<'a, PatKind> {
+        let end = if self.is_pat_range_end_start(0) {
             // Parsing e.g. `X..=Y`.
-            self.parse_pat_range_end()
+            Some(self.parse_pat_range_end()?)
         } else {
             // Parsing e.g. `X..`.
-            let range_span = begin.span.to(self.prev_span);
+            self.sess.gated_spans.gate(sym::half_open_range_patterns, begin.span.to(re.span));
+            if let RangeEnd::Included(_) = re.node {
+                // FIXME(Centril): Consider semantic errors instead in `ast_validation`.
+                // Possibly also do this for `X..=` in *expression* contexts.
+                self.error_inclusive_range_with_no_end(re.span);
+            }
+            None
+        };
+        Ok(PatKind::Range(Some(begin), end, re))
+    }
 
-            self.struct_span_err(
-                range_span,
-                &format!("`X{}` range patterns are not supported", form),
-            )
-            .span_suggestion(
-                range_span,
-                "try using the maximum value for the type",
-                format!("{}{}MAX", pprust::expr_to_string(&begin), form),
-                Applicability::HasPlaceholders,
+    pub(super) fn error_inclusive_range_with_no_end(&self, span: Span) {
+        use rustc_error_codes::E0586;
+        struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
+            .span_suggestion_short(
+                span,
+                "use `..` instead",
+                "..".to_string(),
+                Applicability::MachineApplicable,
             )
+            .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
             .emit();
+    }
 
-            Ok(self.mk_expr(range_span, ExprKind::Err, AttrVec::new()))
+    /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
+    ///
+    /// The form `...X` is prohibited to reduce confusion with the potential
+    /// expression syntax `...expr` for splatting in expressions.
+    fn parse_pat_range_to(&mut self, mut re: Spanned<RangeEnd>) -> PResult<'a, PatKind> {
+        let end = self.parse_pat_range_end()?;
+        self.sess.gated_spans.gate(sym::half_open_range_patterns, re.span.to(self.prev_span));
+        if let RangeEnd::Included(ref mut syn @ RangeSyntax::DotDotDot) = &mut re.node {
+            *syn = RangeSyntax::DotDotEq;
+            self.struct_span_err(re.span, "range-to patterns with `...` are not allowed")
+                .span_suggestion_short(
+                    re.span,
+                    "use `..=` instead",
+                    "..=".to_string(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
         }
+        Ok(PatKind::Range(None, Some(end), re))
+    }
+
+    /// Is the token `dist` away from the current suitable as the start of a range patterns end?
+    fn is_pat_range_end_start(&self, dist: usize) -> bool {
+        self.look_ahead(dist, |t| {
+            t.is_path_start() // e.g. `MY_CONST`;
+                || t.kind == token::Dot // e.g. `.5` for recovery;
+                || t.can_begin_literal_or_bool() // e.g. `42`.
+                || t.is_whole_expr()
+        })
     }
 
     fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
index 4122aa17f83d3507a4b409951f42c09caafb4a98..ea14aa278ac29e3f83455d4b551695b3b9286494 100644 (file)
@@ -4,9 +4,9 @@
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 
 use rustc_error_codes::*;
-use rustc_errors::{pluralize, Applicability, PResult};
+use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, sym};
 use syntax::ast::{
     self, BareFnTy, FunctionRetTy, GenericParam, Ident, Lifetime, MutTy, Ty, TyKind,
 };
 };
 use syntax::ast::{Mac, Mutability};
 use syntax::ptr::P;
-use syntax::struct_span_err;
 use syntax::token::{self, Token};
 
+/// Any `?` or `?const` modifiers that appear at the start of a bound.
+struct BoundModifiers {
+    /// `?Trait`.
+    maybe: Option<Span>,
+
+    /// `?const Trait`.
+    maybe_const: Option<Span>,
+}
+
+impl BoundModifiers {
+    fn trait_bound_modifier(&self) -> TraitBoundModifier {
+        match self.maybe {
+            Some(_) => TraitBoundModifier::Maybe,
+            None => TraitBoundModifier::None,
+        }
+    }
+}
+
 /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
 /// `IDENT<<u8 as Trait>::AssocTy>`.
 ///
@@ -196,7 +213,9 @@ fn parse_remaining_bounds(
         lo: Span,
         parse_plus: bool,
     ) -> PResult<'a, TyKind> {
-        let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
+        assert_ne!(self.token, token::Question);
+
+        let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span));
         let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
         if parse_plus {
             self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
@@ -422,12 +441,15 @@ fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
         let has_parens = self.eat(&token::OpenDelim(token::Paren));
         let inner_lo = self.token.span;
         let is_negative = self.eat(&token::Not);
-        let question = self.eat(&token::Question).then_some(self.prev_span);
+
+        let modifiers = self.parse_ty_bound_modifiers();
         let bound = if self.token.is_lifetime() {
-            self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?
+            self.error_lt_bound_with_modifiers(modifiers);
+            self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
         } else {
-            self.parse_generic_ty_bound(lo, has_parens, question)?
+            self.parse_generic_ty_bound(lo, has_parens, modifiers)?
         };
+
         Ok(if is_negative { Err(anchor_lo.to(self.prev_span)) } else { Ok(bound) })
     }
 
@@ -440,9 +462,7 @@ fn parse_generic_lt_bound(
         lo: Span,
         inner_lo: Span,
         has_parens: bool,
-        question: Option<Span>,
     ) -> PResult<'a, GenericBound> {
-        self.error_opt_out_lifetime(question);
         let bound = GenericBound::Outlives(self.expect_lifetime());
         if has_parens {
             // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
@@ -452,8 +472,17 @@ fn parse_generic_lt_bound(
         Ok(bound)
     }
 
-    fn error_opt_out_lifetime(&self, question: Option<Span>) {
-        if let Some(span) = question {
+    /// Emits an error if any trait bound modifiers were present.
+    fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) {
+        if let Some(span) = modifiers.maybe_const {
+            self.struct_span_err(
+                span,
+                "`?const` may only modify trait bounds, not lifetime bounds",
+            )
+            .emit();
+        }
+
+        if let Some(span) = modifiers.maybe {
             self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds")
                 .emit();
         }
@@ -479,25 +508,58 @@ fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()
         Ok(())
     }
 
+    /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
+    ///
+    /// If no modifiers are present, this does not consume any tokens.
+    ///
+    /// ```
+    /// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
+    /// ```
+    fn parse_ty_bound_modifiers(&mut self) -> BoundModifiers {
+        if !self.eat(&token::Question) {
+            return BoundModifiers { maybe: None, maybe_const: None };
+        }
+
+        // `? ...`
+        let first_question = self.prev_span;
+        if !self.eat_keyword(kw::Const) {
+            return BoundModifiers { maybe: Some(first_question), maybe_const: None };
+        }
+
+        // `?const ...`
+        let maybe_const = first_question.to(self.prev_span);
+        self.sess.gated_spans.gate(sym::const_trait_bound_opt_out, maybe_const);
+        if !self.eat(&token::Question) {
+            return BoundModifiers { maybe: None, maybe_const: Some(maybe_const) };
+        }
+
+        // `?const ? ...`
+        let second_question = self.prev_span;
+        BoundModifiers { maybe: Some(second_question), maybe_const: Some(maybe_const) }
+    }
+
     /// Parses a type bound according to:
     /// ```
     /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
-    /// TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
+    /// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
     /// ```
+    ///
+    /// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
     fn parse_generic_ty_bound(
         &mut self,
         lo: Span,
         has_parens: bool,
-        question: Option<Span>,
+        modifiers: BoundModifiers,
     ) -> PResult<'a, GenericBound> {
         let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
         let path = self.parse_path(PathStyle::Type)?;
         if has_parens {
             self.expect(&token::CloseDelim(token::Paren))?;
         }
-        let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
-        let modifier = question.map_or(TraitBoundModifier::None, |_| TraitBoundModifier::Maybe);
-        Ok(GenericBound::Trait(poly_trait, modifier))
+
+        let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst);
+        let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span));
+        Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier()))
     }
 
     /// Optionally parses `for<$generic_params>`.
index f089361220777fa35b093a3b8e25399d6c7a7d2e..84562fbb46ff2bbfd133982060405d97a0b2f4f7 100644 (file)
@@ -4,10 +4,10 @@
 
 use rustc_errors::{Applicability, PResult};
 use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
+use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Symbol};
 use syntax::ast::{self, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
-use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT;
-use syntax::sess::ParseSess;
 use syntax::tokenstream::DelimSpan;
 
 pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
index ced933ba3ee4228e7e7f2234b4a7da6d0795fca6..639d8639c4bb28281dde9d59de9f2072aebf6be1 100644 (file)
@@ -12,12 +12,12 @@ path = "lib.rs"
 log = "0.4"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_index = { path = "../librustc_index" }
-rustc_parse = { path = "../librustc_parse" }
+rustc_session = { path = "../librustc_session" }
 rustc_target = { path = "../librustc_target" }
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_error_codes = { path = "../librustc_error_codes" }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
deleted file mode 100644 (file)
index 038c428..0000000
+++ /dev/null
@@ -1,940 +0,0 @@
-// Validate AST before lowering it to HIR.
-//
-// This pass is supposed to catch things that fit into AST data structures,
-// but not permitted by the language. It runs after expansion when AST is frozen,
-// so it can check for erroneous constructions produced by syntax extensions.
-// This pass is supposed to perform only simple checks not requiring name resolution
-// or type checking or some other kind of complex analysis.
-
-use errors::{Applicability, FatalError};
-use rustc::lint;
-use rustc::session::Session;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_parse::validate_attr;
-use rustc_span::source_map::Spanned;
-use rustc_span::symbol::{kw, sym};
-use rustc_span::Span;
-use std::mem;
-use syntax::ast::*;
-use syntax::attr;
-use syntax::expand::is_proc_macro_attr;
-use syntax::print::pprust;
-use syntax::visit::{self, Visitor};
-use syntax::{span_err, struct_span_err, walk_list};
-
-use rustc_error_codes::*;
-
-struct AstValidator<'a> {
-    session: &'a Session,
-    has_proc_macro_decls: bool,
-
-    /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
-    /// Nested `impl Trait` _is_ allowed in associated type position,
-    /// e.g., `impl Iterator<Item = impl Debug>`.
-    outer_impl_trait: Option<Span>,
-
-    /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
-    /// or `Foo::Bar<impl Trait>`
-    is_impl_trait_banned: bool,
-
-    /// Used to ban associated type bounds (i.e., `Type<AssocType: Bounds>`) in
-    /// certain positions.
-    is_assoc_ty_bound_banned: bool,
-
-    lint_buffer: &'a mut lint::LintBuffer,
-}
-
-impl<'a> AstValidator<'a> {
-    fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_impl_trait_banned, true);
-        f(self);
-        self.is_impl_trait_banned = old;
-    }
-
-    fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
-        f(self);
-        self.is_assoc_ty_bound_banned = old;
-    }
-
-    fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.outer_impl_trait, outer);
-        f(self);
-        self.outer_impl_trait = old;
-    }
-
-    fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
-        match constraint.kind {
-            AssocTyConstraintKind::Equality { .. } => {}
-            AssocTyConstraintKind::Bound { .. } => {
-                if self.is_assoc_ty_bound_banned {
-                    self.err_handler().span_err(
-                        constraint.span,
-                        "associated type bounds are not allowed within structs, enums, or unions",
-                    );
-                }
-            }
-        }
-        self.visit_assoc_ty_constraint(constraint);
-    }
-
-    // Mirrors `visit::walk_ty`, but tracks relevant state.
-    fn walk_ty(&mut self, t: &'a Ty) {
-        match t.kind {
-            TyKind::ImplTrait(..) => {
-                self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
-            }
-            TyKind::Path(ref qself, ref path) => {
-                // We allow these:
-                //  - `Option<impl Trait>`
-                //  - `option::Option<impl Trait>`
-                //  - `option::Option<T>::Foo<impl Trait>
-                //
-                // But not these:
-                //  - `<impl Trait>::Foo`
-                //  - `option::Option<impl Trait>::Foo`.
-                //
-                // To implement this, we disallow `impl Trait` from `qself`
-                // (for cases like `<impl Trait>::Foo>`)
-                // but we allow `impl Trait` in `GenericArgs`
-                // iff there are no more PathSegments.
-                if let Some(ref qself) = *qself {
-                    // `impl Trait` in `qself` is always illegal
-                    self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
-                }
-
-                // Note that there should be a call to visit_path here,
-                // so if any logic is added to process `Path`s a call to it should be
-                // added both in visit_path and here. This code mirrors visit::walk_path.
-                for (i, segment) in path.segments.iter().enumerate() {
-                    // Allow `impl Trait` iff we're on the final path segment
-                    if i == path.segments.len() - 1 {
-                        self.visit_path_segment(path.span, segment);
-                    } else {
-                        self.with_banned_impl_trait(|this| {
-                            this.visit_path_segment(path.span, segment)
-                        });
-                    }
-                }
-            }
-            _ => visit::walk_ty(self, t),
-        }
-    }
-
-    fn err_handler(&self) -> &errors::Handler {
-        &self.session.diagnostic()
-    }
-
-    fn check_lifetime(&self, ident: Ident) {
-        let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
-        if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
-            self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
-        }
-    }
-
-    fn check_label(&self, ident: Ident) {
-        if ident.without_first_quote().is_reserved() {
-            self.err_handler()
-                .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
-        }
-    }
-
-    fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
-        if let VisibilityKind::Inherited = vis.node {
-            return;
-        }
-
-        let mut err =
-            struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
-        if vis.node.is_pub() {
-            err.span_label(vis.span, "`pub` not permitted here because it's implied");
-        }
-        if let Some(note) = note {
-            err.note(note);
-        }
-        err.emit();
-    }
-
-    fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
-        for Param { pat, .. } in &decl.inputs {
-            match pat.kind {
-                PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
-                PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
-                    report_err(pat.span, true)
-                }
-                _ => report_err(pat.span, false),
-            }
-        }
-    }
-
-    fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
-        if asyncness.is_async() {
-            struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`")
-                .note("`async` trait functions are not currently supported")
-                .note(
-                    "consider using the `async-trait` crate: \
-                       https://crates.io/crates/async-trait",
-                )
-                .emit();
-        }
-    }
-
-    fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
-        if constness.node == Constness::Const {
-            struct_span_err!(
-                self.session,
-                constness.span,
-                E0379,
-                "trait fns cannot be declared const"
-            )
-            .span_label(constness.span, "trait fns cannot be const")
-            .emit();
-        }
-    }
-
-    fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait: bool) {
-        for bound in bounds {
-            if let GenericBound::Trait(ref poly, TraitBoundModifier::Maybe) = *bound {
-                let mut err = self.err_handler().struct_span_err(
-                    poly.span,
-                    &format!("`?Trait` is not permitted in {}", where_),
-                );
-                if is_trait {
-                    let path_str = pprust::path_to_string(&poly.trait_ref.path);
-                    err.note(&format!("traits are `?{}` by default", path_str));
-                }
-                err.emit();
-            }
-        }
-    }
-
-    /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
-    /// or paths for ranges.
-    //
-    // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
-    // That means making this work:
-    //
-    // ```rust,ignore (FIXME)
-    // struct S;
-    // macro_rules! m {
-    //     ($a:expr) => {
-    //         let $a = S;
-    //     }
-    // }
-    // m!(S);
-    // ```
-    fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
-        match expr.kind {
-            ExprKind::Lit(..) | ExprKind::Err => {}
-            ExprKind::Path(..) if allow_paths => {}
-            ExprKind::Unary(UnOp::Neg, ref inner)
-                if match inner.kind {
-                    ExprKind::Lit(_) => true,
-                    _ => false,
-                } => {}
-            _ => self.err_handler().span_err(
-                expr.span,
-                "arbitrary expressions aren't allowed \
-                                                         in patterns",
-            ),
-        }
-    }
-
-    fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
-        // Check only lifetime parameters are present and that the lifetime
-        // parameters that are present have no bounds.
-        let non_lt_param_spans: Vec<_> = params
-            .iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    if !param.bounds.is_empty() {
-                        let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
-                        self.err_handler()
-                            .span_err(spans, "lifetime bounds cannot be used in this context");
-                    }
-                    None
-                }
-                _ => Some(param.ident.span),
-            })
-            .collect();
-        if !non_lt_param_spans.is_empty() {
-            self.err_handler().span_err(
-                non_lt_param_spans,
-                "only lifetime parameters can be used in this context",
-            );
-        }
-    }
-
-    fn check_fn_decl(&self, fn_decl: &FnDecl) {
-        match &*fn_decl.inputs {
-            [Param { ty, span, .. }] => {
-                if let TyKind::CVarArgs = ty.kind {
-                    self.err_handler().span_err(
-                        *span,
-                        "C-variadic function must be declared with at least one named argument",
-                    );
-                }
-            }
-            [ps @ .., _] => {
-                for Param { ty, span, .. } in ps {
-                    if let TyKind::CVarArgs = ty.kind {
-                        self.err_handler().span_err(
-                            *span,
-                            "`...` must be the last argument of a C-variadic function",
-                        );
-                    }
-                }
-            }
-            _ => {}
-        }
-
-        fn_decl
-            .inputs
-            .iter()
-            .flat_map(|i| i.attrs.as_ref())
-            .filter(|attr| {
-                let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
-                !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr)
-            })
-            .for_each(|attr| {
-                if attr.is_doc_comment() {
-                    self.err_handler()
-                        .struct_span_err(
-                            attr.span,
-                            "documentation comments cannot be applied to function parameters",
-                        )
-                        .span_label(attr.span, "doc comments are not allowed here")
-                        .emit();
-                } else {
-                    self.err_handler().span_err(
-                        attr.span,
-                        "allow, cfg, cfg_attr, deny, \
-                forbid, and warn are the only allowed built-in attributes in function parameters",
-                    )
-                }
-            });
-    }
-
-    fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
-        if let Defaultness::Default = defaultness {
-            self.err_handler()
-                .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
-                .emit();
-        }
-    }
-
-    fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
-        if body.is_some() {
-            return;
-        }
-
-        self.err_handler()
-            .struct_span_err(sp, &format!("associated {} in `impl` without body", ctx))
-            .span_suggestion(
-                self.session.source_map().end_point(sp),
-                &format!("provide a definition for the {}", ctx),
-                sugg.to_string(),
-                Applicability::HasPlaceholders,
-            )
-            .emit();
-    }
-
-    fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
-        let span = match bounds {
-            [] => return,
-            [b0] => b0.span(),
-            [b0, .., bl] => b0.span().to(bl.span()),
-        };
-        self.err_handler()
-            .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
-            .emit();
-    }
-
-    fn check_c_varadic_type(&self, decl: &FnDecl) {
-        for Param { ty, span, .. } in &decl.inputs {
-            if let TyKind::CVarArgs = ty.kind {
-                self.err_handler()
-                    .struct_span_err(
-                        *span,
-                        "only foreign or `unsafe extern \"C\" functions may be C-variadic",
-                    )
-                    .emit();
-            }
-        }
-    }
-}
-
-enum GenericPosition {
-    Param,
-    Arg,
-}
-
-fn validate_generics_order<'a>(
-    sess: &Session,
-    handler: &errors::Handler,
-    generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
-    pos: GenericPosition,
-    span: Span,
-) {
-    let mut max_param: Option<ParamKindOrd> = None;
-    let mut out_of_order = FxHashMap::default();
-    let mut param_idents = vec![];
-    let mut found_type = false;
-    let mut found_const = false;
-
-    for (kind, bounds, span, ident) in generics {
-        if let Some(ident) = ident {
-            param_idents.push((kind, bounds, param_idents.len(), ident));
-        }
-        let max_param = &mut max_param;
-        match max_param {
-            Some(max_param) if *max_param > kind => {
-                let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
-                entry.1.push(span);
-            }
-            Some(_) | None => *max_param = Some(kind),
-        };
-        match kind {
-            ParamKindOrd::Type => found_type = true,
-            ParamKindOrd::Const => found_const = true,
-            _ => {}
-        }
-    }
-
-    let mut ordered_params = "<".to_string();
-    if !out_of_order.is_empty() {
-        param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
-        let mut first = true;
-        for (_, bounds, _, ident) in param_idents {
-            if !first {
-                ordered_params += ", ";
-            }
-            ordered_params += &ident;
-            if let Some(bounds) = bounds {
-                if !bounds.is_empty() {
-                    ordered_params += ": ";
-                    ordered_params += &pprust::bounds_to_string(&bounds);
-                }
-            }
-            first = false;
-        }
-    }
-    ordered_params += ">";
-
-    let pos_str = match pos {
-        GenericPosition::Param => "parameter",
-        GenericPosition::Arg => "argument",
-    };
-
-    for (param_ord, (max_param, spans)) in &out_of_order {
-        let mut err = handler.struct_span_err(
-            spans.clone(),
-            &format!(
-                "{} {pos}s must be declared prior to {} {pos}s",
-                param_ord,
-                max_param,
-                pos = pos_str,
-            ),
-        );
-        if let GenericPosition::Param = pos {
-            err.span_suggestion(
-                span,
-                &format!(
-                    "reorder the {}s: lifetimes, then types{}",
-                    pos_str,
-                    if sess.features_untracked().const_generics { ", then consts" } else { "" },
-                ),
-                ordered_params.clone(),
-                Applicability::MachineApplicable,
-            );
-        }
-        err.emit();
-    }
-
-    // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs
-    // if we don't. Const parameters and type parameters can currently conflict if they
-    // are out-of-order.
-    if !out_of_order.is_empty() && found_type && found_const {
-        FatalError.raise();
-    }
-}
-
-impl<'a> Visitor<'a> for AstValidator<'a> {
-    fn visit_attribute(&mut self, attr: &Attribute) {
-        validate_attr::check_meta(&self.session.parse_sess, attr);
-    }
-
-    fn visit_expr(&mut self, expr: &'a Expr) {
-        match &expr.kind {
-            ExprKind::Closure(_, _, _, fn_decl, _, _) => {
-                self.check_fn_decl(fn_decl);
-            }
-            ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
-                span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
-            }
-            _ => {}
-        }
-
-        visit::walk_expr(self, expr);
-    }
-
-    fn visit_ty(&mut self, ty: &'a Ty) {
-        match ty.kind {
-            TyKind::BareFn(ref bfty) => {
-                self.check_fn_decl(&bfty.decl);
-                Self::check_decl_no_pat(&bfty.decl, |span, _| {
-                    struct_span_err!(
-                        self.session,
-                        span,
-                        E0561,
-                        "patterns aren't allowed in function pointer types"
-                    )
-                    .emit();
-                });
-                self.check_late_bound_lifetime_defs(&bfty.generic_params);
-            }
-            TyKind::TraitObject(ref bounds, ..) => {
-                let mut any_lifetime_bounds = false;
-                for bound in bounds {
-                    if let GenericBound::Outlives(ref lifetime) = *bound {
-                        if any_lifetime_bounds {
-                            span_err!(
-                                self.session,
-                                lifetime.ident.span,
-                                E0226,
-                                "only a single explicit lifetime bound is permitted"
-                            );
-                            break;
-                        }
-                        any_lifetime_bounds = true;
-                    }
-                }
-                self.no_questions_in_bounds(bounds, "trait object types", false);
-            }
-            TyKind::ImplTrait(_, ref bounds) => {
-                if self.is_impl_trait_banned {
-                    struct_span_err!(
-                        self.session,
-                        ty.span,
-                        E0667,
-                        "`impl Trait` is not allowed in path parameters"
-                    )
-                    .emit();
-                }
-
-                if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
-                    struct_span_err!(
-                        self.session,
-                        ty.span,
-                        E0666,
-                        "nested `impl Trait` is not allowed"
-                    )
-                    .span_label(outer_impl_trait_sp, "outer `impl Trait`")
-                    .span_label(ty.span, "nested `impl Trait` here")
-                    .emit();
-                }
-
-                if !bounds
-                    .iter()
-                    .any(|b| if let GenericBound::Trait(..) = *b { true } else { false })
-                {
-                    self.err_handler().span_err(ty.span, "at least one trait must be specified");
-                }
-
-                self.walk_ty(ty);
-                return;
-            }
-            _ => {}
-        }
-
-        self.walk_ty(ty)
-    }
-
-    fn visit_label(&mut self, label: &'a Label) {
-        self.check_label(label.ident);
-        visit::walk_label(self, label);
-    }
-
-    fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
-        self.check_lifetime(lifetime.ident);
-        visit::walk_lifetime(self, lifetime);
-    }
-
-    fn visit_item(&mut self, item: &'a Item) {
-        if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
-            self.has_proc_macro_decls = true;
-        }
-
-        match item.kind {
-            ItemKind::Impl(unsafety, polarity, _, _, Some(..), ref ty, ref impl_items) => {
-                self.invalid_visibility(&item.vis, None);
-                if let TyKind::Err = ty.kind {
-                    self.err_handler()
-                        .struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax")
-                        .help("use `auto trait Trait {}` instead")
-                        .emit();
-                }
-                if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
-                    span_err!(self.session, item.span, E0198, "negative impls cannot be unsafe");
-                }
-                for impl_item in impl_items {
-                    self.invalid_visibility(&impl_item.vis, None);
-                    if let AssocItemKind::Fn(ref sig, _) = impl_item.kind {
-                        self.check_trait_fn_not_const(sig.header.constness);
-                        self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
-                    }
-                }
-            }
-            ItemKind::Impl(unsafety, polarity, defaultness, _, None, _, _) => {
-                self.invalid_visibility(
-                    &item.vis,
-                    Some("place qualifiers on individual impl items instead"),
-                );
-                if unsafety == Unsafety::Unsafe {
-                    span_err!(self.session, item.span, E0197, "inherent impls cannot be unsafe");
-                }
-                if polarity == ImplPolarity::Negative {
-                    self.err_handler().span_err(item.span, "inherent impls cannot be negative");
-                }
-                if defaultness == Defaultness::Default {
-                    self.err_handler()
-                        .struct_span_err(item.span, "inherent impls cannot be default")
-                        .note("only trait implementations may be annotated with default")
-                        .emit();
-                }
-            }
-            ItemKind::Fn(ref sig, ref generics, _) => {
-                self.visit_fn_header(&sig.header);
-                self.check_fn_decl(&sig.decl);
-                // We currently do not permit const generics in `const fn`, as
-                // this is tantamount to allowing compile-time dependent typing.
-                if sig.header.constness.node == Constness::Const {
-                    // Look for const generics and error if we find any.
-                    for param in &generics.params {
-                        match param.kind {
-                            GenericParamKind::Const { .. } => {
-                                self.err_handler()
-                                    .struct_span_err(
-                                        item.span,
-                                        "const parameters are not permitted in `const fn`",
-                                    )
-                                    .emit();
-                            }
-                            _ => {}
-                        }
-                    }
-                }
-                // Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
-                match sig.header.ext {
-                    Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. })
-                    | Extern::Implicit
-                        if sig.header.unsafety == Unsafety::Unsafe => {}
-                    _ => self.check_c_varadic_type(&sig.decl),
-                }
-            }
-            ItemKind::ForeignMod(..) => {
-                self.invalid_visibility(
-                    &item.vis,
-                    Some("place qualifiers on individual foreign items instead"),
-                );
-            }
-            ItemKind::Enum(ref def, _) => {
-                for variant in &def.variants {
-                    self.invalid_visibility(&variant.vis, None);
-                    for field in variant.data.fields() {
-                        self.invalid_visibility(&field.vis, None);
-                    }
-                }
-            }
-            ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
-                if is_auto == IsAuto::Yes {
-                    // Auto traits cannot have generics, super traits nor contain items.
-                    if !generics.params.is_empty() {
-                        struct_span_err!(
-                            self.session,
-                            item.span,
-                            E0567,
-                            "auto traits cannot have generic parameters"
-                        )
-                        .emit();
-                    }
-                    if !bounds.is_empty() {
-                        struct_span_err!(
-                            self.session,
-                            item.span,
-                            E0568,
-                            "auto traits cannot have super traits"
-                        )
-                        .emit();
-                    }
-                    if !trait_items.is_empty() {
-                        struct_span_err!(
-                            self.session,
-                            item.span,
-                            E0380,
-                            "auto traits cannot have methods or associated items"
-                        )
-                        .emit();
-                    }
-                }
-                self.no_questions_in_bounds(bounds, "supertraits", true);
-            }
-            ItemKind::Mod(_) => {
-                // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                attr::first_attr_value_str_by_name(&item.attrs, sym::path);
-            }
-            ItemKind::Union(ref vdata, _) => {
-                if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
-                    self.err_handler()
-                        .span_err(item.span, "tuple and unit unions are not permitted");
-                }
-                if vdata.fields().is_empty() {
-                    self.err_handler().span_err(item.span, "unions cannot have zero fields");
-                }
-            }
-            _ => {}
-        }
-
-        visit::walk_item(self, item)
-    }
-
-    fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
-        match fi.kind {
-            ForeignItemKind::Fn(ref decl, _) => {
-                self.check_fn_decl(decl);
-                Self::check_decl_no_pat(decl, |span, _| {
-                    struct_span_err!(
-                        self.session,
-                        span,
-                        E0130,
-                        "patterns aren't allowed in foreign function declarations"
-                    )
-                    .span_label(span, "pattern not allowed in foreign function")
-                    .emit();
-                });
-            }
-            ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
-        }
-
-        visit::walk_foreign_item(self, fi)
-    }
-
-    // Mirrors `visit::walk_generic_args`, but tracks relevant state.
-    fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
-        match *generic_args {
-            GenericArgs::AngleBracketed(ref data) => {
-                walk_list!(self, visit_generic_arg, &data.args);
-                validate_generics_order(
-                    self.session,
-                    self.err_handler(),
-                    data.args.iter().map(|arg| {
-                        (
-                            match arg {
-                                GenericArg::Lifetime(..) => ParamKindOrd::Lifetime,
-                                GenericArg::Type(..) => ParamKindOrd::Type,
-                                GenericArg::Const(..) => ParamKindOrd::Const,
-                            },
-                            None,
-                            arg.span(),
-                            None,
-                        )
-                    }),
-                    GenericPosition::Arg,
-                    generic_args.span(),
-                );
-
-                // Type bindings such as `Item = impl Debug` in `Iterator<Item = Debug>`
-                // are allowed to contain nested `impl Trait`.
-                self.with_impl_trait(None, |this| {
-                    walk_list!(
-                        this,
-                        visit_assoc_ty_constraint_from_generic_args,
-                        &data.constraints
-                    );
-                });
-            }
-            GenericArgs::Parenthesized(ref data) => {
-                walk_list!(self, visit_ty, &data.inputs);
-                if let FunctionRetTy::Ty(ty) = &data.output {
-                    // `-> Foo` syntax is essentially an associated type binding,
-                    // so it is also allowed to contain nested `impl Trait`.
-                    self.with_impl_trait(None, |this| this.visit_ty(ty));
-                }
-            }
-        }
-    }
-
-    fn visit_generics(&mut self, generics: &'a Generics) {
-        let mut prev_ty_default = None;
-        for param in &generics.params {
-            if let GenericParamKind::Type { ref default, .. } = param.kind {
-                if default.is_some() {
-                    prev_ty_default = Some(param.ident.span);
-                } else if let Some(span) = prev_ty_default {
-                    self.err_handler()
-                        .span_err(span, "type parameters with a default must be trailing");
-                    break;
-                }
-            }
-        }
-
-        validate_generics_order(
-            self.session,
-            self.err_handler(),
-            generics.params.iter().map(|param| {
-                let ident = Some(param.ident.to_string());
-                let (kind, ident) = match &param.kind {
-                    GenericParamKind::Lifetime { .. } => (ParamKindOrd::Lifetime, ident),
-                    GenericParamKind::Type { .. } => (ParamKindOrd::Type, ident),
-                    GenericParamKind::Const { ref ty } => {
-                        let ty = pprust::ty_to_string(ty);
-                        (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
-                    }
-                };
-                (kind, Some(&*param.bounds), param.ident.span, ident)
-            }),
-            GenericPosition::Param,
-            generics.span,
-        );
-
-        for predicate in &generics.where_clause.predicates {
-            if let WherePredicate::EqPredicate(ref predicate) = *predicate {
-                self.err_handler()
-                    .struct_span_err(
-                        predicate.span,
-                        "equality constraints are not yet supported in `where` clauses",
-                    )
-                    .span_label(predicate.span, "not supported")
-                    .note(
-                        "for more information, see https://github.com/rust-lang/rust/issues/20041",
-                    )
-                    .emit();
-            }
-        }
-
-        visit::walk_generics(self, generics)
-    }
-
-    fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        if let GenericParamKind::Lifetime { .. } = param.kind {
-            self.check_lifetime(param.ident);
-        }
-        visit::walk_generic_param(self, param);
-    }
-
-    fn visit_pat(&mut self, pat: &'a Pat) {
-        match pat.kind {
-            PatKind::Lit(ref expr) => {
-                self.check_expr_within_pat(expr, false);
-            }
-            PatKind::Range(ref start, ref end, _) => {
-                self.check_expr_within_pat(start, true);
-                self.check_expr_within_pat(end, true);
-            }
-            _ => {}
-        }
-
-        visit::walk_pat(self, pat)
-    }
-
-    fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
-        if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
-            // A type binding, eg `for<'c> Foo: Send+Clone+'c`
-            self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
-        }
-        visit::walk_where_predicate(self, p);
-    }
-
-    fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
-        self.check_late_bound_lifetime_defs(&t.bound_generic_params);
-        visit::walk_poly_trait_ref(self, t, m);
-    }
-
-    fn visit_variant_data(&mut self, s: &'a VariantData) {
-        self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
-    }
-
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'a EnumDef,
-        generics: &'a Generics,
-        item_id: NodeId,
-        _: Span,
-    ) {
-        self.with_banned_assoc_ty_bound(|this| {
-            visit::walk_enum_def(this, enum_definition, generics, item_id)
-        })
-    }
-
-    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
-        match &ii.kind {
-            AssocItemKind::Const(_, body) => {
-                self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
-            }
-            AssocItemKind::Fn(sig, body) => {
-                self.check_impl_item_provided(ii.span, body, "function", " { <body> }");
-                self.check_fn_decl(&sig.decl);
-            }
-            AssocItemKind::TyAlias(bounds, body) => {
-                self.check_impl_item_provided(ii.span, body, "type", " = <type>;");
-                self.check_impl_assoc_type_no_bounds(bounds);
-            }
-            _ => {}
-        }
-        visit::walk_impl_item(self, ii);
-    }
-
-    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
-        self.invalid_visibility(&ti.vis, None);
-        self.check_defaultness(ti.span, ti.defaultness);
-
-        if let AssocItemKind::Fn(sig, block) = &ti.kind {
-            self.check_fn_decl(&sig.decl);
-            self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node);
-            self.check_trait_fn_not_const(sig.header.constness);
-            if block.is_none() {
-                Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
-                    if mut_ident {
-                        self.lint_buffer.buffer_lint(
-                            lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
-                            ti.id,
-                            span,
-                            "patterns aren't allowed in methods without bodies",
-                        );
-                    } else {
-                        struct_span_err!(
-                            self.session,
-                            span,
-                            E0642,
-                            "patterns aren't allowed in methods without bodies"
-                        )
-                        .emit();
-                    }
-                });
-            }
-        }
-
-        visit::walk_trait_item(self, ti);
-    }
-
-    fn visit_assoc_item(&mut self, item: &'a AssocItem) {
-        if let AssocItemKind::Fn(sig, _) = &item.kind {
-            self.check_c_varadic_type(&sig.decl);
-        }
-        visit::walk_assoc_item(self, item);
-    }
-}
-
-pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {
-    let mut validator = AstValidator {
-        session,
-        has_proc_macro_decls: false,
-        outer_impl_trait: None,
-        is_impl_trait_banned: false,
-        is_assoc_ty_bound_banned: false,
-        lint_buffer: lints,
-    };
-    visit::walk_crate(&mut validator, krate);
-
-    validator.has_proc_macro_decls
-}
index 30ec0fe7185cd1eeca22e2649e6a45ade035e1f4..39ba2fbc63b4392dace79cacf1f9dc047e43a4cd 100644 (file)
@@ -7,18 +7,18 @@
 //! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
 //! through, but errors for structured control flow in a `const` should be emitted here.
 
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::map::Map;
 use rustc::session::config::nightly_options;
+use rustc::session::parse::feature_err;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_span::{sym, Span, Symbol};
 use syntax::ast::Mutability;
-use syntax::feature_gate::feature_err;
-use syntax::span_err;
 
 use std::fmt;
 
@@ -154,7 +154,7 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
             required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
 
         match missing_gates.as_slice() {
-            &[] => span_err!(self.tcx.sess, span, E0744, "{}", msg),
+            &[] => struct_span_err!(self.tcx.sess, span, E0744, "{}", msg).emit(),
 
             // If the user enabled `#![feature(const_loop)]` but not `#![feature(const_if_match)]`,
             // explain why their `while` loop is being rejected.
@@ -200,7 +200,9 @@ fn recurse_into(&mut self, kind: Option<ConstKind>, f: impl FnOnce(&mut Self)) {
 }
 
 impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
index 0c435a166636347d3e30edd62d71940c351400d9..f2778b2aa6bcd220d38ba71e8c9a341243302851 100644 (file)
@@ -2,8 +2,7 @@
 // closely. The idea is that all reachable symbols are live, codes called
 // from live codes are live, and everything else is dead.
 
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc::lint;
+use rustc::hir::map::Map;
 use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc::middle::privacy;
 use rustc::ty::{self, DefIdTree, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{Node, PatKind, TyKind};
+use rustc_session::lint;
 
 use rustc_span;
 use rustc_span::symbol::sym;
@@ -210,7 +211,9 @@ fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &[hir::Field<'_>])
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
@@ -563,11 +566,13 @@ fn warn_dead_code(
 }
 
 impl Visitor<'tcx> for DeadVisitor<'tcx> {
+    type Map = Map<'tcx>;
+
     /// Walk nested items in place so that we don't report dead-code
     /// on inner functions when the outer function is already getting
     /// an error. We could do this also by checking the parents, but
     /// this is how the code is setup and it seems harmless enough.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
index f84f998420236fa622dcbbfa822c82ba63cb561b..c083830b730cc0a91f3579c6c7d02389b4667426 100644 (file)
@@ -73,7 +73,7 @@ fn collect_item(
                 )),
             };
             if let Some(span) = tcx.hir().span_if_local(original_def_id) {
-                span_note!(&mut err, span, "first defined here.");
+                err.span_note(span, "first defined here.");
             } else {
                 err.note(&format!(
                     "first defined in crate `{}`.",
index 91b787b7c99f04d726778e583f8a79fe59f1a9b7..028d7c662758a4adf87b3dd69c2e94d8851e7fd4 100644 (file)
@@ -3,11 +3,12 @@
 use rustc::session::{config, Session};
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
+use rustc_errors::struct_span_err;
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ImplItem, Item, ItemKind, TraitItem};
 use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use syntax::attr;
 use syntax::entry::EntryPointType;
 
@@ -108,7 +109,8 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
             if ctxt.main_fn.is_none() {
                 ctxt.main_fn = Some((item.hir_id, item.span));
             } else {
-                span_err!(ctxt.session, item.span, E0136, "multiple `main` functions");
+                struct_span_err!(ctxt.session, item.span, E0136, "multiple `main` functions")
+                    .emit();
             }
         }
         EntryPointType::OtherMain => {
@@ -166,8 +168,9 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
     }
 
     // There is no main function.
-    let mut err = struct_err!(
+    let mut err = struct_span_err!(
         tcx.sess,
+        DUMMY_SP,
         E0601,
         "`main` function not found in crate `{}`",
         tcx.crate_name(LOCAL_CRATE)
index 3eca602cf86038addadc125a69395db28634c1ba..b6ca2b3a595db4d052557ad7af0f6e882bb7d907 100644 (file)
@@ -2,10 +2,11 @@
 // pieces of AST and HIR. The resulting numbers are good approximations but not
 // completely accurate (some things might be counted twice, others missed).
 
-use rustc::hir::intravisit as hir_visit;
+use rustc::hir::map::Map;
 use rustc::util::common::to_readable_str;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
+use rustc_hir::intravisit as hir_visit;
 use rustc_hir::HirId;
 use rustc_span::Span;
 use syntax::ast::{self, AttrId, NodeId};
@@ -92,7 +93,9 @@ fn visit_param(&mut self, param: &'v hir::Param<'v>) {
         hir_visit::walk_param(self, param)
     }
 
-    fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
+    type Map = Map<'v>;
+
+    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<'_, Self::Map> {
         panic!("visit_nested_xxx must be manually implemented in this visitor")
     }
 
index cc311916cab91f159daeb4d69d1a6cf286c4ebcf..2c26707a518508da0e5bee0e374855f9f302f8e8 100644 (file)
@@ -1,11 +1,12 @@
+use rustc::hir::map::Map;
 use rustc::ty::layout::{LayoutError, Pointer, SizeSkeleton, VariantIdx};
 use rustc::ty::query::Providers;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir as hir;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_index::vec::Idx;
 use rustc_span::{sym, Span};
 use rustc_target::spec::abi::Abi::RustIntrinsic;
@@ -123,7 +124,9 @@ fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
 }
 
 impl Visitor<'tcx> for ItemVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
@@ -138,7 +141,9 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
 }
 
 impl Visitor<'tcx> for ExprVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
index a692c45ced40bedf4139cd40993653855665c3e9..65eb07b989d83ab871380cb6048a096c1aa056ad 100644 (file)
 extern crate rustc;
 #[macro_use]
 extern crate log;
-#[macro_use]
-extern crate syntax;
 
 use rustc::ty::query::Providers;
 
-pub mod ast_validation;
 mod check_const;
 pub mod dead;
 mod diagnostic_items;
index df3e4ee3af540383befa1e44756b4011cb1f91c4..8ae729128978655b9268599607bc97a8960b800d 100644 (file)
@@ -4,11 +4,13 @@
 // and `#[unstable (..)]`), but are not declared in one single location
 // (unlike lang features), which means we need to collect them instead.
 
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::middle::lib_features::LibFeatures;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
+use rustc_errors::struct_span_err;
 use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_span::symbol::Symbol;
 use rustc_span::{sym, Span};
 use syntax::ast::{Attribute, MetaItem, MetaItemKind};
@@ -112,7 +114,9 @@ fn span_feature_error(&self, span: Span, msg: &str) {
 }
 
 impl Visitor<'tcx> for LibFeatureCollector<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
index 3ae5e4f72b7444ec45200563b8fa708616238ae7..7718139f6e9246af2b0eb2ef03781ee4c3de31e6 100644 (file)
 use self::LiveNodeKind::*;
 use self::VarKind::*;
 
-use errors::Applicability;
-use rustc::hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::lint;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -153,7 +154,9 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
 }
 
 impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
@@ -1061,7 +1064,7 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
                             .sess
                             .struct_span_err(expr.span, "`break` to unknown label")
                             .emit();
-                        errors::FatalError.raise()
+                        rustc_errors::FatalError.raise()
                     }
                 }
             }
@@ -1348,7 +1351,9 @@ fn propagate_through_loop(
 // Checking for error conditions
 
 impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
@@ -1508,13 +1513,16 @@ fn report_unused(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Vari
                 if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() };
 
             if is_assigned {
-                self.ir.tcx.lint_hir_note(
-                    lint::builtin::UNUSED_VARIABLES,
-                    hir_id,
-                    spans,
-                    &format!("variable `{}` is assigned to, but never used", name),
-                    &format!("consider using `_{}` instead", name),
-                );
+                self.ir
+                    .tcx
+                    .struct_span_lint_hir(
+                        lint::builtin::UNUSED_VARIABLES,
+                        hir_id,
+                        spans,
+                        &format!("variable `{}` is assigned to, but never used", name),
+                    )
+                    .note(&format!("consider using `_{}` instead", name))
+                    .emit();
             } else {
                 let mut err = self.ir.tcx.struct_span_lint_hir(
                     lint::builtin::UNUSED_VARIABLES,
index ec8c8ee8be9b08904ac4e79450e7cb06edc4f8f9..5ad5795c777d48bee1c011cc0abacfd4d7b9a369 100644 (file)
@@ -2,16 +2,15 @@
 
 use rustc::session::Session;
 
-use errors::Applicability;
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::map::Map;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Destination, Movability, Node};
 use rustc_span::Span;
-use syntax::struct_span_err;
 
 use rustc_error_codes::*;
 
@@ -45,7 +44,9 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
 }
 
 impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> {
+    type Map = Map<'hir>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.hir_map)
     }
 
index 9b529401049b0f924e2e262a2b6cb2296bd2b918..5ce677f52cea670a016596344af2f270a0aad1ce 100644 (file)
@@ -5,8 +5,7 @@
 // makes all other generics or inline functions that it references
 // reachable as well.
 
-use rustc::hir::intravisit;
-use rustc::hir::intravisit::{NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc::middle::privacy;
 use rustc::session::config;
@@ -18,6 +17,8 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::intravisit;
+use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirIdSet, Node};
 use rustc_target::spec::abi::Abi;
@@ -82,7 +83,9 @@ struct ReachableContext<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
index f2aa5aff171666d5da695dd99753f191d9e988f7..e79ca5c78d6d64bd5e8dc31961e2b40db38d82d8 100644 (file)
@@ -6,17 +6,19 @@
 //!
 //! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/borrowck.html
 
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::middle::region::*;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Arm, Block, Expr, Local, Node, Pat, PatKind, Stmt};
 use rustc_index::vec::Idx;
 use rustc_span::source_map;
 use rustc_span::Span;
+use syntax::walk_list;
 
 use std::mem;
 
@@ -694,7 +696,9 @@ fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) {
 }
 
 impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
index 4c5b57791c552dd70cd28d09f5a7856bc4e899b0..af37d218d68f08b1ecf4f0327fa68cfd161113c1 100644 (file)
@@ -1,23 +1,26 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::lint;
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability::{DeprecationEntry, Index};
+use rustc::session::parse::feature_err;
 use rustc::session::Session;
+use rustc::traits::misc::can_type_implement_copy;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Generics, HirId, Item, StructField, Variant};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use syntax::ast::Attribute;
 use syntax::attr::{self, Stability};
-use syntax::feature_gate::feature_err;
 
 use std::cmp::Ordering;
 use std::mem::replace;
@@ -202,7 +205,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
@@ -291,7 +296,9 @@ fn check_missing_stability(&self, hir_id: HirId, span: Span, name: &str) {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
@@ -427,10 +434,12 @@ struct Checker<'tcx> {
 }
 
 impl Visitor<'tcx> for Checker<'tcx> {
+    type Map = Map<'tcx>;
+
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
@@ -488,7 +497,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     .emit();
                 } else {
                     let param_env = self.tcx.param_env(def_id);
-                    if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
+                    if !can_type_implement_copy(self.tcx, param_env, ty).is_ok() {
                         feature_err(
                             &self.tcx.sess.parse_sess,
                             sym::untagged_unions,
index 54cceca7d3afb3615a08b8e2737171b9b3bce75a..41e6c699c340ec592b1a243ddc377b34b154a0ef 100644 (file)
@@ -12,7 +12,9 @@ doctest = false
 
 [dependencies]
 rustc = { path = "../librustc" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_lint = { path = "../librustc_lint" }
 rustc_metadata = { path = "../librustc_metadata" }
 syntax = { path = "../libsyntax" }
 rustc_span = { path = "../librustc_span" }
index 682d223f565de3f8ea27b5b55a4e18139bc541ee..10712eb60b9e3bf21de86462d15a5f884b806c86 100644 (file)
@@ -9,7 +9,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(nll)]
 
-use rustc::lint::LintStore;
+use rustc_lint::LintStore;
 
 pub mod build;
 pub mod load;
index 2215e49ec977a9834fdb2545f7936e109f712969..65661ec24f07f9a57ac7c092bdb097ab90dc8e9f 100644 (file)
@@ -3,18 +3,17 @@
 use crate::Registry;
 use rustc::middle::cstore::MetadataLoader;
 use rustc::session::Session;
+use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_metadata::locator;
-
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use syntax::ast::{Crate, Ident};
+
 use std::borrow::ToOwned;
 use std::env;
 use std::mem;
 use std::path::PathBuf;
-use syntax::ast::{Crate, Ident};
-use syntax::struct_span_err;
-
-use rustc_error_codes::*;
 
 /// Pointer to a registrar function.
 type PluginRegistrarFn = fn(&mut Registry<'_>);
index 6c9a2d65ef7df764462fda4c210b0aeb6bf83854..795b6c107fe944040c209b51d553361519eda551 100644 (file)
@@ -10,6 +10,7 @@ path = "lib.rs"
 
 [dependencies]
 rustc = { path = "../librustc" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_typeck = { path = "../librustc_typeck" }
 syntax = { path = "../libsyntax" }
index c932e8bb1f46d061a729e25cacc13872bb109d88..70d4841ec244b15b91fabb6e6c9ffa8eb76058ea 100644 (file)
@@ -3,11 +3,8 @@
 #![feature(nll)]
 #![recursion_limit = "256"]
 
-#[macro_use]
-extern crate syntax;
-
 use rustc::bug;
-use rustc::hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::lint;
 use rustc::middle::privacy::{AccessLevel, AccessLevels};
 use rustc::ty::fold::TypeVisitor;
 use rustc::ty::subst::InternalSubsts;
 use rustc::ty::{self, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, sym};
@@ -374,7 +373,9 @@ struct PubRestrictedVisitor<'tcx> {
 }
 
 impl Visitor<'tcx> for PubRestrictedVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
     fn visit_vis(&mut self, vis: &'tcx hir::Visibility<'tcx>) {
@@ -651,6 +652,9 @@ fn update_visibility_of_intermediate_use_statements(
             if let Some(item) = module
                 .res
                 .and_then(|res| res.mod_def_id())
+                // If the module is `self`, i.e. the current crate,
+                // there will be no corresponding item.
+                .filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
                 .and_then(|def_id| self.tcx.hir().as_local_hir_id(def_id))
                 .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
             {
@@ -672,9 +676,11 @@ fn update_visibility_of_intermediate_use_statements(
 }
 
 impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
+    type Map = Map<'tcx>;
+
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
@@ -1041,9 +1047,11 @@ fn check_field(
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
@@ -1181,9 +1189,11 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
@@ -1439,7 +1449,9 @@ fn item_is_public(&self, id: &hir::HirId, vis: &hir::Visibility<'_>) -> bool {
 }
 
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+    type Map = Map<'v>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
@@ -1465,9 +1477,11 @@ fn visit_expr(&mut self, _: &hir::Expr<'_>) {}
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
@@ -1908,7 +1922,9 @@ fn check_assoc_item(
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
index 01e5d75d2b57d5697d97b7f51dbe47baeb158e20..af37e7b5b76ac5132918f256ba415cc0d2197a42 100644 (file)
@@ -14,16 +14,16 @@ doctest = false
 bitflags = "1.2.1"
 log = "0.4"
 syntax = { path = "../libsyntax" }
-rustc_expand = { path = "../librustc_expand" }
 arena = { path = "../libarena" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
-rustc_span = { path = "../librustc_span" }
 rustc = { path = "../librustc" }
 rustc_ast_lowering = { path = "../librustc_ast_lowering" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_expand = { path = "../librustc_expand" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_session = { path = "../librustc_session" }
+rustc_span = { path = "../librustc_span" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
index 46dde451c7ffc492cc399553f31af4ed1401965d..291386413d647e898ac38a7210c63ed67d5486c0 100644 (file)
 use rustc::hir::exports::Export;
 use rustc::middle::cstore::CrateStore;
 use rustc::ty;
-use rustc_hir::def::{self, *};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc_metadata::creader::LoadedMacro;
-
 use rustc_data_structures::sync::Lrc;
-use std::cell::Cell;
-use std::ptr;
-
-use errors::Applicability;
-
+use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_expand::base::SyntaxExtension;
 use rustc_expand::expand::AstFragment;
+use rustc_hir::def::{self, *};
+use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_metadata::creader::LoadedMacro;
 use rustc_span::hygiene::{ExpnId, MacroKind};
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym};
 use syntax::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind};
 use syntax::ast::{Ident, Name};
 use syntax::attr;
-use syntax::span_err;
 use syntax::token::{self, Token};
 use syntax::visit::{self, Visitor};
 
 use log::debug;
-
-use rustc_error_codes::*;
+use std::cell::Cell;
+use std::ptr;
 
 type Res = def::Res<NodeId>;
 
@@ -954,22 +949,27 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>) -> b
         for attr in &item.attrs {
             if attr.check_name(sym::macro_use) {
                 if self.parent_scope.module.parent.is_some() {
-                    span_err!(
+                    struct_span_err!(
                         self.r.session,
                         item.span,
                         E0468,
                         "an `extern crate` loading macros must be at the crate root"
-                    );
+                    )
+                    .emit();
                 }
                 if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
                     if orig_name == kw::SelfLower {
-                        self.r.session.span_err(
-                            attr.span,
-                            "`macro_use` is not supported on `extern crate self`",
-                        );
+                        self.r
+                            .session
+                            .struct_span_err(
+                                attr.span,
+                                "`macro_use` is not supported on `extern crate self`",
+                            )
+                            .emit();
                     }
                 }
-                let ill_formed = |span| span_err!(self.r.session, span, E0466, "bad macro import");
+                let ill_formed =
+                    |span| struct_span_err!(self.r.session, span, E0466, "bad macro import").emit();
                 match attr.meta() {
                     Some(meta) => match meta.kind {
                         MetaItemKind::Word => {
@@ -1042,7 +1042,8 @@ fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>) -> b
                         allow_shadowing,
                     );
                 } else {
-                    span_err!(self.r.session, ident.span, E0469, "imported macro not found");
+                    struct_span_err!(self.r.session, ident.span, E0469, "imported macro not found")
+                        .emit();
                 }
             }
         }
index 6561072a21bcee699e102c6d779067a17b06e75a..4a6df92d82260fda278de716af1ce5f44fb14bfc 100644 (file)
 use crate::imports::ImportDirectiveSubclass;
 use crate::Resolver;
 
-use errors::pluralize;
 use rustc::{lint, ty};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::pluralize;
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::node_id::NodeMap;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use syntax::ast;
@@ -317,7 +318,7 @@ impl Resolver<'_> {
                 unused.use_tree_id,
                 ms,
                 &msg,
-                lint::builtin::BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
+                BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes),
             );
         }
     }
index ba3d23145692ebf3985484ab5e35b9f9419f9c82..974206797549906f2e40c5f690353338e037b385 100644 (file)
@@ -1,22 +1,21 @@
 use std::cmp::Reverse;
 
-use errors::{Applicability, DiagnosticBuilder};
 use log::debug;
 use rustc::bug;
 use rustc::session::Session;
 use rustc::ty::{self, DefIdTree};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{BytePos, MultiSpan, Span};
 use syntax::ast::{self, Ident, Path};
 use syntax::print::pprust;
-use syntax::struct_span_err;
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use crate::imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver};
@@ -781,8 +780,14 @@ fn lookup_import_candidates_from_module<FilterFn>(
                 suggestion.candidate.to_string(),
                 Applicability::MaybeIncorrect,
             );
-            let def_span =
-                suggestion.res.opt_def_id().and_then(|def_id| self.definitions.opt_span(def_id));
+            let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
+                LOCAL_CRATE => self.definitions.opt_span(def_id),
+                _ => Some(
+                    self.session
+                        .source_map()
+                        .def_span(self.cstore().get_span_untracked(def_id, self.session)),
+                ),
+            });
             if let Some(span) = def_span {
                 err.span_label(
                     span,
index 5ede0564b1ae50759dd12b1c0c8ed49e26582615..8fe17e89444cd0aa11e1607805a40fa64fa54e90 100644 (file)
 use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak};
 use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};
 
-use errors::{pluralize, Applicability};
-
 use rustc::hir::exports::Export;
-use rustc::lint::builtin::BuiltinLintDiagnostics;
 use rustc::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
-use rustc::session::DiagnosticMessageId;
 use rustc::ty;
 use rustc::{bug, span_bug};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
+use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_hir::def::{self, PartialRes};
 use rustc_hir::def_id::DefId;
+use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::DiagnosticMessageId;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::kw;
 use rustc_span::{MultiSpan, Span};
 use syntax::ast::{Ident, Name, NodeId};
+use syntax::unwrap_or;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax::{struct_span_err, unwrap_or};
 
 use rustc_error_codes::*;
 
index fb7aacba2dc48135dc6c57ef7cf7c28b2b634b71..defca4944bcd819fac9dbadbf9120b8fbeb36ba9 100644 (file)
@@ -11,9 +11,9 @@
 use crate::{Module, ModuleOrUniformRoot, NameBindingKind, ParentScope, PathResult};
 use crate::{ResolutionError, Resolver, Segment, UseError};
 
-use log::debug;
 use rustc::{bug, lint, span_bug};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
@@ -27,6 +27,7 @@
 use syntax::visit::{self, FnKind, Visitor};
 use syntax::{unwrap_or, walk_list};
 
+use log::debug;
 use std::collections::BTreeSet;
 use std::mem::replace;
 
@@ -304,32 +305,21 @@ fn descr_expected(self) -> &'static str {
         }
     }
 
-    fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
-        syntax::diagnostic_used!(E0404);
-        syntax::diagnostic_used!(E0405);
-        syntax::diagnostic_used!(E0412);
-        syntax::diagnostic_used!(E0422);
-        syntax::diagnostic_used!(E0423);
-        syntax::diagnostic_used!(E0425);
-        syntax::diagnostic_used!(E0531);
-        syntax::diagnostic_used!(E0532);
-        syntax::diagnostic_used!(E0573);
-        syntax::diagnostic_used!(E0574);
-        syntax::diagnostic_used!(E0575);
-        syntax::diagnostic_used!(E0576);
+    fn error_code(self, has_unexpected_resolution: bool) -> DiagnosticId {
+        use rustc_errors::error_code;
         match (self, has_unexpected_resolution) {
-            (PathSource::Trait(_), true) => "E0404",
-            (PathSource::Trait(_), false) => "E0405",
-            (PathSource::Type, true) => "E0573",
-            (PathSource::Type, false) => "E0412",
-            (PathSource::Struct, true) => "E0574",
-            (PathSource::Struct, false) => "E0422",
-            (PathSource::Expr(..), true) => "E0423",
-            (PathSource::Expr(..), false) => "E0425",
-            (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
-            (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
-            (PathSource::TraitItem(..), true) => "E0575",
-            (PathSource::TraitItem(..), false) => "E0576",
+            (PathSource::Trait(_), true) => error_code!(E0404),
+            (PathSource::Trait(_), false) => error_code!(E0405),
+            (PathSource::Type, true) => error_code!(E0573),
+            (PathSource::Type, false) => error_code!(E0412),
+            (PathSource::Struct, true) => error_code!(E0574),
+            (PathSource::Struct, false) => error_code!(E0422),
+            (PathSource::Expr(..), true) => error_code!(E0423),
+            (PathSource::Expr(..), false) => error_code!(E0425),
+            (PathSource::Pat, true) | (PathSource::TupleStruct, true) => error_code!(E0532),
+            (PathSource::Pat, false) | (PathSource::TupleStruct, false) => error_code!(E0531),
+            (PathSource::TraitItem(..), true) => error_code!(E0575),
+            (PathSource::TraitItem(..), false) => error_code!(E0576),
         }
     }
 }
index 5a12a75a8556ee8861518daf7703ffbf58a1974a..151f3e834e5de83c59307d6630a0722b9a3db2e8 100644 (file)
@@ -4,10 +4,10 @@
 use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
 
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
-use log::debug;
 use rustc::session::config::nightly_options;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_error_codes::*;
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
@@ -18,7 +18,7 @@
 use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
 use syntax::util::lev_distance::find_best_match_for_name;
 
-use rustc_error_codes::*;
+use log::debug;
 
 type Res = def::Res<ast::NodeId>;
 
@@ -73,7 +73,6 @@ pub(crate) fn smart_resolve_report_errors(
         let expected = source.descr_expected();
         let path_str = Segment::names_to_string(path);
         let item_str = path.last().unwrap().ident;
-        let code = source.error_code(res.is_some());
         let (base_msg, fallback_label, base_span, could_be_expr) = if let Some(res) = res {
             (
                 format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
@@ -123,7 +122,7 @@ pub(crate) fn smart_resolve_report_errors(
             )
         };
 
-        let code = DiagnosticId::Error(code.into());
+        let code = source.error_code(res.is_some());
         let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
 
         // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
@@ -140,8 +139,7 @@ pub(crate) fn smart_resolve_report_errors(
 
         // Emit special messages for unresolved `Self` and `self`.
         if is_self_type(path, ns) {
-            syntax::diagnostic_used!(E0411);
-            err.code(DiagnosticId::Error("E0411".into()));
+            err.code(rustc_errors::error_code!(E0411));
             err.span_label(
                 span,
                 format!("`Self` is only available in impls, traits, and type definitions"),
@@ -151,8 +149,7 @@ pub(crate) fn smart_resolve_report_errors(
         if is_self_value(path, ns) {
             debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
 
-            syntax::diagnostic_used!(E0424);
-            err.code(DiagnosticId::Error("E0424".into()));
+            err.code(rustc_errors::error_code!(E0424));
             err.span_label(span, match source {
                 PathSource::Pat => format!(
                     "`self` value is a keyword and may not be bound to variables or shadowed",
index 199752b93c1377e573a247830cd4d423854e64ea..8e4630cf7d69641cac65ad7031e8307037b9123b 100644 (file)
 
 use Determinacy::*;
 
-use errors::{Applicability, DiagnosticBuilder};
 use rustc::hir::exports::ExportMap;
-use rustc::hir::map::Definitions;
+use rustc::hir::map::{DefKey, Definitions};
 use rustc::lint;
 use rustc::middle::cstore::{CrateStore, MetadataLoaderDyn};
-use rustc::session::Session;
 use rustc::span_bug;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, DefIdTree, ResolverOutputs};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_expand::base::SyntaxExtension;
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
@@ -39,7 +38,9 @@
 use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
 use rustc_hir::{GlobMap, TraitMap};
 use rustc_metadata::creader::{CStore, CrateLoader};
+use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::node_id::{NodeMap, NodeSet};
+use rustc_session::Session;
 use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym};
@@ -49,8 +50,8 @@
 use syntax::ast::{ItemKind, Path};
 use syntax::attr;
 use syntax::print::pprust;
+use syntax::unwrap_or;
 use syntax::visit::{self, Visitor};
-use syntax::{struct_span_err, unwrap_or};
 
 use log::debug;
 use std::cell::{Cell, RefCell};
@@ -960,7 +961,7 @@ pub struct Resolver<'a> {
     /// when visiting the correspondent variants.
     variant_vis: DefIdMap<ty::Visibility>,
 
-    lint_buffer: lint::LintBuffer,
+    lint_buffer: LintBuffer,
 
     next_node_id: NodeId,
 }
@@ -1027,8 +1028,12 @@ fn parent(self, id: DefId) -> Option<DefId> {
 /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
 /// the resolver is no longer needed as all the relevant information is inline.
 impl rustc_ast_lowering::Resolver for Resolver<'_> {
-    fn cstore(&self) -> &dyn CrateStore {
-        self.cstore()
+    fn def_key(&mut self, id: DefId) -> DefKey {
+        if id.is_local() { self.definitions().def_key(id.index) } else { self.cstore().def_key(id) }
+    }
+
+    fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
+        self.cstore().item_generics_num_lifetimes(def_id, sess)
     }
 
     fn resolve_str_path(
@@ -1078,7 +1083,7 @@ fn definitions(&mut self) -> &mut Definitions {
         &mut self.definitions
     }
 
-    fn lint_buffer(&mut self) -> &mut lint::LintBuffer {
+    fn lint_buffer(&mut self) -> &mut LintBuffer {
         &mut self.lint_buffer
     }
 
@@ -1237,7 +1242,7 @@ pub fn new(
                 .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
                 .collect(),
             variant_vis: Default::default(),
-            lint_buffer: lint::LintBuffer::default(),
+            lint_buffer: LintBuffer::default(),
             next_node_id: NodeId::from_u32(1),
         }
     }
@@ -1252,7 +1257,7 @@ pub fn next_node_id(&mut self) -> NodeId {
         self.next_node_id
     }
 
-    pub fn lint_buffer(&mut self) -> &mut lint::LintBuffer {
+    pub fn lint_buffer(&mut self) -> &mut LintBuffer {
         &mut self.lint_buffer
     }
 
@@ -1709,10 +1714,10 @@ fn resolve_ident_in_lexical_scope(
                     if let Some(node_id) = poisoned {
                         self.lint_buffer.buffer_lint_with_diagnostic(
                             lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-                            node_id, ident.span,
+                            node_id,
+                            ident.span,
                             &format!("cannot find {} `{}` in this scope", ns.descr(), ident),
-                            lint::builtin::BuiltinLintDiagnostics::
-                                ProcMacroDeriveResolutionFallback(ident.span),
+                            BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(ident.span),
                         );
                     }
                     return Some(LexicalScopeBinding::Item(binding));
@@ -2263,7 +2268,7 @@ fn lint_if_path_starts_with_module(
             }
         }
 
-        let diag = lint::builtin::BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
+        let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
         self.lint_buffer.buffer_lint_with_diagnostic(
             lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
             diag_id,
@@ -2558,9 +2563,10 @@ fn report_errors(&mut self, krate: &Crate) {
                        cannot be referred to by absolute paths";
             self.lint_buffer.buffer_lint_with_diagnostic(
                 lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
-                CRATE_NODE_ID, span_use, msg,
-                lint::builtin::BuiltinLintDiagnostics::
-                    MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
+                CRATE_NODE_ID,
+                span_use,
+                msg,
+                BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
             );
         }
 
index 4cd3a9e1a8082fdfe668619f195fb5da5cd56c69..d6143eec73c00f3e7d22d16c4443fd4754b1a37d 100644 (file)
@@ -5,8 +5,6 @@
 //! used between functions, and they operate in a purely top-down
 //! way. Therefore, we break lifetime name resolution into a separate pass.
 
-use errors::{pluralize, Applicability, DiagnosticBuilder};
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::map::Map;
 use rustc::lint;
 use rustc::middle::resolve_lifetime::*;
 use rustc::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
 use rustc::{bug, span_bug};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
 use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
 use rustc_span::symbol::{kw, sym};
@@ -26,7 +26,7 @@
 use std::mem::{replace, take};
 use syntax::ast;
 use syntax::attr;
-use syntax::{help, span_err, struct_span_err, walk_list};
+use syntax::walk_list;
 
 use log::debug;
 
@@ -361,7 +361,9 @@ fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::All(&self.tcx.hir())
     }
 
@@ -591,13 +593,14 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                                     || krate.impl_items.contains_key(&parent_impl_id)
                                     || krate.trait_items.contains_key(&parent_trait_id))
                                 {
-                                    span_err!(
+                                    struct_span_err!(
                                         self.tcx.sess,
                                         lifetime.span,
                                         E0657,
                                         "`impl Trait` can only capture lifetimes \
                                          bound at the fn or impl level"
-                                    );
+                                    )
+                                    .emit();
                                     self.uninsert_lifetime_on_error(lifetime, def.unwrap());
                                 }
                             }
@@ -943,12 +946,13 @@ fn visit_poly_trait_ref(
             })
         {
             if self.trait_ref_hack {
-                span_err!(
+                struct_span_err!(
                     self.tcx.sess,
                     trait_ref.span,
                     E0316,
                     "nested quantification of lifetimes"
-                );
+                )
+                .emit();
             }
             let next_early_index = self.next_early_index();
             let scope = Scope::Binder {
@@ -1084,7 +1088,9 @@ struct GatherLabels<'a, 'tcx> {
     gather.visit_body(body);
 
     impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
-        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        type Map = Map<'v>;
+
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
             NestedVisitorMap::None
         }
 
@@ -2127,7 +2133,9 @@ fn is_self_ty(&self, res: Res) -> bool {
             }
 
             impl<'a> Visitor<'a> for SelfVisitor<'a> {
-                fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> {
+                type Map = Map<'a>;
+
+                fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
                     NestedVisitorMap::None
                 }
 
@@ -2215,7 +2223,9 @@ struct GatherLifetimes<'a> {
         }
 
         impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> {
-            fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+            type Map = Map<'v>;
+
+            fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
                 NestedVisitorMap::None
             }
 
@@ -2433,36 +2443,32 @@ fn report_elision_failure(
         }
 
         if len == 0 {
-            help!(
-                db,
-                "this function's return type contains a borrowed value, but \
-                 there is no value for it to be borrowed from"
+            db.help(
+                "this function's return type contains a borrowed value, \
+                but there is no value for it to be borrowed from",
             );
             self.suggest_lifetime(db, span, "consider giving it a 'static lifetime")
         } else if elided_len == 0 {
-            help!(
-                db,
+            db.help(
                 "this function's return type contains a borrowed value with \
                  an elided lifetime, but the lifetime cannot be derived from \
-                 the arguments"
+                 the arguments",
             );
             let msg = "consider giving it an explicit bounded or 'static lifetime";
             self.suggest_lifetime(db, span, msg)
         } else if elided_len == 1 {
-            help!(
-                db,
-                "this function's return type contains a borrowed value, but \
-                 the signature does not say which {} it is borrowed from",
+            db.help(&format!(
+                "this function's return type contains a borrowed value, \
+                but the signature does not say which {} it is borrowed from",
                 m
-            );
+            ));
             true
         } else {
-            help!(
-                db,
-                "this function's return type contains a borrowed value, but \
-                 the signature does not say whether it is borrowed from {}",
+            db.help(&format!(
+                "this function's return type contains a borrowed value, \
+                but the signature does not say whether it is borrowed from {}",
                 m
-            );
+            ));
             true
         }
     }
@@ -2804,7 +2810,9 @@ struct ConstrainedCollector {
     }
 
     impl<'v> Visitor<'v> for ConstrainedCollector {
-        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        type Map = Map<'v>;
+
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
             NestedVisitorMap::None
         }
 
@@ -2845,7 +2853,9 @@ struct AllCollector {
     }
 
     impl<'v> Visitor<'v> for AllCollector {
-        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        type Map = Map<'v>;
+
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
             NestedVisitorMap::None
         }
 
index 1103d5b5b7c97dc1590dd52adace70718fb33938..85b5d8ef1cb5d4bcb1a54499e9530cff07f5d463 100644 (file)
@@ -7,6 +7,7 @@
 use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
 use rustc::middle::stability;
+use rustc::session::parse::feature_err;
 use rustc::session::Session;
 use rustc::{lint, span_bug, ty};
 use rustc_data_structures::fx::FxHashSet;
@@ -23,7 +24,6 @@
 use rustc_span::{Span, DUMMY_SP};
 use syntax::ast::{self, Ident, NodeId};
 use syntax::attr::{self, StabilityLevel};
-use syntax::feature_gate::feature_err;
 use syntax::print::pprust;
 
 use rustc_data_structures::sync::Lrc;
index 47c23bc4dcf98c4f074ab88106323720cf9a4d16..377ea141ed57c6678162534a7e0515ebeb0600f0 100644 (file)
@@ -10,6 +10,7 @@ path = "lib.rs"
 
 [dependencies]
 log = "0.4"
+rustc_error_codes = { path = "../librustc_error_codes" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_target = { path = "../librustc_target" }
index 0cce7e848fd6066dafdc955254c471fc303f2bc5..2ba3932c7d97e31eefc441cb3aff7be962e76a65 100644 (file)
@@ -1,8 +1,10 @@
 pub use self::Level::*;
-use crate::node_id::NodeId;
+use crate::node_id::{NodeId, NodeMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_span::edition::Edition;
-use rustc_span::{sym, MultiSpan, Symbol};
+use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
+
+pub mod builtin;
 
 /// Setting for how to handle a lint.
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
@@ -174,7 +176,25 @@ fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
     }
 }
 
-/// Stores buffered lint info which can later be passed to `librustc`.
+// This could be a closure, but then implementing derive trait
+// becomes hacky (and it gets allocated).
+#[derive(PartialEq)]
+pub enum BuiltinLintDiagnostics {
+    Normal,
+    BareTraitObject(Span, /* is_global */ bool),
+    AbsPathWithModule(Span),
+    ProcMacroDeriveResolutionFallback(Span),
+    MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
+    ElidedLifetimesInPaths(usize, Span, bool, Span, String),
+    UnknownCrateTypes(Span, String, String),
+    UnusedImports(String, Vec<(Span, String)>),
+    RedundantImport(Vec<(Span, bool)>, Ident),
+    DeprecatedMacro(Option<Symbol>, Span),
+}
+
+/// Lints that are buffered up early on in the `Session` before the
+/// `LintLevels` is calculated. These are later passed to `librustc`.
+#[derive(PartialEq)]
 pub struct BufferedEarlyLint {
     /// The span of code that we are linting on.
     pub span: MultiSpan,
@@ -183,10 +203,65 @@ pub struct BufferedEarlyLint {
     pub msg: String,
 
     /// The `NodeId` of the AST node that generated the lint.
-    pub id: NodeId,
+    pub node_id: NodeId,
 
     /// A lint Id that can be passed to `rustc::lint::Lint::from_parser_lint_id`.
-    pub lint_id: &'static Lint,
+    pub lint_id: LintId,
+
+    /// Customization of the `DiagnosticBuilder<'_>` for the lint.
+    pub diagnostic: BuiltinLintDiagnostics,
+}
+
+#[derive(Default)]
+pub struct LintBuffer {
+    pub map: NodeMap<Vec<BufferedEarlyLint>>,
+}
+
+impl LintBuffer {
+    pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
+        let arr = self.map.entry(early_lint.node_id).or_default();
+        if !arr.contains(&early_lint) {
+            arr.push(early_lint);
+        }
+    }
+
+    pub fn add_lint(
+        &mut self,
+        lint: &'static Lint,
+        node_id: NodeId,
+        span: MultiSpan,
+        msg: &str,
+        diagnostic: BuiltinLintDiagnostics,
+    ) {
+        let lint_id = LintId::of(lint);
+        let msg = msg.to_string();
+        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
+    }
+
+    pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
+        self.map.remove(&id).unwrap_or_default()
+    }
+
+    pub fn buffer_lint(
+        &mut self,
+        lint: &'static Lint,
+        id: NodeId,
+        sp: impl Into<MultiSpan>,
+        msg: &str,
+    ) {
+        self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
+    }
+
+    pub fn buffer_lint_with_diagnostic(
+        &mut self,
+        lint: &'static Lint,
+        id: NodeId,
+        sp: impl Into<MultiSpan>,
+        msg: &str,
+        diagnostic: BuiltinLintDiagnostics,
+    ) {
+        self.add_lint(lint, id, sp.into(), msg, diagnostic)
+    }
 }
 
 /// Declares a static item of type `&'static Lint`.
@@ -253,3 +328,41 @@ macro_rules! declare_tool_lint {
         };
     );
 }
+
+/// Declares a static `LintArray` and return it as an expression.
+#[macro_export]
+macro_rules! lint_array {
+    ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) };
+    ($( $lint:expr ),*) => {{
+        vec![$($lint),*]
+    }}
+}
+
+pub type LintArray = Vec<&'static Lint>;
+
+pub trait LintPass {
+    fn name(&self) -> &'static str;
+}
+
+/// Implements `LintPass for $name` with the given list of `Lint` statics.
+#[macro_export]
+macro_rules! impl_lint_pass {
+    ($name:ident => [$($lint:expr),* $(,)?]) => {
+        impl $crate::lint::LintPass for $name {
+            fn name(&self) -> &'static str { stringify!($name) }
+        }
+        impl $name {
+            pub fn get_lints() -> $crate::lint::LintArray { $crate::lint_array!($($lint),*) }
+        }
+    };
+}
+
+/// Declares a type named `$name` which implements `LintPass`.
+/// To the right of `=>` a comma separated list of `Lint` statics is given.
+#[macro_export]
+macro_rules! declare_lint_pass {
+    ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => {
+        $(#[$m])* #[derive(Copy, Clone)] pub struct $name;
+        $crate::impl_lint_pass!($name => [$($lint),*]);
+    };
+}
diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs
new file mode 100644 (file)
index 0000000..3e8503e
--- /dev/null
@@ -0,0 +1,530 @@
+//! Some lints that are built in to the compiler.
+//!
+//! These are the built-in lints that are emitted direct in the main
+//! compiler code, rather than using their own custom pass. Those
+//! lints are all available in `rustc_lint::builtin`.
+
+use crate::lint::FutureIncompatibleInfo;
+use crate::{declare_lint, declare_lint_pass};
+use rustc_span::edition::Edition;
+
+declare_lint! {
+    pub ILL_FORMED_ATTRIBUTE_INPUT,
+    Deny,
+    "ill-formed attribute inputs that were previously accepted and used in practice",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub META_VARIABLE_MISUSE,
+    Allow,
+    "possible meta-variable misuse at macro definition"
+}
+
+declare_lint! {
+    pub INCOMPLETE_INCLUDE,
+    Deny,
+    "trailing content in included file"
+}
+
+declare_lint! {
+    pub EXCEEDING_BITSHIFTS,
+    Deny,
+    "shift exceeds the type's number of bits"
+}
+
+declare_lint! {
+    pub CONST_ERR,
+    Deny,
+    "constant evaluation detected erroneous expression",
+    report_in_external_macro
+}
+
+declare_lint! {
+    pub UNUSED_IMPORTS,
+    Warn,
+    "imports that are never used"
+}
+
+declare_lint! {
+    pub UNUSED_EXTERN_CRATES,
+    Allow,
+    "extern crates that are never used"
+}
+
+declare_lint! {
+    pub UNUSED_QUALIFICATIONS,
+    Allow,
+    "detects unnecessarily qualified names"
+}
+
+declare_lint! {
+    pub UNKNOWN_LINTS,
+    Warn,
+    "unrecognized lint attribute"
+}
+
+declare_lint! {
+    pub UNUSED_VARIABLES,
+    Warn,
+    "detect variables which are not used in any way"
+}
+
+declare_lint! {
+    pub UNUSED_ASSIGNMENTS,
+    Warn,
+    "detect assignments that will never be read"
+}
+
+declare_lint! {
+    pub DEAD_CODE,
+    Warn,
+    "detect unused, unexported items"
+}
+
+declare_lint! {
+    pub UNUSED_ATTRIBUTES,
+    Warn,
+    "detects attributes that were not used by the compiler"
+}
+
+declare_lint! {
+    pub UNREACHABLE_CODE,
+    Warn,
+    "detects unreachable code paths",
+    report_in_external_macro
+}
+
+declare_lint! {
+    pub UNREACHABLE_PATTERNS,
+    Warn,
+    "detects unreachable patterns"
+}
+
+declare_lint! {
+    pub OVERLAPPING_PATTERNS,
+    Warn,
+    "detects overlapping patterns"
+}
+
+declare_lint! {
+    pub BINDINGS_WITH_VARIANT_NAME,
+    Warn,
+    "detects pattern bindings with the same name as one of the matched variants"
+}
+
+declare_lint! {
+    pub UNUSED_MACROS,
+    Warn,
+    "detects macros that were not used"
+}
+
+declare_lint! {
+    pub WARNINGS,
+    Warn,
+    "mass-change the level for lints which produce warnings"
+}
+
+declare_lint! {
+    pub UNUSED_FEATURES,
+    Warn,
+    "unused features found in crate-level `#[feature]` directives"
+}
+
+declare_lint! {
+    pub STABLE_FEATURES,
+    Warn,
+    "stable features found in `#[feature]` directive"
+}
+
+declare_lint! {
+    pub UNKNOWN_CRATE_TYPES,
+    Deny,
+    "unknown crate type found in `#[crate_type]` directive"
+}
+
+declare_lint! {
+    pub TRIVIAL_CASTS,
+    Allow,
+    "detects trivial casts which could be removed"
+}
+
+declare_lint! {
+    pub TRIVIAL_NUMERIC_CASTS,
+    Allow,
+    "detects trivial casts of numeric types which could be removed"
+}
+
+declare_lint! {
+    pub PRIVATE_IN_PUBLIC,
+    Warn,
+    "detect private items in public interfaces not caught by the old implementation",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub EXPORTED_PRIVATE_DEPENDENCIES,
+    Warn,
+    "public interface leaks type from a private dependency"
+}
+
+declare_lint! {
+    pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+    Deny,
+    "detect public re-exports of private extern crates",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub INVALID_TYPE_PARAM_DEFAULT,
+    Deny,
+    "type parameter default erroneously allowed in invalid location",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub RENAMED_AND_REMOVED_LINTS,
+    Warn,
+    "lints that have been renamed or removed"
+}
+
+declare_lint! {
+    pub SAFE_PACKED_BORROWS,
+    Warn,
+    "safe borrows of fields of packed structs were was erroneously allowed",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub PATTERNS_IN_FNS_WITHOUT_BODY,
+    Deny,
+    "patterns in functions without body were erroneously allowed",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub MISSING_FRAGMENT_SPECIFIER,
+    Deny,
+    "detects missing fragment specifiers in unused `macro_rules!` patterns",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub LATE_BOUND_LIFETIME_ARGUMENTS,
+    Warn,
+    "detects generic lifetime arguments in path segments with late bound lifetime parameters",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub ORDER_DEPENDENT_TRAIT_OBJECTS,
+    Deny,
+    "trait-object types were treated as different depending on marker-trait order",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub DEPRECATED,
+    Warn,
+    "detects use of deprecated items",
+    report_in_external_macro
+}
+
+declare_lint! {
+    pub UNUSED_UNSAFE,
+    Warn,
+    "unnecessary use of an `unsafe` block"
+}
+
+declare_lint! {
+    pub UNUSED_MUT,
+    Warn,
+    "detect mut variables which don't need to be mutable"
+}
+
+declare_lint! {
+    pub UNCONDITIONAL_RECURSION,
+    Warn,
+    "functions that cannot return without calling themselves"
+}
+
+declare_lint! {
+    pub SINGLE_USE_LIFETIMES,
+    Allow,
+    "detects lifetime parameters that are only used once"
+}
+
+declare_lint! {
+    pub UNUSED_LIFETIMES,
+    Allow,
+    "detects lifetime parameters that are never used"
+}
+
+declare_lint! {
+    pub TYVAR_BEHIND_RAW_POINTER,
+    Warn,
+    "raw pointer to an inference variable",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
+        edition: Some(Edition::Edition2018),
+    };
+}
+
+declare_lint! {
+    pub ELIDED_LIFETIMES_IN_PATHS,
+    Allow,
+    "hidden lifetime parameters in types are deprecated"
+}
+
+declare_lint! {
+    pub BARE_TRAIT_OBJECTS,
+    Warn,
+    "suggest using `dyn Trait` for trait objects"
+}
+
+declare_lint! {
+    pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
+    Allow,
+    "fully qualified paths that start with a module name \
+     instead of `crate`, `self`, or an extern crate name",
+     @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>",
+        edition: Some(Edition::Edition2018),
+     };
+}
+
+declare_lint! {
+    pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+    Warn,
+    "floating-point literals cannot be used in patterns",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub UNSTABLE_NAME_COLLISIONS,
+    Warn,
+    "detects name collision with an existing but unstable method",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>",
+        edition: None,
+        // Note: this item represents future incompatibility of all unstable functions in the
+        //       standard library, and thus should never be removed or changed to an error.
+    };
+}
+
+declare_lint! {
+    pub IRREFUTABLE_LET_PATTERNS,
+    Warn,
+    "detects irrefutable patterns in if-let and while-let statements"
+}
+
+declare_lint! {
+    pub UNUSED_LABELS,
+    Warn,
+    "detects labels that are never used"
+}
+
+declare_lint! {
+    pub INTRA_DOC_LINK_RESOLUTION_FAILURE,
+    Warn,
+    "failures in resolving intra-doc link targets"
+}
+
+declare_lint! {
+    pub MISSING_DOC_CODE_EXAMPLES,
+    Allow,
+    "detects publicly-exported items without code samples in their documentation"
+}
+
+declare_lint! {
+    pub PRIVATE_DOC_TESTS,
+    Allow,
+    "detects code samples in docs of private items not documented by rustdoc"
+}
+
+declare_lint! {
+    pub WHERE_CLAUSES_OBJECT_SAFETY,
+    Warn,
+    "checks the object safety of where clauses",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+    Warn,
+    "detects proc macro derives using inaccessible names from parent modules",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub MACRO_USE_EXTERN_CRATE,
+    Allow,
+    "the `#[macro_use]` attribute is now deprecated in favor of using macros \
+     via the module system"
+}
+
+declare_lint! {
+    pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+    Deny,
+    "macro-expanded `macro_export` macros from the current crate \
+     cannot be referred to by absolute paths",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub EXPLICIT_OUTLIVES_REQUIREMENTS,
+    Allow,
+    "outlives requirements can be inferred"
+}
+
+declare_lint! {
+    pub INDIRECT_STRUCTURAL_MATCH,
+    // defaulting to allow until rust-lang/rust#62614 is fixed.
+    Allow,
+    "pattern with const indirectly referencing non-`#[structural_match]` type",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub DEPRECATED_IN_FUTURE,
+    Allow,
+    "detects use of items that will be deprecated in a future version",
+    report_in_external_macro
+}
+
+declare_lint! {
+    pub AMBIGUOUS_ASSOCIATED_ITEMS,
+    Deny,
+    "ambiguous associated items",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub MUTABLE_BORROW_RESERVATION_CONFLICT,
+    Warn,
+    "reservation of a two-phased borrow conflicts with other shared borrows",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>",
+        edition: None,
+    };
+}
+
+declare_lint! {
+    pub SOFT_UNSTABLE,
+    Deny,
+    "a feature gate that doesn't break dependent crates",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>",
+        edition: None,
+    };
+}
+
+declare_lint_pass! {
+    /// Does nothing as a lint pass, but registers some `Lint`s
+    /// that are used by other parts of the compiler.
+    HardwiredLints => [
+        ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+        EXCEEDING_BITSHIFTS,
+        UNUSED_IMPORTS,
+        UNUSED_EXTERN_CRATES,
+        UNUSED_QUALIFICATIONS,
+        UNKNOWN_LINTS,
+        UNUSED_VARIABLES,
+        UNUSED_ASSIGNMENTS,
+        DEAD_CODE,
+        UNREACHABLE_CODE,
+        UNREACHABLE_PATTERNS,
+        OVERLAPPING_PATTERNS,
+        BINDINGS_WITH_VARIANT_NAME,
+        UNUSED_MACROS,
+        WARNINGS,
+        UNUSED_FEATURES,
+        STABLE_FEATURES,
+        UNKNOWN_CRATE_TYPES,
+        TRIVIAL_CASTS,
+        TRIVIAL_NUMERIC_CASTS,
+        PRIVATE_IN_PUBLIC,
+        EXPORTED_PRIVATE_DEPENDENCIES,
+        PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+        INVALID_TYPE_PARAM_DEFAULT,
+        CONST_ERR,
+        RENAMED_AND_REMOVED_LINTS,
+        SAFE_PACKED_BORROWS,
+        PATTERNS_IN_FNS_WITHOUT_BODY,
+        MISSING_FRAGMENT_SPECIFIER,
+        LATE_BOUND_LIFETIME_ARGUMENTS,
+        ORDER_DEPENDENT_TRAIT_OBJECTS,
+        DEPRECATED,
+        UNUSED_UNSAFE,
+        UNUSED_MUT,
+        UNCONDITIONAL_RECURSION,
+        SINGLE_USE_LIFETIMES,
+        UNUSED_LIFETIMES,
+        UNUSED_LABELS,
+        TYVAR_BEHIND_RAW_POINTER,
+        ELIDED_LIFETIMES_IN_PATHS,
+        BARE_TRAIT_OBJECTS,
+        ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
+        UNSTABLE_NAME_COLLISIONS,
+        IRREFUTABLE_LET_PATTERNS,
+        INTRA_DOC_LINK_RESOLUTION_FAILURE,
+        MISSING_DOC_CODE_EXAMPLES,
+        PRIVATE_DOC_TESTS,
+        WHERE_CLAUSES_OBJECT_SAFETY,
+        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+        MACRO_USE_EXTERN_CRATE,
+        MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+        ILL_FORMED_ATTRIBUTE_INPUT,
+        META_VARIABLE_MISUSE,
+        DEPRECATED_IN_FUTURE,
+        AMBIGUOUS_ASSOCIATED_ITEMS,
+        MUTABLE_BORROW_RESERVATION_CONFLICT,
+        INDIRECT_STRUCTURAL_MATCH,
+        SOFT_UNSTABLE,
+    ]
+}
index 656c1b019b2e2ead069151c9589be1316b61a693..4b5736adc17c3f0d4de30fed1499ece9bae4792a 100644 (file)
@@ -772,8 +772,6 @@ fn parse_symbol_mangling_version(
         "set the current terminal width"),
     panic_abort_tests: bool = (false, parse_bool, [TRACKED],
         "support compiling tests with panic=abort"),
-    continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
-        "attempt to recover from parse errors (experimental)"),
     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
         "print tasks that execute and the color their dep node gets (requires debug build)"),
     incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
index 6cc6a1ec276ca85bac483b03d5383cc464052ae2..a98cf929095ead3aa73ea261caace287291f0e14 100644 (file)
@@ -1,15 +1,15 @@
 //! Contains `ParseSess` which holds state living beyond what one `Parser` might.
 //! It also serves as an input to the parser itself.
 
-use crate::lint::BufferedEarlyLint;
+use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
 use crate::node_id::NodeId;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{Lock, Lrc, Once};
-use rustc_errors::{
-    emitter::SilentEmitter, Applicability, ColorConfig, DiagnosticBuilder, Handler,
-};
-use rustc_feature::UnstableFeatures;
+use rustc_error_codes::E0658;
+use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
+use rustc_errors::{error_code, Applicability, DiagnosticBuilder};
+use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
@@ -62,6 +62,45 @@ pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
     }
 }
 
+/// Construct a diagnostic for a language feature error due to the given `span`.
+/// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
+pub fn feature_err<'a>(
+    sess: &'a ParseSess,
+    feature: Symbol,
+    span: impl Into<MultiSpan>,
+    explain: &str,
+) -> DiagnosticBuilder<'a> {
+    feature_err_issue(sess, feature, span, GateIssue::Language, explain)
+}
+
+/// Construct a diagnostic for a feature gate error.
+///
+/// This variant allows you to control whether it is a library or language feature.
+/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
+pub fn feature_err_issue<'a>(
+    sess: &'a ParseSess,
+    feature: Symbol,
+    span: impl Into<MultiSpan>,
+    issue: GateIssue,
+    explain: &str,
+) -> DiagnosticBuilder<'a> {
+    let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
+
+    if let Some(n) = find_feature_issue(feature, issue) {
+        err.note(&format!(
+            "for more information, see https://github.com/rust-lang/rust/issues/{}",
+            n,
+        ));
+    }
+
+    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
+    if sess.unstable_features.is_nightly_build() {
+        err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
+    }
+
+    err
+}
+
 /// Info about a parsing session.
 pub struct ParseSess {
     pub span_diagnostic: Handler,
@@ -123,17 +162,18 @@ pub fn source_map(&self) -> &SourceMap {
 
     pub fn buffer_lint(
         &self,
-        lint_id: &'static crate::lint::Lint,
+        lint: &'static Lint,
         span: impl Into<MultiSpan>,
-        id: NodeId,
+        node_id: NodeId,
         msg: &str,
     ) {
         self.buffered_lints.with_lock(|buffered_lints| {
             buffered_lints.push(BufferedEarlyLint {
                 span: span.into(),
-                id,
+                node_id,
                 msg: msg.into(),
-                lint_id,
+                lint_id: LintId::of(lint),
+                diagnostic: BuiltinLintDiagnostics::Normal,
             });
         });
     }
index dba5b9f3f14c229f47a326de065107e9e7ed0a6a..d979247b46d3af81bb97d307a6575d966f0c3d97 100644 (file)
@@ -1124,6 +1124,32 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
                   See https://github.com/rust-lang/rust/issues/61002 for details.",
         );
     }
+
+    // Sanitizers can only be used on some tested platforms.
+    if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
+        const ASAN_SUPPORTED_TARGETS: &[&str] =
+            &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
+        const TSAN_SUPPORTED_TARGETS: &[&str] =
+            &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
+        const LSAN_SUPPORTED_TARGETS: &[&str] =
+            &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
+        const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
+
+        let supported_targets = match *sanitizer {
+            Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
+            Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
+            Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
+            Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
+        };
+
+        if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
+            sess.err(&format!(
+                "{:?}Sanitizer only works with the `{}` target",
+                sanitizer,
+                supported_targets.join("` or `")
+            ));
+        }
+    }
 }
 
 /// Hash value constructed out of all the `-C metadata` arguments passed to the
index 7806f5e8753f22b9fcea1275ecabcf33e7571ca1..fda11b647490f709c50a3f222cda9b444246ff3d 100644 (file)
@@ -2,11 +2,11 @@
 use rustc_data_structures::profiling::VerboseTimingGuard;
 
 impl Session {
-    pub fn timer<'a>(&'a self, what: &'a str) -> VerboseTimingGuard<'a> {
-        self.prof.sparse_pass(what)
+    pub fn timer<'a>(&'a self, what: &'static str) -> VerboseTimingGuard<'a> {
+        self.prof.verbose_generic_activity(what)
     }
-    pub fn time<R>(&self, what: &str, f: impl FnOnce() -> R) -> R {
-        self.prof.sparse_pass(what).run(f)
+    pub fn time<R>(&self, what: &'static str, f: impl FnOnce() -> R) -> R {
+        self.prof.verbose_generic_activity(what).run(f)
     }
 }
 
index 8cca59df33846b8fda741e268e3565e279279806..5779d17e3e51ebe57cdb66de56232338b192696b 100644 (file)
@@ -5,7 +5,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(const_fn)]
 #![feature(crate_visibility_modifier)]
 #![feature(nll)]
 #![feature(optin_builtin_traits)]
@@ -309,6 +308,11 @@ pub fn from_expansion(self) -> bool {
         self.ctxt() != SyntaxContext::root()
     }
 
+    /// Returns `true` if `span` originates in a derive-macro's expansion.
+    pub fn in_derive_expansion(self) -> bool {
+        matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
+    }
+
     #[inline]
     pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
         Span::new(lo, hi, SyntaxContext::root())
index 0b9b9fe7887f2a29fe86090381877061204624cd..fb5fcf4a8303badacd9ae0bdc69ec90b8607e7bb 100644 (file)
@@ -499,14 +499,15 @@ pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
         // and to the end of the line. Be careful because the line
         // numbers in Loc are 1-based, so we subtract 1 to get 0-based
         // lines.
-        for line_index in lo.line - 1..hi.line - 1 {
+        let hi_line = hi.line.saturating_sub(1);
+        for line_index in lo.line.saturating_sub(1)..hi_line {
             let line_len = lo.file.get_line(line_index).map(|s| s.chars().count()).unwrap_or(0);
             lines.push(LineInfo { line_index, start_col, end_col: CharPos::from_usize(line_len) });
             start_col = CharPos::from_usize(0);
         }
 
         // For the last line, it extends from `start_col` to `hi.col`:
-        lines.push(LineInfo { line_index: hi.line - 1, start_col, end_col: hi.col });
+        lines.push(LineInfo { line_index: hi_line, start_col, end_col: hi.col });
 
         Ok(FileLines { file: lo.file, lines })
     }
@@ -709,7 +710,7 @@ pub fn end_point(&self, sp: Span) -> Span {
     pub fn next_point(&self, sp: Span) -> Span {
         let start_of_next_point = sp.hi().0;
 
-        let width = self.find_width_of_character_at_span(sp, true);
+        let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true);
         // If the width is 1, then the next span should point to the same `lo` and `hi`. However,
         // in the case of a multibyte character, where the width != 1, the next span should
         // span multiple bytes to include the whole character.
index 40abc8b2179b847d8caaa3d9bb78e2f9e7742cd1..889f6099070aebc863863ff68c56d28157ca4a2f 100644 (file)
         const_raw_ptr_deref,
         const_raw_ptr_to_usize_cast,
         const_transmute,
+        const_trait_bound_opt_out,
+        const_trait_impl,
         contents,
         context,
         convert,
         global_allocator,
         global_asm,
         globs,
+        half_open_range_patterns,
         hash,
         Hash,
         HashSet,
@@ -1046,6 +1049,7 @@ pub mod kw {
 }
 
 // This module has a very short name because it's used a lot.
+#[allow(rustc::default_hash_types)]
 pub mod sym {
     use super::Symbol;
     use std::convert::TryInto;
index 51eb231a6144bb3d4e528690f4a958336e0025a6..a6c1d24fa62a17150f01c7012a71bf23130de087 100644 (file)
@@ -8,7 +8,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128".to_string(),
+        data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:128-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "ios".to_string(),
         target_env: String::new(),
index 7dfb2ba9921145ffd73ee236d02db76fa238bbc5..033b87b110e12c54034d9db550de0775a437b7b8 100644 (file)
@@ -20,7 +20,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128".to_string(),
+        data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:128-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "macos".to_string(),
         target_env: String::new(),
index 3f73d24ee848b90d00505b071eb909fc55816bbd..79242f240269c2fba5f26e0412b931303a3451c6 100644 (file)
@@ -18,7 +18,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "android".to_string(),
         target_env: String::new(),
index 9056e0765d8117b813277d0191422bf754858de9..35fbf87573137ef3cc39a20145f8a8fc0bf17bf0 100644 (file)
@@ -18,7 +18,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
+        data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "windows".to_string(),
         target_env: "gnu".to_string(),
index b160007e0621a8d3f07a9d075981fb27c3fef76e..ffb66afc7618270dc74a36a8b15ba499ec7c5adf 100644 (file)
@@ -19,7 +19,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
+        data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "windows".to_string(),
         target_env: "msvc".to_string(),
index f3b40633b40073b31bf31667e319ffc1df19660a..729b1f68e005c516b9536c86508dcf7bc5d5d0f6 100644 (file)
@@ -13,7 +13,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "cloudabi".to_string(),
         target_env: String::new(),
index 71f05a140f3df13f513f04388b5c536724e92f02..88c944a6cb7eb6ad015944d8a6d5300fb5edfc31 100644 (file)
@@ -12,7 +12,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "freebsd".to_string(),
         target_env: String::new(),
index b807e4eee39a5756119e8616535d7d7e464de2f7..4dc27af30dadb3ae6d26862419325507f75cfa8e 100644 (file)
@@ -12,7 +12,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "haiku".to_string(),
         target_env: String::new(),
index 5875cbf78bfe632b011c03e0b12b8a3ef6526511..0d578f22f9825d0d00b714de8dad342703c6e99d 100644 (file)
@@ -12,7 +12,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
index 732949034e824a429880804ddd08998b85501e26..699a0ab45e87234563c374f71a12769fdef9d92b 100644 (file)
@@ -27,7 +27,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
index 01d2b2d76a0b95e86b06d4c4ad029af964968f24..88b1ae7d53c085155f9d3277331ce87222e9f6fc 100644 (file)
@@ -12,7 +12,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "netbsd".to_string(),
         target_env: String::new(),
index d7c323e0d8a8a46283238952d3705141b97861ba..829cd1ac1a3975aac04d02842065b0bd99ea7e29 100644 (file)
@@ -13,7 +13,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "openbsd".to_string(),
         target_env: String::new(),
index e4b8b667ad0db6d17492bab0b880e0dcac450a5c..345590a00be8bbfae4b8a02a19376e12df547a72 100644 (file)
@@ -86,7 +86,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
+        data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            .to_string(),
         target_os: "uefi".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
index 1986474785f50dc3af8c46d41f313912fcf19303..93f396de0a0512e6c8dc6838c658457d88188331 100644 (file)
@@ -18,7 +18,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
+        data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "windows".to_string(),
         target_env: "gnu".to_string(),
index 5e8e8c2a4149c6eb242bb254686dfe8f5b8106e7..ed2dba53589ede286599e6d8e95448002dffbd97 100644 (file)
@@ -11,7 +11,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(),
+        data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "windows".to_string(),
         target_env: "msvc".to_string(),
index c5f9583a358563b2e27c9e26e2d8cbefe30c1f79..f5f66cabb2cfd4bc3e80b91da57e81276632845e 100644 (file)
@@ -12,7 +12,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            f64:32:64-f80:32-n8:16:32-S128"
+            .to_string(),
         arch: "x86".to_string(),
         target_os: "vxworks".to_string(),
         target_env: "gnu".to_string(),
index f08634cc770e0ca3d20c9b405eee291f202dfa92..528ffdf93a01a43ad82822bfa1244a7b61d4eb83 100644 (file)
@@ -805,6 +805,9 @@ pub struct TargetOptions {
 
     /// Whether or not RelaxElfRelocation flag will be passed to the linker
     pub relax_elf_relocations: bool,
+
+    /// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option.
+    pub llvm_args: Vec<String>,
 }
 
 impl Default for TargetOptions {
@@ -893,6 +896,7 @@ fn default() -> TargetOptions {
             target_mcount: "mcount".to_string(),
             llvm_abiname: "".to_string(),
             relax_elf_relocations: false,
+            llvm_args: vec![],
         }
     }
 }
@@ -1206,6 +1210,7 @@ macro_rules! key {
         key!(target_mcount);
         key!(llvm_abiname);
         key!(relax_elf_relocations, bool);
+        key!(llvm_args, list);
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
             for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -1433,6 +1438,7 @@ macro_rules! target_option_val {
         target_option_val!(target_mcount);
         target_option_val!(llvm_abiname);
         target_option_val!(relax_elf_relocations);
+        target_option_val!(llvm_args);
 
         if default.abi_blacklist != self.options.abi_blacklist {
             d.insert(
index 002cee44218e77cde13a3f20c03d28ed8fac2d8c..e846f42f8f849b9b10b8e5225a06057f889aff18 100644 (file)
@@ -20,7 +20,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: arch.to_string(),
         target_os: "macos".to_string(),
         target_env: String::new(),
index f8441f96c989d55d8c45445decb39f1be143a035..ca02e2deabcf2d0cd7e690b0d995fb448860a452 100644 (file)
@@ -8,7 +8,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "ios".to_string(),
         target_env: String::new(),
index 101d83607d91fcd9d78359293d2243488b8abcd1..5f4f6ade682d8138875a2cf39a65fddd1d5370ae 100644 (file)
@@ -8,7 +8,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "ios".to_string(),
         target_env: String::new(),
index 6105eaef7b0af23a45fae1e46ac63459f6a58ff3..3e9552ef0cf34106501f698456a5b6146020e21a 100644 (file)
@@ -81,7 +81,8 @@ pub fn target() -> Result<Target, String> {
         target_os: "unknown".into(),
         target_env: "sgx".into(),
         target_vendor: "fortanix".into(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".into(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .into(),
         arch: "x86_64".into(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
index 5b315bb957ce98f77f1d5553171939fa38a3fc53..37b6d57366cf569fdf7fe1bb50f72077ba47a9f1 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "fuchsia".to_string(),
         target_env: String::new(),
index c3c6c7bf56fef92808915cc6a6f6ca16be1e2aaf..74097f5bf6f5e08ef34d9e99873e1f2836cb7741 100644 (file)
@@ -14,7 +14,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "android".to_string(),
         target_env: String::new(),
index a80b021208ed736185c4c1b3b35b1af015df038f..89070c99e39410090dcacd838126a6d5636e604d 100644 (file)
@@ -19,7 +19,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         target_os: "none".to_string(),
         target_env: "gnu".to_string(),
         target_vendor: "unknown".to_string(),
index 35e0d55cd045e183c6edc958c51d8ece5008ad92..8f523a3b6c6d9c3c8c1ca226ab00d86045d4ce4f 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "windows".to_string(),
         target_env: "gnu".to_string(),
index 073d49be5a9ab5b93f5bbea484b9235fe3b4791e..75ff6b97a2e1e1935a5c00f7d2fb52aefee553e5 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "windows".to_string(),
         target_env: "msvc".to_string(),
index d71112b87de183ce977491d405b45a8ee63028d6..fbade02c5569037845aa399678bab9690206d5bc 100644 (file)
@@ -18,7 +18,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "netbsd".to_string(),
         target_env: String::new(),
index 3bf3f51ae2512e53a7031da07090a55edc459e37..53f4df9651819d6a66426d3b0ed1de59946ad1f9 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "solaris".to_string(),
         target_env: String::new(),
index d48120c5401c28af99dc0354127d7914bd8e2180..dbc5f965020e947986e1e4907e92037834f69071 100644 (file)
@@ -13,7 +13,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "cloudabi".to_string(),
         target_env: String::new(),
index f55ee6969092b6e3c3c1822a0d26d8131a141a41..fd1871b1a57c3361e7b177856842923b3415a9e1 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "dragonfly".to_string(),
         target_env: String::new(),
index 1d9c5cce3f729628294edccf407a1dfc50d864d7..a124f582bf3fc3d1fb1cfd9583cba85b19b7b6a2 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "freebsd".to_string(),
         target_env: String::new(),
index 4ab15fa4e90f5dc791ed87f09794d6e8a67f8e3e..51237697714a4de17ce033dc19fe4718246132b3 100644 (file)
@@ -14,7 +14,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "haiku".to_string(),
         target_env: String::new(),
index c9123aae90dda799b49a38397f48a98a5240d6a6..4a526f90ed5bc0f3d9ab504ece7e5476ef284207 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "hermit".to_string(),
         target_env: String::new(),
index 0b1c8340b6d145a49853962cd97df9b52c0d1dfd..c25cd0809eed810d80b5f3dafcfa83a82301ad30 100644 (file)
@@ -14,7 +14,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "hermit".to_string(),
         target_env: String::new(),
index e5fdb386ef3017aa8b3a7add485bf814b5d0d1b3..cab19f149a77c51827aa82e15aa32c5cd43547ea 100644 (file)
@@ -10,7 +10,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "l4re".to_string(),
         target_env: "uclibc".to_string(),
index cb279e86f149886e136120f323ab2f32a2a29716..29cbb777db5d7549526e80625ca535c3df3fc254 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
index 0b2d7aacc4ddf79160293087a3c40fff1bb6fd9a..0a37399e2fac3f7649e733274d193137b5be064d 100644 (file)
@@ -16,7 +16,9 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
+            i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "linux".to_string(),
         target_env: "gnu".to_string(),
index 2e1bc839873c7279da9ad8563fb50980ca1c827c..34c628e8f67bd2da63dd3ee11f6bd269f4f403f9 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
index b0fad314662b08141b7ce5ee164daf6aab6b33a0..adf09c89c426b624f1131e0a2bc78b41376a6870 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "netbsd".to_string(),
         target_env: String::new(),
index f2abd1071227ebfeed10bbcd0f4063b7f2244bc7..dbd163db36b4573138eaa20a9cf6e782e19eea88 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "openbsd".to_string(),
         target_env: String::new(),
index 8a5af27f13aacab8d7b25c25dc819ffb35b1d73e..3d40bafbe1fd401a8e9c3992472d5a36c94a3f3a 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "redox".to_string(),
         target_env: "relibc".to_string(),
index 443479f55f04a2361bbca5520e1ea820842587b2..7660b68aae62e447f5631763f5032bf2cd0ccab5 100644 (file)
@@ -38,7 +38,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         target_os: "uefi".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
index da0c324e4861873d1647a32e8abb2dbb964a9e5e..48366e24a39e4daf738528e93b531a0192b67a20 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "windows".to_string(),
         target_env: "gnu".to_string(),
index 40dd52c159151f5c4484fedd6dfa5dfe244b6112..258df010aae0cf1a6a019f0ef6bb8940e0c2b3e3 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "windows".to_string(),
         target_env: "msvc".to_string(),
index 1ab2f3a47c481abc55db7a07d7047e216d80fb9b..f1e27f4d8beaf95c4f0edf67042b5728bbd5e2f0 100644 (file)
@@ -13,7 +13,8 @@ pub fn target() -> TargetResult {
         target_endian: "little".to_string(),
         target_pointer_width: "64".to_string(),
         target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .to_string(),
         arch: "x86_64".to_string(),
         target_os: "vxworks".to_string(),
         target_env: "gnu".to_string(),
index 0e959cecaa9bbd0fde7b2d27ddbcc464410442f4..40f821c29d366f2c215556270fb5dd5a76c87b0a 100644 (file)
@@ -5,11 +5,11 @@
 use rustc::infer::InferCtxt;
 use rustc::traits::query::outlives_bounds::OutlivesBound;
 use rustc::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
+use rustc::traits::wf;
 use rustc::traits::FulfillmentContext;
 use rustc::traits::{TraitEngine, TraitEngineExt};
 use rustc::ty::outlives::Component;
 use rustc::ty::query::Providers;
-use rustc::ty::wf;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as hir;
 use rustc_span::source_map::DUMMY_SP;
index 47009ac41232fcc7c7f8108c08c2c84fc7c126a3..4b4fa4b7147fc0a780109ab8c2a57c4b3e440e99 100644 (file)
@@ -1,7 +1,7 @@
 mod environment;
 
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::map::definitions::DefPathData;
+use rustc::hir::map::Map;
 use rustc::traits::{
     Clause, Clauses, DomainGoal, FromEnv, GoalKind, PolyDomainGoal, ProgramClause,
     ProgramClauseCategory, WellFormed, WhereClause,
@@ -12,6 +12,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_span::symbol::sym;
 use syntax::ast;
 
@@ -600,7 +601,9 @@ fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) {
 }
 
 impl Visitor<'tcx> for ClauseDumper<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
diff --git a/src/librustc_tsan/Cargo.toml b/src/librustc_tsan/Cargo.toml
deleted file mode 100644 (file)
index 82045dd..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-build = "build.rs"
-name = "rustc_tsan"
-version = "0.0.0"
-edition = "2018"
-
-[lib]
-name = "rustc_tsan"
-path = "lib.rs"
-test = false
-
-[build-dependencies]
-build_helper = { path = "../build_helper" }
-cmake = "0.1.38"
-
-[dependencies]
-alloc = { path = "../liballoc" }
-core = { path = "../libcore" }
-compiler_builtins = "0.1.0"
diff --git a/src/librustc_tsan/build.rs b/src/librustc_tsan/build.rs
deleted file mode 100644 (file)
index 570642a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-use build_helper::sanitizer_lib_boilerplate;
-use std::env;
-
-use cmake::Config;
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=RUSTC_BUILD_SANITIZERS");
-    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
-        return;
-    }
-    if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
-        build_helper::restore_library_path();
-
-        let (native, target) = match sanitizer_lib_boilerplate("tsan") {
-            Ok(native) => native,
-            _ => return,
-        };
-
-        Config::new(&native.src_dir)
-            .define("COMPILER_RT_BUILD_SANITIZERS", "ON")
-            .define("COMPILER_RT_BUILD_BUILTINS", "OFF")
-            .define("COMPILER_RT_BUILD_XRAY", "OFF")
-            .define("LLVM_CONFIG_PATH", llvm_config)
-            .out_dir(&native.out_dir)
-            .build_target(&target)
-            .build();
-        native.fixup_sanitizer_lib_name("tsan");
-    }
-    println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
-}
diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs
deleted file mode 100644 (file)
index bdbc154..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#![sanitizer_runtime]
-#![feature(nll)]
-#![feature(sanitizer_runtime)]
-#![feature(staged_api)]
-#![no_std]
-#![unstable(
-    feature = "sanitizer_runtime_lib",
-    reason = "internal implementation detail of sanitizers",
-    issue = "none"
-)]
index a489d0cd02b40045b1bff629ae98ccabe876c57a..84e5f56d9c208456ee22139fc78073a91a8fa71a 100644 (file)
@@ -15,8 +15,8 @@ arena = { path = "../libarena" }
 log = "0.4"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
 rustc_hir = { path = "../librustc_hir" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
index 36d119bf7698f47cf8fde2f78a4d40fc8a307cd1..dae394b8f4bd46deb027ce702939e346082e8033 100644 (file)
@@ -9,18 +9,21 @@
 use crate::namespace::Namespace;
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::ErrorReported;
-use errors::{Applicability, DiagnosticId};
-use rustc::hir::intravisit::Visitor;
 use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
+use rustc::session::parse::feature_err;
 use rustc::traits;
+use rustc::traits::astconv_object_safety_violations;
+use rustc::traits::error_reporting::report_object_safety_error;
+use rustc::traits::wf::object_region_bounds;
 use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
-use rustc::ty::wf::object_region_bounds;
 use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::print;
 use rustc_hir::{ExprKind, GenericArg, GenericArgs};
 use rustc_span::symbol::sym;
@@ -28,8 +31,6 @@
 use rustc_target::spec::abi;
 use smallvec::SmallVec;
 use syntax::ast;
-use syntax::errors::pluralize;
-use syntax::feature_gate::feature_err;
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use std::collections::BTreeSet;
@@ -1117,13 +1118,14 @@ pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bo
                 if unbound.is_none() {
                     unbound = Some(&ptr.trait_ref);
                 } else {
-                    span_err!(
+                    struct_span_err!(
                         tcx.sess,
                         span,
                         E0203,
                         "type parameter has more than one relaxed default \
                         bound, only one is supported"
-                    );
+                    )
+                    .emit();
                 }
             }
         }
@@ -1443,7 +1445,13 @@ fn conv_object_ty_poly_trait_ref(
         }
 
         if regular_traits.is_empty() && auto_traits.is_empty() {
-            span_err!(tcx.sess, span, E0224, "at least one trait is required for an object type");
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0224,
+                "at least one trait is required for an object type"
+            )
+            .emit();
             return tcx.types.err;
         }
 
@@ -1452,9 +1460,10 @@ fn conv_object_ty_poly_trait_ref(
         // to avoid ICEs.
         for item in &regular_traits {
             let object_safety_violations =
-                tcx.astconv_object_safety_violations(item.trait_ref().def_id());
+                astconv_object_safety_violations(tcx, item.trait_ref().def_id());
             if !object_safety_violations.is_empty() {
-                tcx.report_object_safety_error(
+                report_object_safety_error(
+                    tcx,
                     span,
                     item.trait_ref().def_id(),
                     object_safety_violations,
@@ -1598,13 +1607,14 @@ fn conv_object_ty_poly_trait_ref(
                     self.ast_region_to_region(lifetime, None)
                 } else {
                     self.re_infer(None, span).unwrap_or_else(|| {
-                        span_err!(
+                        struct_span_err!(
                             tcx.sess,
                             span,
                             E0228,
                             "the lifetime bound for this object type cannot be deduced \
                              from context; please supply an explicit bound"
-                        );
+                        )
+                        .emit();
                         tcx.lifetimes.re_static
                     })
                 }
@@ -2114,9 +2124,13 @@ pub fn associated_path_to_ty(
                     let msg = format!("expected type, found variant `{}`", assoc_ident);
                     tcx.sess.span_err(span, &msg);
                 } else if qself_ty.is_enum() {
-                    let mut err = tcx.sess.struct_span_err(
+                    let mut err = struct_span_err!(
+                        tcx.sess,
                         assoc_ident.span,
-                        &format!("no variant `{}` in enum `{}`", assoc_ident, qself_ty),
+                        E0599,
+                        "no variant named `{}` found for enum `{}`",
+                        assoc_ident,
+                        qself_ty,
                     );
 
                     let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
@@ -2686,7 +2700,11 @@ pub fn ast_const_to_const(
         let def_id = tcx.hir().local_def_id(ast_const.hir_id);
 
         let mut const_ = ty::Const {
-            val: ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id)),
+            val: ty::ConstKind::Unevaluated(
+                def_id,
+                InternalSubsts::identity_for_item(tcx, def_id),
+                None,
+            ),
             ty,
         };
 
@@ -2792,7 +2810,7 @@ pub fn ty_of_fn(
             // allowed. `allow_ty_infer` gates this behavior.
             crate::collect::placeholder_type_error(
                 tcx,
-                ident_span.unwrap_or(DUMMY_SP),
+                ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP),
                 generic_params,
                 visitor.0,
                 ident_span.is_some(),
@@ -2877,12 +2895,13 @@ fn compute_object_lifetime_bound(
         // error.
         let r = derived_region_bounds[0];
         if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
-            span_err!(
+            struct_span_err!(
                 tcx.sess,
                 span,
                 E0227,
                 "ambiguous lifetime bound, explicit lifetime bound required"
-            );
+            )
+            .emit();
         }
         return Some(r);
     }
index 3b4f408b8aae8dd419db3b00d8450799ff54d904..8d6b74c3015c93772984a84e1e7e0b79d73489db 100644 (file)
@@ -7,6 +7,7 @@
 use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc::ty::{self, TraitRef, Ty, TyCtxt};
 use rustc::ty::{ToPredicate, TypeFoldable};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 
 use rustc_span::Span;
index 23db0fc463dae07ba48fe2f4ef1bda758382deb1..58f407b89027851a9211630cfe4ae4d6cc2794b5 100644 (file)
@@ -1,23 +1,22 @@
 use super::autoderef::Autoderef;
 use super::method::MethodCallee;
 use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
+use crate::type_error_struct;
 
-use errors::{Applicability, DiagnosticBuilder};
-use hir::def::Res;
-use hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::{infer, traits};
+use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::Span;
 use rustc_target::spec::abi;
 use syntax::ast::Ident;
 
-use rustc_hir as hir;
-
-use rustc_error_codes::*;
-
 /// Checks that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
 /// method that is called).
@@ -241,7 +240,7 @@ fn identify_bad_closure_def_and_call(
         ) = (parent_node, callee_node)
         {
             let start = sp.shrink_to_lo();
-            let end = self.tcx.sess.source_map().next_point(callee_span);
+            let end = callee_span.shrink_to_hi();
             err.multipart_suggestion(
                 "if you meant to create this closure and immediately call it, surround the \
                 closure with parenthesis",
@@ -318,9 +317,8 @@ fn confirm_builtin_call(
                             let call_is_multiline =
                                 self.tcx.sess.source_map().is_multiline(call_expr.span);
                             if call_is_multiline {
-                                let span = self.tcx.sess.source_map().next_point(callee.span);
                                 err.span_suggestion(
-                                    span,
+                                    callee.span.shrink_to_hi(),
                                     "try adding a semicolon",
                                     ";".to_owned(),
                                     Applicability::MaybeIncorrect,
index 332921f45f4d5b9ea0e65ce6218d0a622a3b054a..ba5e5fd8ac188dddf73300adb42993d9f649b6d0 100644 (file)
 
 use crate::hir::def_id::DefId;
 use crate::lint;
+use crate::type_error_struct;
 use crate::util::common::ErrorReported;
-use errors::{Applicability, DiagnosticBuilder};
 use rustc::middle::lang_items;
 use rustc::session::Session;
 use rustc::traits;
+use rustc::traits::error_reporting::report_object_safety_error;
+use rustc::traits::object_safety_violations;
 use rustc::ty::adjustment::AllowTwoPhase;
 use rustc::ty::cast::{CastKind, CastTy};
 use rustc::ty::error::TypeError;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_span::Span;
 use syntax::ast;
@@ -423,17 +426,16 @@ fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) {
                             );
                         }
                         Err(_) => {
-                            span_help!(err, self.cast_span, "did you mean `&{}{}`?", mtstr, tstr)
+                            let msg = &format!("did you mean `&{}{}`?", mtstr, tstr);
+                            err.span_help(self.cast_span, msg);
                         }
                     }
                 } else {
-                    span_help!(
-                        err,
-                        self.span,
+                    let msg = &format!(
                         "consider using an implicit coercion to `&{}{}` instead",
-                        mtstr,
-                        tstr
+                        mtstr, tstr
                     );
+                    err.span_help(self.span, msg);
                 }
             }
             ty::Adt(def, ..) if def.is_box() => {
@@ -446,11 +448,13 @@ fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) {
                             Applicability::MachineApplicable,
                         );
                     }
-                    Err(_) => span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
+                    Err(_) => {
+                        err.span_help(self.cast_span, &format!("did you mean `Box<{}>`?", tstr));
+                    }
                 }
             }
             _ => {
-                span_help!(err, self.expr.span, "consider using a box or reference as appropriate");
+                err.span_help(self.expr.span, "consider using a box or reference as appropriate");
             }
         }
         err.emit();
@@ -518,8 +522,8 @@ pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
     }
 
     fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
-        let violations = fcx.tcx.object_safety_violations(did);
-        let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
+        let violations = object_safety_violations(fcx.tcx, did);
+        let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations);
         err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
         err.emit();
     }
index 68cbd73a8aa9b2d64b3c63f25ad60da2d9aecef0..1afb703ca1506818d6b938f1fb1a13ad1fc9135c 100644 (file)
@@ -51,9 +51,9 @@
 //! we may want to adjust precisely when coercions occur.
 
 use crate::check::{FnCtxt, Needs};
-use errors::DiagnosticBuilder;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::infer::{Coercion, InferOk, InferResult};
+use rustc::session::parse::feature_err;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -63,6 +63,8 @@
 use rustc::ty::relate::RelateResult;
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeAndMut};
+use rustc_error_codes::*;
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_span;
@@ -70,9 +72,6 @@
 use rustc_target::spec::abi::Abi;
 use smallvec::{smallvec, SmallVec};
 use std::ops::Deref;
-use syntax::feature_gate;
-
-use rustc_error_codes::*;
 
 struct Coerce<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -544,7 +543,8 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
         // and almost never more than 3. By using a SmallVec we avoid an
         // allocation, at the (very small) cost of (occasionally) having to
         // shift subsequent elements down when removing the front element.
-        let mut queue: SmallVec<[_; 4]> = smallvec![self.tcx.predicate_for_trait_def(
+        let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def(
+            self.tcx,
             self.fcx.param_env,
             cause,
             coerce_unsized_did,
@@ -626,7 +626,7 @@ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tc
         }
 
         if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
-            feature_gate::feature_err(
+            feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::unsized_tuple_coercion,
                 self.cause.span,
index 13e37c124e0144ecdb28fbf636d9eee64a117be7..c35661ac649fc8e70e2d017c2929fcdf8bb7ac6f 100644 (file)
@@ -1,5 +1,4 @@
-use errors::{Applicability, DiagnosticId};
-use rustc::hir::intravisit;
+use rustc::hir::map::Map;
 use rustc::infer::{self, InferOk};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
@@ -7,11 +6,12 @@
 use rustc::ty::util::ExplicitSelf;
 use rustc::ty::{self, GenericParamDefKind, TyCtxt};
 use rustc::util::common::ErrorReported;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_span::Span;
-use syntax::errors::pluralize;
 
 use super::{potentially_plural_count, FnCtxt, Inherited};
 
@@ -891,9 +891,10 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                                     }
                                 }
                             }
-                            fn nested_visit_map<'this>(
-                                &'this mut self,
-                            ) -> intravisit::NestedVisitorMap<'this, 'v>
+                            type Map = Map<'v>;
+                            fn nested_visit_map(
+                                &mut self,
+                            ) -> intravisit::NestedVisitorMap<'_, Self::Map>
                             {
                                 intravisit::NestedVisitorMap::None
                             }
index 1be65b5f1894bc3afa18174fcc90129482963a83..e0f9fcc69325c1a91921f69ae40612472ae96e97 100644 (file)
@@ -2,9 +2,9 @@
 use rustc::infer::InferOk;
 use rustc::traits::{self, ObligationCause};
 
-use errors::{Applicability, DiagnosticBuilder};
 use rustc::ty::adjustment::AllowTwoPhase;
 use rustc::ty::{self, AssocItem, Ty};
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, print, Node};
 use rustc_span::symbol::sym;
index 004fce7e35b7098a67e787eb1f1ddb7dc46af9da..88e7a265ebbcf52ce1d8f3db502ed6b1a0ced97a 100644 (file)
@@ -1,5 +1,4 @@
 use crate::check::regionck::RegionCtxt;
-
 use crate::hir;
 use crate::hir::def_id::DefId;
 use crate::util::common::ErrorReported;
@@ -11,6 +10,7 @@
 use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc::ty::subst::{Subst, SubstsRef};
 use rustc::ty::{self, Predicate, Ty, TyCtxt};
+use rustc_errors::struct_span_err;
 
 use rustc_span::Span;
 
index c12d8400f086345ef7f4888a88fdffe2eea46479..35342de59a08254effd5be747367d83b03c02139 100644 (file)
@@ -14,9 +14,9 @@
 use crate::check::FnCtxt;
 use crate::check::Needs;
 use crate::check::TupleArgumentsFlag::DontTupleArguments;
+use crate::type_error_struct;
 use crate::util::common::ErrorReported;
 
-use errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc::infer;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::middle::lang_items;
@@ -27,6 +27,7 @@
 use rustc::ty::TypeFoldable;
 use rustc::ty::{AdtKind, Visibility};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -1108,13 +1109,14 @@ fn check_expr_struct(
         // Prohibit struct expressions when non-exhaustive flag is set.
         let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
         if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
-            span_err!(
+            struct_span_err!(
                 self.tcx.sess,
                 expr.span,
                 E0639,
                 "cannot create non-exhaustive {} using struct expression",
                 adt.variant_descr()
-            );
+            )
+            .emit();
         }
 
         let error_happened = self.check_expr_struct_fields(
@@ -1152,12 +1154,13 @@ fn check_expr_struct(
                             .insert(expr.hir_id, fru_field_types);
                     }
                     _ => {
-                        span_err!(
+                        struct_span_err!(
                             self.tcx.sess,
                             base_expr.span,
                             E0436,
                             "functional record update syntax requires a struct"
-                        );
+                        )
+                        .emit();
                     }
                 }
             }
index f004d04fdfeba1528ce02c75e90d6c0ac9003d32..9d8805f225d7e1452816d10dddd764d83d7da4e5 100644 (file)
@@ -4,13 +4,14 @@
 //! types computed here.
 
 use super::FnCtxt;
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::middle::region::{self, YieldData};
 use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_span::Span;
 
@@ -193,7 +194,9 @@ pub fn resolve_interior<'a, 'tcx>(
 // librustc/middle/region.rs since `expr_count` is compared against the results
 // there.
 impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
index a267b9786f1d8b6f3afaefad6dce8937241fd17e..0441514c83c9d05e28fad6112ec13a7040e1fc99 100644 (file)
@@ -2,17 +2,16 @@
 //! intrinsics that the compiler exposes.
 
 use crate::require_same_types;
+
 use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt};
-
+use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::abi::Abi;
 
-use rustc_hir as hir;
-
-use rustc_error_codes::*;
-
 use std::iter;
 
 fn equate_intrinsic_type<'tcx>(
@@ -413,19 +412,20 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
                 (2, params, param(1))
             }
             Err(_) => {
-                span_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.span_err(it.span, &msg);
+            tcx.sess.struct_span_err(it.span, &msg).emit();
             return;
         }
     };
index 83890cfce670c933e4013098debf8d1ff1f66eb4..636ea5b87d6596ff64af85eda498138d588270ea 100644 (file)
@@ -596,7 +596,7 @@ fn upcast(
         target_trait_def_id: DefId,
     ) -> ty::PolyTraitRef<'tcx> {
         let upcast_trait_refs =
-            self.tcx.upcast_choices(source_trait_ref.clone(), target_trait_def_id);
+            traits::upcast_choices(self.tcx, source_trait_ref.clone(), target_trait_def_id);
 
         // must be exactly one trait ref or we'd get an ambig error etc
         if upcast_trait_refs.len() != 1 {
index e9356a04c01d46d67170cec39d42ce559f06423b..711c285d17e88b1f2c6e38f0813bc807169a620d 100644 (file)
@@ -12,7 +12,6 @@
 
 use crate::check::FnCtxt;
 use crate::namespace::Namespace;
-use errors::{Applicability, DiagnosticBuilder};
 use rustc::infer::{self, InferOk};
 use rustc::traits;
 use rustc::ty::subst::Subst;
@@ -20,6 +19,7 @@
 use rustc::ty::GenericParamDefKind;
 use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable};
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::def_id::DefId;
index 50f22eabf62c2733b1499783c71dbb01b6d18c6f..b2542cc27a55119831ad054554313e39a0027f3f 100644 (file)
@@ -28,6 +28,7 @@
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_span::{symbol::Symbol, Span, DUMMY_SP};
 use std::cmp::max;
@@ -373,13 +374,14 @@ fn probe_op<OP, R>(
                 // so we do a future-compat lint here for the 2015 edition
                 // (see https://github.com/rust-lang/rust/issues/46906)
                 if self.tcx.sess.rust_2018() {
-                    span_err!(
+                    struct_span_err!(
                         self.tcx.sess,
                         span,
                         E0699,
                         "the type of this value must be known \
                                to call a method on a raw pointer on it"
-                    );
+                    )
+                    .emit();
                 } else {
                     self.tcx.lint_hir(
                         lint::builtin::TYVAR_BEHIND_RAW_POINTER,
index 1cc1eb2c7b2df287e31a4c50ef1f3055fbe6d6d6..b84e1d37b06ff489a674693bc970dcfc4755fa66 100644 (file)
@@ -4,17 +4,18 @@
 use crate::check::FnCtxt;
 use crate::middle::lang_items::FnOnceTraitLangItem;
 use crate::namespace::Namespace;
-use errors::{pluralize, Applicability, DiagnosticBuilder};
-use rustc::hir::intravisit;
 use rustc::hir::map as hir_map;
+use rustc::hir::map::Map;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::traits::Obligation;
 use rustc::ty::print::with_crate_prefix;
 use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::intravisit;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_span::{source_map, FileName, Span};
 use syntax::ast;
@@ -193,21 +194,19 @@ pub fn report_method_error<'b>(
                         let item_span =
                             self.tcx.sess.source_map().def_span(self.tcx.def_span(item.def_id));
                         let idx = if sources.len() > 1 {
-                            span_note!(
-                                err,
-                                item_span,
+                            let msg = &format!(
                                 "candidate #{} is defined in the trait `{}`",
                                 idx + 1,
                                 self.tcx.def_path_str(trait_did)
                             );
+                            err.span_note(item_span, msg);
                             Some(idx + 1)
                         } else {
-                            span_note!(
-                                err,
-                                item_span,
+                            let msg = &format!(
                                 "the candidate is defined in the trait `{}`",
                                 self.tcx.def_path_str(trait_did)
                             );
+                            err.span_note(item_span, msg);
                             None
                         };
                         let path = self.tcx.def_path_str(trait_did);
@@ -361,10 +360,11 @@ pub fn report_method_error<'b>(
                             tcx.sess,
                             span,
                             E0599,
-                            "no {} named `{}` found for type `{}` in the current scope",
+                            "no {} named `{}` found for {} `{}` in the current scope",
                             item_kind,
                             item_name,
-                            ty_str
+                            actual.prefix_string(),
+                            ty_str,
                         );
                         if let Some(span) =
                             tcx.sess.confused_type_with_std_module.borrow().get(&span)
@@ -1126,7 +1126,9 @@ fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirI
         }
     }
 
-    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
         intravisit::NestedVisitorMap::None
     }
 }
index eacd94f7da7f7e9194766dfb08067abafd159e74..92a7e18a8600f557dbf5195689e6baf92906a50d 100644 (file)
@@ -90,8 +90,7 @@
 use crate::astconv::{AstConv, PathSeg};
 use crate::middle::lang_items;
 use crate::namespace::Namespace;
-use errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::{self, InferCtxt, InferOk, InferResult};
 use rustc::middle::region;
 use rustc::mir::interpret::ConstValue;
+use rustc::session::parse::feature_err;
+use rustc::traits::error_reporting::recursive_type_with_infinite_size_error;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
     self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
     ToPredicate, Ty, TyCtxt, UserType,
 };
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath};
 use rustc_index::vec::Idx;
 use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::feature_gate::feature_err;
 use syntax::util::parser::ExprPrecedence;
 
 use rustc_error_codes::*;
 use crate::require_c_abi_if_c_variadic;
 use crate::session::config::EntryFnType;
 use crate::session::Session;
-use crate::util::captures::Captures;
 use crate::util::common::{indenter, ErrorReported};
 use crate::TypeAndSubsts;
 
 pub use self::Expectation::*;
 use self::TupleArgumentsFlag::*;
 
+#[macro_export]
+macro_rules! type_error_struct {
+    ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
+        if $typ.references_error() {
+            $session.diagnostic().struct_dummy()
+        } else {
+            rustc_errors::struct_span_err!($session, $span, $code, $($message)*)
+        }
+    })
+}
+
 /// The type of a local binding, including the revealed type for anon types.
 #[derive(Copy, Clone, Debug)]
 pub struct LocalTy<'tcx> {
@@ -1158,7 +1171,9 @@ fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>)
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
@@ -1900,7 +1915,7 @@ fn check_specialization_validity<'tcx>(
         match parent_item {
             // Parent impl exists, and contains the parent item we're trying to specialize, but
             // doesn't mark it `default`.
-            Some(parent_item) if tcx.impl_item_is_final(&parent_item) => {
+            Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
                 Some(Err(parent_impl.def_id()))
             }
 
@@ -1911,7 +1926,7 @@ fn check_specialization_validity<'tcx>(
             // grandparent. In that case, if parent is a `default impl`, inherited items use the
             // "defaultness" from the grandparent, else they are final.
             None => {
-                if tcx.impl_is_default(parent_impl.def_id()) {
+                if traits::impl_is_default(tcx, parent_impl.def_id()) {
                     None
                 } else {
                     Some(Err(parent_impl.def_id()))
@@ -2075,7 +2090,7 @@ fn check_impl_items_against_trait<'tcx>(
             .map(|node_item| !node_item.node.is_from_trait())
             .unwrap_or(false);
 
-        if !is_implemented && !tcx.impl_is_default(impl_id) {
+        if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
             if !trait_item.defaultness.has_value() {
                 missing_items.push(trait_item);
             } else if associated_type_overridden {
@@ -2090,7 +2105,7 @@ fn check_impl_items_against_trait<'tcx>(
 
     if !invalidated_items.is_empty() {
         let invalidator = overridden_associated_type.unwrap();
-        span_err!(
+        struct_span_err!(
             tcx.sess,
             invalidator.span,
             E0399,
@@ -2098,6 +2113,7 @@ fn check_impl_items_against_trait<'tcx>(
             invalidator.ident,
             invalidated_items.iter().map(|name| name.to_string()).collect::<Vec<_>>().join("`, `")
         )
+        .emit();
     }
 }
 
@@ -2222,7 +2238,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: DefId) -> bool {
     // caught by case 1.
     match rty.is_representable(tcx, sp) {
         Representability::SelfRecursive(spans) => {
-            let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
+            let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id);
             for span in spans {
                 err.span_label(span, "recursive without indirection");
             }
@@ -2240,7 +2256,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
         if def.is_struct() {
             let fields = &def.non_enum_variant().fields;
             if fields.is_empty() {
-                span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty");
+                struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
                 return;
             }
             let e = fields[0].ty(tcx, substs);
@@ -2254,12 +2270,13 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
                 ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
                 _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
                 _ => {
-                    span_err!(
+                    struct_span_err!(
                         tcx.sess,
                         sp,
                         E0077,
                         "SIMD vector element type should be machine type"
-                    );
+                    )
+                    .emit();
                     return;
                 }
             }
@@ -2544,14 +2561,15 @@ pub fn check_enum<'tcx>(
 }
 
 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span, qpath: &QPath<'_>) {
-    span_err!(
+    struct_span_err!(
         tcx.sess,
         span,
         E0533,
         "expected unit struct, unit variant or constant, found {} `{}`",
         res.descr(),
         hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))
-    );
+    )
+    .emit();
 }
 
 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
@@ -3761,13 +3779,14 @@ fn check_argument_types(
                     arg_types.iter().map(|k| k.expect_ty()).collect()
                 }
                 _ => {
-                    span_err!(
+                    struct_span_err!(
                         tcx.sess,
                         sp,
                         E0059,
                         "cannot use call notation; the first type parameter \
                          for the function trait is neither a tuple nor unit"
-                    );
+                    )
+                    .emit();
                     expected_arg_tys = vec![];
                     self.err_args(args.len())
                 }
@@ -4727,14 +4746,13 @@ fn suggest_fn_call(
                         .join(", ");
                 }
                 Some(Node::Expr(hir::Expr {
-                    kind: ExprKind::Closure(_, _, body_id, closure_span, _),
+                    kind: ExprKind::Closure(_, _, body_id, _, _),
                     span: full_closure_span,
                     ..
                 })) => {
                     if *full_closure_span == expr.span {
                         return false;
                     }
-                    err.span_label(*closure_span, "closure defined here");
                     msg = "call this closure";
                     let body = hir.body(*body_id);
                     sugg_call = body
@@ -4934,9 +4952,8 @@ fn suggest_missing_semicolon(
                 | ExprKind::Loop(..)
                 | ExprKind::Match(..)
                 | ExprKind::Block(..) => {
-                    let sp = self.tcx.sess.source_map().next_point(cause_span);
                     err.span_suggestion(
-                        sp,
+                        cause_span.shrink_to_hi(),
                         "try adding a semicolon",
                         ";".to_string(),
                         Applicability::MachineApplicable,
index 691469e48835a8def8e188ad0816a94194d74e1c..edf9d19dea37785ad58b35e6966d3878d4739dbc 100644 (file)
@@ -2,11 +2,11 @@
 
 use super::method::MethodCallee;
 use super::{FnCtxt, Needs};
-use errors::{self, Applicability};
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
 use rustc::ty::{self, Ty, TypeFoldable};
+use rustc_errors::{self, struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_span::Span;
 use syntax::ast::Ident;
@@ -279,7 +279,7 @@ fn check_overloaded_binop(
                                             lhs_expr.span,
                                             msg,
                                             format!("*{}", lstring),
-                                            errors::Applicability::MachineApplicable,
+                                            rustc_errors::Applicability::MachineApplicable,
                                         );
                                         suggested_deref = true;
                                     }
@@ -330,7 +330,7 @@ fn check_overloaded_binop(
                                     Some("std::ops::Add"),
                                 ),
                                 hir::BinOpKind::Sub => (
-                                    format!("cannot substract `{}` from `{}`", rhs_ty, lhs_ty),
+                                    format!("cannot subtract `{}` from `{}`", rhs_ty, lhs_ty),
                                     Some("std::ops::Sub"),
                                 ),
                                 hir::BinOpKind::Mul => (
@@ -482,7 +482,7 @@ fn check_overloaded_binop(
     /// suggest calling the function. Returns wether a suggestion was given.
     fn add_type_neq_err_label(
         &self,
-        err: &mut errors::DiagnosticBuilder<'_>,
+        err: &mut rustc_errors::DiagnosticBuilder<'_>,
         span: Span,
         ty: Ty<'tcx>,
         other_ty: Ty<'tcx>,
@@ -565,7 +565,7 @@ fn check_str_addition(
         rhs_expr: &'tcx hir::Expr<'tcx>,
         lhs_ty: Ty<'tcx>,
         rhs_ty: Ty<'tcx>,
-        err: &mut errors::DiagnosticBuilder<'_>,
+        err: &mut rustc_errors::DiagnosticBuilder<'_>,
         is_assign: bool,
         op: hir::BinOp,
     ) -> bool {
index 051bf61c90a8c09ea77bed2d00b71216b3db0d13..1478b35a25ddc8785ff54d8f1b576ee4a5772e75 100644 (file)
@@ -1,11 +1,11 @@
 use crate::check::FnCtxt;
-use errors::{pluralize, Applicability, DiagnosticBuilder};
 use rustc::infer;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc::traits::Pattern;
 use rustc::ty::subst::GenericArg;
 use rustc::ty::{self, BindingMode, Ty, TypeFoldable};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
@@ -135,12 +135,7 @@ fn check_pat(
         let ty = match pat.kind {
             PatKind::Wild => expected,
             PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
-            PatKind::Range(begin, end, _) => {
-                match self.check_pat_range(pat.span, begin, end, expected, ti) {
-                    None => return,
-                    Some(ty) => ty,
-                }
-            }
+            PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
             PatKind::Binding(ba, var_id, _, sub) => {
                 self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti)
             }
@@ -395,39 +390,49 @@ fn check_pat_lit(
     fn check_pat_range(
         &self,
         span: Span,
-        lhs: &'tcx hir::Expr<'tcx>,
-        rhs: &'tcx hir::Expr<'tcx>,
+        lhs: Option<&'tcx hir::Expr<'tcx>>,
+        rhs: Option<&'tcx hir::Expr<'tcx>>,
         expected: Ty<'tcx>,
         ti: TopInfo<'tcx>,
-    ) -> Option<Ty<'tcx>> {
-        let lhs_ty = self.check_expr(lhs);
-        let rhs_ty = self.check_expr(rhs);
-
-        // Check that both end-points are of numeric or char type.
-        let numeric_or_char = |ty: Ty<'_>| ty.is_numeric() || ty.is_char() || ty.references_error();
-        let lhs_fail = !numeric_or_char(lhs_ty);
-        let rhs_fail = !numeric_or_char(rhs_ty);
-
-        if lhs_fail || rhs_fail {
-            self.emit_err_pat_range(span, lhs.span, rhs.span, lhs_fail, rhs_fail, lhs_ty, rhs_ty);
-            return None;
+    ) -> Ty<'tcx> {
+        let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
+            None => (None, None),
+            Some(expr) => {
+                let ty = self.check_expr(expr);
+                // Check that the end-point is of numeric or char type.
+                let fail = !(ty.is_numeric() || ty.is_char() || ty.references_error());
+                (Some(ty), Some((fail, ty, expr.span)))
+            }
+        };
+        let (lhs_ty, lhs) = calc_side(lhs);
+        let (rhs_ty, rhs) = calc_side(rhs);
+
+        if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
+            // There exists a side that didn't meet our criteria that the end-point
+            // be of a numeric or char type, as checked in `calc_side` above.
+            self.emit_err_pat_range(span, lhs, rhs);
+            return self.tcx.types.err;
         }
 
-        // Now that we know the types can be unified we find the unified type and use
-        // it to type the entire expression.
-        let common_type = self.resolve_vars_if_possible(&lhs_ty);
+        // Now that we know the types can be unified we find the unified type
+        // and use it to type the entire expression.
+        let common_type = self.resolve_vars_if_possible(&lhs_ty.or(rhs_ty).unwrap_or(expected));
 
         // Subtyping doesn't matter here, as the value is some kind of scalar.
-        let demand_eqtype = |x_span, y_span, x_ty, y_ty| {
-            self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti).map(|mut err| {
-                self.endpoint_has_type(&mut err, y_span, y_ty);
-                err.emit();
-            });
+        let demand_eqtype = |x, y| {
+            if let Some((_, x_ty, x_span)) = x {
+                self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti).map(|mut err| {
+                    if let Some((_, y_ty, y_span)) = y {
+                        self.endpoint_has_type(&mut err, y_span, y_ty);
+                    }
+                    err.emit();
+                });
+            }
         };
-        demand_eqtype(lhs.span, rhs.span, lhs_ty, rhs_ty);
-        demand_eqtype(rhs.span, lhs.span, rhs_ty, lhs_ty);
+        demand_eqtype(lhs, rhs);
+        demand_eqtype(rhs, lhs);
 
-        Some(common_type)
+        common_type
     }
 
     fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) {
@@ -439,21 +444,15 @@ fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<
     fn emit_err_pat_range(
         &self,
         span: Span,
-        begin_span: Span,
-        end_span: Span,
-        lhs_fail: bool,
-        rhs_fail: bool,
-        lhs_ty: Ty<'tcx>,
-        rhs_ty: Ty<'tcx>,
+        lhs: Option<(bool, Ty<'tcx>, Span)>,
+        rhs: Option<(bool, Ty<'tcx>, Span)>,
     ) {
-        let span = if lhs_fail && rhs_fail {
-            span
-        } else if lhs_fail {
-            begin_span
-        } else {
-            end_span
+        let span = match (lhs, rhs) {
+            (Some((true, ..)), Some((true, ..))) => span,
+            (Some((true, _, sp)), _) => sp,
+            (_, Some((true, _, sp))) => sp,
+            _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
         };
-
         let mut err = struct_span_err!(
             self.tcx.sess,
             span,
@@ -461,17 +460,20 @@ fn emit_err_pat_range(
             "only char and numeric types are allowed in range patterns"
         );
         let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty);
-        let mut one_side_err = |first_span, first_ty, second_span, second_ty: Ty<'_>| {
+        let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
             err.span_label(first_span, &msg(first_ty));
-            self.endpoint_has_type(&mut err, second_span, second_ty);
+            if let Some((_, ty, sp)) = second {
+                self.endpoint_has_type(&mut err, sp, ty);
+            }
         };
-        if lhs_fail && rhs_fail {
-            err.span_label(begin_span, &msg(lhs_ty));
-            err.span_label(end_span, &msg(rhs_ty));
-        } else if lhs_fail {
-            one_side_err(begin_span, lhs_ty, end_span, rhs_ty);
-        } else {
-            one_side_err(end_span, rhs_ty, begin_span, lhs_ty);
+        match (lhs, rhs) {
+            (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
+                err.span_label(lhs_sp, &msg(lhs_ty));
+                err.span_label(rhs_sp, &msg(rhs_ty));
+            }
+            (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
+            (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
+            _ => span_bug!(span, "Impossible, verified above."),
         }
         if self.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
@@ -983,22 +985,25 @@ fn check_struct_pat_fields(
 
         // Require `..` if struct has non_exhaustive attribute.
         if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
-            span_err!(
+            struct_span_err!(
                 tcx.sess,
                 span,
                 E0638,
                 "`..` required with {} marked as non-exhaustive",
                 kind_name
-            );
+            )
+            .emit();
         }
 
         // Report an error if incorrect number of the fields were specified.
         if kind_name == "union" {
             if fields.len() != 1 {
-                tcx.sess.span_err(span, "union patterns should have exactly one field");
+                tcx.sess
+                    .struct_span_err(span, "union patterns should have exactly one field")
+                    .emit();
             }
             if etc {
-                tcx.sess.span_err(span, "`..` cannot be used in union patterns");
+                tcx.sess.struct_span_err(span, "`..` cannot be used in union patterns").emit();
             }
         } else if !etc && unmentioned_fields.len() > 0 {
             self.error_unmentioned_fields(span, &unmentioned_fields, variant);
index 3b2f3d17e8da6a7e4bd89c31146dc6a0d7904151..967741092febe41b6b277a382d2bd506e0739a86 100644 (file)
@@ -76,7 +76,7 @@
 use crate::check::FnCtxt;
 use crate::mem_categorization as mc;
 use crate::middle::region;
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::infer::{self, RegionObligation, SuppressRegionErrors};
 use rustc::ty::adjustment;
@@ -84,6 +84,7 @@
 use rustc::ty::{self, Ty};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::PatKind;
 use rustc_span::Span;
 use std::mem;
@@ -414,7 +415,9 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
     // hierarchy, and in particular the relationships between free
     // regions, until regionck, as described in #3238.
 
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
index be912b6bcafc03d2c8d3df190f6e24d3da7af2cf..e4502bf134d765675f51312a2c267ffa20ba2934 100644 (file)
 use crate::expr_use_visitor as euv;
 use crate::mem_categorization as mc;
 use crate::mem_categorization::PlaceBase;
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::infer::UpvarRegion;
 use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts};
 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_span::Span;
 use syntax::ast;
 
@@ -59,7 +60,9 @@ struct InferBorrowKindVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
@@ -209,7 +212,7 @@ fn analyze_closure(
         }
     }
 
-    // Returns a list of `ClosureUpvar`s for each upvar.
+    // Returns a list of `Ty`s for each upvar.
     fn final_upvar_tys(&self, closure_id: hir::HirId) -> Vec<Ty<'tcx>> {
         // Presently an unboxed closure type cannot "escape" out of a
         // function, so we will only encounter ones that originated in the
index 2da27d59829cfbd0548978d869cf2dd93fca8433..a496a6e12ce1a0f7d5c4ce0c54c47068fc434410 100644 (file)
@@ -3,18 +3,17 @@
 
 use rustc::infer::opaque_types::may_define_opaque_type;
 use rustc::middle::lang_items;
+use rustc::session::parse::feature_err;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir::def_id::DefId;
 use rustc_hir::ItemKind;
-
-use errors::DiagnosticBuilder;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use syntax::ast;
-use syntax::feature_gate;
 
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ParItemLikeVisitor;
@@ -113,13 +112,14 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: DefId) {
                 ty::ImplPolarity::Negative => {
                     // FIXME(#27579): what amount of WF checking do we need for neg impls?
                     if trait_ref.is_some() && !is_auto {
-                        span_err!(
+                        struct_span_err!(
                             tcx.sess,
                             item.span,
                             E0192,
                             "negative impls are only allowed for \
                                    auto traits (e.g., `Send` and `Sync`)"
                         )
+                        .emit()
                     }
                 }
                 ty::ImplPolarity::Reservation => {
@@ -417,7 +417,7 @@ fn check_impl<'tcx>(
                 let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
                 let trait_ref =
                     fcx.normalize_associated_types_in(ast_trait_ref.path.span, &trait_ref);
-                let obligations = ty::wf::trait_obligations(
+                let obligations = traits::wf::trait_obligations(
                     fcx,
                     fcx.param_env,
                     fcx.body_id,
@@ -596,7 +596,7 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
     let wf_obligations = predicates
         .predicates
         .iter()
-        .flat_map(|p| ty::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span));
+        .flat_map(|p| traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span));
 
     for obligation in wf_obligations.chain(default_obligations) {
         debug!("next obligation cause: {:?}", obligation.cause);
@@ -821,7 +821,7 @@ fn check_method_receiver<'fcx, 'tcx>(
         if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) {
             if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
                 // Report error; would have worked with `arbitrary_self_types`.
-                feature_gate::feature_err(
+                feature_err(
                     &fcx.tcx.sess.parse_sess,
                     sym::arbitrary_self_types,
                     span,
index ad9a2f2e2b45e44d5c23e00561f4f1a18160ddd4..b4798fb67f80f42ae99ade0af70c0cd4ba44f71b 100644 (file)
@@ -4,7 +4,7 @@
 
 use crate::check::FnCtxt;
 
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc::infer::InferCtxt;
 use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast};
@@ -13,6 +13,7 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdSet, DefIndex};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
@@ -242,7 +243,9 @@ fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
 // traffic in node-ids or update tables in the type context etc.
 
 impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
 
index ab8e4ce6975a976b966b2ea55e68486be9524e5a..ec098c1d89679c9ec1456c359fd6c45f60e140cf 100644 (file)
@@ -1,15 +1,13 @@
 use crate::lint;
 use rustc::ty::TyCtxt;
-
-use errors::Applicability;
-use rustc_span::Span;
-use syntax::ast;
-
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::print::visibility_qualified;
+use rustc_span::Span;
+use syntax::ast;
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let mut used_trait_imports = DefIdSet::default();
index 6d97661e5272a7e3c25e5dc8dbe3e367b2a61ac2..8b3db15c02b4ecd18337b651dacb9bacb4ae26b9 100644 (file)
@@ -1,24 +1,23 @@
 //! Check properties that are required by built-in traits and set
 //! up data structures required by type-checking/codegen.
 
+use rustc::infer;
 use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::infer::SuppressRegionErrors;
 use rustc::middle::lang_items::UnsizeTraitLangItem;
 use rustc::middle::region;
-
-use rustc::infer;
+use rustc::traits::misc::{can_type_implement_copy, CopyImplementationError};
+use rustc::traits::predicate_for_trait_def;
 use rustc::traits::{self, ObligationCause, TraitEngine};
 use rustc::ty::adjustment::CoerceUnsizedInfo;
-use rustc::ty::util::CopyImplementationError;
 use rustc::ty::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt};
-
+use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::ItemKind;
 
-use rustc_error_codes::*;
-
 pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
     Checker { tcx, trait_def_id }
         .check(tcx.lang_items().drop_trait(), visit_implementation_of_drop)
@@ -91,7 +90,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: DefId) {
 
     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
-    match param_env.can_type_implement_copy(tcx, self_type) {
+    match can_type_implement_copy(tcx, param_env, self_type) {
         Ok(()) => {}
         Err(CopyImplementationError::InfrigingFields(fields)) => {
             let item = tcx.hir().expect_item(impl_hir_id);
@@ -284,7 +283,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) {
                         let mut fulfill_cx = TraitEngine::new(infcx.tcx);
 
                         for field in coerced_fields {
-                            let predicate = tcx.predicate_for_trait_def(
+                            let predicate = predicate_for_trait_def(
+                                tcx,
                                 param_env,
                                 cause.clone(),
                                 dispatch_from_dyn_trait,
@@ -391,7 +391,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                 if def_a != def_b {
                     let source_path = tcx.def_path_str(def_a.did);
                     let target_path = tcx.def_path_str(def_b.did);
-                    span_err!(
+                    struct_span_err!(
                         tcx.sess,
                         span,
                         E0377,
@@ -400,7 +400,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                                definition; expected `{}`, found `{}`",
                         source_path,
                         target_path
-                    );
+                    )
+                    .emit();
                     return err_info;
                 }
 
@@ -477,14 +478,15 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                     .collect::<Vec<_>>();
 
                 if diff_fields.is_empty() {
-                    span_err!(
+                    struct_span_err!(
                         tcx.sess,
                         span,
                         E0374,
                         "the trait `CoerceUnsized` may only be implemented \
                                for a coercion between structures with one field \
                                being coerced, none found"
-                    );
+                    )
+                    .emit();
                     return err_info;
                 } else if diff_fields.len() > 1 {
                     let item = tcx.hir().expect_item(impl_hir_id);
@@ -494,19 +496,19 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                         tcx.hir().span(impl_hir_id)
                     };
 
-                    let mut err = struct_span_err!(
+                    struct_span_err!(
                         tcx.sess,
                         span,
                         E0375,
                         "implementing the trait \
                                                     `CoerceUnsized` requires multiple \
                                                     coercions"
-                    );
-                    err.note(
+                    )
+                    .note(
                         "`CoerceUnsized` may only be implemented for \
                               a coercion between structures with one field being coerced",
-                    );
-                    err.note(&format!(
+                    )
+                    .note(&format!(
                         "currently, {} fields need coercions: {}",
                         diff_fields.len(),
                         diff_fields
@@ -516,9 +518,9 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                             })
                             .collect::<Vec<_>>()
                             .join(", ")
-                    ));
-                    err.span_label(span, "requires multiple coercions");
-                    err.emit();
+                    ))
+                    .span_label(span, "requires multiple coercions")
+                    .emit();
                     return err_info;
                 }
 
@@ -528,13 +530,14 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
             }
 
             _ => {
-                span_err!(
+                struct_span_err!(
                     tcx.sess,
                     span,
                     E0376,
                     "the trait `CoerceUnsized` may only be implemented \
                            for a coercion between structures"
-                );
+                )
+                .emit();
                 return err_info;
             }
         };
@@ -543,7 +546,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
 
         // Register an obligation for `A: Trait<B>`.
         let cause = traits::ObligationCause::misc(span, impl_hir_id);
-        let predicate = tcx.predicate_for_trait_def(
+        let predicate = predicate_for_trait_def(
+            tcx,
             param_env,
             cause,
             trait_def_id,
index 76de177e8e5104e96540a072ff0cb3a73abec032..673c1bd9fd83103ec99bfa9d65adc420b2eb29ee 100644 (file)
@@ -8,6 +8,7 @@
 //! is computed by selecting an idea from this table.
 
 use rustc::ty::{self, CrateInherentImpls, TyCtxt};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
index fed8ed53468d6ab3c8efe4fca759f2e97a5f3ba0..a9228c7f6bb4c86dc655dbbce9e8c2020f44de3e 100644 (file)
@@ -1,6 +1,7 @@
 use crate::namespace::Namespace;
 use rustc::traits::{self, IntercrateMode};
 use rustc::ty::TyCtxt;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
index 2d19b73eac380ff995056821071a7ae9533e5e42..fd685e77b418ccc09543a761f73638c3f7f48b1a 100644 (file)
@@ -5,13 +5,13 @@
 // done by the orphan and overlap modules. Then we build up various
 // mappings. That mapping code resides here.
 
-use crate::hir::def_id::{DefId, LOCAL_CRATE};
-use crate::hir::HirId;
 use rustc::traits;
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
-
 use rustc_error_codes::*;
+use rustc_errors::struct_span_err;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::HirId;
 
 mod builtin;
 mod inherent_impls;
@@ -145,8 +145,8 @@ pub fn check_coherence(tcx: TyCtxt<'_>) {
         tcx.ensure().coherent_trait(trait_def_id);
     }
 
-    tcx.sess.time("unsafety checking", || unsafety::check(tcx));
-    tcx.sess.time("orphan checking", || orphan::check(tcx));
+    tcx.sess.time("unsafety_checking", || unsafety::check(tcx));
+    tcx.sess.time("orphan_checking", || orphan::check(tcx));
 
     // these queries are executed for side-effects (error reporting):
     tcx.ensure().crate_inherent_impls(LOCAL_CRATE);
index 8a87bcabeecdfa4df455acdd89d4aecff672614f..1878f9385a891696e2a63d66075f4162585a6b9a 100644 (file)
@@ -3,6 +3,7 @@
 
 use rustc::traits;
 use rustc::ty::{self, TyCtxt};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 
index ed0d9ba643a31856f608fbfa113e2834269faa28..3f4035b0998d64c4d756cb0b485db4c674859202 100644 (file)
@@ -2,6 +2,7 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc::ty::TyCtxt;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Unsafety;
@@ -33,23 +34,25 @@ fn check_unsafety_coherence(
             });
             match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
                 (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
-                    span_err!(
+                    struct_span_err!(
                         self.tcx.sess,
                         item.span,
                         E0199,
                         "implementing the trait `{}` is not unsafe",
                         trait_ref.print_only_trait_path()
-                    );
+                    )
+                    .emit();
                 }
 
                 (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
-                    span_err!(
+                    struct_span_err!(
                         self.tcx.sess,
                         item.span,
                         E0200,
                         "the trait `{}` requires an `unsafe impl` declaration",
                         trait_ref.print_only_trait_path()
-                    );
+                    )
+                    .emit();
                 }
 
                 (
@@ -58,13 +61,14 @@ fn check_unsafety_coherence(
                     Unsafety::Normal,
                     hir::ImplPolarity::Positive,
                 ) => {
-                    span_err!(
+                    struct_span_err!(
                         self.tcx.sess,
                         item.span,
                         E0569,
                         "requires an `unsafe impl` declaration due to `#[{}]` attribute",
                         attr_name
-                    );
+                    )
+                    .emit();
                 }
 
                 (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
index 1fefeaf720fcc267283455516145d76baeac6712..ad750d5ab8341691f82a909fae80a76b2de6edef 100644 (file)
 use crate::lint;
 use crate::middle::resolve_lifetime as rl;
 use crate::middle::weak_lang_items;
-use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc::hir::map::Map;
 use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc::mir::mono::Linkage;
+use rustc::session::parse::feature_err;
+use rustc::traits;
 use rustc::ty::query::Providers;
 use rustc::ty::subst::GenericArgKind;
 use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::{ReprOptions, ToPredicate};
-use rustc::util::captures::Captures;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{struct_span_err, Applicability, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{GenericParamKind, Node, Unsafety};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -42,9 +46,6 @@
 use syntax::ast;
 use syntax::ast::{Ident, MetaItemKind};
 use syntax::attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr};
-use syntax::feature_gate;
-
-use errors::{Applicability, StashKey};
 
 use rustc_error_codes::*;
 
@@ -104,7 +105,9 @@ pub struct ItemCtxt<'tcx> {
 crate struct PlaceholderHirTyCollector(crate Vec<Span>);
 
 impl<'v> Visitor<'v> for PlaceholderHirTyCollector {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+    type Map = Map<'v>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::None
     }
     fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
@@ -124,7 +127,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>,
-    ident_span: Span,
+    span: Span,
     generics: &[hir::GenericParam<'_>],
     placeholder_types: Vec<Span>,
     suggest: bool,
@@ -150,7 +153,14 @@ struct CollectItemTypesVisitor<'tcx> {
     let mut sugg: Vec<_> =
         placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect();
     if generics.is_empty() {
-        sugg.push((ident_span.shrink_to_hi(), format!("<{}>", type_name)));
+        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,
+    }) {
+        // Account for `_` already present in cases like `struct S<_>(_);` and suggest
+        // `struct S<T>(T);` instead of `struct S<_, T>(T);`.
+        sugg.push((arg.span, format!("{}", type_name)));
     } else {
         sugg.push((
             generics.iter().last().unwrap().span.shrink_to_hi(),
@@ -172,8 +182,12 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
     let (generics, suggest) = match &item.kind {
         hir::ItemKind::Union(_, generics)
         | hir::ItemKind::Enum(_, generics)
-        | hir::ItemKind::Struct(_, generics) => (&generics.params[..], true),
-        hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false),
+        | hir::ItemKind::TraitAlias(generics, _)
+        | hir::ItemKind::Trait(_, _, generics, ..)
+        | hir::ItemKind::Impl(_, _, _, generics, ..)
+        | hir::ItemKind::Struct(_, generics) => (generics, true),
+        hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
+        | hir::ItemKind::TyAlias(_, generics) => (generics, false),
         // `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
         _ => return,
     };
@@ -181,11 +195,13 @@ 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, item.ident.span, generics, visitor.0, suggest);
+    placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest);
 }
 
 impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
     }
 
@@ -239,7 +255,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
 fn bad_placeholder_type(
     tcx: TyCtxt<'tcx>,
     mut spans: Vec<Span>,
-) -> errors::DiagnosticBuilder<'tcx> {
+) -> rustc_errors::DiagnosticBuilder<'tcx> {
     spans.sort();
     let mut err = struct_span_err!(
         tcx.sess,
@@ -319,13 +335,14 @@ fn projected_ty_from_poly_trait_ref(
             self.tcx().mk_projection(item_def_id, item_substs)
         } else {
             // There are no late-bound regions; we can just ignore the binder.
-            span_err!(
+            struct_span_err!(
                 self.tcx().sess,
                 span,
                 E0212,
                 "cannot extract an associated type from a higher-ranked trait bound \
                  in this context"
-            );
+            )
+            .emit();
             self.tcx().types.err
         }
     }
@@ -860,17 +877,14 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TraitDef {
 
     let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
     if paren_sugar && !tcx.features().unboxed_closures {
-        let mut err = tcx.sess.struct_span_err(
-            item.span,
-            "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
+        tcx.sess
+            .struct_span_err(
+                item.span,
+                "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
              which traits can use parenthetical notation",
-        );
-        help!(
-            &mut err,
-            "add `#![feature(unboxed_closures)]` to \
-             the crate attributes to use it"
-        );
-        err.emit();
+            )
+            .help("add `#![feature(unboxed_closures)]` to the crate attributes to use it")
+            .emit();
     }
 
     let is_marker = tcx.has_attr(def_id, sym::marker);
@@ -887,7 +901,9 @@ struct LateBoundRegionsDetector<'tcx> {
     }
 
     impl Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
-        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        type Map = Map<'tcx>;
+
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
             NestedVisitorMap::None
         }
 
@@ -1205,12 +1221,13 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
 }
 
 fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) {
-    span_err!(
+    struct_span_err!(
         tcx.sess,
         span,
         E0202,
         "associated types are not yet supported in inherent impls (see #8995)"
-    );
+    )
+    .emit();
 }
 
 fn infer_placeholder_type(
@@ -1509,48 +1526,48 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             }
         }
 
-        Node::GenericParam(param) => {
-            match &param.kind {
-                hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
-                hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
-                    let ty = icx.to_ty(hir_ty);
-                    if !tcx.features().const_compare_raw_pointers {
-                        let err = match ty.peel_refs().kind {
-                            ty::FnPtr(_) => Some("function pointers"),
-                            ty::RawPtr(_) => Some("raw pointers"),
-                            _ => None,
-                        };
-                        if let Some(unsupported_type) = err {
-                            feature_gate::feature_err(
-                                &tcx.sess.parse_sess,
-                                sym::const_compare_raw_pointers,
-                                hir_ty.span,
-                                &format!(
-                                    "using {} as const generic parameters is unstable",
-                                    unsupported_type
-                                ),
-                            )
-                            .emit();
-                        };
-                    }
-                    if ty::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
-                        .is_some()
-                    {
-                        struct_span_err!(
+        Node::GenericParam(param) => match &param.kind {
+            hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
+            hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
+                let ty = icx.to_ty(hir_ty);
+                if !tcx.features().const_compare_raw_pointers {
+                    let err = match ty.peel_refs().kind {
+                        ty::FnPtr(_) => Some("function pointers"),
+                        ty::RawPtr(_) => Some("raw pointers"),
+                        _ => None,
+                    };
+                    if let Some(unsupported_type) = err {
+                        feature_err(
+                            &tcx.sess.parse_sess,
+                            sym::const_compare_raw_pointers,
+                            hir_ty.span,
+                            &format!(
+                                "using {} as const generic parameters is unstable",
+                                unsupported_type
+                            ),
+                        )
+                        .emit();
+                    };
+                }
+                if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
+                    .is_some()
+                {
+                    struct_span_err!(
                         tcx.sess,
                         hir_ty.span,
                         E0741,
                         "the types of const generic parameters must derive `PartialEq` and `Eq`",
-                    ).span_label(
+                    )
+                    .span_label(
                         hir_ty.span,
                         format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
-                    ).emit();
-                    }
-                    ty
+                    )
+                    .emit();
                 }
-                x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
+                ty
             }
-        }
+            x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
+        },
 
         x => {
             bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
@@ -1716,7 +1733,9 @@ fn check(&mut self, def_id: DefId) {
     }
 
     impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
-        fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+        type Map = Map<'tcx>;
+
+        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
             intravisit::NestedVisitorMap::All(&self.tcx.hir())
         }
         fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
@@ -1790,10 +1809,19 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
 /// Whether `ty` is a type with `_` placeholders that can be infered. Used in diagnostics only to
 /// use inference to provide suggestions for the appropriate type if possible.
 fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
+    use hir::TyKind::*;
     match &ty.kind {
-        hir::TyKind::Infer => true,
-        hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_suggestable_infer_ty(ty),
-        hir::TyKind::Tup(tys) => tys.iter().any(|ty| is_suggestable_infer_ty(ty)),
+        Infer => true,
+        Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
+        Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
+        Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
+        Def(_, generic_args) => generic_args
+            .iter()
+            .filter_map(|arg| match arg {
+                hir::GenericArg::Type(ty) => Some(ty),
+                _ => None,
+            })
+            .any(is_suggestable_infer_ty),
         _ => false,
     }
 }
@@ -2605,7 +2633,7 @@ fn from_target_feature(
                 None => true,
             };
             if !allowed && id.is_local() {
-                feature_gate::feature_err(
+                feature_err(
                     &tcx.sess.parse_sess,
                     feature_gate.unwrap(),
                     item.span(),
@@ -2766,14 +2794,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 mark_used(attr);
                 inline_span = Some(attr.span);
                 if items.len() != 1 {
-                    span_err!(tcx.sess.diagnostic(), attr.span, E0534, "expected one argument");
+                    struct_span_err!(
+                        tcx.sess.diagnostic(),
+                        attr.span,
+                        E0534,
+                        "expected one argument"
+                    )
+                    .emit();
                     InlineAttr::None
                 } else if list_contains_name(&items[..], sym::always) {
                     InlineAttr::Always
                 } else if list_contains_name(&items[..], sym::never) {
                     InlineAttr::Never
                 } else {
-                    span_err!(tcx.sess.diagnostic(), items[0].span(), E0535, "invalid argument");
+                    struct_span_err!(
+                        tcx.sess.diagnostic(),
+                        items[0].span(),
+                        E0535,
+                        "invalid argument"
+                    )
+                    .emit();
 
                     InlineAttr::None
                 }
@@ -2787,7 +2827,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         if !attr.has_name(sym::optimize) {
             return ia;
         }
-        let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s);
+        let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
         match attr.meta().map(|i| i.kind) {
             Some(MetaItemKind::Word) => {
                 err(attr.span, "expected one argument");
index b22d7c68cf9b6247cf4f54dd4c3c39b02b7c6864..fb87b285fa29f56e139ea257cfdcb815ed643c0a 100644 (file)
@@ -12,6 +12,7 @@
 use rustc::ty::query::Providers;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
index 8fba65db30981fdb5690bb3c634c3335237e19b5..b951883ac195a2888c8b9803765d3e823e61e264 100644 (file)
@@ -71,8 +71,6 @@
 
 #[macro_use]
 extern crate log;
-#[macro_use]
-extern crate syntax;
 
 #[macro_use]
 extern crate rustc;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util;
 use rustc::util::common::ErrorReported;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::Node;
@@ -310,7 +309,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
     // have valid types and not error
     // FIXME(matthewjasper) We shouldn't need to do this.
     tcx.sess.track_errors(|| {
-        tcx.sess.time("type collecting", || {
+        tcx.sess.time("type_collecting", || {
             for &module in tcx.hir().krate().modules.keys() {
                 tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
             }
@@ -319,35 +318,35 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
 
     if tcx.features().rustc_attrs {
         tcx.sess.track_errors(|| {
-            tcx.sess.time("outlives testing", || outlives::test::test_inferred_outlives(tcx));
+            tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
         })?;
     }
 
     tcx.sess.track_errors(|| {
-        tcx.sess.time("impl wf inference", || impl_wf_check::impl_wf_check(tcx));
+        tcx.sess.time("impl_wf_inference", || impl_wf_check::impl_wf_check(tcx));
     })?;
 
     tcx.sess.track_errors(|| {
-        tcx.sess.time("coherence checking", || coherence::check_coherence(tcx));
+        tcx.sess.time("coherence_checking", || coherence::check_coherence(tcx));
     })?;
 
     if tcx.features().rustc_attrs {
         tcx.sess.track_errors(|| {
-            tcx.sess.time("variance testing", || variance::test::test_variance(tcx));
+            tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
         })?;
     }
 
     tcx.sess.track_errors(|| {
-        tcx.sess.time("wf checking", || check::check_wf_new(tcx));
+        tcx.sess.time("wf_checking", || check::check_wf_new(tcx));
     })?;
 
-    tcx.sess.time("item-types checking", || {
+    tcx.sess.time("item_types_checking", || {
         for &module in tcx.hir().krate().modules.keys() {
             tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
         }
     });
 
-    tcx.sess.time("item-bodies checking", || tcx.typeck_item_bodies(LOCAL_CRATE));
+    tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(LOCAL_CRATE));
 
     check_unused::check_crate(tcx);
     check_for_entry_fn(tcx);
index f8907c85218ee8dc89df597edd997699cfbc2d8b..908429c8dc48a8b215cde8db0ffd4635c412bac7 100644 (file)
@@ -1,4 +1,5 @@
 use rustc::ty::TyCtxt;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_span::symbol::sym;
@@ -21,7 +22,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         // attribute and report an error with various results if found.
         if self.tcx.has_attr(item_def_id, sym::rustc_outlives) {
             let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
-            span_err!(self.tcx.sess, item.span, E0640, "{:?}", inferred_outlives_of);
+            struct_span_err!(self.tcx.sess, item.span, E0640, "{:?}", inferred_outlives_of).emit();
         }
     }
 
index 251732b6f12335e302d9c082c528ad07a058ba44..068814723f52d758e6a578062a5e6887f90c5db1 100644 (file)
@@ -1,6 +1,6 @@
-use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc::session::Session;
 use rustc::ty::{Ty, TypeFoldable};
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_span::Span;
 
 use rustc_error_codes::*;
@@ -50,8 +50,7 @@ fn session(&self) -> &Session {
     }
 
     fn code(&self) -> DiagnosticId {
-        syntax::diagnostic_used!(E0617);
-        DiagnosticId::Error("E0617".to_owned())
+        rustc_errors::error_code!(E0617)
     }
 
     fn common(&self) -> DiagnosticBuilder<'tcx> {
@@ -112,8 +111,7 @@ fn session(&self) -> &Session {
     }
 
     fn code(&self) -> DiagnosticId {
-        syntax::diagnostic_used!(E0607);
-        DiagnosticId::Error("E0607".to_owned())
+        rustc_errors::error_code!(E0607)
     }
 
     fn common(&self) -> DiagnosticBuilder<'tcx> {
index a8003a588ba3a75854bd5e07b9ecf07339d7abf3..2f41bee1819cd32dce67b698112d11c556e76aa8 100644 (file)
@@ -1,4 +1,5 @@
 use rustc::ty::TyCtxt;
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_span::symbol::sym;
@@ -21,7 +22,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         // attribute and report an error with various results if found.
         if self.tcx.has_attr(item_def_id, sym::rustc_variance) {
             let variances_of = self.tcx.variances_of(item_def_id);
-            span_err!(self.tcx.sess, item.span, E0208, "{:?}", variances_of);
+            struct_span_err!(self.tcx.sess, item.span, E0208, "{:?}", variances_of).emit();
         }
     }
 
index 13df1892a5f1776305a98e2970613410be8bdc07..84e6ff648a38ff9d7652a05225a8ef980aac9c7d 100644 (file)
@@ -202,23 +202,34 @@ fn not(self) -> Cfg {
 
 impl ops::BitAndAssign for Cfg {
     fn bitand_assign(&mut self, other: Cfg) {
-        if *self == other {
-            return;
-        }
         match (self, other) {
             (&mut Cfg::False, _) | (_, Cfg::True) => {}
             (s, Cfg::False) => *s = Cfg::False,
             (s @ &mut Cfg::True, b) => *s = b,
-            (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => a.append(b),
-            (&mut Cfg::All(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
+            (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => {
+                for c in b.drain(..) {
+                    if !a.contains(&c) {
+                        a.push(c);
+                    }
+                }
+            }
+            (&mut Cfg::All(ref mut a), ref mut b) => {
+                if !a.contains(b) {
+                    a.push(mem::replace(b, Cfg::True));
+                }
+            }
             (s, Cfg::All(mut a)) => {
                 let b = mem::replace(s, Cfg::True);
-                a.push(b);
+                if !a.contains(&b) {
+                    a.push(b);
+                }
                 *s = Cfg::All(a);
             }
             (s, b) => {
-                let a = mem::replace(s, Cfg::True);
-                *s = Cfg::All(vec![a, b]);
+                if *s != b {
+                    let a = mem::replace(s, Cfg::True);
+                    *s = Cfg::All(vec![a, b]);
+                }
             }
         }
     }
@@ -234,23 +245,34 @@ fn bitand(mut self, other: Cfg) -> Cfg {
 
 impl ops::BitOrAssign for Cfg {
     fn bitor_assign(&mut self, other: Cfg) {
-        if *self == other {
-            return;
-        }
         match (self, other) {
             (&mut Cfg::True, _) | (_, Cfg::False) => {}
             (s, Cfg::True) => *s = Cfg::True,
             (s @ &mut Cfg::False, b) => *s = b,
-            (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => a.append(b),
-            (&mut Cfg::Any(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
+            (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => {
+                for c in b.drain(..) {
+                    if !a.contains(&c) {
+                        a.push(c);
+                    }
+                }
+            }
+            (&mut Cfg::Any(ref mut a), ref mut b) => {
+                if !a.contains(b) {
+                    a.push(mem::replace(b, Cfg::True));
+                }
+            }
             (s, Cfg::Any(mut a)) => {
                 let b = mem::replace(s, Cfg::True);
-                a.push(b);
+                if !a.contains(&b) {
+                    a.push(b);
+                }
                 *s = Cfg::Any(a);
             }
             (s, b) => {
-                let a = mem::replace(s, Cfg::True);
-                *s = Cfg::Any(vec![a, b]);
+                if *s != b {
+                    let a = mem::replace(s, Cfg::True);
+                    *s = Cfg::Any(vec![a, b]);
+                }
             }
         }
     }
index 309f72040615d162d5616050a1e9e1a859df6a41..d090bf325038f53def6469ba94aef723fa69bc40 100644 (file)
@@ -87,6 +87,12 @@ fn test_cfg_and() {
         x &= word_cfg("test3");
         assert_eq!(x, word_cfg("test3"));
 
+        x &= word_cfg("test3");
+        assert_eq!(x, word_cfg("test3"));
+
+        x &= word_cfg("test4");
+        assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
+
         x &= word_cfg("test4");
         assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
 
@@ -105,6 +111,18 @@ fn test_cfg_and() {
             ])
         );
 
+        x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
+        assert_eq!(
+            x,
+            Cfg::All(vec![
+                word_cfg("test3"),
+                word_cfg("test4"),
+                word_cfg("test5"),
+                word_cfg("test6"),
+                word_cfg("test7"),
+            ])
+        );
+
         let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
         y &= x;
         assert_eq!(
@@ -119,6 +137,14 @@ fn test_cfg_and() {
             ])
         );
 
+        let mut z = word_cfg("test8");
+        z &= Cfg::All(vec![word_cfg("test9"), word_cfg("test10")]);
+        assert_eq!(z, Cfg::All(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
+
+        let mut z = word_cfg("test11");
+        z &= Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]);
+        assert_eq!(z, Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]));
+
         assert_eq!(
             word_cfg("a") & word_cfg("b") & word_cfg("c"),
             Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
@@ -145,6 +171,12 @@ fn test_cfg_or() {
         x |= word_cfg("test3");
         assert_eq!(x, word_cfg("test3"));
 
+        x |= word_cfg("test3");
+        assert_eq!(x, word_cfg("test3"));
+
+        x |= word_cfg("test4");
+        assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
+
         x |= word_cfg("test4");
         assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
 
@@ -163,6 +195,18 @@ fn test_cfg_or() {
             ])
         );
 
+        x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
+        assert_eq!(
+            x,
+            Cfg::Any(vec![
+                word_cfg("test3"),
+                word_cfg("test4"),
+                word_cfg("test5"),
+                word_cfg("test6"),
+                word_cfg("test7"),
+            ])
+        );
+
         let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
         y |= x;
         assert_eq!(
@@ -177,6 +221,14 @@ fn test_cfg_or() {
             ])
         );
 
+        let mut z = word_cfg("test8");
+        z |= Cfg::Any(vec![word_cfg("test9"), word_cfg("test10")]);
+        assert_eq!(z, Cfg::Any(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
+
+        let mut z = word_cfg("test11");
+        z |= Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]);
+        assert_eq!(z, Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]));
+
         assert_eq!(
             word_cfg("a") | word_cfg("b") | word_cfg("c"),
             Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
index 2400dded666686be65c41963a85be2cee521b0b0..c7e0f1e9e704ba0683a838307205f56a39ac8341 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::Mutability;
 use rustc_metadata::creader::LoadedMacro;
+use rustc_mir::const_eval::is_min_const_fn;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -212,7 +213,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
     let sig = cx.tcx.fn_sig(did);
 
     let constness =
-        if cx.tcx.is_min_const_fn(did) { hir::Constness::Const } else { hir::Constness::NotConst };
+        if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
     let asyncness = cx.tcx.asyncness(did);
     let predicates = cx.tcx.predicates_of(did);
     let (generics, decl) = clean::enter_impl_trait(cx, || {
index bb46a15258e0fbec33c0e78d3e6974e3b82acf47..be9654612f504e91163a02adc414d459735c08bd 100644 (file)
@@ -21,6 +21,7 @@
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_mir::const_eval::is_min_const_fn;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{self, Pos};
@@ -895,7 +896,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
             enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx)));
 
         let did = cx.tcx.hir().local_def_id(self.id);
-        let constness = if cx.tcx.is_min_const_fn(did) {
+        let constness = if is_min_const_fn(cx.tcx, did) {
             hir::Constness::Const
         } else {
             hir::Constness::NotConst
@@ -1187,7 +1188,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Item {
                 };
                 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
                 if provided {
-                    let constness = if cx.tcx.is_min_const_fn(self.def_id) {
+                    let constness = if is_min_const_fn(cx.tcx, self.def_id) {
                         hir::Constness::Const
                     } else {
                         hir::Constness::NotConst
index c8f1dff703fb40b22f93ab552ab958f478792e98..5d8e27ecadb828dbe8edbd7db05671ddf777c39c 100644 (file)
@@ -497,7 +497,7 @@ pub fn has_doc_flag(&self, flag: Symbol) -> bool {
         false
     }
 
-    pub fn from_ast(diagnostic: &::errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
+    pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
         let mut doc_strings = vec![];
         let mut sp = None;
         let mut cfg = Cfg::True;
index 874cb9b8a5c9ea2d4adef5fecd181e15aec1ccca..8058536d60b3194ed199ccce23befe3dd02cbd7d 100644 (file)
@@ -460,12 +460,16 @@ pub fn name_from_pat(p: &hir::Pat) -> String {
 
 pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
     match n.val {
-        ty::ConstKind::Unevaluated(def_id, _) => {
-            if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
+        ty::ConstKind::Unevaluated(def_id, _, promoted) => {
+            let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
                 print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
             } else {
                 inline::print_inlined_const(cx, def_id)
+            };
+            if let Some(promoted) = promoted {
+                s.push_str(&format!("::{:?}", promoted))
             }
+            s
         }
         _ => {
             let mut s = n.to_string();
index 0af25efc04234fd23577ea5e50535f2d411fc0ac..22f5d0dc2c07869c594a1e168abf46594c6dc169 100644 (file)
@@ -3,7 +3,6 @@
 use std::fmt;
 use std::path::PathBuf;
 
-use errors;
 use getopts;
 use rustc::lint::Level;
 use rustc::session;
@@ -24,7 +23,7 @@
 use crate::html::markdown::IdMap;
 use crate::html::static_files;
 use crate::opts;
-use crate::passes::{self, DefaultPassOption};
+use crate::passes::{self, Condition, DefaultPassOption};
 use crate::theme;
 
 /// Configuration options for rustdoc.
@@ -98,6 +97,10 @@ pub struct Options {
     ///
     /// Be aware: This option can come both from the CLI and from crate attributes!
     pub default_passes: DefaultPassOption,
+    /// Document items that have lower than `pub` visibility.
+    pub document_private: bool,
+    /// Document items that have `doc(hidden)`.
+    pub document_hidden: bool,
     /// Any passes manually selected by the user.
     ///
     /// Be aware: This option can come both from the CLI and from crate attributes!
@@ -146,6 +149,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             .field("test_args", &self.test_args)
             .field("persist_doctests", &self.persist_doctests)
             .field("default_passes", &self.default_passes)
+            .field("document_private", &self.document_private)
+            .field("document_hidden", &self.document_hidden)
             .field("manual_passes", &self.manual_passes)
             .field("display_warnings", &self.display_warnings)
             .field("show_coverage", &self.show_coverage)
@@ -240,22 +245,26 @@ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
                 println!("{:>20} - {}", pass.name, pass.description);
             }
             println!("\nDefault passes for rustdoc:");
-            for pass in passes::DEFAULT_PASSES {
-                println!("{:>20}", pass.name);
-            }
-            println!("\nPasses run with `--document-private-items`:");
-            for pass in passes::DEFAULT_PRIVATE_PASSES {
-                println!("{:>20}", pass.name);
+            for p in passes::DEFAULT_PASSES {
+                print!("{:>20}", p.pass.name);
+                println_condition(p.condition);
             }
 
             if nightly_options::is_nightly_build() {
                 println!("\nPasses run with `--show-coverage`:");
-                for pass in passes::DEFAULT_COVERAGE_PASSES {
-                    println!("{:>20}", pass.name);
+                for p in passes::COVERAGE_PASSES {
+                    print!("{:>20}", p.pass.name);
+                    println_condition(p.condition);
                 }
-                println!("\nPasses run with `--show-coverage --document-private-items`:");
-                for pass in passes::PRIVATE_COVERAGE_PASSES {
-                    println!("{:>20}", pass.name);
+            }
+
+            fn println_condition(condition: Condition) {
+                use Condition::*;
+                match condition {
+                    Always => println!(),
+                    WhenDocumentPrivate => println!("  (when --document-private-items)"),
+                    WhenNotDocumentPrivate => println!("  (when not --document-private-items)"),
+                    WhenNotDocumentHidden => println!("  (when not --document-hidden-items)"),
                 }
             }
 
@@ -444,16 +453,11 @@ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
             });
 
         let show_coverage = matches.opt_present("show-coverage");
-        let document_private = matches.opt_present("document-private-items");
 
         let default_passes = if matches.opt_present("no-defaults") {
             passes::DefaultPassOption::None
-        } else if show_coverage && document_private {
-            passes::DefaultPassOption::PrivateCoverage
         } else if show_coverage {
             passes::DefaultPassOption::Coverage
-        } else if document_private {
-            passes::DefaultPassOption::Private
         } else {
             passes::DefaultPassOption::Default
         };
@@ -492,6 +496,8 @@ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
         let runtool = matches.opt_str("runtool");
         let runtool_args = matches.opt_strs("runtool-arg");
         let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
+        let document_private = matches.opt_present("document-private-items");
+        let document_hidden = matches.opt_present("document-hidden-items");
 
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
@@ -518,6 +524,8 @@ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
             should_test,
             test_args,
             default_passes,
+            document_private,
+            document_hidden,
             manual_passes,
             display_warnings,
             show_coverage,
@@ -557,7 +565,7 @@ pub fn markdown_input(&self) -> bool {
 }
 
 /// Prints deprecation warnings for deprecated options
-fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
+fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Handler) {
     let deprecated_flags = ["input-format", "output-format", "no-defaults", "passes"];
 
     for flag in deprecated_flags.iter() {
index efac0d28d3b542dcf2c724b2304ba430a427e812..4c8b8112fa85a1c49aa319248394029385ce4ced 100644 (file)
@@ -1,4 +1,3 @@
-use rustc::lint;
 use rustc::middle::cstore::CrateStore;
 use rustc::middle::privacy::AccessLevels;
 use rustc::session::config::ErrorOutputType;
 use rustc_interface::interface;
 use rustc_lint;
 use rustc_resolve as resolve;
+use rustc_session::lint;
 
-use errors::emitter::{Emitter, EmitterWriter};
-use errors::json::JsonEmitter;
+use rustc_errors::emitter::{Emitter, EmitterWriter};
+use rustc_errors::json::JsonEmitter;
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
@@ -33,7 +33,7 @@
 use crate::config::{Options as RustdocOptions, RenderOptions};
 use crate::html::render::RenderInfo;
 
-use crate::passes;
+use crate::passes::{self, Condition::*, ConditionalPass};
 
 pub use rustc::session::config::{CodegenOptions, DebuggingOptions, Input, Options};
 pub use rustc::session::search_paths::SearchPath;
@@ -171,7 +171,7 @@ pub fn new_handler(
     error_format: ErrorOutputType,
     source_map: Option<Lrc<source_map::SourceMap>>,
     debugging_opts: &DebuggingOptions,
-) -> errors::Handler {
+) -> rustc_errors::Handler {
     let emitter: Box<dyn Emitter + sync::Send> = match error_format {
         ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
@@ -198,7 +198,10 @@ pub fn new_handler(
         }
     };
 
-    errors::Handler::with_emitter_and_flags(emitter, debugging_opts.diagnostic_handler_flags(true))
+    rustc_errors::Handler::with_emitter_and_flags(
+        emitter,
+        debugging_opts.diagnostic_handler_flags(true),
+    )
 }
 
 pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions) {
@@ -221,6 +224,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         describe_lints,
         lint_cap,
         mut default_passes,
+        mut document_private,
+        document_hidden,
         mut manual_passes,
         display_warnings,
         render_options,
@@ -406,7 +411,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
                 let mut krate = clean::krate(&mut ctxt);
 
-                fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
+                fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
                     let mut msg = diag.struct_warn(&format!(
                         "the `#![doc({})]` attribute is \
                                                          considered deprecated",
@@ -456,16 +461,14 @@ fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
                     }
 
                     if attr.is_word() && name == sym::document_private_items {
-                        if default_passes == passes::DefaultPassOption::Default {
-                            default_passes = passes::DefaultPassOption::Private;
-                        }
+                        document_private = true;
                     }
                 }
 
-                let passes = passes::defaults(default_passes).iter().chain(
+                let passes = passes::defaults(default_passes).iter().copied().chain(
                     manual_passes.into_iter().flat_map(|name| {
                         if let Some(pass) = passes::find_pass(&name) {
-                            Some(pass)
+                            Some(ConditionalPass::always(pass))
                         } else {
                             error!("unknown pass {}, skipping", name);
                             None
@@ -475,9 +478,17 @@ fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
 
                 info!("Executing passes");
 
-                for pass in passes {
-                    debug!("running pass {}", pass.name);
-                    krate = (pass.pass)(krate, &ctxt);
+                for p in passes {
+                    let run = match p.condition {
+                        Always => true,
+                        WhenDocumentPrivate => document_private,
+                        WhenNotDocumentPrivate => !document_private,
+                        WhenNotDocumentHidden => !document_hidden,
+                    };
+                    if run {
+                        debug!("running pass {}", p.pass.name);
+                        krate = (p.pass.run)(krate, &ctxt);
+                    }
                 }
 
                 ctxt.sess().abort_if_errors();
index 2a107e828f75ffafb9cc63bfc4b316a5c2e5eb38..ecc394a2bc992082dc558992658a7fa080023bf1 100644 (file)
@@ -9,8 +9,6 @@
 //! needs to read-after-write from a file, then it would be added to this
 //! abstraction.
 
-use errors;
-
 use std::fs;
 use std::io;
 use std::path::Path;
@@ -42,7 +40,7 @@ pub fn new() -> ErrorStorage {
     }
 
     /// Prints all stored errors. Returns the number of printed errors.
-    pub fn write_errors(&mut self, diag: &errors::Handler) -> usize {
+    pub fn write_errors(&mut self, diag: &rustc_errors::Handler) -> usize {
         let mut printed = 0;
         // In order to drop the sender part of the channel.
         self.sender = None;
index e0ed02c11c71a5aba491f6161ac0496e975b4f01..8b5a3a2ba61313cd209faf6862537882358d1bc2 100644 (file)
@@ -1,6 +1,5 @@
 use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
 use crate::rustc_span::edition::Edition;
-use errors;
 use rustc_feature::UnstableFeatures;
 use std::fs;
 use std::path::Path;
@@ -26,7 +25,7 @@ pub fn load(
         after_content: &[String],
         md_before_content: &[String],
         md_after_content: &[String],
-        diag: &errors::Handler,
+        diag: &rustc_errors::Handler,
         id_map: &mut IdMap,
         edition: Edition,
         playground: &Option<Playground>,
@@ -58,7 +57,7 @@ pub enum LoadStringError {
 
 pub fn load_string<P: AsRef<Path>>(
     file_path: P,
-    diag: &errors::Handler,
+    diag: &rustc_errors::Handler,
 ) -> Result<String, LoadStringError> {
     let file_path = file_path.as_ref();
     let contents = match fs::read(file_path) {
@@ -77,7 +76,7 @@ pub fn load_string<P: AsRef<Path>>(
     }
 }
 
-fn load_external_files(names: &[String], diag: &errors::Handler) -> Option<String> {
+fn load_external_files(names: &[String], diag: &rustc_errors::Handler) -> Option<String> {
     let mut out = String::new();
     for name in names {
         let s = match load_string(name, diag) {
index a01e2f793948e668967b94697d720d9473193c95..2d932eb7668c41041ee767be827f74d3c91834a0 100644 (file)
@@ -42,7 +42,6 @@
 use std::str;
 use std::sync::Arc;
 
-use errors;
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
 use rustc_data_structures::flock;
@@ -394,7 +393,7 @@ pub fn run(
     mut krate: clean::Crate,
     options: RenderOptions,
     renderinfo: RenderInfo,
-    diag: &errors::Handler,
+    diag: &rustc_errors::Handler,
     edition: Edition,
 ) -> Result<(), Error> {
     // need to save a copy of the options for rendering the index page
@@ -528,7 +527,7 @@ fn write_shared(
     krate: &clean::Crate,
     search_index: String,
     options: &RenderOptions,
-    diag: &errors::Handler,
+    diag: &rustc_errors::Handler,
 ) -> Result<(), Error> {
     // Write out the shared files. Note that these are shared among all rustdoc
     // docs placed in the output directory, so this needs to be a synchronized
index 62fe23029d92f6f5575ab174c26e55be8a7e134f..a91fdb7a10e0da5587c6f3f097e55017e8844680 100644 (file)
@@ -542,11 +542,11 @@ h4 > code, h3 > code, .invisible > code {
 }
 
 .content .stability::before {
-       content: '˪';
-       font-size: 30px;
+       content: '';
+       font-size: 25px;
        position: absolute;
-       top: -9px;
-       left: -13px;
+       top: -6px;
+       left: -19px;
 }
 
 .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
index f46bd6d6a10052530880791548e987c46ffe38c3..9a0e7bbabcba932d35ee51c3be0c90a16fff30a9 100644 (file)
@@ -105,6 +105,8 @@ pre {
 .content .highlighted.primitive { background-color: #00708a; }
 .content .highlighted.keyword { background-color: #884719; }
 
+.content .stability::before { color: #ccc; }
+
 .content span.enum, .content a.enum, .block a.current.enum { color: #82b089; }
 .content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; }
 .content span.type, .content a.type, .block a.current.type { color: #ff7f00; }
index ca67b1c1f8241993e474b0f0824447ba4d889ebf..ca8ea1c456a2c86745d8390b0f4031b015544be1 100644 (file)
@@ -105,6 +105,8 @@ pre {
 .content .highlighted.primitive { background-color: #9aecff; }
 .content .highlighted.keyword { background-color: #f99650; }
 
+.content .stability::before { color: #ccc; }
+
 .content span.enum, .content a.enum, .block a.current.enum { color: #508157; }
 .content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; }
 .content span.type, .content a.type, .block a.current.type { color: #ba5d00; }
index eeaac1d8c74318f2a7b1bd975e90e674e9baf7bd..1da00e3a47b8268db9e73c0a87bdc028cb719fa2 100644 (file)
@@ -10,9 +10,9 @@
 #![feature(nll)]
 #![feature(set_stdio)]
 #![feature(test)]
+#![feature(vec_remove_item)]
 #![feature(ptr_offset_from)]
 #![feature(crate_visibility_modifier)]
-#![feature(const_fn)]
 #![feature(drain_filter)]
 #![feature(never_type)]
 #![feature(unicode_internals)]
@@ -24,6 +24,7 @@
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_error_codes;
+extern crate rustc_errors;
 extern crate rustc_expand;
 extern crate rustc_feature;
 extern crate rustc_hir;
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_metadata;
+extern crate rustc_mir;
 extern crate rustc_parse;
 extern crate rustc_resolve;
+extern crate rustc_session;
 extern crate rustc_span as rustc_span;
 extern crate rustc_target;
 extern crate rustc_typeck;
@@ -41,7 +44,6 @@
 extern crate test as testing;
 #[macro_use]
 extern crate log;
-extern crate rustc_errors as errors;
 
 use std::default::Default;
 use std::env;
@@ -173,6 +175,9 @@ fn opts() -> Vec<RustcOptGroup> {
         stable("document-private-items", |o| {
             o.optflag("", "document-private-items", "document private items")
         }),
+        unstable("document-hidden-items", |o| {
+            o.optflag("", "document-hidden-items", "document items that have doc(hidden)")
+        }),
         stable("test", |o| o.optflag("", "test", "run code examples as tests")),
         stable("test-args", |o| {
             o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
@@ -514,6 +519,6 @@ fn rust_input<R, F>(options: config::Options, f: F) -> R
 
     match result {
         Ok(output) => output,
-        Err(_) => panic::resume_unwind(Box::new(errors::FatalErrorMarker)),
+        Err(_) => panic::resume_unwind(Box::new(rustc_errors::FatalErrorMarker)),
     }
 }
index 69aa248aa8e987f6cfc7486afc7334391d6b21a2..912a40722b8aff133c752ae4737a9a40b516c618 100644 (file)
@@ -2,7 +2,6 @@
 use std::io::prelude::*;
 use std::path::PathBuf;
 
-use errors;
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::DUMMY_SP;
@@ -39,7 +38,7 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
 pub fn render(
     input: PathBuf,
     options: RenderOptions,
-    diag: &errors::Handler,
+    diag: &rustc_errors::Handler,
     edition: Edition,
 ) -> i32 {
     let mut output = options.output;
@@ -128,7 +127,7 @@ pub fn render(
 }
 
 /// Runs any tests/code examples in the markdown file `input`.
-pub fn test(mut options: Options, diag: &errors::Handler) -> i32 {
+pub fn test(mut options: Options, diag: &rustc_errors::Handler) -> i32 {
     let input_str = match load_string(&options.input, diag) {
         Ok(s) => s,
         Err(LoadStringError::ReadFail) => return 1,
index 803bcc2cfdf862ac6b9f5d8a024c0dba3d93573d..7ed531c9206af0db4df96227d42aa7b150631e92 100644 (file)
@@ -12,7 +12,7 @@
 
 pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
     name: "calculate-doc-coverage",
-    pass: calculate_doc_coverage,
+    run: calculate_doc_coverage,
     description: "counts the number of items with and without documentation",
 };
 
index a4ca9010f2e9ff5f51c55d98d7d3043a14db18b4..0bab4423b3dfdb38449d97465df38b52620a4b07 100644 (file)
@@ -1,5 +1,5 @@
-use errors::{emitter::Emitter, Applicability, Diagnostic, Handler};
 use rustc_data_structures::sync::{Lock, Lrc};
+use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler};
 use rustc_parse::lexer::StringReader as Lexer;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::{FileName, InnerSpan};
@@ -14,7 +14,7 @@
 
 pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
     name: "check-code-block-syntax",
-    pass: check_code_block_syntax,
+    run: check_code_block_syntax,
     description: "validates syntax inside Rust code blocks",
 };
 
index c6b22883e97234856debaab95ee96d72d2ea5ec8..c2185592d14837846d223d070532e025692b010d 100644 (file)
@@ -8,7 +8,7 @@
 
 pub const COLLAPSE_DOCS: Pass = Pass {
     name: "collapse-docs",
-    pass: collapse_docs,
+    run: collapse_docs,
     description: "concatenates all document attributes into one document attribute",
 };
 
index 8a3966c320b8e017b756ddc8a94c42b80e29da06..50d5f70f4889a37eb45960d977d1d543ee924787 100644 (file)
@@ -1,6 +1,6 @@
-use errors::Applicability;
 use rustc::lint;
 use rustc::ty;
+use rustc_errors::Applicability;
 use rustc_expand::base::SyntaxExtensionKind;
 use rustc_feature::UnstableFeatures;
 use rustc_hir as hir;
@@ -28,7 +28,7 @@
 
 pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     name: "collect-intra-doc-links",
-    pass: collect_intra_doc_links,
+    run: collect_intra_doc_links,
     description: "reads a crate's documentation to resolve intra-doc-links",
 };
 
index c00e231ef70a2940589660e1fa3fd2d52878614d..da0e97f1075b00f8d50d3e185318f7cde33e6279 100644 (file)
@@ -9,7 +9,7 @@
 
 pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
     name: "collect-trait-impls",
-    pass: collect_trait_impls,
+    run: collect_trait_impls,
     description: "retrieves trait impls for items in the crate",
 };
 
index aebed9171d0e478a93c6453fcf8e1c2deee76bb2..355ea15223b0c1a2a35c5fcdf8e08c11e3fcb85e 100644 (file)
@@ -8,6 +8,7 @@
 use std::mem;
 use std::ops::Range;
 
+use self::Condition::*;
 use crate::clean::{self, GetDefId, Item};
 use crate::core::DocContext;
 use crate::fold::{DocFolder, StripItem};
 #[derive(Copy, Clone)]
 pub struct Pass {
     pub name: &'static str,
-    pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
+    pub run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
     pub description: &'static str,
 }
 
+/// In a list of passes, a pass that may or may not need to be run depending on options.
+#[derive(Copy, Clone)]
+pub struct ConditionalPass {
+    pub pass: Pass,
+    pub condition: Condition,
+}
+
+/// How to decide whether to run a conditional pass.
+#[derive(Copy, Clone)]
+pub enum Condition {
+    Always,
+    /// When `--document-private-items` is passed.
+    WhenDocumentPrivate,
+    /// When `--document-private-items` is not passed.
+    WhenNotDocumentPrivate,
+    /// When `--document-hidden-items` is not passed.
+    WhenNotDocumentHidden,
+}
+
 /// The full list of passes.
 pub const PASSES: &[Pass] = &[
     CHECK_PRIVATE_ITEMS_DOC_TESTS,
@@ -72,63 +92,58 @@ pub struct Pass {
 ];
 
 /// The list of passes run by default.
-pub const DEFAULT_PASSES: &[Pass] = &[
-    COLLECT_TRAIT_IMPLS,
-    COLLAPSE_DOCS,
-    UNINDENT_COMMENTS,
-    CHECK_PRIVATE_ITEMS_DOC_TESTS,
-    STRIP_HIDDEN,
-    STRIP_PRIVATE,
-    COLLECT_INTRA_DOC_LINKS,
-    CHECK_CODE_BLOCK_SYNTAX,
-    PROPAGATE_DOC_CFG,
+pub const DEFAULT_PASSES: &[ConditionalPass] = &[
+    ConditionalPass::always(COLLECT_TRAIT_IMPLS),
+    ConditionalPass::always(COLLAPSE_DOCS),
+    ConditionalPass::always(UNINDENT_COMMENTS),
+    ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS),
+    ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
+    ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
+    ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
+    ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
+    ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
+    ConditionalPass::always(PROPAGATE_DOC_CFG),
 ];
 
-/// The list of default passes run with `--document-private-items` is passed to rustdoc.
-pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[
-    COLLECT_TRAIT_IMPLS,
-    COLLAPSE_DOCS,
-    UNINDENT_COMMENTS,
-    CHECK_PRIVATE_ITEMS_DOC_TESTS,
-    STRIP_PRIV_IMPORTS,
-    COLLECT_INTRA_DOC_LINKS,
-    CHECK_CODE_BLOCK_SYNTAX,
-    PROPAGATE_DOC_CFG,
+/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
+pub const COVERAGE_PASSES: &[ConditionalPass] = &[
+    ConditionalPass::always(COLLECT_TRAIT_IMPLS),
+    ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
+    ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
+    ConditionalPass::always(CALCULATE_DOC_COVERAGE),
 ];
 
-/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
-pub const DEFAULT_COVERAGE_PASSES: &[Pass] =
-    &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE];
+impl ConditionalPass {
+    pub const fn always(pass: Pass) -> Self {
+        Self::new(pass, Always)
+    }
 
-/// The list of default passes run when `--doc-coverage --document-private-items` is passed to
-/// rustdoc.
-pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE];
+    pub const fn new(pass: Pass, condition: Condition) -> Self {
+        ConditionalPass { pass, condition }
+    }
+}
 
 /// A shorthand way to refer to which set of passes to use, based on the presence of
-/// `--no-defaults` or `--document-private-items`.
+/// `--no-defaults` and `--show-coverage`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum DefaultPassOption {
     Default,
-    Private,
     Coverage,
-    PrivateCoverage,
     None,
 }
 
 /// Returns the given default set of passes.
-pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] {
+pub fn defaults(default_set: DefaultPassOption) -> &'static [ConditionalPass] {
     match default_set {
         DefaultPassOption::Default => DEFAULT_PASSES,
-        DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES,
-        DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES,
-        DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES,
+        DefaultPassOption::Coverage => COVERAGE_PASSES,
         DefaultPassOption::None => &[],
     }
 }
 
 /// If the given name matches a known pass, returns its information.
-pub fn find_pass(pass_name: &str) -> Option<&'static Pass> {
-    PASSES.iter().find(|p| p.name == pass_name)
+pub fn find_pass(pass_name: &str) -> Option<Pass> {
+    PASSES.iter().find(|p| p.name == pass_name).copied()
 }
 
 struct Stripper<'a> {
index 23e272709705df40fe7c1613d61c0788b1aed66b..aec5a6bd4e221f8745ce722bff640007ff0cb671 100644 (file)
@@ -5,7 +5,7 @@
 
 pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
     name: "check-private-items-doc-tests",
-    pass: check_private_items_doc_tests,
+    run: check_private_items_doc_tests,
     description: "check private items doc tests",
 };
 
index a296e73e3b5fd6f923ae7036261624bd97c5146f..64b0c45ba65d3a67a3ee27dc0837aca3268cfe8d 100644 (file)
@@ -8,7 +8,7 @@
 
 pub const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
-    pass: propagate_doc_cfg,
+    run: propagate_doc_cfg,
     description: "propagates `#[doc(cfg(...))]` to child items",
 };
 
index 08a88c00cb0ddb927104f762c563e107cbdc1a28..f82e72b488bb764b753750a3273a0f3b4570871c 100644 (file)
@@ -10,7 +10,7 @@
 
 pub const STRIP_HIDDEN: Pass = Pass {
     name: "strip-hidden",
-    pass: strip_hidden,
+    run: strip_hidden,
     description: "strips all doc(hidden) items from the output",
 };
 
index af34842ad0f89d5d1831033c84ebcccf69ef2bb8..35b26fb8ab0be6633d33c882fa419fa518fe43b2 100644 (file)
@@ -5,7 +5,7 @@
 
 pub const STRIP_PRIV_IMPORTS: Pass = Pass {
     name: "strip-priv-imports",
-    pass: strip_priv_imports,
+    run: strip_priv_imports,
     description: "strips all private import statements (`use`, `extern crate`) from a crate",
 };
 
index f4ec9cc364904136db2f58d62502726640886c10..f244956e50336e0a24798bbff1534de76779b0d1 100644 (file)
@@ -7,7 +7,7 @@
 
 pub const STRIP_PRIVATE: Pass = Pass {
     name: "strip-private",
-    pass: strip_private,
+    run: strip_private,
     description: "strips all private items from a crate which cannot be seen externally, \
         implies strip-priv-imports",
 };
index 3212af055efc559adda32e4a78e84bb2860822d6..d4e09ce47a3c1aa173e5c83e7c83664eb6d9f015 100644 (file)
@@ -12,7 +12,7 @@
 
 pub const UNINDENT_COMMENTS: Pass = Pass {
     name: "unindent-comments",
-    pass: unindent_comments,
+    run: unindent_comments,
     description: "removes excess indentation on comments in order for markdown to like it",
 };
 
index d94e940a7f72cfee08d8984d15d7a1a6f81f3739..b5731ff0fec21cafc04f668f810958eeffe1c522 100644 (file)
@@ -1,10 +1,10 @@
-use rustc::hir::intravisit;
 use rustc::hir::map::Map;
 use rustc::session::{self, config, DiagnosticOutput};
 use rustc::util::common::ErrorReported;
 use rustc_data_structures::sync::Lrc;
 use rustc_feature::UnstableFeatures;
 use rustc_hir as hir;
+use rustc_hir::intravisit;
 use rustc_interface::interface;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMap;
@@ -300,7 +300,6 @@ fn drop(&mut self) {
             eprint!("{}", self.0);
         }
     }
-
     let out = str::from_utf8(&output.stderr).unwrap();
     let _bomb = Bomb(&out);
     match (output.status.success(), compile_fail) {
@@ -310,7 +309,7 @@ fn drop(&mut self) {
         (true, false) => {}
         (false, true) => {
             if !error_codes.is_empty() {
-                error_codes.retain(|err| !out.contains(err));
+                error_codes.retain(|err| !out.contains(&format!("error[{}]: ", err)));
 
                 if !error_codes.is_empty() {
                     return Err(TestFailure::MissingErrorCodes(error_codes));
@@ -389,8 +388,8 @@ pub fn make_test(
     // crate already is included.
     let result = rustc_driver::catch_fatal_errors(|| {
         with_globals(edition, || {
-            use errors::emitter::EmitterWriter;
-            use errors::Handler;
+            use rustc_errors::emitter::EmitterWriter;
+            use rustc_errors::Handler;
             use rustc_parse::maybe_new_parser_from_source_str;
             use rustc_span::source_map::FilePathMapping;
             use syntax::sess::ParseSess;
@@ -899,7 +898,9 @@ fn visit_testable<F: FnOnce(&mut Self)>(
 }
 
 impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
-    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'hir> {
+    type Map = Map<'hir>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
         intravisit::NestedVisitorMap::All(&self.map)
     }
 
index b45531d7252a163eab1a9c3e439b9e944c9148e2..af1c50acb0a357bc7939761626ecf057f7bb8643 100644 (file)
@@ -3,7 +3,7 @@
 use std::hash::{Hash, Hasher};
 use std::path::Path;
 
-use errors::Handler;
+use rustc_errors::Handler;
 
 #[cfg(test)]
 mod tests;
index a22e162bbff4804b1332c867483c8748b65d58d0..c9ff93eac0295f3f2db15754a22ccf2631d14f43 100644 (file)
@@ -34,16 +34,6 @@ features = [ "rustc-dep-of-std" ] # enable build support for integrating into li
 [dev-dependencies]
 rand = "0.7"
 
-[target.x86_64-apple-darwin.dependencies]
-rustc_asan = { path = "../librustc_asan" }
-rustc_tsan = { path = "../librustc_tsan" }
-
-[target.x86_64-unknown-linux-gnu.dependencies]
-rustc_asan = { path = "../librustc_asan" }
-rustc_lsan = { path = "../librustc_lsan" }
-rustc_msan = { path = "../librustc_msan" }
-rustc_tsan = { path = "../librustc_tsan" }
-
 [target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
 dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
 
index 566e5146cf8576f38874c77bd187e4adcbac35f5..b48700fb94420b0a044d701f18e3b6edd1de8b99 100644 (file)
@@ -631,6 +631,38 @@ pub fn get_or_insert(&mut self, value: T) -> &T {
         self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0
     }
 
+    /// Inserts an owned copy of the given `value` into the set if it is not
+    /// present, then returns a reference to the value in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set: HashSet<String> = ["cat", "dog", "horse"]
+    ///     .iter().map(|&pet| pet.to_owned()).collect();
+    ///
+    /// assert_eq!(set.len(), 3);
+    /// for &pet in &["cat", "dog", "fish"] {
+    ///     let value = set.get_or_insert_owned(pet);
+    ///     assert_eq!(value, pet);
+    /// }
+    /// assert_eq!(set.len(), 4); // a new "fish" was inserted
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get_or_insert_owned<Q: ?Sized>(&mut self, value: &Q) -> &T
+    where
+        T: Borrow<Q>,
+        Q: Hash + Eq + ToOwned<Owned = T>,
+    {
+        // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
+        // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
+        self.map.raw_entry_mut().from_key(value).or_insert_with(|| (value.to_owned(), ())).0
+    }
+
     /// Inserts a value computed from `f` into the set if the given `value` is
     /// not present, then returns a reference to the value in the set.
     ///
index 1407fe27715538dbaa1d30a612a51afd686dc2c5..b480581e21ba90c093664699ae88974dd8dd9bef 100644 (file)
@@ -250,6 +250,7 @@ impl From<String> for Box<dyn Error + Send + Sync> {
     /// assert!(
     ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
     /// ```
+    #[inline]
     fn from(err: String) -> Box<dyn Error + Send + Sync> {
         struct StringError(String);
 
@@ -317,6 +318,7 @@ impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
     /// assert!(
     ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
     /// ```
+    #[inline]
     fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
         From::from(String::from(err))
     }
index d2ee65f0a74eb47cbace4479d4391888c5da175b..700e015b08edc0e282cdb288f0bc69a2cfec618c 100644 (file)
@@ -1187,11 +1187,6 @@ pub fn to_bytes_with_nul(&self) -> &[u8] {
     /// function will return the corresponding [`&str`] slice. Otherwise,
     /// it will return an error with details of where UTF-8 validation failed.
     ///
-    /// > **Note**: This method is currently implemented to check for validity
-    /// > after a constant-time cast, but it is planned to alter its definition
-    /// > in the future to perform the length calculation in addition to the
-    /// > UTF-8 check whenever this method is called.
-    ///
     /// [`&str`]: ../primitive.str.html
     ///
     /// # Examples
@@ -1220,11 +1215,6 @@ pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
     /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
     /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
     ///
-    /// > **Note**: This method is currently implemented to check for validity
-    /// > after a constant-time cast, but it is planned to alter its definition
-    /// > in the future to perform the length calculation in addition to the
-    /// > UTF-8 check whenever this method is called.
-    ///
     /// [`Cow`]: ../borrow/enum.Cow.html
     /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
     /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
index 4c308327b83b7feeaa93d7c196c5ad567aec299b..77da97219b14762d56684d724b2e5349ff876814 100644 (file)
@@ -615,6 +615,7 @@ pub fn to_os_string(&self) -> OsString {
     /// assert!(!os_str.is_empty());
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+    #[inline]
     pub fn is_empty(&self) -> bool {
         self.inner.inner.is_empty()
     }
@@ -965,6 +966,7 @@ fn as_ref(&self) -> &OsStr {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for OsString {
+    #[inline]
     fn as_ref(&self) -> &OsStr {
         self
     }
index a9d88370c612fa1afa826b9510e0e536162b125f..a59d7f0263bb0a3b7955d9cb407a3b7b7c34be45 100644 (file)
@@ -227,10 +227,7 @@ pub fn set_port(&mut self, new_port: u16) {
     /// ```
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
     pub fn is_ipv4(&self) -> bool {
-        match *self {
-            SocketAddr::V4(_) => true,
-            SocketAddr::V6(_) => false,
-        }
+        matches!(*self, SocketAddr::V4(_))
     }
 
     /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
@@ -252,10 +249,7 @@ pub fn is_ipv4(&self) -> bool {
     /// ```
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
     pub fn is_ipv6(&self) -> bool {
-        match *self {
-            SocketAddr::V4(_) => false,
-            SocketAddr::V6(_) => true,
-        }
+        matches!(*self, SocketAddr::V6(_))
     }
 }
 
index 15d2361acd916e83f923a6c6c954fd73f7968aef..6410a4f2b65b3762fd15044a8de4a862990fb69c 100644 (file)
@@ -281,10 +281,7 @@ pub fn is_documentation(&self) -> bool {
     /// ```
     #[stable(feature = "ipaddr_checker", since = "1.16.0")]
     pub fn is_ipv4(&self) -> bool {
-        match self {
-            IpAddr::V4(_) => true,
-            IpAddr::V6(_) => false,
-        }
+        matches!(self, IpAddr::V4(_))
     }
 
     /// Returns [`true`] if this address is an [IPv6 address], and [`false`] otherwise.
@@ -303,10 +300,7 @@ pub fn is_ipv4(&self) -> bool {
     /// ```
     #[stable(feature = "ipaddr_checker", since = "1.16.0")]
     pub fn is_ipv6(&self) -> bool {
-        match self {
-            IpAddr::V4(_) => false,
-            IpAddr::V6(_) => true,
-        }
+        matches!(self, IpAddr::V6(_))
     }
 }
 
index f308d511cf85041fe343ce995c7c2e4fb5887b79..a703cb748e06b4e111d7f649e9444809c7dec470 100644 (file)
@@ -224,18 +224,12 @@ fn os_str_len(s: &OsStr) -> usize {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_verbatim(&self) -> bool {
         use self::Prefix::*;
-        match *self {
-            Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true,
-            _ => false,
-        }
+        matches!(*self, Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..))
     }
 
     #[inline]
     fn is_drive(&self) -> bool {
-        match *self {
-            Prefix::Disk(_) => true,
-            _ => false,
-        }
+        matches!(*self, Prefix::Disk(_))
     }
 
     #[inline]
@@ -1481,6 +1475,7 @@ impl From<OsString> for PathBuf {
     /// Converts a `OsString` into a `PathBuf`
     ///
     /// This conversion does not allocate or copy memory.
+    #[inline]
     fn from(s: OsString) -> PathBuf {
         PathBuf { inner: s }
     }
@@ -1541,7 +1536,7 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ops::Deref for PathBuf {
     type Target = Path;
-
+    #[inline]
     fn deref(&self) -> &Path {
         Path::new(&self.inner)
     }
@@ -2661,6 +2656,7 @@ fn as_ref(&self) -> &Path {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for str {
+    #[inline]
     fn as_ref(&self) -> &Path {
         Path::new(self)
     }
@@ -2675,6 +2671,7 @@ fn as_ref(&self) -> &Path {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for PathBuf {
+    #[inline]
     fn as_ref(&self) -> &Path {
         self
     }
index eddbdff257a992a21b09eb1a5acdd707340203a7..01314370ce3994842a625c213a233ef3cb3b5414 100644 (file)
@@ -199,10 +199,7 @@ fn test_barrier() {
 
         // At this point, all spawned threads should be blocked,
         // so we shouldn't get anything from the port
-        assert!(match rx.try_recv() {
-            Err(TryRecvError::Empty) => true,
-            _ => false,
-        });
+        assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty)));
 
         let mut leader_found = barrier.wait().is_leader();
 
index bbe77e7d0fb5c41f201782a8f72f760361df66c7..5b41525e06aaaccaa565945e47bb733e0b83c783 100644 (file)
@@ -118,12 +118,7 @@ pub fn send(&self, t: T) -> Result<(), T> {
     // Just tests whether this channel has been sent on or not, this is only
     // safe to use from the sender.
     pub fn sent(&self) -> bool {
-        unsafe {
-            match *self.upgrade.get() {
-                NothingSent => false,
-                _ => true,
-            }
-        }
+        unsafe { !matches!(*self.upgrade.get(), NothingSent) }
     }
 
     pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
index 5999fdd4f8d58308f763a9aa038f0f7f25439afa..78eabf8f81e984e149bd551efed65503381eed02 100644 (file)
@@ -6,7 +6,6 @@
 use crate::marker::PhantomData;
 use crate::memchr;
 use crate::path::{self, PathBuf};
-use crate::ptr;
 use crate::str;
 use crate::sync::Mutex;
 use crate::sys::hermit::abi;
@@ -77,13 +76,17 @@ pub fn init_environment(env: *const *const i8) {
     unsafe {
         ENV = Some(Mutex::new(HashMap::new()));
 
+        if env.is_null() {
+            return;
+        }
+
         let mut guard = ENV.as_ref().unwrap().lock().unwrap();
         let mut environ = env;
-        while environ != ptr::null() && *environ != ptr::null() {
+        while !(*environ).is_null() {
             if let Some((key, value)) = parse(CStr::from_ptr(*environ).to_bytes()) {
                 guard.insert(key, value);
             }
-            environ = environ.offset(1);
+            environ = environ.add(1);
         }
     }
 
index ba967c7676c3fd6118a9999d18735c3d5ad928ac..c6f8adb21623a0f26581ed14e20d7988d3b32b9e 100644 (file)
 static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
 
 unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
-    if KEYS == ptr::null_mut() {
+    if KEYS.is_null() {
         KEYS = Box::into_raw(Box::new(BTreeMap::new()));
     }
     &mut *KEYS
 }
 
 unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
-    if LOCALS == ptr::null_mut() {
+    if LOCALS.is_null() {
         LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
     }
     &mut *LOCALS
index 81a766e367d6eb270eec84ff38b9b382eed04fe6..2b0485c4f03635041b91de0f320d5681496a046a 100644 (file)
@@ -70,7 +70,7 @@ fn drop(&mut self) {
             any_non_null_dtor = false;
             for (value, dtor) in TLS_KEY_IN_USE.iter().filter_map(&value_with_destructor) {
                 let value = value.replace(ptr::null_mut());
-                if value != ptr::null_mut() {
+                if !value.is_null() {
                     any_non_null_dtor = true;
                     unsafe { dtor(value) }
                 }
index 4fa9095c89983afd02ba32a54d0c9f3e03a6a953..ab2a871b92df45f846d73d74432ddada4729a582 100644 (file)
 
 pub struct File(FileDesc);
 
-// FIXME: This should be available on Linux with all `target_arch` and `target_env`.
-// https://github.com/rust-lang/libc/issues/1545
+// FIXME: This should be available on Linux with all `target_env`.
+// But currently only glibc exposes `statx` fn and structs.
+// We don't want to import unverified raw C structs here directly.
+// https://github.com/rust-lang/rust/pull/67774
 macro_rules! cfg_has_statx {
     ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
         cfg_if::cfg_if! {
-            if #[cfg(all(target_os = "linux", target_env = "gnu", any(
-                target_arch = "x86",
-                target_arch = "arm",
-                // target_arch = "mips",
-                target_arch = "powerpc",
-                target_arch = "x86_64",
-                // target_arch = "aarch64",
-                target_arch = "powerpc64",
-                // target_arch = "mips64",
-                // target_arch = "s390x",
-                target_arch = "sparc64",
-                target_arch = "riscv64",
-            )))] {
+            if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
                 $($then_tt)*
             } else {
                 $($else_tt)*
@@ -76,19 +66,7 @@ macro_rules! cfg_has_statx {
         }
     };
     ($($block_inner:tt)*) => {
-        #[cfg(all(target_os = "linux", target_env = "gnu", any(
-            target_arch = "x86",
-            target_arch = "arm",
-            // target_arch = "mips",
-            target_arch = "powerpc",
-            target_arch = "x86_64",
-            // target_arch = "aarch64",
-            target_arch = "powerpc64",
-            // target_arch = "mips64",
-            // target_arch = "s390x",
-            target_arch = "sparc64",
-            target_arch = "riscv64",
-        )))]
+        #[cfg(all(target_os = "linux", target_env = "gnu"))]
         {
             $($block_inner)*
         }
index b277b3d5899b80663f6e023bab1b8927ef20abc0..91f7d1524ccef79f9c0d451ef5ccfab86e0a70a0 100644 (file)
@@ -480,11 +480,13 @@ pub fn env() -> Env {
         let _guard = env_lock();
         let mut environ = *environ();
         let mut result = Vec::new();
-        while environ != ptr::null() && *environ != ptr::null() {
-            if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
-                result.push(key_value);
+        if !environ.is_null() {
+            while !(*environ).is_null() {
+                if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+                    result.push(key_value);
+                }
+                environ = environ.add(1);
             }
-            environ = environ.offset(1);
         }
         return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData };
     }
index f102e4d6adf59250581e5b864dc95107cddb5414..12bbfa1d4e1a6e8151f71dd4fe57e0cbe119a0bf 100644 (file)
 
 #[cfg(not(test))]
 pub fn init() {
-    // By default, some platforms will send a *signal* when an EPIPE error
-    // would otherwise be delivered. This runtime doesn't install a SIGPIPE
-    // handler, causing it to kill the program, which isn't exactly what we
-    // want!
-    //
-    // Hence, we set SIGPIPE to ignore when the program starts up in order
-    // to prevent this problem.
+    // ignore SIGPIPE
     unsafe {
-        reset_sigpipe();
+        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
     }
-
-    unsafe fn reset_sigpipe() {}
 }
 
 pub use libc::signal;
index d42191544994487e42ddbe5058d9ca2264ec7fe1..1fadf71613561fb6b45498f8e22b63dd48272092 100644 (file)
@@ -7,7 +7,6 @@
 use crate::mem;
 use crate::memchr;
 use crate::path::{self, Path, PathBuf};
-use crate::ptr;
 use crate::slice;
 use crate::str;
 use crate::sys::cvt;
@@ -226,15 +225,15 @@ pub fn env() -> Env {
     unsafe {
         let _guard = env_lock();
         let mut environ = *environ();
-        if environ == ptr::null() {
+        if environ.is_null() {
             panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error());
         }
         let mut result = Vec::new();
-        while *environ != ptr::null() {
+        while !(*environ).is_null() {
             if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
                 result.push(key_value);
             }
-            environ = environ.offset(1);
+            environ = environ.add(1);
         }
         return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData };
     }
diff --git a/src/libstd/sys/vxworks/weak.rs b/src/libstd/sys/vxworks/weak.rs
deleted file mode 100644 (file)
index 4c6fdde..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-//! Support for "weak linkage" to symbols on Unix
-//!
-//! Some I/O operations we do in libstd require newer versions of OSes but we
-//! need to maintain binary compatibility with older releases for now. In order
-//! to use the new functionality when available we use this module for
-//! detection.
-//!
-//! One option to use here is weak linkage, but that is unfortunately only
-//! really workable on Linux. Hence, use dlsym to get the symbol value at
-//! runtime. This is also done for compatibility with older versions of glibc,
-//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
-//! we've been dynamically linked to the library the symbol comes from, but that
-//! is currently always the case for things like libpthread/libc.
-//!
-//! A long time ago this used weak linkage for the __pthread_get_minstack
-//! symbol, but that caused Debian to detect an unnecessarily strict versioned
-//! dependency on libc6 (#23628).
-
-use crate::ffi::CStr;
-use crate::marker;
-use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering};
-
-pub struct Weak<F> {
-    name: &'static str,
-    addr: AtomicUsize,
-    _marker: marker::PhantomData<F>,
-}
-
-impl<F> Weak<F> {
-    pub const fn new(name: &'static str) -> Weak<F> {
-        Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
-    }
-
-    pub fn get(&self) -> Option<F> {
-        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
-        unsafe {
-            if self.addr.load(Ordering::SeqCst) == 1 {
-                self.addr.store(fetch(self.name), Ordering::SeqCst);
-            }
-            match self.addr.load(Ordering::SeqCst) {
-                0 => None,
-                addr => Some(mem::transmute_copy::<usize, F>(&addr)),
-            }
-        }
-    }
-}
-
-unsafe fn fetch(name: &str) -> usize {
-    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
-        Ok(cstr) => cstr,
-        Err(..) => return 0,
-    };
-    assert!(false, "FIXME: fetch");
-    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
-}
index 3baec6bf09924c25967fbf87c2455169a382ce58..8052c0aa8a8d9bc59756c3920bc3559720779b5d 100644 (file)
@@ -6,7 +6,6 @@
 use crate::marker::PhantomData;
 use crate::os::wasi::prelude::*;
 use crate::path::{self, PathBuf};
-use crate::ptr;
 use crate::str;
 use crate::sys::memchr;
 use crate::sys::{unsupported, Void};
@@ -107,11 +106,13 @@ pub fn env() -> Env {
         let _guard = env_lock();
         let mut environ = libc::environ;
         let mut result = Vec::new();
-        while environ != ptr::null_mut() && *environ != ptr::null_mut() {
-            if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
-                result.push(key_value);
+        if !environ.is_null() {
+            while !(*environ).is_null() {
+                if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+                    result.push(key_value);
+                }
+                environ = environ.add(1);
             }
-            environ = environ.offset(1);
         }
         return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData };
     }
index c5354671c9843db6d418e8513d95642145269001..cc4ae4059069385ea4dd0e0e93801d75abc24a48 100644 (file)
@@ -43,7 +43,7 @@ pub fn error_string(mut errnum: i32) -> String {
             ];
             module = c::GetModuleHandleW(NTDLL_DLL.as_ptr());
 
-            if module != ptr::null_mut() {
+            if !module.is_null() {
                 errnum ^= c::FACILITY_NT_BIT as i32;
                 flags = c::FORMAT_MESSAGE_FROM_HMODULE;
             }
index eb8a881ec8881f522e75e852f785b0b2f982b291..e965ea79aa03946a54b1a45672e763187e76c224 100644 (file)
@@ -104,6 +104,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
         self.inner.shrink_to(min_capacity)
     }
 
+    #[inline]
     pub fn as_slice(&self) -> &Slice {
         unsafe { mem::transmute(&*self.inner) }
     }
index 0dce8f810eb137d520ec6b0876230774fecc9e03..0b6e728dceb1d49719d9130d575f2ba8b3d0a273 100644 (file)
@@ -67,7 +67,7 @@
 /// |:---------:|:--------------------------------------------------------------------:|
 /// | Cloud ABI | [clock_time_get (Monotonic Clock)]                                   |
 /// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
-/// | UNIX      | [clock_time_get (Monotonic Clock)]                                   |
+/// | UNIX      | [clock_gettime (Monotonic Clock)]                                    |
 /// | Darwin    | [mach_absolute_time]                                                 |
 /// | VXWorks   | [clock_gettime (Monotonic Clock)]                                    |
 /// | WASI      | [__wasi_clock_time_get (Monotonic Clock)]                            |
index 2098656db9822b0c4f51e7a06996bed8025ad55f..7d9f715e9feb8c809ead5da130cfa946e95081b4 100644 (file)
@@ -10,13 +10,11 @@ path = "lib.rs"
 doctest = false
 
 [dependencies]
-bitflags = "1.2.1"
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 log = "0.4"
 scoped-tls = "1.0"
-lazy_static = "1.0.0"
+rustc_errors = { path = "../librustc_errors" }
 rustc_span = { path = "../librustc_span" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_index = { path = "../librustc_index" }
index 47070261385a2d3aecd12e0313a4be10583d0281..33acba8eba0109fe09f89f1e64639bd33b4de103 100644 (file)
@@ -649,7 +649,7 @@ pub enum PatKind {
     Lit(P<Expr>),
 
     /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`).
-    Range(P<Expr>, P<Expr>, Spanned<RangeEnd>),
+    Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),
 
     /// A slice pattern `[a, b, c]`.
     Slice(Vec<P<Pat>>),
@@ -1033,7 +1033,7 @@ pub fn returns(&self) -> bool {
     pub fn to_bound(&self) -> Option<GenericBound> {
         match &self.kind {
             ExprKind::Path(None, path) => Some(GenericBound::Trait(
-                PolyTraitRef::new(Vec::new(), path.clone(), self.span),
+                PolyTraitRef::new(Vec::new(), path.clone(), None, self.span),
                 TraitBoundModifier::None,
             )),
             _ => None,
@@ -2376,6 +2376,15 @@ pub enum AttrKind {
 pub struct TraitRef {
     pub path: Path,
     pub ref_id: NodeId,
+
+    /// The `const` modifier, if any, that appears before this trait.
+    ///
+    /// |                | `constness`                 |
+    /// |----------------|-----------------------------|
+    /// | `Trait`        | `None`                      |
+    /// | `const Trait`  | `Some(Constness::Const)`    |
+    /// | `?const Trait` | `Some(Constness::NotConst)` |
+    pub constness: Option<Constness>,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -2390,10 +2399,15 @@ pub struct PolyTraitRef {
 }
 
 impl PolyTraitRef {
-    pub fn new(generic_params: Vec<GenericParam>, path: Path, span: Span) -> Self {
+    pub fn new(
+        generic_params: Vec<GenericParam>,
+        path: Path,
+        constness: Option<Constness>,
+        span: Span,
+    ) -> Self {
         PolyTraitRef {
             bound_generic_params: generic_params,
-            trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID },
+            trait_ref: TraitRef { path, constness, ref_id: DUMMY_NODE_ID },
             span,
         }
     }
index 04c28dd5c5bcbaaee959646c69bb0abecbab2cdd..70f4f47621a348ce36acbef9d39d83b42db36d6c 100644 (file)
@@ -2,11 +2,10 @@
 
 use super::{mark_used, MetaItemKind};
 use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
-use crate::feature_gate::feature_err;
 use crate::print::pprust;
-use crate::sess::ParseSess;
+use crate::sess::{feature_err, ParseSess};
 
-use errors::{Applicability, Handler};
+use rustc_errors::{struct_span_err, Applicability, Handler};
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
 use rustc_macros::HashStable_Generic;
 use rustc_span::hygiene::Transparency;
@@ -31,17 +30,21 @@ enum AttrError {
 fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
     let diag = &sess.span_diagnostic;
     match error {
-        AttrError::MultipleItem(item) => span_err!(diag, span, E0538, "multiple '{}' items", item),
+        AttrError::MultipleItem(item) => {
+            struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit();
+        }
         AttrError::UnknownMetaItem(item, expected) => {
             let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
             struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item)
                 .span_label(span, format!("expected one of {}", expected.join(", ")))
                 .emit();
         }
-        AttrError::MissingSince => span_err!(diag, span, E0542, "missing 'since'"),
-        AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"),
+        AttrError::MissingSince => struct_span_err!(diag, span, E0542, "missing 'since'").emit(),
+        AttrError::MissingFeature => {
+            struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
+        }
         AttrError::MultipleStabilityLevels => {
-            span_err!(diag, span, E0544, "multiple stability levels")
+            struct_span_err!(diag, span, E0544, "multiple stability levels").emit();
         }
         AttrError::UnsupportedLiteral(msg, is_bytestr) => {
             let mut err = struct_span_err!(diag, span, E0565, "{}", msg);
@@ -283,7 +286,7 @@ fn find_stability_generic<'a, I>(
                     *item = Some(v);
                     true
                 } else {
-                    span_err!(diagnostic, meta.span, E0539, "incorrect meta item");
+                    struct_span_err!(diagnostic, meta.span, E0539, "incorrect meta item").emit();
                     false
                 }
             };
@@ -331,12 +334,13 @@ macro_rules! get_meta {
             match meta_name {
                 sym::rustc_deprecated => {
                     if rustc_depr.is_some() {
-                        span_err!(
+                        struct_span_err!(
                             diagnostic,
                             item_sp,
                             E0540,
                             "multiple rustc_deprecated attributes"
-                        );
+                        )
+                        .emit();
                         continue 'outer;
                     }
 
@@ -351,7 +355,8 @@ macro_rules! get_meta {
                             continue;
                         }
                         _ => {
-                            span_err!(diagnostic, attr.span, E0543, "missing 'reason'");
+                            struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'")
+                                .emit();
                             continue;
                         }
                     }
@@ -426,12 +431,13 @@ macro_rules! get_meta {
                                         // Disallowing this requires updates to some submodules
                                         NonZeroU32::new(num)
                                     } else {
-                                        span_err!(
+                                        struct_span_err!(
                                             diagnostic,
                                             attr.span,
                                             E0545,
                                             "incorrect 'issue'"
-                                        );
+                                        )
+                                        .emit();
                                         continue;
                                     }
                                 }
@@ -453,7 +459,8 @@ macro_rules! get_meta {
                             continue;
                         }
                         _ => {
-                            span_err!(diagnostic, attr.span, E0547, "missing 'issue'");
+                            struct_span_err!(diagnostic, attr.span, E0547, "missing 'issue'")
+                                .emit();
                             continue;
                         }
                     }
@@ -539,13 +546,14 @@ macro_rules! get_meta {
         if let Some(ref mut stab) = stab {
             stab.rustc_depr = Some(rustc_depr);
         } else {
-            span_err!(
+            struct_span_err!(
                 diagnostic,
                 item_sp,
                 E0549,
                 "rustc_deprecated attribute must be paired with \
                        either stable or unstable attribute"
-            );
+            )
+            .emit();
         }
     }
 
@@ -555,14 +563,15 @@ macro_rules! get_meta {
             stab.promotable = promotable;
             stab.allow_const_fn_ptr = allow_const_fn_ptr;
         } else {
-            span_err!(
+            struct_span_err!(
                 diagnostic,
                 item_sp,
                 E0717,
                 "rustc_promotable and rustc_allow_const_fn_ptr attributes \
                       must be paired with either a rustc_const_unstable or a rustc_const_stable \
                       attribute"
-            );
+            )
+            .emit();
         }
     }
 
@@ -649,20 +658,27 @@ pub fn eval_condition(
                 }
                 sym::not => {
                     if mis.len() != 1 {
-                        span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
+                        struct_span_err!(
+                            sess.span_diagnostic,
+                            cfg.span,
+                            E0536,
+                            "expected 1 cfg-pattern"
+                        )
+                        .emit();
                         return false;
                     }
 
                     !eval_condition(mis[0].meta_item().unwrap(), sess, eval)
                 }
                 _ => {
-                    span_err!(
+                    struct_span_err!(
                         sess.span_diagnostic,
                         cfg.span,
                         E0537,
                         "invalid predicate `{}`",
                         pprust::path_to_string(&cfg.path)
-                    );
+                    )
+                    .emit();
                     false
                 }
             }
@@ -703,7 +719,7 @@ fn find_deprecation_generic<'a, I>(
         }
 
         if depr.is_some() {
-            span_err!(diagnostic, item_sp, E0550, "multiple deprecated attributes");
+            struct_span_err!(diagnostic, item_sp, E0550, "multiple deprecated attributes").emit();
             break;
         }
 
@@ -741,7 +757,8 @@ fn find_deprecation_generic<'a, I>(
                                 ),
                             );
                         } else {
-                            span_err!(diagnostic, meta.span, E0551, "incorrect meta item");
+                            struct_span_err!(diagnostic, meta.span, E0551, "incorrect meta item")
+                                .emit();
                         }
 
                         false
@@ -900,13 +917,14 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                         };
                     }
                     if let Some(literal_error) = literal_error {
-                        span_err!(
+                        struct_span_err!(
                             diagnostic,
                             item.span(),
                             E0589,
                             "invalid `repr(align)` attribute: {}",
                             literal_error
-                        );
+                        )
+                        .emit();
                     }
                 } else {
                     if let Some(meta_item) = item.meta_item() {
@@ -945,7 +963,13 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                 }
                 if !recognised {
                     // Not a word we recognize
-                    span_err!(diagnostic, item.span(), E0552, "unrecognized representation hint");
+                    struct_span_err!(
+                        diagnostic,
+                        item.span(),
+                        E0552,
+                        "unrecognized representation hint"
+                    )
+                    .emit();
                 }
             }
         }
index 8449b61f7b0bbb61afb1e1bf34f8cd68cea85e66..ec05dab451af85c9da71f64c2ee87e1721fe9c71 100644 (file)
@@ -384,7 +384,7 @@ pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
 
 pub fn allow_internal_unstable<'a>(
     attrs: &[Attribute],
-    span_diagnostic: &'a errors::Handler,
+    span_diagnostic: &'a rustc_errors::Handler,
 ) -> Option<impl Iterator<Item = Symbol> + 'a> {
     find_by_name(attrs, sym::allow_internal_unstable).and_then(|attr| {
         attr.meta_item_list()
diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs
deleted file mode 100644 (file)
index 4ed1741..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-#[macro_export]
-macro_rules! diagnostic_used {
-    ($code:ident) => {
-        let _ = $code;
-    };
-}
-
-#[macro_export]
-macro_rules! span_fatal {
-    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        $session.span_fatal_with_code(
-            $span,
-            &format!($($message)*),
-            $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-        )
-    })
-}
-
-#[macro_export]
-macro_rules! span_err {
-    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        $session.span_err_with_code(
-            $span,
-            &format!($($message)*),
-            $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-        )
-    })
-}
-
-#[macro_export]
-macro_rules! span_warn {
-    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        $session.span_warn_with_code(
-            $span,
-            &format!($($message)*),
-            $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-        )
-    })
-}
-
-#[macro_export]
-macro_rules! struct_err {
-    ($session:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        $session.struct_err_with_code(
-            &format!($($message)*),
-            $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-        )
-    })
-}
-
-#[macro_export]
-macro_rules! span_err_or_warn {
-    ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        if $is_warning {
-            $session.span_warn_with_code(
-                $span,
-                &format!($($message)*),
-                $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-            )
-        } else {
-            $session.span_err_with_code(
-                $span,
-                &format!($($message)*),
-                $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-            )
-        }
-    })
-}
-
-#[macro_export]
-macro_rules! struct_span_fatal {
-    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        $session.struct_span_fatal_with_code(
-            $span,
-            &format!($($message)*),
-            $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-        )
-    })
-}
-
-#[macro_export]
-macro_rules! struct_span_err {
-    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        $session.struct_span_err_with_code(
-            $span,
-            &format!($($message)*),
-            $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-        )
-    })
-}
-
-#[macro_export]
-macro_rules! stringify_error_code {
-    ($code:ident) => {{
-        $crate::diagnostic_used!($code);
-        $crate::errors::DiagnosticId::Error(stringify!($code).to_owned())
-    }};
-}
-
-#[macro_export]
-macro_rules! type_error_struct {
-    ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
-        if $typ.references_error() {
-            $session.diagnostic().struct_dummy()
-        } else {
-            struct_span_err!($session, $span, $code, $($message)*)
-        }
-    })
-}
-
-#[macro_export]
-macro_rules! struct_span_warn {
-    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        $session.struct_span_warn_with_code(
-            $span,
-            &format!($($message)*),
-            $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-        )
-    })
-}
-
-#[macro_export]
-macro_rules! struct_span_err_or_warn {
-    ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $crate::diagnostic_used!($code);
-        if $is_warning {
-            $session.struct_span_warn_with_code(
-                $span,
-                &format!($($message)*),
-                $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-            )
-        } else {
-            $session.struct_span_err_with_code(
-                $span,
-                &format!($($message)*),
-                $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
-            )
-        }
-    })
-}
-
-#[macro_export]
-macro_rules! span_note {
-    ($err:expr, $span:expr, $($message:tt)*) => ({
-        ($err).span_note($span, &format!($($message)*));
-    })
-}
-
-#[macro_export]
-macro_rules! span_help {
-    ($err:expr, $span:expr, $($message:tt)*) => ({
-        ($err).span_help($span, &format!($($message)*));
-    })
-}
-
-#[macro_export]
-macro_rules! help {
-    ($err:expr, $($message:tt)*) => ({
-        ($err).help(&format!($($message)*));
-    })
-}
diff --git a/src/libsyntax/early_buffered_lints.rs b/src/libsyntax/early_buffered_lints.rs
deleted file mode 100644 (file)
index 7724107..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-//! Allows the buffering of lints for later.
-//!
-//! Since we cannot have a dependency on `librustc`, we implement some types here that are somewhat
-//! redundant. Later, these types can be converted to types for use by the rest of the compiler.
-
-use rustc_session::declare_lint;
-pub use rustc_session::lint::BufferedEarlyLint;
-use rustc_session::lint::FutureIncompatibleInfo;
-
-declare_lint! {
-    pub ILL_FORMED_ATTRIBUTE_INPUT,
-    Deny,
-    "ill-formed attribute inputs that were previously accepted and used in practice",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
-        edition: None,
-    };
-}
-
-declare_lint! {
-    pub META_VARIABLE_MISUSE,
-    Allow,
-    "possible meta-variable misuse at macro definition"
-}
-
-declare_lint! {
-    pub INCOMPLETE_INCLUDE,
-    Deny,
-    "trailing content in included file"
-}
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
deleted file mode 100644 (file)
index 0e94a72..0000000
+++ /dev/null
@@ -1,965 +0,0 @@
-use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
-use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
-use crate::attr;
-use crate::sess::ParseSess;
-use crate::visit::{self, FnKind, Visitor};
-
-use errors::{Applicability, DiagnosticBuilder, Handler};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_error_codes::*;
-use rustc_feature::{find_feature_issue, GateIssue};
-use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
-use rustc_feature::{Feature, Features, State as FeatureState, UnstableFeatures};
-use rustc_feature::{
-    ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
-};
-use rustc_span::edition::{Edition, ALL_EDITIONS};
-use rustc_span::source_map::Spanned;
-use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{MultiSpan, Span, DUMMY_SP};
-
-use log::debug;
-
-macro_rules! gate_feature_fn {
-    ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
-        let (cx, has_feature, span, name, explain, level) =
-            (&*$cx, $has_feature, $span, $name, $explain, $level);
-        let has_feature: bool = has_feature(&$cx.features);
-        debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
-        if !has_feature && !span.allows_unstable($name) {
-            leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
-                .emit();
-        }
-    }};
-}
-
-macro_rules! gate_feature {
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
-        gate_feature_fn!(
-            $cx,
-            |x: &Features| x.$feature,
-            $span,
-            sym::$feature,
-            $explain,
-            GateStrength::Hard
-        )
-    };
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
-        gate_feature_fn!($cx, |x: &Features| x.$feature, $span, sym::$feature, $explain, $level)
-    };
-}
-
-pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
-    PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
-}
-
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum GateStrength {
-    /// A hard error. (Most feature gates should use this.)
-    Hard,
-    /// Only a warning. (Use this only as backwards-compatibility demands.)
-    Soft,
-}
-
-pub fn feature_err<'a>(
-    sess: &'a ParseSess,
-    feature: Symbol,
-    span: impl Into<MultiSpan>,
-    explain: &str,
-) -> DiagnosticBuilder<'a> {
-    feature_err_issue(sess, feature, span, GateIssue::Language, explain)
-}
-
-pub fn feature_err_issue<'a>(
-    sess: &'a ParseSess,
-    feature: Symbol,
-    span: impl Into<MultiSpan>,
-    issue: GateIssue,
-    explain: &str,
-) -> DiagnosticBuilder<'a> {
-    leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
-}
-
-fn leveled_feature_err<'a>(
-    sess: &'a ParseSess,
-    feature: Symbol,
-    span: impl Into<MultiSpan>,
-    issue: GateIssue,
-    explain: &str,
-    level: GateStrength,
-) -> DiagnosticBuilder<'a> {
-    let diag = &sess.span_diagnostic;
-
-    let mut err = match level {
-        GateStrength::Hard => {
-            diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658))
-        }
-        GateStrength::Soft => diag.struct_span_warn(span, explain),
-    };
-
-    if let Some(n) = find_feature_issue(feature, issue) {
-        err.note(&format!(
-            "for more information, see https://github.com/rust-lang/rust/issues/{}",
-            n,
-        ));
-    }
-
-    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
-    if sess.unstable_features.is_nightly_build() {
-        err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
-    }
-
-    // If we're on stable and only emitting a "soft" warning, add a note to
-    // clarify that the feature isn't "on" (rather than being on but
-    // warning-worthy).
-    if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
-        err.help("a nightly build of the compiler is required to enable this feature");
-    }
-
-    err
-}
-
-struct PostExpansionVisitor<'a> {
-    parse_sess: &'a ParseSess,
-    features: &'a Features,
-}
-
-macro_rules! gate_feature_post {
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
-        let (cx, span) = ($cx, $span);
-        if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx, $feature, span, $explain)
-        }
-    }};
-    ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
-        let (cx, span) = ($cx, $span);
-        if !span.allows_unstable(sym::$feature) {
-            gate_feature!(cx, $feature, span, $explain, $level)
-        }
-    }};
-}
-
-impl<'a> PostExpansionVisitor<'a> {
-    fn check_abi(&self, abi: ast::StrLit) {
-        let ast::StrLit { symbol_unescaped, span, .. } = abi;
-
-        match &*symbol_unescaped.as_str() {
-            // Stable
-            "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
-            | "system" => {}
-            "rust-intrinsic" => {
-                gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change");
-            }
-            "platform-intrinsic" => {
-                gate_feature_post!(
-                    &self,
-                    platform_intrinsics,
-                    span,
-                    "platform intrinsics are experimental and possibly buggy"
-                );
-            }
-            "vectorcall" => {
-                gate_feature_post!(
-                    &self,
-                    abi_vectorcall,
-                    span,
-                    "vectorcall is experimental and subject to change"
-                );
-            }
-            "thiscall" => {
-                gate_feature_post!(
-                    &self,
-                    abi_thiscall,
-                    span,
-                    "thiscall is experimental and subject to change"
-                );
-            }
-            "rust-call" => {
-                gate_feature_post!(
-                    &self,
-                    unboxed_closures,
-                    span,
-                    "rust-call ABI is subject to change"
-                );
-            }
-            "ptx-kernel" => {
-                gate_feature_post!(
-                    &self,
-                    abi_ptx,
-                    span,
-                    "PTX ABIs are experimental and subject to change"
-                );
-            }
-            "unadjusted" => {
-                gate_feature_post!(
-                    &self,
-                    abi_unadjusted,
-                    span,
-                    "unadjusted ABI is an implementation detail and perma-unstable"
-                );
-            }
-            "msp430-interrupt" => {
-                gate_feature_post!(
-                    &self,
-                    abi_msp430_interrupt,
-                    span,
-                    "msp430-interrupt ABI is experimental and subject to change"
-                );
-            }
-            "x86-interrupt" => {
-                gate_feature_post!(
-                    &self,
-                    abi_x86_interrupt,
-                    span,
-                    "x86-interrupt ABI is experimental and subject to change"
-                );
-            }
-            "amdgpu-kernel" => {
-                gate_feature_post!(
-                    &self,
-                    abi_amdgpu_kernel,
-                    span,
-                    "amdgpu-kernel ABI is experimental and subject to change"
-                );
-            }
-            "efiapi" => {
-                gate_feature_post!(
-                    &self,
-                    abi_efiapi,
-                    span,
-                    "efiapi ABI is experimental and subject to change"
-                );
-            }
-            abi => self
-                .parse_sess
-                .span_diagnostic
-                .delay_span_bug(span, &format!("unrecognized ABI not caught in lowering: {}", abi)),
-        }
-    }
-
-    fn check_extern(&self, ext: ast::Extern) {
-        if let ast::Extern::Explicit(abi) = ext {
-            self.check_abi(abi);
-        }
-    }
-
-    fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
-        let has_fields = variants.iter().any(|variant| match variant.data {
-            VariantData::Tuple(..) | VariantData::Struct(..) => true,
-            VariantData::Unit(..) => false,
-        });
-
-        let discriminant_spans = variants
-            .iter()
-            .filter(|variant| match variant.data {
-                VariantData::Tuple(..) | VariantData::Struct(..) => false,
-                VariantData::Unit(..) => true,
-            })
-            .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
-            .collect::<Vec<_>>();
-
-        if !discriminant_spans.is_empty() && has_fields {
-            let mut err = feature_err(
-                self.parse_sess,
-                sym::arbitrary_enum_discriminant,
-                discriminant_spans.clone(),
-                "custom discriminant values are not allowed in enums with tuple or struct variants",
-            );
-            for sp in discriminant_spans {
-                err.span_label(sp, "disallowed custom discriminant");
-            }
-            for variant in variants.iter() {
-                match &variant.data {
-                    VariantData::Struct(..) => {
-                        err.span_label(variant.span, "struct variant defined here");
-                    }
-                    VariantData::Tuple(..) => {
-                        err.span_label(variant.span, "tuple variant defined here");
-                    }
-                    VariantData::Unit(..) => {}
-                }
-            }
-            err.emit();
-        }
-    }
-
-    fn check_gat(&self, generics: &ast::Generics, span: Span) {
-        if !generics.params.is_empty() {
-            gate_feature_post!(
-                &self,
-                generic_associated_types,
-                span,
-                "generic associated types are unstable"
-            );
-        }
-        if !generics.where_clause.predicates.is_empty() {
-            gate_feature_post!(
-                &self,
-                generic_associated_types,
-                span,
-                "where clauses on associated types are unstable"
-            );
-        }
-    }
-
-    /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
-    fn check_impl_trait(&self, ty: &ast::Ty) {
-        struct ImplTraitVisitor<'a> {
-            vis: &'a PostExpansionVisitor<'a>,
-        }
-        impl Visitor<'_> for ImplTraitVisitor<'_> {
-            fn visit_ty(&mut self, ty: &ast::Ty) {
-                if let ast::TyKind::ImplTrait(..) = ty.kind {
-                    gate_feature_post!(
-                        &self.vis,
-                        type_alias_impl_trait,
-                        ty.span,
-                        "`impl Trait` in type aliases is unstable"
-                    );
-                }
-                visit::walk_ty(self, ty);
-            }
-        }
-        ImplTraitVisitor { vis: self }.visit_ty(ty);
-    }
-}
-
-impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
-    fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        let attr_info =
-            attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
-        // Check feature gates for built-in attributes.
-        if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
-            gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
-        }
-        // Check unstable flavors of the `#[doc]` attribute.
-        if attr.check_name(sym::doc) {
-            for nested_meta in attr.meta_item_list().unwrap_or_default() {
-                macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
-                    $(if nested_meta.check_name(sym::$name) {
-                        let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
-                        gate_feature!(self, $feature, attr.span, msg);
-                    })*
-                }}
-
-                gate_doc!(
-                    include => external_doc
-                    cfg => doc_cfg
-                    masked => doc_masked
-                    spotlight => doc_spotlight
-                    alias => doc_alias
-                    keyword => doc_keyword
-                );
-            }
-        }
-    }
-
-    fn visit_name(&mut self, sp: Span, name: ast::Name) {
-        if !name.as_str().is_ascii() {
-            gate_feature_post!(
-                &self,
-                non_ascii_idents,
-                self.parse_sess.source_map().def_span(sp),
-                "non-ascii idents are not fully supported"
-            );
-        }
-    }
-
-    fn visit_item(&mut self, i: &'a ast::Item) {
-        match i.kind {
-            ast::ItemKind::ForeignMod(ref foreign_module) => {
-                if let Some(abi) = foreign_module.abi {
-                    self.check_abi(abi);
-                }
-            }
-
-            ast::ItemKind::Fn(..) => {
-                if attr::contains_name(&i.attrs[..], sym::plugin_registrar) {
-                    gate_feature_post!(
-                        &self,
-                        plugin_registrar,
-                        i.span,
-                        "compiler plugins are experimental and possibly buggy"
-                    );
-                }
-                if attr::contains_name(&i.attrs[..], sym::start) {
-                    gate_feature_post!(
-                        &self,
-                        start,
-                        i.span,
-                        "`#[start]` functions are experimental \
-                                       and their signature may change \
-                                       over time"
-                    );
-                }
-                if attr::contains_name(&i.attrs[..], sym::main) {
-                    gate_feature_post!(
-                        &self,
-                        main,
-                        i.span,
-                        "declaration of a non-standard `#[main]` \
-                                        function may change over time, for now \
-                                        a top-level `fn main()` is required"
-                    );
-                }
-            }
-
-            ast::ItemKind::Struct(..) => {
-                for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
-                    for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-                        if item.check_name(sym::simd) {
-                            gate_feature_post!(
-                                &self,
-                                repr_simd,
-                                attr.span,
-                                "SIMD types are experimental and possibly buggy"
-                            );
-                        }
-                    }
-                }
-            }
-
-            ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
-                for variant in variants {
-                    match (&variant.data, &variant.disr_expr) {
-                        (ast::VariantData::Unit(..), _) => {}
-                        (_, Some(disr_expr)) => gate_feature_post!(
-                            &self,
-                            arbitrary_enum_discriminant,
-                            disr_expr.value.span,
-                            "discriminants on non-unit variants are experimental"
-                        ),
-                        _ => {}
-                    }
-                }
-
-                let has_feature = self.features.arbitrary_enum_discriminant;
-                if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
-                    self.maybe_report_invalid_custom_discriminants(&variants);
-                }
-            }
-
-            ast::ItemKind::Impl(_, polarity, defaultness, ..) => {
-                if polarity == ast::ImplPolarity::Negative {
-                    gate_feature_post!(
-                        &self,
-                        optin_builtin_traits,
-                        i.span,
-                        "negative trait bounds are not yet fully implemented; \
-                                        use marker types for now"
-                    );
-                }
-
-                if let ast::Defaultness::Default = defaultness {
-                    gate_feature_post!(&self, specialization, i.span, "specialization is unstable");
-                }
-            }
-
-            ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
-                gate_feature_post!(
-                    &self,
-                    optin_builtin_traits,
-                    i.span,
-                    "auto traits are experimental and possibly buggy"
-                );
-            }
-
-            ast::ItemKind::TraitAlias(..) => {
-                gate_feature_post!(&self, trait_alias, i.span, "trait aliases are experimental");
-            }
-
-            ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
-                let msg = "`macro` is experimental";
-                gate_feature_post!(&self, decl_macro, i.span, msg);
-            }
-
-            ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty),
-
-            _ => {}
-        }
-
-        visit::walk_item(self, i);
-    }
-
-    fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
-        match i.kind {
-            ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
-                let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
-                let links_to_llvm = match link_name {
-                    Some(val) => val.as_str().starts_with("llvm."),
-                    _ => false,
-                };
-                if links_to_llvm {
-                    gate_feature_post!(
-                        &self,
-                        link_llvm_intrinsics,
-                        i.span,
-                        "linking to LLVM intrinsics is experimental"
-                    );
-                }
-            }
-            ast::ForeignItemKind::Ty => {
-                gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
-            }
-            ast::ForeignItemKind::Macro(..) => {}
-        }
-
-        visit::walk_foreign_item(self, i)
-    }
-
-    fn visit_ty(&mut self, ty: &'a ast::Ty) {
-        match ty.kind {
-            ast::TyKind::BareFn(ref bare_fn_ty) => {
-                self.check_extern(bare_fn_ty.ext);
-            }
-            ast::TyKind::Never => {
-                gate_feature_post!(&self, never_type, ty.span, "The `!` type is experimental");
-            }
-            _ => {}
-        }
-        visit::walk_ty(self, ty)
-    }
-
-    fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
-        if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
-            if let ast::TyKind::Never = output_ty.kind {
-                // Do nothing.
-            } else {
-                self.visit_ty(output_ty)
-            }
-        }
-    }
-
-    fn visit_expr(&mut self, e: &'a ast::Expr) {
-        match e.kind {
-            ast::ExprKind::Box(_) => {
-                gate_feature_post!(
-                    &self,
-                    box_syntax,
-                    e.span,
-                    "box expression syntax is experimental; you can call `Box::new` instead"
-                );
-            }
-            ast::ExprKind::Type(..) => {
-                // To avoid noise about type ascription in common syntax errors, only emit if it
-                // is the *only* error.
-                if self.parse_sess.span_diagnostic.err_count() == 0 {
-                    gate_feature_post!(
-                        &self,
-                        type_ascription,
-                        e.span,
-                        "type ascription is experimental"
-                    );
-                }
-            }
-            ast::ExprKind::TryBlock(_) => {
-                gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
-            }
-            ast::ExprKind::Block(_, opt_label) => {
-                if let Some(label) = opt_label {
-                    gate_feature_post!(
-                        &self,
-                        label_break_value,
-                        label.ident.span,
-                        "labels on blocks are unstable"
-                    );
-                }
-            }
-            _ => {}
-        }
-        visit::walk_expr(self, e)
-    }
-
-    fn visit_arm(&mut self, arm: &'a ast::Arm) {
-        visit::walk_arm(self, arm)
-    }
-
-    fn visit_pat(&mut self, pattern: &'a ast::Pat) {
-        match &pattern.kind {
-            PatKind::Slice(pats) => {
-                for pat in &*pats {
-                    let span = pat.span;
-                    let inner_pat = match &pat.kind {
-                        PatKind::Ident(.., Some(pat)) => pat,
-                        _ => pat,
-                    };
-                    if inner_pat.is_rest() {
-                        gate_feature_post!(
-                            &self,
-                            slice_patterns,
-                            span,
-                            "subslice patterns are unstable"
-                        );
-                    }
-                }
-            }
-            PatKind::Box(..) => {
-                gate_feature_post!(
-                    &self,
-                    box_patterns,
-                    pattern.span,
-                    "box pattern syntax is experimental"
-                );
-            }
-            PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
-                gate_feature_post!(
-                    &self,
-                    exclusive_range_pattern,
-                    pattern.span,
-                    "exclusive range pattern syntax is experimental"
-                );
-            }
-            _ => {}
-        }
-        visit::walk_pat(self, pattern)
-    }
-
-    fn visit_fn(
-        &mut self,
-        fn_kind: FnKind<'a>,
-        fn_decl: &'a ast::FnDecl,
-        span: Span,
-        _node_id: NodeId,
-    ) {
-        if let Some(header) = fn_kind.header() {
-            // Stability of const fn methods are covered in
-            // `visit_trait_item` and `visit_impl_item` below; this is
-            // because default methods don't pass through this point.
-            self.check_extern(header.ext);
-        }
-
-        if fn_decl.c_variadic() {
-            gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
-        }
-
-        visit::walk_fn(self, fn_kind, fn_decl, span)
-    }
-
-    fn visit_generic_param(&mut self, param: &'a GenericParam) {
-        match param.kind {
-            GenericParamKind::Const { .. } => gate_feature_post!(
-                &self,
-                const_generics,
-                param.ident.span,
-                "const generics are unstable"
-            ),
-            _ => {}
-        }
-        visit::walk_generic_param(self, param)
-    }
-
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
-        match constraint.kind {
-            AssocTyConstraintKind::Bound { .. } => gate_feature_post!(
-                &self,
-                associated_type_bounds,
-                constraint.span,
-                "associated type bounds are unstable"
-            ),
-            _ => {}
-        }
-        visit::walk_assoc_ty_constraint(self, constraint)
-    }
-
-    fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) {
-        match ti.kind {
-            ast::AssocItemKind::Fn(ref sig, ref block) => {
-                if block.is_none() {
-                    self.check_extern(sig.header.ext);
-                }
-                if sig.header.constness.node == ast::Constness::Const {
-                    gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
-                }
-            }
-            ast::AssocItemKind::TyAlias(_, ref default) => {
-                if let Some(_) = default {
-                    gate_feature_post!(
-                        &self,
-                        associated_type_defaults,
-                        ti.span,
-                        "associated type defaults are unstable"
-                    );
-                }
-            }
-            _ => {}
-        }
-        visit::walk_trait_item(self, ti)
-    }
-
-    fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) {
-        if ii.defaultness == ast::Defaultness::Default {
-            gate_feature_post!(&self, specialization, ii.span, "specialization is unstable");
-        }
-
-        match ii.kind {
-            ast::AssocItemKind::Fn(ref sig, _) => {
-                if sig.decl.c_variadic() {
-                    gate_feature_post!(
-                        &self,
-                        c_variadic,
-                        ii.span,
-                        "C-variadic functions are unstable"
-                    );
-                }
-            }
-            ast::AssocItemKind::TyAlias(_, ref ty) => {
-                if let Some(ty) = ty {
-                    self.check_impl_trait(ty);
-                }
-                self.check_gat(&ii.generics, ii.span);
-            }
-            _ => {}
-        }
-        visit::walk_assoc_item(self, ii)
-    }
-
-    fn visit_vis(&mut self, vis: &'a ast::Visibility) {
-        if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node {
-            gate_feature_post!(
-                &self,
-                crate_visibility_modifier,
-                vis.span,
-                "`crate` visibility modifier is experimental"
-            );
-        }
-        visit::walk_vis(self, vis)
-    }
-}
-
-pub fn get_features(
-    span_handler: &Handler,
-    krate_attrs: &[ast::Attribute],
-    crate_edition: Edition,
-    allow_features: &Option<Vec<String>>,
-) -> Features {
-    fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
-        let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
-        err.span_label(span, "feature has been removed");
-        if let Some(reason) = reason {
-            err.note(reason);
-        }
-        err.emit();
-    }
-
-    let mut features = Features::default();
-    let mut edition_enabled_features = FxHashMap::default();
-
-    for &edition in ALL_EDITIONS {
-        if edition <= crate_edition {
-            // The `crate_edition` implies its respective umbrella feature-gate
-            // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
-            edition_enabled_features.insert(edition.feature_name(), edition);
-        }
-    }
-
-    for feature in active_features_up_to(crate_edition) {
-        feature.set(&mut features, DUMMY_SP);
-        edition_enabled_features.insert(feature.name, crate_edition);
-    }
-
-    // Process the edition umbrella feature-gates first, to ensure
-    // `edition_enabled_features` is completed before it's queried.
-    for attr in krate_attrs {
-        if !attr.check_name(sym::feature) {
-            continue;
-        }
-
-        let list = match attr.meta_item_list() {
-            Some(list) => list,
-            None => continue,
-        };
-
-        for mi in list {
-            if !mi.is_word() {
-                continue;
-            }
-
-            let name = mi.name_or_empty();
-
-            let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
-            if let Some(edition) = edition {
-                if edition <= crate_edition {
-                    continue;
-                }
-
-                for feature in active_features_up_to(edition) {
-                    // FIXME(Manishearth) there is currently no way to set
-                    // lib features by edition
-                    feature.set(&mut features, DUMMY_SP);
-                    edition_enabled_features.insert(feature.name, edition);
-                }
-            }
-        }
-    }
-
-    for attr in krate_attrs {
-        if !attr.check_name(sym::feature) {
-            continue;
-        }
-
-        let list = match attr.meta_item_list() {
-            Some(list) => list,
-            None => continue,
-        };
-
-        let bad_input = |span| {
-            struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
-        };
-
-        for mi in list {
-            let name = match mi.ident() {
-                Some(ident) if mi.is_word() => ident.name,
-                Some(ident) => {
-                    bad_input(mi.span())
-                        .span_suggestion(
-                            mi.span(),
-                            "expected just one word",
-                            format!("{}", ident.name),
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
-                    continue;
-                }
-                None => {
-                    bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
-                    continue;
-                }
-            };
-
-            if let Some(edition) = edition_enabled_features.get(&name) {
-                struct_span_warn!(
-                    span_handler,
-                    mi.span(),
-                    E0705,
-                    "the feature `{}` is included in the Rust {} edition",
-                    name,
-                    edition,
-                )
-                .emit();
-                continue;
-            }
-
-            if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
-                // Handled in the separate loop above.
-                continue;
-            }
-
-            let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
-            let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
-            if let Some(Feature { state, .. }) = removed.or(stable_removed) {
-                if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } =
-                    state
-                {
-                    feature_removed(span_handler, mi.span(), *reason);
-                    continue;
-                }
-            }
-
-            if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
-                let since = Some(Symbol::intern(since));
-                features.declared_lang_features.push((name, mi.span(), since));
-                continue;
-            }
-
-            if let Some(allowed) = allow_features.as_ref() {
-                if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
-                    span_err!(
-                        span_handler,
-                        mi.span(),
-                        E0725,
-                        "the feature `{}` is not in the list of allowed features",
-                        name
-                    );
-                    continue;
-                }
-            }
-
-            if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
-                f.set(&mut features, mi.span());
-                features.declared_lang_features.push((name, mi.span(), None));
-                continue;
-            }
-
-            features.declared_lib_features.push((name, mi.span()));
-        }
-    }
-
-    features
-}
-
-fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> {
-    ACTIVE_FEATURES.iter().filter(move |feature| {
-        if let Some(feature_edition) = feature.edition { feature_edition <= edition } else { false }
-    })
-}
-
-pub fn check_crate(
-    krate: &ast::Crate,
-    parse_sess: &ParseSess,
-    features: &Features,
-    unstable: UnstableFeatures,
-) {
-    maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
-    let mut visitor = PostExpansionVisitor { parse_sess, features };
-
-    let spans = parse_sess.gated_spans.spans.borrow();
-    macro_rules! gate_all {
-        ($gate:ident, $msg:literal) => {
-            for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
-                gate_feature!(&visitor, $gate, *span, $msg);
-            }
-        };
-    }
-    gate_all!(let_chains, "`let` expressions in this position are experimental");
-    gate_all!(async_closure, "async closures are unstable");
-    gate_all!(generators, "yield syntax is experimental");
-    gate_all!(or_patterns, "or-patterns syntax is experimental");
-    gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
-    gate_all!(raw_ref_op, "raw address of syntax is experimental");
-
-    // All uses of `gate_all!` below this point were added in #65742,
-    // and subsequently disabled (with the non-early gating readded).
-    macro_rules! gate_all {
-        ($gate:ident, $msg:literal) => {
-            // FIXME(eddyb) do something more useful than always
-            // disabling these uses of early feature-gatings.
-            if false {
-                for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
-                    gate_feature!(&visitor, $gate, *span, $msg);
-                }
-            }
-        };
-    }
-
-    gate_all!(trait_alias, "trait aliases are experimental");
-    gate_all!(associated_type_bounds, "associated type bounds are unstable");
-    gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
-    gate_all!(const_generics, "const generics are unstable");
-    gate_all!(decl_macro, "`macro` is experimental");
-    gate_all!(box_patterns, "box pattern syntax is experimental");
-    gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
-    gate_all!(try_blocks, "`try` blocks are unstable");
-    gate_all!(label_break_value, "labels on blocks are unstable");
-    gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
-    // To avoid noise about type ascription in common syntax errors,
-    // only emit if it is the *only* error. (Also check it last.)
-    if parse_sess.span_diagnostic.err_count() == 0 {
-        gate_all!(type_ascription, "type ascription is experimental");
-    }
-
-    visit::walk_crate(&mut visitor, krate);
-}
-
-fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
-    if !unstable.is_nightly_build() {
-        for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
-            span_err!(
-                span_handler,
-                attr.span,
-                E0554,
-                "`#![feature]` may not be used on the {} release channel",
-                option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
-            );
-        }
-    }
-}
index 72beddf7bb516202e8dbf3153c0a68fec20a1300..0184a3214b5b4985748e5d17f6e99f4d52be8f35 100644 (file)
@@ -7,7 +7,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
-#![feature(const_fn)]
+#![feature(const_fn)] // For the `transmute` in `P::new`
 #![feature(const_transmute)]
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
@@ -18,7 +18,6 @@
 #![recursion_limit = "256"]
 
 use ast::AttrId;
-pub use errors;
 use rustc_data_structures::sync::Lock;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
@@ -62,12 +61,6 @@ pub fn with_default_globals<R>(f: impl FnOnce() -> R) -> R {
 
 scoped_tls::scoped_thread_local!(pub static GLOBALS: Globals);
 
-#[macro_use]
-pub mod diagnostics {
-    #[macro_use]
-    pub mod macros;
-}
-
 pub mod util {
     pub mod classify;
     pub mod comments;
@@ -82,13 +75,8 @@ pub mod util {
 pub mod attr;
 pub mod entry;
 pub mod expand;
-pub mod feature_gate {
-    mod check;
-    pub use check::{check_attribute, check_crate, feature_err, feature_err_issue, get_features};
-}
 pub mod mut_visit;
 pub mod ptr;
-pub mod show_span;
 pub use rustc_session::parse as sess;
 pub mod token;
 pub mod tokenstream;
@@ -100,8 +88,6 @@ pub mod print {
     pub mod pprust;
 }
 
-pub mod early_buffered_lints;
-
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
index 1413f1566d0438f5ebe3d028e9183c3b9aa1770b..58d4e46111b83adb5dc7344c014724dd4b793d0a 100644 (file)
@@ -838,7 +838,8 @@ pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut
     }
 }
 
-pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
+pub fn noop_visit_trait_ref<T: MutVisitor>(tr: &mut TraitRef, vis: &mut T) {
+    let TraitRef { path, ref_id, constness: _ } = tr;
     vis.visit_path(path);
     vis.visit_id(ref_id);
 }
@@ -1074,8 +1075,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
         PatKind::Box(inner) => vis.visit_pat(inner),
         PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
         PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
-            vis.visit_expr(e1);
-            vis.visit_expr(e2);
+            visit_opt(e1, |e| vis.visit_expr(e));
+            visit_opt(e2, |e| vis.visit_expr(e));
             vis.visit_span(span);
         }
         PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
index dd9976510dccfff68bb85ea7520dab2fb276d830..11c8cb8ef750017b1137cbb7266f1871799c3ea1 100644 (file)
@@ -2329,14 +2329,18 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa
             }
             PatKind::Lit(ref e) => self.print_expr(&**e),
             PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
-                self.print_expr(begin);
-                self.s.space();
+                if let Some(e) = begin {
+                    self.print_expr(e);
+                    self.s.space();
+                }
                 match *end_kind {
                     RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."),
                     RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="),
                     RangeEnd::Excluded => self.s.word(".."),
                 }
-                self.print_expr(end);
+                if let Some(e) = end {
+                    self.print_expr(e);
+                }
             }
             PatKind::Slice(ref elts) => {
                 self.s.word("[");
diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs
deleted file mode 100644 (file)
index fb64123..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-//! Span debugger
-//!
-//! This module shows spans for all expressions in the crate
-//! to help with compiler debugging.
-
-use std::str::FromStr;
-
-use crate::ast;
-use crate::visit;
-use crate::visit::Visitor;
-
-enum Mode {
-    Expression,
-    Pattern,
-    Type,
-}
-
-impl FromStr for Mode {
-    type Err = ();
-    fn from_str(s: &str) -> Result<Mode, ()> {
-        let mode = match s {
-            "expr" => Mode::Expression,
-            "pat" => Mode::Pattern,
-            "ty" => Mode::Type,
-            _ => return Err(()),
-        };
-        Ok(mode)
-    }
-}
-
-struct ShowSpanVisitor<'a> {
-    span_diagnostic: &'a errors::Handler,
-    mode: Mode,
-}
-
-impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
-    fn visit_expr(&mut self, e: &'a ast::Expr) {
-        if let Mode::Expression = self.mode {
-            self.span_diagnostic.span_warn(e.span, "expression");
-        }
-        visit::walk_expr(self, e);
-    }
-
-    fn visit_pat(&mut self, p: &'a ast::Pat) {
-        if let Mode::Pattern = self.mode {
-            self.span_diagnostic.span_warn(p.span, "pattern");
-        }
-        visit::walk_pat(self, p);
-    }
-
-    fn visit_ty(&mut self, t: &'a ast::Ty) {
-        if let Mode::Type = self.mode {
-            self.span_diagnostic.span_warn(t.span, "type");
-        }
-        visit::walk_ty(self, t);
-    }
-
-    fn visit_mac(&mut self, mac: &'a ast::Mac) {
-        visit::walk_mac(self, mac);
-    }
-}
-
-pub fn run(span_diagnostic: &errors::Handler, mode: &str, krate: &ast::Crate) {
-    let mode = match mode.parse().ok() {
-        Some(mode) => mode,
-        None => return,
-    };
-    let mut v = ShowSpanVisitor { span_diagnostic, mode };
-    visit::walk_crate(&mut v, krate);
-}
index fc697026fe4f8352a81d0fc0441e46a30abfa3b5..cce86fed9891c14fe3b4e5c8e44d556338df3271 100644 (file)
@@ -54,14 +54,16 @@ pub fn find_best_match_for_name<'a, T>(
     T: Iterator<Item = &'a Symbol>,
 {
     let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
+    let name_vec: Vec<&Symbol> = iter_names.collect();
 
-    let (case_insensitive_match, levenstein_match) = iter_names
+    let (case_insensitive_match, levenshtein_match) = name_vec
+        .iter()
         .filter_map(|&name| {
             let dist = lev_distance(lookup, &name.as_str());
             if dist <= max_dist { Some((name, dist)) } else { None }
         })
         // Here we are collecting the next structure:
-        // (case_insensitive_match, (levenstein_match, levenstein_distance))
+        // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
         .fold((None, None), |result, (candidate, dist)| {
             (
                 if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
@@ -75,10 +77,31 @@ pub fn find_best_match_for_name<'a, T>(
                 },
             )
         });
-
+    // Priority of matches:
+    // 1. Exact case insensitive match
+    // 2. Levenshtein distance match
+    // 3. Sorted word match
     if let Some(candidate) = case_insensitive_match {
-        Some(candidate) // exact case insensitive match has a higher priority
+        Some(*candidate)
+    } else if levenshtein_match.is_some() {
+        levenshtein_match.map(|(candidate, _)| *candidate)
     } else {
-        levenstein_match.map(|(candidate, _)| candidate)
+        find_match_by_sorted_words(name_vec, lookup)
     }
 }
+
+fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> Option<Symbol> {
+    iter_names.iter().fold(None, |result, candidate| {
+        if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) {
+            Some(**candidate)
+        } else {
+            result
+        }
+    })
+}
+
+fn sort_by_words(name: &str) -> String {
+    let mut split_words: Vec<&str> = name.split('_').collect();
+    split_words.sort();
+    split_words.join("_")
+}
index f65f9275d0341ed9680561a92f7f690ed5401fac..222661687c1c29d459d3eb7baee0a60b6e019548 100644 (file)
@@ -46,5 +46,11 @@ fn test_find_best_match_for_name() {
             find_best_match_for_name(input.iter(), "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),
+            Some(Symbol::intern("a_longer_variable_name"))
+        );
     })
 }
index ebb49abebb01e826ac9fb2265316e03e5c1bb7ae..3c2ebacbc4e346a7c2d403cb5035f9b933dafced 100644 (file)
@@ -492,8 +492,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
         }
         PatKind::Lit(ref expression) => visitor.visit_expr(expression),
         PatKind::Range(ref lower_bound, ref upper_bound, _) => {
-            visitor.visit_expr(lower_bound);
-            visitor.visit_expr(upper_bound);
+            walk_list!(visitor, visit_expr, lower_bound);
+            walk_list!(visitor, visit_expr, upper_bound);
         }
         PatKind::Wild | PatKind::Rest => {}
         PatKind::Tuple(ref elems) | PatKind::Slice(ref elems) | PatKind::Or(ref elems) => {
index ea6d632f48a59df627b6665705e598d253ec130d..edff8bea0f3d0b036896cb70e829e00495f262bd 100644 (file)
@@ -125,6 +125,8 @@ fn optgroups() -> getopts::Options {
             `RUST_TEST_TIME_DOCTEST` environment variables.
 
             Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.
+            Durations must be specified in milliseconds, e.g. `500,2000` means that the warn time
+            is 0.5 seconds, and the critical time is 2 seconds.
 
             Not available for --format=terse",
             "plain|colored",
index 86a93d7d0cbfec9d3be91a46cbb52bb2f40f55c7..5e0f167bb380179399da8a5fab534bb59f285d27 100644 (file)
@@ -9,7 +9,6 @@ name = "rustc_binary"
 path = "rustc.rs"
 
 [dependencies]
-rustc_target = { path = "../librustc_target" }
 rustc_driver = { path = "../librustc_driver" }
 
 # Make sure rustc_codegen_ssa ends up in the sysroot, because this
index dd0111d3f2c83ea92285818a8bed609977810ffd..678d787571ed7c368fb3d05bf05f758df1b593b6 100644 (file)
@@ -89,7 +89,11 @@ extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
 extern "C" LLVMRustArchiveIteratorRef
 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
   Archive *Archive = RustArchive->getBinary();
+#if LLVM_VERSION_GE(10, 0)
+  std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
+#else
   std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success());
+#endif
   auto Cur = Archive->child_begin(*Err);
   if (*Err) {
     LLVMRustSetLastError(toString(std::move(*Err)).c_str());
index 7916721943a5fca28b09f15702b82536c42bfe0a..69176f9cb1f6d528134a2109e5ca4348d1cbea90 100644 (file)
@@ -18,8 +18,7 @@ extern "C" RustLinker*
 LLVMRustLinkerNew(LLVMModuleRef DstRef) {
   Module *Dst = unwrap(DstRef);
 
-  auto Ret = llvm::make_unique<RustLinker>(*Dst);
-  return Ret.release();
+  return new RustLinker(*Dst);
 }
 
 extern "C" void
index 6698e5d58be2f0ed97a7c05c013b1bbe4707f110..eaa845a279fe8f8da6fca0fe12fe8a2b99aa5f66 100644 (file)
@@ -8,6 +8,7 @@
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/InitializePasses.h"
 #include "llvm/IR/AutoUpgrade.h"
 #include "llvm/IR/AssemblyAnnotationWriter.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -532,6 +533,18 @@ enum class LLVMRustFileType {
   ObjectFile,
 };
 
+#if LLVM_VERSION_GE(10, 0)
+static CodeGenFileType fromRust(LLVMRustFileType Type) {
+  switch (Type) {
+  case LLVMRustFileType::AssemblyFile:
+    return CGFT_AssemblyFile;
+  case LLVMRustFileType::ObjectFile:
+    return CGFT_ObjectFile;
+  default:
+    report_fatal_error("Bad FileType.");
+  }
+}
+#else
 static TargetMachine::CodeGenFileType fromRust(LLVMRustFileType Type) {
   switch (Type) {
   case LLVMRustFileType::AssemblyFile:
@@ -542,6 +555,7 @@ static TargetMachine::CodeGenFileType fromRust(LLVMRustFileType Type) {
     report_fatal_error("Bad FileType.");
   }
 }
+#endif
 
 extern "C" LLVMRustResult
 LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
@@ -849,7 +863,11 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
                           int num_modules,
                           const char **preserved_symbols,
                           int num_symbols) {
+#if LLVM_VERSION_GE(10, 0)
+  auto Ret = std::make_unique<LLVMRustThinLTOData>();
+#else
   auto Ret = llvm::make_unique<LLVMRustThinLTOData>();
+#endif
 
   // Load each module's summary and merge it into one combined index
   for (int i = 0; i < num_modules; i++) {
@@ -944,6 +962,15 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
         ExportedGUIDs.insert(GUID);
     }
   }
+#if LLVM_VERSION_GE(10, 0)
+  auto isExported = [&](StringRef ModuleIdentifier, ValueInfo VI) {
+    const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier);
+    return (ExportList != Ret->ExportLists.end() &&
+      ExportList->second.count(VI)) ||
+      ExportedGUIDs.count(VI.getGUID());
+  };
+  thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported, isPrevailing);
+#else
   auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
     const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier);
     return (ExportList != Ret->ExportLists.end() &&
@@ -951,6 +978,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
       ExportedGUIDs.count(GUID);
   };
   thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported);
+#endif
 
   return Ret.release();
 }
@@ -1081,7 +1109,11 @@ struct LLVMRustThinLTOBuffer {
 
 extern "C" LLVMRustThinLTOBuffer*
 LLVMRustThinLTOBufferCreate(LLVMModuleRef M) {
+#if LLVM_VERSION_GE(10, 0)
+  auto Ret = std::make_unique<LLVMRustThinLTOBuffer>();
+#else
   auto Ret = llvm::make_unique<LLVMRustThinLTOBuffer>();
+#endif
   {
     raw_string_ostream OS(Ret->data);
     {
index 720928e48e3820869ac6a89db05aee3cb12af572..46e467011b91a4e2fa17ab0d84d203bd80d27016 100644 (file)
@@ -496,9 +496,11 @@ static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) {
   if (isSet(Flags & LLVMRustDIFlags::FlagAppleBlock)) {
     Result |= DINode::DIFlags::FlagAppleBlock;
   }
+#if LLVM_VERSION_LT(10, 0)
   if (isSet(Flags & LLVMRustDIFlags::FlagBlockByrefStruct)) {
     Result |= DINode::DIFlags::FlagBlockByrefStruct;
   }
+#endif
   if (isSet(Flags & LLVMRustDIFlags::FlagVirtual)) {
     Result |= DINode::DIFlags::FlagVirtual;
   }
@@ -825,6 +827,9 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
   llvm::DIGlobalVariableExpression *VarExpr = Builder->createGlobalVariableExpression(
       unwrapDI<DIDescriptor>(Context), Name, LinkageName,
       unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit,
+#if LLVM_VERSION_GE(10, 0)
+      /* isDefined */ true,
+#endif
       InitExpr, unwrapDIPtr<MDNode>(Decl),
 #if LLVM_VERSION_GE(8, 0)
       /* templateParams */ nullptr,
@@ -998,11 +1003,19 @@ inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
 
 extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI,
                                          const char **Ptr) {
+#if LLVM_VERSION_GE(10, 0)
+  auto NameOrErr = (*unwrap(SI))->getName();
+  if (!NameOrErr)
+    report_fatal_error(NameOrErr.takeError());
+  *Ptr = NameOrErr->data();
+  return NameOrErr->size();
+#else
   StringRef Ret;
   if (std::error_code EC = (*unwrap(SI))->getName(Ret))
     report_fatal_error(EC.message());
   *Ptr = Ret.data();
   return Ret.size();
+#endif
 }
 
 // LLVMArrayType function does not support 64-bit ElementCount
@@ -1253,20 +1266,34 @@ extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
                                             LLVMValueRef Dst, unsigned DstAlign,
                                             LLVMValueRef Src, unsigned SrcAlign,
                                             LLVMValueRef Size, bool IsVolatile) {
+#if LLVM_VERSION_GE(10, 0)
+  return wrap(unwrap(B)->CreateMemCpy(
+      unwrap(Dst), MaybeAlign(DstAlign),
+      unwrap(Src), MaybeAlign(SrcAlign),
+      unwrap(Size), IsVolatile));
+#else
   return wrap(unwrap(B)->CreateMemCpy(
       unwrap(Dst), DstAlign,
       unwrap(Src), SrcAlign,
       unwrap(Size), IsVolatile));
+#endif
 }
 
 extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B,
                                              LLVMValueRef Dst, unsigned DstAlign,
                                              LLVMValueRef Src, unsigned SrcAlign,
                                              LLVMValueRef Size, bool IsVolatile) {
+#if LLVM_VERSION_GE(10, 0)
+  return wrap(unwrap(B)->CreateMemMove(
+      unwrap(Dst), MaybeAlign(DstAlign),
+      unwrap(Src), MaybeAlign(SrcAlign),
+      unwrap(Size), IsVolatile));
+#else
   return wrap(unwrap(B)->CreateMemMove(
       unwrap(Dst), DstAlign,
       unwrap(Src), SrcAlign,
       unwrap(Size), IsVolatile));
+#endif
 }
 
 extern "C" LLVMValueRef
@@ -1450,7 +1477,11 @@ struct LLVMRustModuleBuffer {
 
 extern "C" LLVMRustModuleBuffer*
 LLVMRustModuleBufferCreate(LLVMModuleRef M) {
+#if LLVM_VERSION_GE(10, 0)
+  auto Ret = std::make_unique<LLVMRustModuleBuffer>();
+#else
   auto Ret = llvm::make_unique<LLVMRustModuleBuffer>();
+#endif
   {
     raw_string_ostream OS(Ret->data);
     {
index c7aab09edec711ec2c50f439d640c6ed8ff68aec..a7a4520ff95454901edd774117e05a100ad5d48f 100644 (file)
@@ -7,4 +7,4 @@
 fn main() {
 }
 
-// CHECK: define i32 @main(i32, i8**)
+// CHECK: define i32 @main(i32{{( %0)?}}, i8**{{( %1)?}})
index 8769a4cb5e1898f078d07d031939342e3036a4e8..5090f7c378c3662f23071ee6edd9b7ee2ecb1503 100644 (file)
@@ -10,8 +10,9 @@
 // CHECK-LABEL: @cmp_bool
 #[no_mangle]
 pub fn cmp_bool(a: bool, b: bool) -> Ordering {
+// LLVM 10 produces (zext a) + (sext b), but the final lowering is (zext a) - (zext b).
 // CHECK: zext i1
-// CHECK: zext i1
-// CHECK: sub nsw
+// CHECK: {{z|s}}ext i1
+// CHECK: {{sub|add}} nsw
     a.cmp(&b)
 }
index 7d65ad1435e121d8502e03a99897e8e67df98b3f..a89ecdfd3a90153f05d20bc01378c8a461d1cd64 100644 (file)
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
-// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}}, align 4
+// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @2, i32 0, i32 0, i32 0), {{.*}},
 
 #[derive(Copy, Clone)]
-
 // repr(i16) is required for the {low,high}_align_const test
 #[repr(i16)]
 pub enum E<A, B> {
@@ -31,7 +30,7 @@ pub enum E<A, B> {
 // CHECK-LABEL: @static_enum_const
 #[no_mangle]
 pub fn static_enum_const() -> E<i16, i32> {
-   STATIC
+    STATIC
 }
 
 // CHECK-LABEL: @inline_enum_const
@@ -43,15 +42,15 @@ pub fn inline_enum_const() -> E<i8, i16> {
 // CHECK-LABEL: @low_align_const
 #[no_mangle]
 pub fn low_align_const() -> E<i16, [i16; 3]> {
-// Check that low_align_const and high_align_const use the same constant
-// CHECK: i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
+    // Check that low_align_const and high_align_const use the same constant
+    // CHECK: load %"E<i16, [i16; 3]>"*, %"E<i16, [i16; 3]>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, [i16; 3]>"**),
     *&E::A(0)
 }
 
 // CHECK-LABEL: @high_align_const
 #[no_mangle]
 pub fn high_align_const() -> E<i16, i32> {
-// Check that low_align_const and high_align_const use the same constant
-// CHECK: i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
+    // Check that low_align_const and high_align_const use the same constant
+    // CHECK: load %"E<i16, i32>"*, %"E<i16, i32>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, i32>"**),
     *&E::A(0)
 }
index 5c9aa48c0a5d6ba2e0c5e8a1ab042d03857d5e93..3511c7c5185eee446bca720270ab120b1ccb181f 100644 (file)
@@ -73,7 +73,7 @@ pub fn _box(x: Box<i32>) -> Box<i32> {
   x
 }
 
-// CHECK: @struct_return(%S* noalias nocapture sret dereferenceable(32))
+// CHECK: @struct_return(%S* noalias nocapture sret dereferenceable(32){{( %0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
   S {
@@ -117,7 +117,7 @@ pub fn str(_: &[u8]) {
 pub fn trait_borrow(_: &Drop) {
 }
 
-// CHECK: @trait_box({}* noalias nonnull align 1, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}))
+// CHECK: @trait_box({}* noalias nonnull align 1{{( %0)?}}, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
 #[no_mangle]
 pub fn trait_box(_: Box<Drop>) {
 }
index 4cd38e142824ab12a93c7a4d83feedc7db9cce2d..2386fc43007a272e03dc80f96a233b3838b1dbae 100644 (file)
@@ -9,13 +9,13 @@
 #[no_mangle]
 pub fn check_prefetch_read_data(data: &[i8]) {
     unsafe {
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 0, i32 1)
         prefetch_read_data(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 1, i32 1)
         prefetch_read_data(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 2, i32 1)
         prefetch_read_data(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 3, i32 1)
         prefetch_read_data(data.as_ptr(), 3);
     }
 }
@@ -23,13 +23,13 @@ pub fn check_prefetch_read_data(data: &[i8]) {
 #[no_mangle]
 pub fn check_prefetch_write_data(data: &[i8]) {
     unsafe {
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 0, i32 1)
         prefetch_write_data(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 1, i32 1)
         prefetch_write_data(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 2, i32 1)
         prefetch_write_data(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 1)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 3, i32 1)
         prefetch_write_data(data.as_ptr(), 3);
     }
 }
@@ -37,13 +37,13 @@ pub fn check_prefetch_write_data(data: &[i8]) {
 #[no_mangle]
 pub fn check_prefetch_read_instruction(data: &[i8]) {
     unsafe {
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 0, i32 0)
         prefetch_read_instruction(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 1, i32 0)
         prefetch_read_instruction(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 2, i32 0)
         prefetch_read_instruction(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 3, i32 0)
         prefetch_read_instruction(data.as_ptr(), 3);
     }
 }
@@ -51,13 +51,13 @@ pub fn check_prefetch_read_instruction(data: &[i8]) {
 #[no_mangle]
 pub fn check_prefetch_write_instruction(data: &[i8]) {
     unsafe {
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 0, i32 0)
         prefetch_write_instruction(data.as_ptr(), 0);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 1, i32 0)
         prefetch_write_instruction(data.as_ptr(), 1);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 2, i32 0)
         prefetch_write_instruction(data.as_ptr(), 2);
-        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 0)
+        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 3, i32 0)
         prefetch_write_instruction(data.as_ptr(), 3);
     }
 }
index 2050193b61b54ec5144b88e07405ffd87f724302..5050ed149941483a8c585fc0509ba2b6d4938977 100644 (file)
@@ -17,7 +17,7 @@ pub fn naked_empty() {
 // CHECK: Function Attrs: naked
 #[no_mangle]
 #[naked]
-// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+}})
+// CHECK-NEXT: define void @naked_with_args(i{{[0-9]+( %0)?}})
 pub fn naked_with_args(a: isize) {
     // CHECK-NEXT: {{.+}}:
     // CHECK-NEXT: %a = alloca i{{[0-9]+}}
@@ -36,7 +36,7 @@ pub fn naked_with_return() -> isize {
 }
 
 // CHECK: Function Attrs: naked
-// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}})
+// CHECK-NEXT: define i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+( %0)?}})
 #[no_mangle]
 #[naked]
 pub fn naked_with_args_and_return(a: isize) -> isize {
index 99f3464c0768d9b9ad096488fcb706b8523dd712..8fbe712065bde2e8453bb3cae4a2d08cbd15fbf2 100644 (file)
@@ -13,6 +13,6 @@ pub fn helper(_: usize) {
 // CHECK-LABEL: @repeat_take_collect
 #[no_mangle]
 pub fn repeat_take_collect() -> Vec<u8> {
-// CHECK: call void @llvm.memset.p0i8.[[USIZE]](i8* {{(nonnull )?}}align 1 %{{[0-9]+}}, i8 42, [[USIZE]] 100000, i1 false)
+// CHECK: call void @llvm.memset.p0i8.[[USIZE]](i8* {{(nonnull )?}}align 1{{.*}} %{{[0-9]+}}, i8 42, [[USIZE]] 100000, i1 false)
     iter::repeat(42).take(100000).collect()
 }
index b71cb14a4ff084b0ade84fe9fff52db020e55535..886b0dd9e7b08900ca522850e0732eece8cb03a5 100644 (file)
@@ -10,7 +10,7 @@ pub struct Rgb8 { r: u8, g: u8, b: u8 }
 #[repr(transparent)]
 pub struct Rgb8Wrap(Rgb8);
 
-// CHECK: i24 @test_Rgb8Wrap(i24)
+// CHECK: i24 @test_Rgb8Wrap(i24{{( %0)?}})
 #[no_mangle]
 pub extern "sysv64" fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} }
 
@@ -23,6 +23,6 @@ pub union FloatBits {
 #[repr(transparent)]
 pub struct SmallUnion(FloatBits);
 
-// CHECK: i32 @test_SmallUnion(i32)
+// CHECK: i32 @test_SmallUnion(i32{{( %0)?}})
 #[no_mangle]
 pub extern "sysv64" fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} }
index 98a9ff9cbe441da5b50473fe093740cdd359ad78..afea01e9a2d035a75ac2125b7f3d4d8a87e825bb 100644 (file)
@@ -54,7 +54,7 @@ pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} }
 
 pub union UnionF32U32{a:f32, b:u32}
 
-// CHECK: define i32 @test_UnionF32U32(i32)
+// CHECK: define i32 @test_UnionF32U32(i32{{( %0)?}})
 #[no_mangle]
 pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} }
 
index 5d26059644d17a04dd5832cd2ff4bcdaa98c1dac..9db595af63efbd5c8259f267d53c6fd171735ba8 100644 (file)
@@ -6,6 +6,7 @@ const fn f(x: usize) -> usize {
     let mut sum = 0;
     for i in 0..x {
         //~^ ERROR E0015
+        //~| ERROR E0015
         //~| ERROR E0658
         //~| ERROR E0080
         //~| ERROR E0744
index ee37aaa5e13b943c7b715e3d42f24c47e210454a..597fbbf00d53cf8c36fea2a2afa87745b4f83c42 100644 (file)
@@ -8,6 +8,7 @@ fn main() {
     //~| WARN denote infinite loops with
     [(); { for _ in 0usize.. {}; 0}];
     //~^ ERROR calls in constants are limited to constant functions
+    //~| ERROR calls in constants are limited to constant functions
     //~| ERROR `for` is not allowed in a `const`
     //~| ERROR references in constants may only refer to immutable values
     //~| ERROR evaluation of constant value failed
diff --git a/src/test/debuginfo/borrowed-enum-legacy.rs b/src/test/debuginfo/borrowed-enum-legacy.rs
deleted file mode 100644 (file)
index 9a973ed..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-// ignore-tidy-linelength
-// min-lldb-version: 310
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 7.11.90 - 7.12.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:run
-
-// gdb-command:print *the_a_ref
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
-// gdbr-check:$1 = borrowed_enum_legacy::ABC::TheA{x: 0, y: 8970181431921507452}
-
-// gdb-command:print *the_b_ref
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
-// gdbr-check:$2 = borrowed_enum_legacy::ABC::TheB(0, 286331153, 286331153)
-
-// gdb-command:print *univariant_ref
-// gdbg-check:$3 = {{__0 = 4820353753753434}}
-// gdbr-check:$3 = borrowed_enum_legacy::Univariant::TheOnlyCase(4820353753753434)
-
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:print *the_a_ref
-// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
-// lldbr-check:(borrowed_enum_legacy::ABC::TheA) *the_a_ref = TheA { borrowed_enum_legacy::ABC::TheA: 0, borrowed_enum_legacy::ABC::TheB: 8970181431921507452 }
-// lldb-command:print *the_b_ref
-// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
-// lldbr-check:(borrowed_enum_legacy::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 }
-// lldb-command:print *univariant_ref
-// lldbg-check:[...]$2 = TheOnlyCase(4820353753753434)
-// lldbr-check:(borrowed_enum_legacy::Univariant) *univariant_ref = { borrowed_enum_legacy::TheOnlyCase = { = 4820353753753434 } }
-
-#![allow(unused_variables)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-// The first element is to ensure proper alignment, irrespective of the machines word size. Since
-// the size of the discriminant value is machine dependent, this has be taken into account when
-// datatype layout should be predictable as in this case.
-enum ABC {
-    TheA { x: i64, y: i64 },
-    TheB (i64, i32, i32),
-}
-
-// This is a special case since it does not have the implicit discriminant field.
-enum Univariant {
-    TheOnlyCase(i64)
-}
-
-fn main() {
-
-    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
-    // 0b01111100011111000111110001111100 = 2088533116
-    // 0b0111110001111100 = 31868
-    // 0b01111100 = 124
-    let the_a = ABC::TheA { x: 0, y: 8970181431921507452 };
-    let the_a_ref: &ABC = &the_a;
-
-    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
-    // 0b00010001000100010001000100010001 = 286331153
-    // 0b0001000100010001 = 4369
-    // 0b00010001 = 17
-    let the_b = ABC::TheB (0, 286331153, 286331153);
-    let the_b_ref: &ABC = &the_b;
-
-    let univariant = Univariant::TheOnlyCase(4820353753753434);
-    let univariant_ref: &Univariant = &univariant;
-
-    zzz(); // #break
-}
-
-fn zzz() {()}
diff --git a/src/test/debuginfo/generic-enum-with-different-disr-sizes-legacy.rs b/src/test/debuginfo/generic-enum-with-different-disr-sizes-legacy.rs
deleted file mode 100644 (file)
index 4f17e48..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-// ignore-tidy-linelength
-// ignore-lldb: FIXME(#27089)
-// min-lldb-version: 310
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-// gdb-command:run
-
-// gdb-command:print eight_bytes1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Variant1, __0 = 100}, {RUST$ENUM$DISR = Variant1, __0 = 100}}
-// gdbr-check:$1 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(100)
-
-// gdb-command:print four_bytes1
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Variant1, __0 = 101}, {RUST$ENUM$DISR = Variant1, __0 = 101}}
-// gdbr-check:$2 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(101)
-
-// gdb-command:print two_bytes1
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Variant1, __0 = 102}, {RUST$ENUM$DISR = Variant1, __0 = 102}}
-// gdbr-check:$3 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(102)
-
-// gdb-command:print one_byte1
-// gdbg-check:$4 = {{RUST$ENUM$DISR = Variant1, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant1, __0 = 65 'A'}}
-// gdbr-check:$4 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant1(65)
-
-
-// gdb-command:print eight_bytes2
-// gdbg-check:$5 = {{RUST$ENUM$DISR = Variant2, __0 = 100}, {RUST$ENUM$DISR = Variant2, __0 = 100}}
-// gdbr-check:$5 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(100)
-
-// gdb-command:print four_bytes2
-// gdbg-check:$6 = {{RUST$ENUM$DISR = Variant2, __0 = 101}, {RUST$ENUM$DISR = Variant2, __0 = 101}}
-// gdbr-check:$6 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(101)
-
-// gdb-command:print two_bytes2
-// gdbg-check:$7 = {{RUST$ENUM$DISR = Variant2, __0 = 102}, {RUST$ENUM$DISR = Variant2, __0 = 102}}
-// gdbr-check:$7 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(102)
-
-// gdb-command:print one_byte2
-// gdbg-check:$8 = {{RUST$ENUM$DISR = Variant2, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant2, __0 = 65 'A'}}
-// gdbr-check:$8 = generic_enum_with_different_disr_sizes_legacy::Enum::Variant2(65)
-
-// gdb-command:continue
-
-// === LLDB TESTS ==================================================================================
-// lldb-command:run
-
-// lldb-command:print eight_bytes1
-// lldb-check:[...]$0 = Variant1(100)
-// lldb-command:print four_bytes1
-// lldb-check:[...]$1 = Variant1(101)
-// lldb-command:print two_bytes1
-// lldb-check:[...]$2 = Variant1(102)
-// lldb-command:print one_byte1
-// lldb-check:[...]$3 = Variant1('A')
-
-// lldb-command:print eight_bytes2
-// lldb-check:[...]$4 = Variant2(100)
-// lldb-command:print four_bytes2
-// lldb-check:[...]$5 = Variant2(101)
-// lldb-command:print two_bytes2
-// lldb-check:[...]$6 = Variant2(102)
-// lldb-command:print one_byte2
-// lldb-check:[...]$7 = Variant2('A')
-
-// lldb-command:continue
-
-#![allow(unused_variables)]
-#![allow(dead_code)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-// This test case makes sure that we get correct type descriptions for the enum
-// discriminant of different instantiations of the same generic enum type where,
-// dependending on the generic type parameter(s), the discriminant has a
-// different size in memory.
-
-enum Enum<T> {
-    Variant1(T),
-    Variant2(T)
-}
-
-fn main() {
-    // These are ordered for descending size on purpose
-    let eight_bytes1 = Enum::Variant1(100.0f64);
-    let four_bytes1 = Enum::Variant1(101i32);
-    let two_bytes1 = Enum::Variant1(102i16);
-    let one_byte1 = Enum::Variant1(65u8);
-
-    let eight_bytes2 = Enum::Variant2(100.0f64);
-    let four_bytes2 = Enum::Variant2(101i32);
-    let two_bytes2 = Enum::Variant2(102i16);
-    let one_byte2 = Enum::Variant2(65u8);
-
-    zzz(); // #break
-}
-
-fn zzz() { () }
diff --git a/src/test/debuginfo/generic-struct-style-enum-legacy.rs b/src/test/debuginfo/generic-struct-style-enum-legacy.rs
deleted file mode 100644 (file)
index 37a875a..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-// ignore-tidy-linelength
-// min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// gdb-command:set print union on
-// gdb-command:run
-
-// gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
-// gdbr-check:$1 = generic_struct_style_enum_legacy::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
-
-// gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
-// gdbr-check:$2 = generic_struct_style_enum_legacy::Regular::Case2{a: 0, b: 286331153, c: 286331153}
-
-// gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
-// gdbr-check:$3 = generic_struct_style_enum_legacy::Regular::Case3{a: 0, b: 6438275382588823897}
-
-// gdb-command:print univariant
-// gdbg-check:$4 = {{a = -1}}
-// gdbr-check:$4 = generic_struct_style_enum_legacy::Univariant<i32>::TheOnlyCase{a: -1}
-
-
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-use self::Regular::{Case1, Case2, Case3};
-use self::Univariant::TheOnlyCase;
-
-// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
-// substituted with something of size `xx` bits and the same alignment as an integer type of the
-// same size.
-
-// The first element is to ensure proper alignment, irrespective of the machines word size. Since
-// the size of the discriminant value is machine dependent, this has be taken into account when
-// datatype layout should be predictable as in this case.
-enum Regular<T16, T32, T64> {
-    Case1 { a: T64, b: T16, c: T16, d: T16, e: T16},
-    Case2 { a: T64, b: T32, c: T32},
-    Case3 { a: T64, b: T64 }
-}
-
-enum Univariant<T> {
-    TheOnlyCase { a: T }
-}
-
-fn main() {
-
-    // In order to avoid endianness trouble all of the following test values consist of a single
-    // repeated byte. This way each interpretation of the union should look the same, no matter if
-    // this is a big or little endian machine.
-
-    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
-    // 0b01111100011111000111110001111100 = 2088533116
-    // 0b0111110001111100 = 31868
-    // 0b01111100 = 124
-    let case1: Regular<u16, u32, i64> = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 };
-
-    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
-    // 0b00010001000100010001000100010001 = 286331153
-    // 0b0001000100010001 = 4369
-    // 0b00010001 = 17
-    let case2: Regular<i16, u32, i64>  = Case2 { a: 0, b: 286331153, c: 286331153 };
-
-    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
-    // 0b01011001010110010101100101011001 = 1499027801
-    // 0b0101100101011001 = 22873
-    // 0b01011001 = 89
-    let case3: Regular<u16, i32, u64>  = Case3 { a: 0, b: 6438275382588823897 };
-
-    let univariant = TheOnlyCase { a: -1 };
-
-    zzz(); // #break
-}
-
-fn zzz() {()}
diff --git a/src/test/debuginfo/generic-tuple-style-enum-legacy.rs b/src/test/debuginfo/generic-tuple-style-enum-legacy.rs
deleted file mode 100644 (file)
index 452e900..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-// ignore-tidy-linelength
-// min-lldb-version: 310
-// ignore-gdb-version: 7.11.90 - 7.12.9
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:set print union on
-// gdb-command:run
-
-// gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
-// gdbr-check:$1 = generic_tuple_style_enum_legacy::Regular::Case1(0, 31868, 31868, 31868, 31868)
-
-// gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
-// gdbr-check:$2 = generic_tuple_style_enum_legacy::Regular::Case2(0, 286331153, 286331153)
-
-// gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
-// gdbr-check:$3 = generic_tuple_style_enum_legacy::Regular::Case3(0, 6438275382588823897)
-
-// gdb-command:print univariant
-// gdbg-check:$4 = {{__0 = -1}}
-// gdbr-check:$4 = generic_tuple_style_enum_legacy::Univariant<i64>::TheOnlyCase(-1)
-
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:print case1
-// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
-// lldbr-check:(generic_tuple_style_enum_legacy::Regular<u16, u32, u64>::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
-
-// lldb-command:print case2
-// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
-// lldbr-check:(generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case2) case2 = Regular<i16, i32, i64>::Case2 { generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case2: 286331153, generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case3: 286331153 }
-
-// lldb-command:print case3
-// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
-// lldbr-check:(generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case3) case3 = Regular<i16, i32, i64>::Case3 { generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum_legacy::Regular<i16, i32, i64>::Case2: 6438275382588823897 }
-
-// lldb-command:print univariant
-// lldbg-check:[...]$3 = TheOnlyCase(-1)
-// lldbr-check:(generic_tuple_style_enum_legacy::Univariant<i64>) univariant = { generic_tuple_style_enum_legacy::TheOnlyCase = { = -1 } }
-
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-use self::Regular::{Case1, Case2, Case3};
-use self::Univariant::TheOnlyCase;
-
-// NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be
-// substituted with something of size `xx` bits and the same alignment as an integer type of the
-// same size.
-
-// The first element is to ensure proper alignment, irrespective of the machines word size. Since
-// the size of the discriminant value is machine dependent, this has be taken into account when
-// datatype layout should be predictable as in this case.
-enum Regular<T16, T32, T64> {
-    Case1(T64, T16, T16, T16, T16),
-    Case2(T64, T32, T32),
-    Case3(T64, T64)
-}
-
-enum Univariant<T64> {
-    TheOnlyCase(T64)
-}
-
-fn main() {
-
-    // In order to avoid endianness trouble all of the following test values consist of a single
-    // repeated byte. This way each interpretation of the union should look the same, no matter if
-    // this is a big or little endian machine.
-
-    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
-    // 0b01111100011111000111110001111100 = 2088533116
-    // 0b0111110001111100 = 31868
-    // 0b01111100 = 124
-    let case1: Regular<u16, u32, u64> = Case1(0_u64, 31868_u16, 31868_u16, 31868_u16, 31868_u16);
-
-    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
-    // 0b00010001000100010001000100010001 = 286331153
-    // 0b0001000100010001 = 4369
-    // 0b00010001 = 17
-    let case2: Regular<i16, i32, i64> = Case2(0_i64, 286331153_i32, 286331153_i32);
-
-    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
-    // 0b01011001010110010101100101011001 = 1499027801
-    // 0b0101100101011001 = 22873
-    // 0b01011001 = 89
-    let case3: Regular<i16, i32, i64> = Case3(0_i64, 6438275382588823897_i64);
-
-    let univariant = TheOnlyCase(-1_i64);
-
-    zzz(); // #break
-}
-
-fn zzz() { () }
diff --git a/src/test/debuginfo/recursive-struct-legacy.rs b/src/test/debuginfo/recursive-struct-legacy.rs
deleted file mode 100644 (file)
index 9928670..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-// ignore-tidy-linelength
-// ignore-lldb
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 7.11.90 - 7.12.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// gdb-command:run
-
-// gdb-command:print stack_unique.value
-// gdb-check:$1 = 0
-// gdbg-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value
-// gdbr-command:print stack_unique.next.val.value
-// gdb-check:$2 = 1
-
-// gdbg-command:print unique_unique->value
-// gdbr-command:print unique_unique.value
-// gdb-check:$3 = 2
-// gdbg-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
-// gdbr-command:print unique_unique.next.val.value
-// gdb-check:$4 = 3
-
-// gdb-command:print vec_unique[0].value
-// gdb-check:$5 = 6.5
-// gdbg-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value
-// gdbr-command:print vec_unique[0].next.val.value
-// gdb-check:$6 = 7.5
-
-// gdbg-command:print borrowed_unique->value
-// gdbr-command:print borrowed_unique.value
-// gdb-check:$7 = 8.5
-// gdbg-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value
-// gdbr-command:print borrowed_unique.next.val.value
-// gdb-check:$8 = 9.5
-
-// LONG CYCLE
-// gdb-command:print long_cycle1.value
-// gdb-check:$9 = 20
-// gdbg-command:print long_cycle1.next->value
-// gdbr-command:print long_cycle1.next.value
-// gdb-check:$10 = 21
-// gdbg-command:print long_cycle1.next->next->value
-// gdbr-command:print long_cycle1.next.next.value
-// gdb-check:$11 = 22
-// gdbg-command:print long_cycle1.next->next->next->value
-// gdbr-command:print long_cycle1.next.next.next.value
-// gdb-check:$12 = 23
-
-// gdb-command:print long_cycle2.value
-// gdb-check:$13 = 24
-// gdbg-command:print long_cycle2.next->value
-// gdbr-command:print long_cycle2.next.value
-// gdb-check:$14 = 25
-// gdbg-command:print long_cycle2.next->next->value
-// gdbr-command:print long_cycle2.next.next.value
-// gdb-check:$15 = 26
-
-// gdb-command:print long_cycle3.value
-// gdb-check:$16 = 27
-// gdbg-command:print long_cycle3.next->value
-// gdbr-command:print long_cycle3.next.value
-// gdb-check:$17 = 28
-
-// gdb-command:print long_cycle4.value
-// gdb-check:$18 = 29.5
-
-// gdbg-command:print (*****long_cycle_w_anonymous_types).value
-// gdbr-command:print long_cycle_w_anonymous_types.value
-// gdb-check:$19 = 30
-
-// gdbg-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value
-// gdbr-command:print long_cycle_w_anonymous_types.next.val.value
-// gdb-check:$20 = 31
-
-// gdb-command:continue
-
-#![allow(unused_variables)]
-#![feature(box_syntax)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-use self::Opt::{Empty, Val};
-
-enum Opt<T> {
-    Empty,
-    Val { val: T }
-}
-
-struct UniqueNode<T> {
-    next: Opt<Box<UniqueNode<T>>>,
-    value: T
-}
-
-struct LongCycle1<T> {
-    next: Box<LongCycle2<T>>,
-    value: T,
-}
-
-struct LongCycle2<T> {
-    next: Box<LongCycle3<T>>,
-    value: T,
-}
-
-struct LongCycle3<T> {
-    next: Box<LongCycle4<T>>,
-    value: T,
-}
-
-struct LongCycle4<T> {
-    next: Option<Box<LongCycle1<T>>>,
-    value: T,
-}
-
-struct LongCycleWithAnonymousTypes {
-    next: Opt<Box<Box<Box<Box<Box<LongCycleWithAnonymousTypes>>>>>>,
-    value: usize,
-}
-
-// This test case makes sure that recursive structs are properly described. The Node structs are
-// generic so that we can have a new type (that newly needs to be described) for the different
-// cases. The potential problem with recursive types is that the DI generation algorithm gets
-// trapped in an endless loop. To make sure, we actually test this in the different cases, we have
-// to operate on a new type each time, otherwise we would just hit the DI cache for all but the
-// first case.
-
-// The different cases below (stack_*, unique_*, box_*, etc) are set up so that the type description
-// algorithm will enter the type reference cycle that is created by a recursive definition from a
-// different context each time.
-
-// The "long cycle" cases are constructed to span a longer, indirect recursion cycle between types.
-// The different locals will cause the DI algorithm to enter the type reference cycle at different
-// points.
-
-fn main() {
-    let stack_unique: UniqueNode<u16> = UniqueNode {
-        next: Val {
-            val: box UniqueNode {
-                next: Empty,
-                value: 1,
-            }
-        },
-        value: 0,
-    };
-
-    let unique_unique: Box<UniqueNode<u32>> = box UniqueNode {
-        next: Val {
-            val: box UniqueNode {
-                next: Empty,
-                value: 3,
-            }
-        },
-        value: 2,
-    };
-
-    let vec_unique: [UniqueNode<f32>; 1] = [UniqueNode {
-        next: Val {
-            val: box UniqueNode {
-                next: Empty,
-                value: 7.5,
-            }
-        },
-        value: 6.5,
-    }];
-
-    let borrowed_unique: &UniqueNode<f64> = &UniqueNode {
-        next: Val {
-            val: box UniqueNode {
-                next: Empty,
-                value: 9.5,
-            }
-        },
-        value: 8.5,
-    };
-
-    // LONG CYCLE
-    let long_cycle1: LongCycle1<u16> = LongCycle1 {
-        next: box LongCycle2 {
-            next: box LongCycle3 {
-                next: box LongCycle4 {
-                    next: None,
-                    value: 23,
-                },
-                value: 22,
-            },
-            value: 21
-        },
-        value: 20
-    };
-
-    let long_cycle2: LongCycle2<u32> = LongCycle2 {
-        next: box LongCycle3 {
-            next: box LongCycle4 {
-                next: None,
-                value: 26,
-            },
-            value: 25,
-        },
-        value: 24
-    };
-
-    let long_cycle3: LongCycle3<u64> = LongCycle3 {
-        next: box LongCycle4 {
-            next: None,
-            value: 28,
-        },
-        value: 27,
-    };
-
-    let long_cycle4: LongCycle4<f32> = LongCycle4 {
-        next: None,
-        value: 29.5,
-    };
-
-    // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the
-    // `box` chain.
-    let long_cycle_w_anonymous_types = box box box box box LongCycleWithAnonymousTypes {
-        next: Val {
-            val: box box box box box LongCycleWithAnonymousTypes {
-                next: Empty,
-                value: 31,
-            }
-        },
-        value: 30
-    };
-
-    zzz(); // #break
-}
-
-fn zzz() {()}
diff --git a/src/test/debuginfo/struct-style-enum-legacy.rs b/src/test/debuginfo/struct-style-enum-legacy.rs
deleted file mode 100644 (file)
index 1433493..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-// ignore-tidy-linelength
-// min-lldb-version: 310
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 7.11.90 - 7.12.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:set print union on
-// gdb-command:run
-
-// gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
-// gdbr-check:$1 = struct_style_enum_legacy::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868}
-
-// gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
-// gdbr-check:$2 = struct_style_enum_legacy::Regular::Case2{a: 0, b: 286331153, c: 286331153}
-
-// gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}}
-// gdbr-check:$3 = struct_style_enum_legacy::Regular::Case3{a: 0, b: 6438275382588823897}
-
-// gdb-command:print univariant
-// gdbg-check:$4 = {{a = -1}}
-// gdbr-check:$4 = struct_style_enum_legacy::Univariant::TheOnlyCase{a: -1}
-
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:print case1
-// lldbg-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }
-// lldbr-check:(struct_style_enum_legacy::Regular::Case1) case1 = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 }
-
-// lldb-command:print case2
-// lldbg-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 }
-// lldbr-check:(struct_style_enum_legacy::Regular::Case2) case2 = Case2 { struct_style_enum_legacy::Regular::Case1: 0, struct_style_enum_legacy::Regular::Case2: 286331153, struct_style_enum_legacy::Regular::Case3: 286331153 }
-
-// lldb-command:print case3
-// lldbg-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 }
-// lldbr-check:(struct_style_enum_legacy::Regular::Case3) case3 = Case3 { struct_style_enum_legacy::Regular::Case1: 0, struct_style_enum_legacy::Regular::Case2: 6438275382588823897 }
-
-// lldb-command:print univariant
-// lldbg-check:[...]$3 = TheOnlyCase { a: -1 }
-// lldbr-check:(struct_style_enum_legacy::Univariant) univariant = Univariant { struct_style_enum_legacy::TheOnlyCase: TheOnlyCase { a: -1 } }
-
-#![allow(unused_variables)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-use self::Regular::{Case1, Case2, Case3};
-use self::Univariant::TheOnlyCase;
-
-// The first element is to ensure proper alignment, irrespective of the machines word size. Since
-// the size of the discriminant value is machine dependent, this has be taken into account when
-// datatype layout should be predictable as in this case.
-enum Regular {
-    Case1 { a: u64, b: u16, c: u16, d: u16, e: u16},
-    Case2 { a: u64, b: u32, c: u32},
-    Case3 { a: u64, b: u64 }
-}
-
-enum Univariant {
-    TheOnlyCase { a: i64 }
-}
-
-fn main() {
-
-    // In order to avoid endianness trouble all of the following test values consist of a single
-    // repeated byte. This way each interpretation of the union should look the same, no matter if
-    // this is a big or little endian machine.
-
-    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
-    // 0b01111100011111000111110001111100 = 2088533116
-    // 0b0111110001111100 = 31868
-    // 0b01111100 = 124
-    let case1 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 };
-
-    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
-    // 0b00010001000100010001000100010001 = 286331153
-    // 0b0001000100010001 = 4369
-    // 0b00010001 = 17
-    let case2 = Case2 { a: 0, b: 286331153, c: 286331153 };
-
-    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
-    // 0b01011001010110010101100101011001 = 1499027801
-    // 0b0101100101011001 = 22873
-    // 0b01011001 = 89
-    let case3 = Case3 { a: 0, b: 6438275382588823897 };
-
-    let univariant = TheOnlyCase { a: -1 };
-
-    zzz(); // #break
-}
-
-fn zzz() {()}
diff --git a/src/test/debuginfo/tuple-style-enum-legacy.rs b/src/test/debuginfo/tuple-style-enum-legacy.rs
deleted file mode 100644 (file)
index ebc8e03..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-// ignore-tidy-linelength
-// min-lldb-version: 310
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 7.11.90 - 7.12.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:set print union on
-// gdb-command:run
-
-// gdb-command:print case1
-// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, [...]}, {RUST$ENUM$DISR = Case1, [...]}}
-// gdbr-check:$1 = tuple_style_enum_legacy::Regular::Case1(0, 31868, 31868, 31868, 31868)
-
-// gdb-command:print case2
-// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, [...]}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, [...]}}
-// gdbr-check:$2 = tuple_style_enum_legacy::Regular::Case2(0, 286331153, 286331153)
-
-// gdb-command:print case3
-// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, [...]}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}}
-// gdbr-check:$3 = tuple_style_enum_legacy::Regular::Case3(0, 6438275382588823897)
-
-// gdb-command:print univariant
-// gdbg-check:$4 = {{__0 = -1}}
-// gdbr-check:$4 = tuple_style_enum_legacy::Univariant::TheOnlyCase(-1)
-
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:print case1
-// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
-// lldbr-check:(tuple_style_enum_legacy::Regular::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
-
-// lldb-command:print case2
-// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
-// lldbr-check:(tuple_style_enum_legacy::Regular::Case2) case2 = Case2 { tuple_style_enum_legacy::Regular::Case1: 0, tuple_style_enum_legacy::Regular::Case2: 286331153, tuple_style_enum_legacy::Regular::Case3: 286331153 }
-
-// lldb-command:print case3
-// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
-// lldbr-check:(tuple_style_enum_legacy::Regular::Case3) case3 = Case3 { tuple_style_enum_legacy::Regular::Case1: 0, tuple_style_enum_legacy::Regular::Case2: 6438275382588823897 }
-
-// lldb-command:print univariant
-// lldbg-check:[...]$3 = TheOnlyCase(-1)
-// lldbr-check:(tuple_style_enum_legacy::Univariant) univariant = { tuple_style_enum_legacy::TheOnlyCase = { = -1 } }
-
-#![allow(unused_variables)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-use self::Regular::{Case1, Case2, Case3};
-use self::Univariant::TheOnlyCase;
-
-// The first element is to ensure proper alignment, irrespective of the machines word size. Since
-// the size of the discriminant value is machine dependent, this has be taken into account when
-// datatype layout should be predictable as in this case.
-enum Regular {
-    Case1(u64, u16, u16, u16, u16),
-    Case2(u64, u32, u32),
-    Case3(u64, u64)
-}
-
-enum Univariant {
-    TheOnlyCase(i64)
-}
-
-fn main() {
-
-    // In order to avoid endianness trouble all of the following test values consist of a single
-    // repeated byte. This way each interpretation of the union should look the same, no matter if
-    // this is a big or little endian machine.
-
-    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
-    // 0b01111100011111000111110001111100 = 2088533116
-    // 0b0111110001111100 = 31868
-    // 0b01111100 = 124
-    let case1 = Case1(0, 31868, 31868, 31868, 31868);
-
-    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
-    // 0b00010001000100010001000100010001 = 286331153
-    // 0b0001000100010001 = 4369
-    // 0b00010001 = 17
-    let case2 = Case2(0, 286331153, 286331153);
-
-    // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897
-    // 0b01011001010110010101100101011001 = 1499027801
-    // 0b0101100101011001 = 22873
-    // 0b01011001 = 89
-    let case3 = Case3(0, 6438275382588823897);
-
-    let univariant = TheOnlyCase(-1);
-
-    zzz(); // #break
-}
-
-fn zzz() {()}
diff --git a/src/test/debuginfo/unique-enum-legacy.rs b/src/test/debuginfo/unique-enum-legacy.rs
deleted file mode 100644 (file)
index e7c9357..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// ignore-tidy-linelength
-// min-lldb-version: 310
-
-// As long as LLVM 5 and LLVM 6 are supported, we want to test the
-// enum debuginfo fallback mode.  Once those are desupported, this
-// test can be removed, as there is another (non-"legacy") test that
-// tests the new mode.
-// ignore-llvm-version: 7.0 - 9.9.9
-// ignore-gdb-version: 7.11.90 - 7.12.9
-// ignore-gdb-version: 8.2 - 9.9
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:run
-
-// gdb-command:print *the_a
-// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, [...]}}
-// gdbr-check:$1 = unique_enum_legacy::ABC::TheA{x: 0, y: 8970181431921507452}
-
-// gdb-command:print *the_b
-// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, [...]}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}}
-// gdbr-check:$2 = unique_enum_legacy::ABC::TheB(0, 286331153, 286331153)
-
-// gdb-command:print *univariant
-// gdbg-check:$3 = {{__0 = 123234}}
-// gdbr-check:$3 = unique_enum_legacy::Univariant::TheOnlyCase(123234)
-
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:print *the_a
-// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
-// lldbr-check:(unique_enum_legacy::ABC::TheA) *the_a = TheA { unique_enum_legacy::ABC::TheA: 0, unique_enum_legacy::ABC::TheB: 8970181431921507452 }
-
-// lldb-command:print *the_b
-// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
-// lldbr-check:(unique_enum_legacy::ABC::TheB) *the_b = { = 0 = 286331153 = 286331153 }
-
-// lldb-command:print *univariant
-// lldbg-check:[...]$2 = TheOnlyCase(123234)
-// lldbr-check:(unique_enum_legacy::Univariant) *univariant = { unique_enum_legacy::TheOnlyCase = { = 123234 } }
-
-#![allow(unused_variables)]
-#![feature(box_syntax)]
-#![feature(omit_gdb_pretty_printer_section)]
-#![omit_gdb_pretty_printer_section]
-
-// The first element is to ensure proper alignment, irrespective of the machines word size. Since
-// the size of the discriminant value is machine dependent, this has be taken into account when
-// datatype layout should be predictable as in this case.
-enum ABC {
-    TheA { x: i64, y: i64 },
-    TheB (i64, i32, i32),
-}
-
-// This is a special case since it does not have the implicit discriminant field.
-enum Univariant {
-    TheOnlyCase(i64)
-}
-
-fn main() {
-
-    // In order to avoid endianness trouble all of the following test values consist of a single
-    // repeated byte. This way each interpretation of the union should look the same, no matter if
-    // this is a big or little endian machine.
-
-    // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
-    // 0b01111100011111000111110001111100 = 2088533116
-    // 0b0111110001111100 = 31868
-    // 0b01111100 = 124
-    let the_a: Box<_> = box ABC::TheA { x: 0, y: 8970181431921507452 };
-
-    // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
-    // 0b00010001000100010001000100010001 = 286331153
-    // 0b0001000100010001 = 4369
-    // 0b00010001 = 17
-    let the_b: Box<_> = box ABC::TheB (0, 286331153, 286331153);
-
-    let univariant: Box<_> = box Univariant::TheOnlyCase(123234);
-
-    zzz(); // #break
-}
-
-fn zzz() {()}
diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs
new file mode 100644 (file)
index 0000000..3abc90e
--- /dev/null
@@ -0,0 +1,73 @@
+extern "C" {
+    static X: i32;
+}
+
+static Y: i32 = 42;
+
+static mut BAR: *const &'static i32 = [&Y].as_ptr();
+
+static mut FOO: *const &'static i32 = [unsafe { &X }].as_ptr();
+
+fn main() {}
+
+// END RUST SOURCE
+// START rustc.FOO.PromoteTemps.before.mir
+// bb0: {
+// ...
+//     _5 = const Scalar(AllocId(1).0x0) : &i32;
+//     _4 = &(*_5);
+//     _3 = [move _4];
+//     _2 = &_3;
+//     _1 = move _2 as &[&'static i32] (Pointer(Unsize));
+//     _0 = const core::slice::<impl [&'static i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1];
+// }
+// ...
+// bb2: {
+//     StorageDead(_5);
+//     StorageDead(_3);
+//     return;
+// }
+// END rustc.FOO.PromoteTemps.before.mir
+// START rustc.BAR.PromoteTemps.before.mir
+// bb0: {
+// ...
+//     _5 = const Scalar(AllocId(0).0x0) : &i32;
+//     _4 = &(*_5);
+//     _3 = [move _4];
+//     _2 = &_3;
+//     _1 = move _2 as &[&'static i32] (Pointer(Unsize));
+//     _0 = const core::slice::<impl [&'static i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1];
+// }
+// ...
+// bb2: {
+//     StorageDead(_5);
+//     StorageDead(_3);
+//     return;
+// }
+// END rustc.BAR.PromoteTemps.before.mir
+// START rustc.BAR.PromoteTemps.after.mir
+// bb0: {
+// ...
+//     _6 = const BAR::promoted[0];
+//     _2 = &(*_6);
+//     _1 = move _2 as &[&'static i32] (Pointer(Unsize));
+//     _0 = const core::slice::<impl [&'static i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1];
+// }
+// ...
+// bb2: {
+//     return;
+// }
+// END rustc.BAR.PromoteTemps.after.mir
+// START rustc.FOO.PromoteTemps.after.mir
+// bb0: {
+// ...
+//     _6 = const FOO::promoted[0];
+//     _2 = &(*_6);
+//     _1 = move _2 as &[&'static i32] (Pointer(Unsize));
+//     _0 = const core::slice::<impl [&'static i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1];
+// }
+// ...
+// bb2: {
+//     return;
+// }
+// END rustc.FOO.PromoteTemps.after.mir
index d45ffdc87753539fdbcdeab9e5d6f20694a32388..8b48296a5d9111f9a2dd7ff9e4b6300899aed84a 100644 (file)
@@ -3,10 +3,29 @@ fn main() {
 }
 
 // END RUST SOURCE
+// START rustc.main.PromoteTemps.before.mir
+// bb0: {
+//     ...
+//     _3 = const 4i32;
+//     _2 = &_3;
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.before.mir
+// START rustc.main.PromoteTemps.after.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &(*_4);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.after.mir
 // START rustc.main.ConstProp.before.mir
 // bb0: {
 //     ...
-//     _2 = &(promoted[0]: i32);
+//     _4 = const main::promoted[0];
+//     _2 = _4;
 //     _1 = (*_2);
 //     ...
 //}
@@ -14,7 +33,8 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 // bb0: {
 //     ...
-//     _2 = &(promoted[0]: i32);
+//     _4 = const main::promoted[0];
+//     _2 = _4;
 //     _1 = const 4i32;
 //     ...
 // }
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.rs b/src/test/mir-opt/const_prop/ref_deref_project.rs
new file mode 100644 (file)
index 0000000..5808a8b
--- /dev/null
@@ -0,0 +1,41 @@
+fn main() {
+    *(&(4, 5).1);
+}
+
+// END RUST SOURCE
+// START rustc.main.PromoteTemps.before.mir
+// bb0: {
+//     ...
+//     _3 = (const 4i32, const 5i32);
+//     _2 = &(_3.1: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.before.mir
+// START rustc.main.PromoteTemps.after.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &((*_4).1: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.PromoteTemps.after.mir
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &((*_4).1: i32);
+//     _1 = (*_2);
+//     ...
+//}
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+//     ...
+//     _4 = const main::promoted[0];
+//     _2 = &((*_4).1: i32);
+//     _1 = const 5i32;
+//     ...
+// }
+// END rustc.main.ConstProp.after.mir
index d6ff76b34b9b5fb7de1a4249bf2cff203ea48d94..43813e43d3681f9f46fb86c328606fcee2680137 100644 (file)
@@ -6,7 +6,8 @@ fn main() {
 // START rustc.main.ConstProp.before.mir
 //  bb0: {
 //      ...
-//      _4 = &(promoted[0]: [u32; 3]);
+//      _9 = const main::promoted[0];
+//      _4 = _9;
 //      _3 = _4;
 //      _2 = move _3 as &[u32] (Pointer(Unsize));
 //      ...
@@ -24,7 +25,8 @@ fn main() {
 // START rustc.main.ConstProp.after.mir
 //  bb0: {
 //      ...
-//      _4 = &(promoted[0]: [u32; 3]);
+//      _9 = const main::promoted[0];
+//      _4 = _9;
 //      _3 = _4;
 //      _2 = move _3 as &[u32] (Pointer(Unsize));
 //      ...
index 6cdbcfdb0add731d3f89e7858c597f6c0217a7cb..7b78fc339f2c1309d2deb204593d1c8f477a38ed 100644 (file)
@@ -25,11 +25,11 @@ fn foo(x: &i32, y: &i32) -> bool {
 //         ...
 //         Retag(_3);
 //         Retag(_6);
-//         StorageLive(_9);
-//         _9 = (*_3);
-//         StorageLive(_10);
-//         _10 = (*_6);
-//         _0 = Eq(move _9, move _10);
+//         StorageLive(_11);
+//         _11 = (*_3);
+//         StorageLive(_12);
+//         _12 = (*_6);
+//         _0 = Eq(move _11, move _12);
 //         ...
 //         return;
 //     }
index 648856b5523d318df57e3db964064eaef656306c..2c20c35e4a49169f1aece74409fdf1ef2b094f6f 100644 (file)
@@ -65,7 +65,8 @@ fn main() {
 //  }
 //  bb6: { // binding1 and guard
 //      StorageLive(_6);
-//      _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
+//      _11 = const full_tested_match::promoted[0];
+//      _6 = &(((*_11) as Some).0: i32);
 //      _4 = &shallow _2;
 //      StorageLive(_7);
 //      _7 = const guard() -> [return: bb7, unwind: bb1];
index 3a377c32993d5497ef982964a1198944b3c9df4d..7f5e9049b2f77e3acd72cb1bef34b33ef39e377e 100644 (file)
@@ -23,7 +23,7 @@ endif
 endif
 
 all:
-       $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | $(CGREP) librustc_asan
+       $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | $(CGREP) rustc_rt.asan
        # Verify that stack buffer overflow is detected:
        $(TMPDIR)/overflow 2>&1 | $(CGREP) stack-buffer-overflow
        # Verify that variable name is included in address sanitizer report:
diff --git a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile
deleted file mode 100644 (file)
index 9581ac5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# needs-sanitizer-support
-
--include ../tools.mk
-
-# NOTE the address sanitizer only supports x86_64 linux and macOS
-
-ifeq ($(TARGET),x86_64-apple-darwin)
-EXTRA_RUSTFLAG=-C rpath
-else
-ifeq ($(TARGET),x86_64-unknown-linux-gnu)
-EXTRA_RUSTFLAG=
-endif
-endif
-
-all:
-       $(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | $(CGREP) '-Z sanitizer'
diff --git a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/hello.rs b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/hello.rs
deleted file mode 100644 (file)
index e7a11a9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("Hello, world!");
-}
index df8afee15ce073856f3ddf33695eed614a5b379f..2a23f0fe3d4ef1d5465db9e0b7ecf59ac0c44b9c 100644 (file)
@@ -2,4 +2,4 @@
 
 all:
        $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | \
-               $(CGREP) 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` target'
+               $(CGREP) 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target'
index 101e8272ab91e40114655aef9eeed17c77b28fe4..d8598b8ac93f90815226bf832d06c647d8bc6dac 100644 (file)
@@ -7,5 +7,5 @@
 # FIXME(#46126) ThinLTO for libstd broke this test
 
 all:
-       $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) librustc_lsan
+       $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) rustc_rt.lsan
        $(TMPDIR)/leak 2>&1 | $(CGREP) 'detected memory leaks'
index f5787903a2b594e3e6f440e3c6f25f086423da7d..8bc9df1b4baebbaa5d23d2521e1891439df19d97 100644 (file)
@@ -5,7 +5,7 @@
 # only-x86_64
 
 all:
-       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) librustc_msan
+       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) rustc_rt.msan
        $(TMPDIR)/uninit 2>&1 | $(CGREP) use-of-uninitialized-value
-       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args maybeuninit.rs | $(CGREP) librustc_msan
+       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args maybeuninit.rs | $(CGREP) rustc_rt.msan
        $(TMPDIR)/maybeuninit 2>&1 | $(CGREP) use-of-uninitialized-value
index 75d95a4eaf146fc863b68248ee591feb3b3acfcd..c63fe4ddce214aa9874a7d6a8495f608fab4cc4d 100644 (file)
@@ -4,35 +4,28 @@
 // cross-compiled standard libraries.
 #![feature(no_core, optin_builtin_traits)]
 #![no_core]
-
 #![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items, rustc_attrs)]
 
-
-#[repr(C)]
 #[derive(Copy)]
 #[repr(simd)]
 pub struct f32x4(f32, f32, f32, f32);
 
-
-extern {
+extern "C" {
     #[link_name = "llvm.sqrt.v4f32"]
     fn vsqrt(x: f32x4) -> f32x4;
 }
 
 pub fn foo(x: f32x4) -> f32x4 {
-    unsafe {vsqrt(x)}
+    unsafe { vsqrt(x) }
 }
 
-#[repr(C)]
 #[derive(Copy)]
 #[repr(simd)]
 pub struct i32x4(i32, i32, i32, i32);
 
-
-extern {
+extern "C" {
     // _mm_sll_epi32
-    #[cfg(any(target_arch = "x86",
-              target_arch = "x86-64"))]
+    #[cfg(any(target_arch = "x86", target_arch = "x86-64"))]
     #[link_name = "llvm.x86.sse2.psll.d"]
     fn integer(a: i32x4, b: i32x4) -> i32x4;
 
@@ -48,22 +41,24 @@ pub fn foo(x: f32x4) -> f32x4 {
     // just some substitute foreign symbol, not an LLVM intrinsic; so
     // we still get type checking, but not as detailed as (ab)using
     // LLVM.
-    #[cfg(not(any(target_arch = "x86",
-                  target_arch = "x86-64",
-                  target_arch = "arm",
-                  target_arch = "aarch64")))]
+    #[cfg(not(any(
+        target_arch = "x86",
+        target_arch = "x86-64",
+        target_arch = "arm",
+        target_arch = "aarch64"
+    )))]
     fn integer(a: i32x4, b: i32x4) -> i32x4;
 }
 
 pub fn bar(a: i32x4, b: i32x4) -> i32x4 {
-    unsafe {integer(a, b)}
+    unsafe { integer(a, b) }
 }
 
 #[lang = "sized"]
-pub trait Sized { }
+pub trait Sized {}
 
 #[lang = "copy"]
-pub trait Copy { }
+pub trait Copy {}
 
 impl Copy for f32 {}
 impl Copy for i32 {}
@@ -77,4 +72,6 @@ pub mod marker {
 
 #[macro_export]
 #[rustc_builtin_macro]
-macro_rules! Copy { () => () }
+macro_rules! Copy {
+    () => {};
+}
index c5de87e8e723072b85d249e6f3baca80a3e28dd2..ac9c20a57e5a4e005e0d665a2cd65f2a7d4eab8e 100644 (file)
@@ -2,3 +2,6 @@
 
 #[no_mangle]
 pub extern fn foo() {}
+
+#[no_mangle]
+pub static FOO: u64 = 42;
index 7b6fc7a45682b2b96bee0f99af97c2662506fb14..72db3356f5635146259f438b8019973eda1c906c 100644 (file)
@@ -9,16 +9,20 @@ console.log('exports', list);
 
 const my_exports = {};
 let nexports = 0;
+
 for (const entry of list) {
-  if (entry.kind !== 'function')
-    continue;
-  my_exports[entry.name] = true;
-  nexports += 1;
+  if (entry.kind == 'function'){
+    nexports += 1;
+  }
+  my_exports[entry.name] = entry.kind;
 }
 
-if (my_exports.foo === undefined)
+if (my_exports.foo != "function")
   throw new Error("`foo` wasn't defined");
 
+if (my_exports.FOO != "global")
+  throw new Error("`FOO` wasn't defined");
+
 if (my_exports.main === undefined) {
   if (nexports != 1)
     throw new Error("should only have one function export");
index 505d6ee769ab3040c364f7f6830cac26c405f7ac..9ccc5d7882eb8d5e781d7bef316eeb20c3b386ba 100644 (file)
@@ -1,15 +1,42 @@
+// ignore-tidy-linelength
+
 #![crate_name = "foo"]
 #![feature(doc_cfg)]
 
-// @has 'foo/index.html'
-// @!has '-' '//*[@class="stab portability"]' 'feature="sync" and'
-// @has '-' '//*[@class="stab portability"]' 'feature="sync"'
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
 #[doc(cfg(feature = "sync"))]
 #[doc(cfg(feature = "sync"))]
 pub struct Foo;
 
+// @has 'foo/bar/struct.Bar.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
 #[doc(cfg(feature = "sync"))]
 pub mod bar {
     #[doc(cfg(feature = "sync"))]
     pub struct Bar;
 }
+
+// @has 'foo/baz/struct.Baz.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.'
+#[doc(cfg(all(feature = "sync", feature = "send")))]
+pub mod baz {
+    #[doc(cfg(feature = "sync"))]
+    pub struct Baz;
+}
+
+// @has 'foo/qux/struct.Qux.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.'
+#[doc(cfg(feature = "sync"))]
+pub mod qux {
+    #[doc(cfg(all(feature = "sync", feature = "send")))]
+    pub struct Qux;
+}
+
+// @has 'foo/quux/struct.Quux.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" and foo and bar only.'
+#[doc(cfg(all(feature = "sync", feature = "send", foo)))]
+pub mod quux {
+    #[doc(cfg(all(feature = "send", feature = "sync", bar)))]
+    pub struct Quux;
+}
diff --git a/src/test/rustdoc/issue-46380.rs b/src/test/rustdoc/issue-46380.rs
deleted file mode 100644 (file)
index 8837a6b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-// compile-flags: --document-private-items
-
-// @has issue_46380/struct.Hidden.html
-#[doc(hidden)]
-pub struct Hidden;
diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs
new file mode 100644 (file)
index 0000000..d69b943
--- /dev/null
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-private-items --document-hidden-items
+
+// @has issue_67851_both/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_both/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs
new file mode 100644 (file)
index 0000000..8a3cafe
--- /dev/null
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-hidden-items
+
+// @has issue_67851_hidden/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_hidden/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs
new file mode 100644 (file)
index 0000000..4e3cd83
--- /dev/null
@@ -0,0 +1,6 @@
+// @!has issue_67851_neither/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_neither/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs
new file mode 100644 (file)
index 0000000..8addc7f
--- /dev/null
@@ -0,0 +1,8 @@
+// compile-flags: --document-private-items
+
+// @!has issue_67851_private/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_private/struct.Private.html
+struct Private;
index ee14d71573041bbf88ab0406a5d4a21c30a52f15..725c350fe4e227d8071198e8b4c453b22af13e8e 100644 (file)
@@ -1,17 +1,17 @@
 #![feature(box_syntax, plugin, plugin_registrar, rustc_private)]
 #![crate_type = "dylib"]
 
-#[macro_use] extern crate rustc;
-#[macro_use] extern crate rustc_session;
 extern crate rustc_driver;
 extern crate rustc_hir;
+#[macro_use] extern crate rustc_lint;
+#[macro_use] extern crate rustc_session;
 extern crate rustc_span;
 extern crate syntax;
 
-use rustc::hir::intravisit;
+use rustc_hir::intravisit;
 use rustc_hir as hir;
 use rustc_hir::Node;
-use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
 use rustc_driver::plugin::Registry;
 use rustc_span::source_map;
 use syntax::print::pprust;
index 4ccbe8a3c0eb0f6cbf2c7c229cd074315e5f894c..98963a180c8502be1618accb24629d599a24fc3b 100644 (file)
@@ -2,14 +2,14 @@
 
 #![feature(plugin_registrar, rustc_private)]
 #![feature(box_syntax)]
-#[macro_use] extern crate rustc;
-#[macro_use] extern crate rustc_session;
 extern crate rustc_driver;
 extern crate rustc_hir;
 extern crate rustc_span;
+#[macro_use] extern crate rustc_lint;
+#[macro_use] extern crate rustc_session;
 extern crate syntax;
 
-use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass};
+use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass};
 use rustc_driver::plugin::Registry;
 use rustc_span::symbol::Symbol;
 use syntax::attr;
index 360bffaa46f2bfb3b6d0350a5ee6971536373808..589477da62527d0a2dc662cc5d29967cffdac8f7 100644 (file)
@@ -3,14 +3,14 @@
 #![feature(plugin_registrar, rustc_private)]
 #![feature(box_syntax)]
 
-#[macro_use] extern crate rustc;
-#[macro_use] extern crate rustc_session;
 extern crate rustc_driver;
 extern crate rustc_hir;
+#[macro_use] extern crate rustc_lint;
+#[macro_use] extern crate rustc_session;
 extern crate rustc_span;
 extern crate syntax;
 
-use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray};
+use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray};
 use rustc_driver::plugin::Registry;
 use rustc_span::symbol::Symbol;
 use syntax::attr;
index 786c699947e47080c39c0757b1adae50bb3320df..2cc288c21e6978f7ad95302c742d54e54cfb4590 100644 (file)
@@ -4,12 +4,12 @@
 #![feature(box_syntax, rustc_private)]
 
 // Load rustc as a plugin to get macros.
-#[macro_use] extern crate rustc;
-#[macro_use] extern crate rustc_session;
 extern crate rustc_driver;
 extern crate rustc_hir;
+#[macro_use] extern crate rustc_lint;
+#[macro_use] extern crate rustc_session;
 
-use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
+use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
 use rustc_driver::plugin::Registry;
 
 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
index bb96dba21fc2ee6c92594c5601f5be1ec4da8515..c704701cc480b4573386c81daf229b9d9ed69fdc 100644 (file)
@@ -6,11 +6,11 @@
 extern crate syntax;
 
 // Load rustc as a plugin to get macros
-#[macro_use] extern crate rustc;
-#[macro_use] extern crate rustc_session;
 extern crate rustc_driver;
+#[macro_use] extern crate rustc_lint;
+#[macro_use] extern crate rustc_session;
 
-use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
+use rustc_lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
 use rustc_driver::plugin::Registry;
 use syntax::ast;
 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
index 170490981379794306608a1f633e6b62db4a6511..fa545ddc2bc6be860b82bd6e063c7cba6dd66cf1 100644 (file)
@@ -4,11 +4,11 @@
 extern crate syntax;
 
 // Load rustc as a plugin to get macros
-#[macro_use] extern crate rustc;
-#[macro_use] extern crate rustc_session;
 extern crate rustc_driver;
+#[macro_use] extern crate rustc_lint;
+#[macro_use] extern crate rustc_session;
 
-use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
 use rustc_driver::plugin::Registry;
 use syntax::ast;
 declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
index 7ce2a1dd9a62dfe780d8d69d15c0b5733fe8459e..8d9cbe45fc69686fc47814f0fd97e9280d91dd46 100644 (file)
@@ -6,9 +6,8 @@
 extern crate rustc;
 extern crate rustc_session;
 
-use rustc::lint::{LintArray, LintPass};
-use rustc::{declare_lint_pass, impl_lint_pass};
-use rustc_session::declare_lint;
+use rustc_session::lint::{LintArray, LintPass};
+use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 
 declare_lint! {
     pub TEST_LINT,
index ad8670c6c83c8b92bbec2074738abbad9e608608..39ac0019aac239063452504f5476a7a6f7485775 100644 (file)
@@ -1,5 +1,5 @@
 error: implementing `LintPass` by hand
-  --> $DIR/lint_pass_impl_without_macro.rs:21:6
+  --> $DIR/lint_pass_impl_without_macro.rs:20:6
    |
 LL | impl LintPass for Foo {
    |      ^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(rustc::lint_pass_impl_without_macro)]
    = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead
 
 error: implementing `LintPass` by hand
-  --> $DIR/lint_pass_impl_without_macro.rs:31:14
+  --> $DIR/lint_pass_impl_without_macro.rs:30:14
    |
 LL |         impl LintPass for Custom {
    |              ^^^^^^^^
index 569f04d18ffd16cb689f58e8344b89a7cba71bd8..35ddab95831db0ee18964ec9f5537e56fb62d6ac 100644 (file)
@@ -10,6 +10,8 @@ fn lintme() { } //~ ERROR item is named 'lintme'
 
 #[allow(test_lint)]
 //~^ ERROR allow(test_lint) overruled by outer forbid(test_lint)
+//~| ERROR allow(test_lint) overruled by outer forbid(test_lint)
+//~| ERROR allow(test_lint) overruled by outer forbid(test_lint)
 pub fn main() {
     lintme();
 }
index c0de1feee7d46cf92d2ec5441ff7f68a2cce56a4..f93a0a0de5377d17b38743a427d3672e92fc6b73 100644 (file)
@@ -7,6 +7,15 @@ LL | #![forbid(test_lint)]
 LL | #[allow(test_lint)]
    |         ^^^^^^^^^ overruled by previous forbid
 
+error[E0453]: allow(test_lint) overruled by outer forbid(test_lint)
+  --> $DIR/lint-plugin-forbid-attrs.rs:11:9
+   |
+LL | #![forbid(test_lint)]
+   |           --------- `forbid` level set here
+...
+LL | #[allow(test_lint)]
+   |         ^^^^^^^^^ overruled by previous forbid
+
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin-forbid-attrs.rs:5:1
    |
@@ -27,6 +36,15 @@ note: lint level defined here
 LL | #![forbid(test_lint)]
    |           ^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error[E0453]: allow(test_lint) overruled by outer forbid(test_lint)
+  --> $DIR/lint-plugin-forbid-attrs.rs:11:9
+   |
+LL | #![forbid(test_lint)]
+   |           --------- `forbid` level set here
+...
+LL | #[allow(test_lint)]
+   |         ^^^^^^^^^ overruled by previous forbid
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 82313f6912067acac44e02d88eef7c375293806d..695d3aef169051656b4c5ab6c63b2d868f6a25c8 100644 (file)
@@ -8,6 +8,8 @@
 fn lintme() { } //~ ERROR item is named 'lintme'
 
 #[allow(test_lint)] //~ ERROR allow(test_lint) overruled by outer forbid(test_lint)
+                    //~| ERROR allow(test_lint) overruled by outer forbid(test_lint)
+                    //~| ERROR allow(test_lint) overruled by outer forbid(test_lint)
 pub fn main() {
     lintme();
 }
index f189efbf61d859b96ebb2443e5fe736c15568260..0302ec84d56206f3c9683759075569e667af753e 100644 (file)
@@ -6,6 +6,14 @@ LL | #[allow(test_lint)]
    |
    = note: `forbid` lint level was set on command line
 
+error[E0453]: allow(test_lint) overruled by outer forbid(test_lint)
+  --> $DIR/lint-plugin-forbid-cmdline.rs:10:9
+   |
+LL | #[allow(test_lint)]
+   |         ^^^^^^^^^ overruled by previous forbid
+   |
+   = note: `forbid` lint level was set on command line
+
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin-forbid-cmdline.rs:6:1
    |
@@ -22,6 +30,14 @@ LL | fn lintme() { }
    |
    = note: requested on the command line with `-F test-lint`
 
-error: aborting due to 2 previous errors
+error[E0453]: allow(test_lint) overruled by outer forbid(test_lint)
+  --> $DIR/lint-plugin-forbid-cmdline.rs:10:9
+   |
+LL | #[allow(test_lint)]
+   |         ^^^^^^^^^ overruled by previous forbid
+   |
+   = note: `forbid` lint level was set on command line
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 825a341c5d3273fb0654571899ce92e1dd7456ee..2f1c29ea7b83219cf75a7d0df684b771ddc6740a 100644 (file)
@@ -2,6 +2,10 @@ warning: lint name `test_lint` is deprecated and does not have an effect anymore
    |
    = note: requested on the command line with `-A test_lint`
 
+warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+   |
+   = note: requested on the command line with `-A test_lint`
+
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-tool-cmdline-allow.rs:7:1
    |
@@ -10,6 +14,10 @@ LL | #![plugin(lint_tool_test)]
    |
    = note: `#[warn(deprecated)]` on by default
 
+warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+   |
+   = note: requested on the command line with `-A test_lint`
+
 warning: item is named 'lintme'
   --> $DIR/lint-tool-cmdline-allow.rs:9:1
    |
@@ -18,3 +26,7 @@ LL | fn lintme() {}
    |
    = note: `#[warn(clippy::test_lint)]` on by default
 
+warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+   |
+   = note: requested on the command line with `-A test_lint`
+
index 216a8cb95e31edba68be398a6ec31c4a48275245..f92bcd213b844a272914c36cf2ceea10bb58ab0f 100644 (file)
@@ -8,9 +8,12 @@
 #![allow(dead_code)]
 #![cfg_attr(foo, warn(test_lint))]
 //~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
-//~^^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
 #![deny(clippy_group)]
 //~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
 
 fn lintme() { } //~ ERROR item is named 'lintme'
 
@@ -25,6 +28,8 @@ fn lintmetoo() { } //~ ERROR item is named 'lintmetoo'
 
 #[allow(test_group)]
 //~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
 #[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
 fn hello() {
     fn lintmetoo() { }
index d4031a780c3d47e0d3e8ed0adf42eafeecada0b2..809b9ac16205dba995214363e3795e885632ab93 100644 (file)
@@ -7,19 +7,19 @@ LL | #![cfg_attr(foo, warn(test_lint))]
    = note: `#[warn(renamed_and_removed_lints)]` on by default
 
 warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
-  --> $DIR/lint-tool-test.rs:12:9
+  --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
 
 warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
-  --> $DIR/lint-tool-test.rs:26:9
+  --> $DIR/lint-tool-test.rs:29:9
    |
 LL | #[allow(test_group)]
    |         ^^^^^^^^^^ help: change it to: `clippy::test_group`
 
 warning: unknown lint: `this_lint_does_not_exist`
-  --> $DIR/lint-tool-test.rs:28:8
+  --> $DIR/lint-tool-test.rs:33:8
    |
 LL | #[deny(this_lint_does_not_exist)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,6 +32,18 @@ warning: lint name `test_lint` is deprecated and may not have an effect in the f
 LL | #![cfg_attr(foo, warn(test_lint))]
    |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
 
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+  --> $DIR/lint-tool-test.rs:13:9
+   |
+LL | #![deny(clippy_group)]
+   |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
+
+warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+  --> $DIR/lint-tool-test.rs:29:9
+   |
+LL | #[allow(test_group)]
+   |         ^^^^^^^^^^ help: change it to: `clippy::test_group`
+
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-tool-test.rs:6:1
    |
@@ -40,31 +52,49 @@ LL | #![plugin(lint_tool_test)]
    |
    = note: `#[warn(deprecated)]` on by default
 
+warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+  --> $DIR/lint-tool-test.rs:9:23
+   |
+LL | #![cfg_attr(foo, warn(test_lint))]
+   |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
+
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+  --> $DIR/lint-tool-test.rs:13:9
+   |
+LL | #![deny(clippy_group)]
+   |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
+
 error: item is named 'lintme'
-  --> $DIR/lint-tool-test.rs:15:1
+  --> $DIR/lint-tool-test.rs:18:1
    |
 LL | fn lintme() { }
    | ^^^^^^^^^^^^^^^
    |
 note: lint level defined here
-  --> $DIR/lint-tool-test.rs:12:9
+  --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^
    = note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]`
 
 error: item is named 'lintmetoo'
-  --> $DIR/lint-tool-test.rs:23:5
+  --> $DIR/lint-tool-test.rs:26:5
    |
 LL |     fn lintmetoo() { }
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: lint level defined here
-  --> $DIR/lint-tool-test.rs:12:9
+  --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^
    = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]`
 
+warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+  --> $DIR/lint-tool-test.rs:29:9
+   |
+LL | #[allow(test_group)]
+   |         ^^^^^^^^^^ help: change it to: `clippy::test_group`
+
 error: aborting due to 2 previous errors
 
index 35fb662f63aeecb18d6e5b28d65f820340c99aaf..024d14e21b5fd2efe9185d3b67b162e76d720dce 100644 (file)
@@ -3,7 +3,7 @@ trait Foo {
 }
 
 const X: i32 = <i32>::ID;
-//~^ ERROR no associated item named `ID` found for type `i32`
+//~^ ERROR no associated item named `ID` found
 
 fn main() {
     assert_eq!(1, X);
index 23916a3ba440c0919623229701881fea5b416ece..3a70e7d43c25ef96bc7dd859b2e635aef659af06 100644 (file)
@@ -5,9 +5,13 @@ LL |     const C: usize;
    |     --------------- required by `A::C`
 LL | 
 LL |     fn f() -> ([u8; A::C], [u8; A::C]);
-   |                     ^^^^ cannot infer type
+   |                     ^^^^
+   |                     |
+   |                     cannot infer type
+   |                     help: use the fully qualified path to an implementation: `<Type as A>::C`
    |
    = note: cannot resolve `_: A`
+   = note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
 
 error[E0283]: type annotations needed
   --> $DIR/issue-63496.rs:4:33
@@ -16,9 +20,13 @@ LL |     const C: usize;
    |     --------------- required by `A::C`
 LL | 
 LL |     fn f() -> ([u8; A::C], [u8; A::C]);
-   |                                 ^^^^ cannot infer type
+   |                                 ^^^^
+   |                                 |
+   |                                 cannot infer type
+   |                                 help: use the fully qualified path to an implementation: `<Type as A>::C`
    |
    = note: cannot resolve `_: A`
+   = note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
 
 error: aborting due to 2 previous errors
 
index 5a62b9736dedda5e145ba823f43c3d5da016e912..6f89530eac93306b3fe065ffc49999b061c296ba 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no variant or associated item named `mispellable` found for type `Enum` in the current scope
+error[E0599]: no variant or associated item named `mispellable` found for enum `Enum` in the current scope
   --> $DIR/associated-item-enum.rs:17:11
    |
 LL | enum Enum { Variant }
@@ -10,7 +10,7 @@ LL |     Enum::mispellable();
    |           variant or associated item not found in `Enum`
    |           help: there is a method with a similar name: `misspellable`
 
-error[E0599]: no variant or associated item named `mispellable_trait` found for type `Enum` in the current scope
+error[E0599]: no variant or associated item named `mispellable_trait` found for enum `Enum` in the current scope
   --> $DIR/associated-item-enum.rs:18:11
    |
 LL | enum Enum { Variant }
@@ -19,7 +19,7 @@ LL | enum Enum { Variant }
 LL |     Enum::mispellable_trait();
    |           ^^^^^^^^^^^^^^^^^ variant or associated item not found in `Enum`
 
-error[E0599]: no variant or associated item named `MISPELLABLE` found for type `Enum` in the current scope
+error[E0599]: no variant or associated item named `MISPELLABLE` found for enum `Enum` in the current scope
   --> $DIR/associated-item-enum.rs:19:11
    |
 LL | enum Enum { Variant }
index 9c825d593d3e499ef64f9460c2c25d67b613121c..ddabd552897a8e79eb25480f014522732e2ead71 100644 (file)
@@ -13,9 +13,13 @@ error[E0283]: type annotations needed
 LL |     const X: usize;
    |     --------------- required by `Bar::X`
 LL |     fn return_n(&self) -> [u8; Bar::X];
-   |                                ^^^^^^ cannot infer type
+   |                                ^^^^^^
+   |                                |
+   |                                cannot infer type
+   |                                help: use the fully qualified path to an implementation: `<Type as Bar>::X`
    |
    = note: cannot resolve `_: Bar`
+   = note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
 
 error: aborting due to 2 previous errors
 
index 64bc9eeec25293c91bc51f5042cb702ec0d8f886..65ca017e2f269cf5df0c165671c2dba048d61dad 100644 (file)
@@ -157,10 +157,13 @@ trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
 //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
 //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
+//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
 //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
+//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
 //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
+//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
 //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
 trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
index caecc5e85f6e7312763a263d53b852605dbd3c44..defa62994e9e12a47a4b2bb11cb4dc9040f44588 100644 (file)
@@ -531,7 +531,23 @@ LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:160:46
+  --> $DIR/duplicate.rs:158:46
+   |
+LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:161:46
+   |
+LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
+   |                                  ----------  ^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:161:46
    |
 LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
    |                                  ----------  ^^^^^^^^^^ re-bound here
@@ -539,7 +555,15 @@ LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:162:49
+  --> $DIR/duplicate.rs:164:49
+   |
+LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
+   |                                  -------------  ^^^^^^^^^^^^^ re-bound here
+   |                                  |
+   |                                  `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
+  --> $DIR/duplicate.rs:164:49
    |
 LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
    |                                  -------------  ^^^^^^^^^^^^^ re-bound here
@@ -547,7 +571,7 @@ LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:164:43
+  --> $DIR/duplicate.rs:167:43
    |
 LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
    |                               ----------  ^^^^^^^^^^ re-bound here
@@ -555,7 +579,7 @@ LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
    |                               `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:166:43
+  --> $DIR/duplicate.rs:169:43
    |
 LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
    |                               ----------  ^^^^^^^^^^ re-bound here
@@ -563,7 +587,7 @@ LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
    |                               `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:168:46
+  --> $DIR/duplicate.rs:171:46
    |
 LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
    |                               -------------  ^^^^^^^^^^^^^ re-bound here
@@ -571,7 +595,7 @@ LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
    |                               `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:171:40
+  --> $DIR/duplicate.rs:174:40
    |
 LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -579,7 +603,7 @@ LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:175:44
+  --> $DIR/duplicate.rs:178:44
    |
 LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                ----------  ^^^^^^^^^^ re-bound here
@@ -587,7 +611,7 @@ LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified
-  --> $DIR/duplicate.rs:179:43
+  --> $DIR/duplicate.rs:182:43
    |
 LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -667,40 +691,40 @@ LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    |                                           ^^^^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/duplicate.rs:171:28
+  --> $DIR/duplicate.rs:174:28
    |
 LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                            ^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/duplicate.rs:171:40
+  --> $DIR/duplicate.rs:174:40
    |
 LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                                        ^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/duplicate.rs:175:32
+  --> $DIR/duplicate.rs:178:32
    |
 LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                ^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/duplicate.rs:175:44
+  --> $DIR/duplicate.rs:178:44
    |
 LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                            ^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/duplicate.rs:179:28
+  --> $DIR/duplicate.rs:182:28
    |
 LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
    |                            ^^^^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/duplicate.rs:179:43
+  --> $DIR/duplicate.rs:182:43
    |
 LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
    |                                           ^^^^^^^^^^^^^
 
-error: aborting due to 93 previous errors
+error: aborting due to 96 previous errors
 
index 239f801c39d4e0f6b26726b2d2b9d9f89c39d0ca..dc3a4752fb1f7205613e8d4fbf375002c3b44317 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/dont-suggest-missing-await.rs:14:18
    |
+LL | async fn make_u32() -> u32 {
+   |                        --- the `Output` of this `async fn`'s found opaque type
+...
 LL |         take_u32(x)
    |                  ^ expected `u32`, found opaque type
    |
index 155c5cc8ea13796a9a690453155bf39549b7e0e6..d6828172928dd7792826fbd92c8ee3ed18c23d72 100644 (file)
@@ -3,6 +3,9 @@ error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::
    |
 LL | fn is_qux<T: Qux>(t: T) { }
    |    ------    --- required by this bound in `is_qux`
+LL | 
+LL | async fn bar() {
+   |                - within this `impl std::future::Future`
 ...
 LL |     is_qux(bar());
    |     ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo`
index 2c7a5cd378fc2d4e4723d32bcbb3d5811b8887e0..b12d7bccecead8c2f13b6f212ceeaf03773a433e 100644 (file)
@@ -8,6 +8,7 @@ impl<T> Trait<'_, '_> for T { }
 
 async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
     //~^ ERROR ambiguous lifetime bound
+    //~| ERROR ambiguous lifetime bound
     (a, b)
 }
 
index 59d7728d41c4cfa2a67d27c3495a8aaa7611f8bf..f9a1b4b3394c107f0759c8aca9a96f7f5a70fd12 100644 (file)
@@ -6,5 +6,13 @@ LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'
    |
    = help: add #![feature(member_constraints)] to the crate attributes to enable
 
-error: aborting due to previous error
+error: ambiguous lifetime bound in `impl Trait`
+  --> $DIR/ret-impl-trait-no-fg.rs:9:64
+   |
+LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
+   |                                                                ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
+   |
+   = help: add #![feature(member_constraints)] to the crate attributes to enable
+
+error: aborting due to 2 previous errors
 
index 1efc20082a08aef29ee62786d14ed323c2eb63a3..2703cec581ddfe39fcde31558a2017c8544fa6e6 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await-closure.rs:16:18
    |
+LL | async fn make_u32() -> u32 {
+   |                        --- the `Output` of this `async fn`'s found opaque type
+...
 LL |         take_u32(x)
    |                  ^
    |                  |
index 7ab024434b2bf86250d4c2db32263b20e8259be3..6ac05a87aae8096e8e75f4798fa4ff9cd398dac9 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:13:14
    |
+LL | async fn make_u32() -> u32 {
+   |                        --- the `Output` of this `async fn`'s found opaque type
+...
 LL |     take_u32(x)
    |              ^
    |              |
@@ -13,6 +16,9 @@ LL |     take_u32(x)
 error[E0308]: mismatched types
   --> $DIR/suggest-missing-await.rs:23:5
    |
+LL | async fn dummy() {}
+   |                  - the `Output` of this `async fn`'s found opaque type
+...
 LL |     dummy()
    |     ^^^^^^^ expected `()`, found opaque type
    |
index 79c043b701ddb249c69a3bea60a09c1a2eca3527..d313691b388577ffb80a60888bf95c513ad5a3aa 100644 (file)
@@ -8,8 +8,16 @@ async fn bar<T>() -> () {}
 async fn foo() {
     bar().await;
     //~^ ERROR type inside `async fn` body must be known in this context
+    //~| ERROR type inside `async fn` body must be known in this context
+    //~| ERROR type inside `async fn` body must be known in this context
     //~| NOTE cannot infer type for type parameter `T`
+    //~| NOTE cannot infer type for type parameter `T`
+    //~| NOTE cannot infer type for type parameter `T`
+    //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE the type is part of the `async fn` body because of this `await`
+    //~| NOTE the type is part of the `async fn` body because of this `await`
+    //~| NOTE in this expansion of desugaring of `await`
+    //~| NOTE in this expansion of desugaring of `await`
     //~| NOTE in this expansion of desugaring of `await`
 }
 fn main() {}
index 3ffdb8ce6b9a1634b2c345e7190b4cb8c016024c..6b9e960ca1ae69d27e8149a9e905f81068a156bf 100644 (file)
@@ -10,6 +10,30 @@ note: the type is part of the `async fn` body because of this `await`
 LL |     bar().await;
    |     ^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^^^^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+   |
+note: the type is part of the `async fn` body because of this `await`
+  --> $DIR/unresolved_type_param.rs:9:5
+   |
+LL |     bar().await;
+   |     ^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0698`.
index 3d0cf9154fbca1e4ad6345f6bfc567786e4d6cf9..e01dc4dfa49be5c45fa8908c9e31fb1a5aaef7d2 100644 (file)
@@ -11,4 +11,5 @@
 
 #[renamed_attr] //~ ERROR cannot use an explicitly registered attribute through an import
 #[renamed_tool::attr] //~ ERROR cannot use a tool module through an import
+                      //~| ERROR cannot use a tool module through an import
 fn main() {}
index 6f280c8e0d931ab2e83325c8a377644e1858256a..59f5a8620ab11fb742ed42302717074b9f452fff 100644 (file)
@@ -22,5 +22,17 @@ note: the tool module imported here
 LL | use tool as renamed_tool; // OK
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: cannot use a tool module through an import
+  --> $DIR/register-attr-tool-import.rs:13:3
+   |
+LL | #[renamed_tool::attr]
+   |   ^^^^^^^^^^^^
+   |
+note: the tool module imported here
+  --> $DIR/register-attr-tool-import.rs:10:5
+   |
+LL | use tool as renamed_tool; // OK
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
index 3e36f2402a99080af536df5b6006906af7d8abab..a0739a7a90b0a2f6b13b1f9574f7f94ad71fe4d5 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `test_mut` found for type `std::vec::Vec<{integer}>` in the current scope
+error[E0599]: no method named `test_mut` found for struct `std::vec::Vec<{integer}>` in the current scope
   --> $DIR/auto-ref-slice-plus-ref.rs:7:7
    |
 LL |     a.test_mut();
@@ -8,7 +8,7 @@ LL |     a.test_mut();
    = note: the following trait defines an item `test_mut`, perhaps you need to implement it:
            candidate #1: `MyIter`
 
-error[E0599]: no method named `test` found for type `std::vec::Vec<{integer}>` in the current scope
+error[E0599]: no method named `test` found for struct `std::vec::Vec<{integer}>` in the current scope
   --> $DIR/auto-ref-slice-plus-ref.rs:8:7
    |
 LL |     a.test();
@@ -18,7 +18,7 @@ LL |     a.test();
    = note: the following trait defines an item `test`, perhaps you need to implement it:
            candidate #1: `MyIter`
 
-error[E0599]: no method named `test` found for type `[{integer}; 1]` in the current scope
+error[E0599]: no method named `test` found for array `[{integer}; 1]` in the current scope
   --> $DIR/auto-ref-slice-plus-ref.rs:10:11
    |
 LL |     ([1]).test();
@@ -28,7 +28,7 @@ LL |     ([1]).test();
    = note: the following trait defines an item `test`, perhaps you need to implement it:
            candidate #1: `MyIter`
 
-error[E0599]: no method named `test` found for type `&[{integer}; 1]` in the current scope
+error[E0599]: no method named `test` found for reference `&[{integer}; 1]` in the current scope
   --> $DIR/auto-ref-slice-plus-ref.rs:11:12
    |
 LL |     (&[1]).test();
index 9b313d3e9b2787a4d9547a5b589b93f98e4980f9..0b652a1f54bf2635d87e0f4278fe1d14b19d2842 100644 (file)
@@ -1,7 +1,7 @@
 trait A {
     fn a(&self) {
         || self.b()
-        //~^ ERROR no method named `b` found for type `&Self` in the current scope
+        //~^ ERROR no method named `b` found
     }
 }
 fn main() {}
index 237b8c54ce301dffb03a4631f0da665182cae777..be551f6e889fc63964d44af2f699d84027a373ab 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `b` found for type `&Self` in the current scope
+error[E0599]: no method named `b` found for reference `&Self` in the current scope
   --> $DIR/issue-3563.rs:3:17
    |
 LL |         || self.b()
index 890f6800c22af7bb03f08829f369060c6f5ecd73..cb3199e7c886ecb1ce15fb963a7274894975c0fa 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no variant or associated item named `Hsl` found for type `Color` in the current scope
+error[E0599]: no variant or associated item named `Hsl` found for enum `Color` in the current scope
   --> $DIR/bogus-tag.rs:7:16
    |
 LL | enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), }
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs
new file mode 100644 (file)
index 0000000..232d436
--- /dev/null
@@ -0,0 +1,118 @@
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        [.., _y] => {} //~ ERROR use of moved value
+    }
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., _y] => {} //~ ERROR use of moved value
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., (_y, _)] => {} //~ ERROR use of moved value
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, _, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, _, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _, _] => {}
+    }
+    match a {
+        [(_x, _), _, _] => {} //~ ERROR use of moved value
+    }
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    match a {
+        [_, _, _y @ ..] => {}
+    }
+    match a {
+        [.., (_x, _)] => {} //~ ERROR use of moved value
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
new file mode 100644 (file)
index 0000000..e46a58a
--- /dev/null
@@ -0,0 +1,113 @@
+error[E0382]: use of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-match.rs:15:14
+   |
+LL |         [_, _, _x] => {}
+   |                -- value moved here
+...
+LL |         [.., _y] => {}
+   |              ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-match.rs:25:14
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+...
+LL |         [.., _y] => {}
+   |              ^^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-match.rs:35:15
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+...
+LL |         [.., (_y, _)] => {}
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:46:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:57:11
+   |
+LL |         [.., _x] => {}
+   |              -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:68:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:79:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-match.rs:91:11
+   |
+LL |         [_y @ .., _, _] => {}
+   |          ------- value moved here
+...
+LL |         [(_x, _), _, _] => {}
+   |           ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-match.rs:101:15
+   |
+LL |         [_, _, _y @ ..] => {}
+   |                ------- value moved here
+...
+LL |         [.., (_x, _)] => {}
+   |               ^^ value used here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-match.rs:112:11
+   |
+LL |         [x @ .., _] => {}
+   |          ------ value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs
new file mode 100644 (file)
index 0000000..e5e6169
--- /dev/null
@@ -0,0 +1,117 @@
+// Due to #53114, which causes a "read" of the `_` patterns,
+// the borrow-checker refuses this code, while it should probably be allowed.
+// Once the bug is fixed, the test, which is derived from a
+// passing test for `let` statements, should become check-pass.
+
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [.., _y, _] => {}
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [.., (_, _y)] => {}
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    match a {
+        [_, _y @ ..] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [(_x, _), _, _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [.., (_x, _)] => {}
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, _y @ ..] => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
new file mode 100644 (file)
index 0000000..72cd420
--- /dev/null
@@ -0,0 +1,102 @@
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:19:11
+   |
+LL |         [_, _, _x] => {}
+   |                -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:30:11
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:43:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:54:11
+   |
+LL |         [.., _x] => {}
+   |              -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:65:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:76:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:87:11
+   |
+LL |         [_, _y @ ..] => {}
+   |             ------- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:98:11
+   |
+LL |         [_y @ .., _] => {}
+   |          ------- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:111:11
+   |
+LL |         [x @ .., _, _] => {}
+   |          ------ value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.rs
new file mode 100644 (file)
index 0000000..1ca3df5
--- /dev/null
@@ -0,0 +1,152 @@
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        [.., ref _y] => {} //~ ERROR [E0382]
+    }
+}
+
+fn move_out_from_begin_field_and_end() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., ref _y] => {} //~ ERROR [E0382]
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        [.., (ref _y, _)] => {} //~ ERROR [E0382]
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [ref _y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [_, _, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [ref _y @ .., _, _] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [_, _, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _, _] => {}
+    }
+    match a {
+        [(ref _x, _), _, _] => {} //~ ERROR [E0382]
+    }
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+    let a = array();
+    match a {
+        [_, _, _y @ ..] => {}
+    }
+    match a {
+        [.., (ref _x, _)] => {} //~ ERROR [E0382]
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR [E0382]
+        [_, ref _y @ ..] => {}
+    }
+}
+
+// Move + Assign
+
+fn move_out_and_assign_end() {
+    let mut a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    a[2] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_and_assign_end_field() {
+    let mut a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    a[2].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end() {
+    let mut a = array();
+    match a {
+        [_, _, _x @ ..] => {}
+    }
+    a[0] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end_field() {
+    let mut a = array();
+    match a {
+        [_, _, _x @ ..] => {}
+    }
+    a[0].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
new file mode 100644 (file)
index 0000000..028442a
--- /dev/null
@@ -0,0 +1,157 @@
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:15:14
+   |
+LL |         [_, _, _x] => {}
+   |                -- value moved here
+...
+LL |         [.., ref _y] => {}
+   |              ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:25:14
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+...
+LL |         [.., ref _y] => {}
+   |              ^^^^^^ value borrowed here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..].0`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:35:15
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+...
+LL |         [.., (ref _y, _)] => {}
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:46:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:57:11
+   |
+LL |         [.., _x] => {}
+   |              -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:68:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:79:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:91:11
+   |
+LL |         [_y @ .., _, _] => {}
+   |          ------- value moved here
+...
+LL |         [(ref _x, _), _, _] => {}
+   |           ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:101:15
+   |
+LL |         [_, _, _y @ ..] => {}
+   |                ------- value moved here
+...
+LL |         [.., (ref _x, _)] => {}
+   |               ^^^^^^ value borrowed here after move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:112:11
+   |
+LL |         [x @ .., _] => {}
+   |          ------ value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:125:5
+   |
+LL |         [_, _, _x] => {}
+   |                -- value moved here
+LL |     }
+LL |     a[2] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:133:5
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+LL |     }
+LL |     a[2].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:141:5
+   |
+LL |         [_, _, _x @ ..] => {}
+   |                ------- value moved here
+LL |     }
+LL |     a[0] = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-match.rs:149:5
+   |
+LL |         [_, _, _x @ ..] => {}
+   |                ------- value moved here
+LL |     }
+LL |     a[0].1 = Default::default();
+   |     ^^^^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs
new file mode 100644 (file)
index 0000000..79fe593
--- /dev/null
@@ -0,0 +1,117 @@
+// Due to #53114, which causes a "read" of the `_` patterns,
+// the borrow-checker refuses this code, while it should probably be allowed.
+// Once the bug is fixed, the test, which is derived from a
+// passing test for `let` statements, should become check-pass.
+
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+    Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+    let a = array();
+    match a {
+        [_, _, _x] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [.., ref _y, _] => {}
+    }
+}
+
+fn move_out_from_begin_field_and_end_field() {
+    let a = array();
+    match a {
+        [_, _, (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [.., (_, ref _y)] => {}
+    }
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+    let a = array();
+    match a {
+        [_x, _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+    let a = array();
+    match a {
+        [.., _x] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [ref _y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+    let a = array();
+    match a {
+        [(_x, _), _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, ref _y @ ..] => {}
+    }
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+    let a = array();
+    match a {
+        [.., (_x, _)] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [ref _y @ .., _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+    let a = array();
+    match a {
+        [_, _y @ ..] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [(ref _x, _), _, _] => {}
+    }
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+    let a = array();
+    match a {
+        [_y @ .., _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [.., (ref _x, _)] => {}
+    }
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+    let a = array();
+    match a {
+        [x @ .., _, _] => {}
+    }
+    match a {
+        //~^ ERROR use of moved value
+        [_, ref _y @ ..] => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
new file mode 100644 (file)
index 0000000..43ba2b6
--- /dev/null
@@ -0,0 +1,102 @@
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:19:11
+   |
+LL |         [_, _, _x] => {}
+   |                -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:30:11
+   |
+LL |         [_, _, (_x, _)] => {}
+   |                 -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:43:11
+   |
+LL |         [_x, _, _] => {}
+   |          -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:54:11
+   |
+LL |         [.., _x] => {}
+   |              -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:65:11
+   |
+LL |         [(_x, _), _, _] => {}
+   |           -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:76:11
+   |
+LL |         [.., (_x, _)] => {}
+   |               -- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:87:11
+   |
+LL |         [_, _y @ ..] => {}
+   |             ------- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:98:11
+   |
+LL |         [_y @ .., _] => {}
+   |          ------- value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:111:11
+   |
+LL |         [x @ .., _, _] => {}
+   |          ------ value moved here
+LL |     }
+LL |     match a {
+   |           ^ value used here after partial move
+   |
+   = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
index da918ba92b8637c1fa2251117ffb51da3528fa1f..141ad5bd2c482bdcd4d4ce5ede1c16113c54f2cc 100644 (file)
@@ -26,6 +26,7 @@ fn has_bound<'b>(self, b: Inv<'b>) {
 
     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
         //~^ ERROR method not compatible with trait
+        //~| ERROR method not compatible with trait
         //
         // Note: This is a terrible error message. It is caused
         // because, in the trait, 'b is early bound, and in the impl,
index 4f86ffb2b79af2632c65fe854164dc2128061ed2..ad39b3601bffb0a7ecebbb23c23619051ece7714 100644 (file)
@@ -35,8 +35,27 @@ note: ...does not necessarily outlive the lifetime `'c` as defined on the method
 LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
    |                        ^^
 
+error[E0308]: method not compatible with trait
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:5
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected fn pointer `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)`
+              found fn pointer `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)`
+note: the lifetime `'c` as defined on the method body at 27:24...
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |                        ^^
+note: ...does not necessarily outlive the lifetime `'c` as defined on the method body at 27:24
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
+   |
+LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+   |                        ^^
+
 error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration
-  --> $DIR/regions-bound-missing-bound-in-impl.rs:41:20
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:42:20
    |
 LL |     fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
    |                    ---------------- lifetimes in impl do not match this method in trait
@@ -45,7 +64,7 @@ LL |     fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
    |                    ^ lifetimes do not match method in trait
 
 error[E0276]: impl has stricter requirements than trait
-  --> $DIR/regions-bound-missing-bound-in-impl.rs:48:5
+  --> $DIR/regions-bound-missing-bound-in-impl.rs:49:5
    |
 LL |     fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
    |     ------------------------------------------------------- definition of `another_bound` from trait
@@ -53,7 +72,7 @@ LL |     fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
 LL |     fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0195, E0276, E0308.
 For more information about an error, try `rustc --explain E0195`.
index 4cab52e3e974ca40075bbd727de647df0454ee29..0f932cda07fc36bdf732077c813f45e19385fb9f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `eat` found for type `std::boxed::Box<dyn Noisy>` in the current scope
+error[E0599]: no method named `eat` found for struct `std::boxed::Box<dyn Noisy>` in the current scope
   --> $DIR/class-cast-to-trait.rs:53:8
    |
 LL |   nyan.eat();
index 63236cf542464ec9e6619b76a29f34e05c46157c..3c4ae450764dae72ccb5da2579b3c3e32c8705d4 100644 (file)
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/closure-reform-bad.rs:11:15
    |
+LL |     let f = |s: &str| println!("{}{}", s, string);
+   |             ------------------------------------- the found closure
 LL |     call_bare(f)
    |               ^ expected fn pointer, found closure
    |
index e719d5254f639a2862588c1e0cfa60255df9876b..3d37d8af31df3485b661525f8ec9451ac079e897 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `the_fn` found for type `&Lib::TheStruct` in the current scope
+error[E0599]: no method named `the_fn` found for reference `&Lib::TheStruct` in the current scope
   --> $DIR/coherence_inherent.rs:31:11
    |
 LL |         s.the_fn();
index c666c1a3d1b3f9de395e07ec56f09628cf1b55bb..d968c8b4680dff77343162df2d910c3d152c6541 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `the_fn` found for type `&coherence_inherent_cc_lib::TheStruct` in the current scope
+error[E0599]: no method named `the_fn` found for reference `&coherence_inherent_cc_lib::TheStruct` in the current scope
   --> $DIR/coherence_inherent_cc.rs:23:11
    |
 LL |         s.the_fn();
index cc986b252196271271c0f0ce762d28e46b5ca6eb..8e9c11690a824a7c6618118d67fc2a1a8e012e3f 100644 (file)
@@ -1,16 +1,24 @@
 #![allow(dead_code)]
 
 #[repr(C)]
-enum A { A }
+enum A {
+    A,
+}
 
 #[repr(u64)]
-enum B { B }
+enum B {
+    B,
+}
 
-#[repr(C, u64)] //~ WARNING conflicting representation hints
-enum C { C }
+#[repr(C, u64)] //~ ERROR conflicting representation hints
+enum C {
+    C,
+}
 
-#[repr(u32, u64)] //~ WARNING conflicting representation hints
-enum D { D }
+#[repr(u32, u64)] //~ ERROR conflicting representation hints
+enum D {
+    D,
+}
 
 #[repr(C, packed)]
 struct E(i32);
@@ -37,20 +45,23 @@ enum D { D }
 struct K(i32);
 
 #[repr(packed, align(8))]
-union X { //~ ERROR type has conflicting packed and align representation hints
-    i: i32
+union X {
+    //~^ ERROR type has conflicting packed and align representation hints
+    i: i32,
 }
 
 #[repr(packed)]
 #[repr(align(8))]
-union Y { //~ ERROR type has conflicting packed and align representation hints
-    i: i32
+union Y {
+    //~^ ERROR type has conflicting packed and align representation hints
+    i: i32,
 }
 
 #[repr(align(8))]
 #[repr(packed)]
-union Z { //~ ERROR type has conflicting packed and align representation hints
-    i: i32
+union Z {
+    //~^ ERROR type has conflicting packed and align representation hints
+    i: i32,
 }
 
 fn main() {}
index 414c15f93bc18731ad9769d4a55bcee68220c02e..0dfe360dbb3c49fe77b5d9dd920b438833f2e4de 100644 (file)
@@ -1,70 +1,73 @@
-warning[E0566]: conflicting representation hints
-  --> $DIR/conflicting-repr-hints.rs:9:8
+error[E0566]: conflicting representation hints
+  --> $DIR/conflicting-repr-hints.rs:13:8
    |
 LL | #[repr(C, u64)]
    |        ^  ^^^
 
-warning[E0566]: conflicting representation hints
-  --> $DIR/conflicting-repr-hints.rs:12:8
+error[E0566]: conflicting representation hints
+  --> $DIR/conflicting-repr-hints.rs:18:8
    |
 LL | #[repr(u32, u64)]
    |        ^^^  ^^^
 
 error[E0587]: type has conflicting packed and align representation hints
-  --> $DIR/conflicting-repr-hints.rs:19:1
+  --> $DIR/conflicting-repr-hints.rs:27:1
    |
 LL | struct F(i32);
    | ^^^^^^^^^^^^^^
 
 error[E0587]: type has conflicting packed and align representation hints
-  --> $DIR/conflicting-repr-hints.rs:23:1
+  --> $DIR/conflicting-repr-hints.rs:31:1
    |
 LL | struct G(i32);
    | ^^^^^^^^^^^^^^
 
 error[E0587]: type has conflicting packed and align representation hints
-  --> $DIR/conflicting-repr-hints.rs:27:1
+  --> $DIR/conflicting-repr-hints.rs:35:1
    |
 LL | struct H(i32);
    | ^^^^^^^^^^^^^^
 
 error[E0634]: type has conflicting packed representation hints
-  --> $DIR/conflicting-repr-hints.rs:30:1
+  --> $DIR/conflicting-repr-hints.rs:38:1
    |
 LL | struct I(i32);
    | ^^^^^^^^^^^^^^
 
 error[E0634]: type has conflicting packed representation hints
-  --> $DIR/conflicting-repr-hints.rs:34:1
+  --> $DIR/conflicting-repr-hints.rs:42:1
    |
 LL | struct J(i32);
    | ^^^^^^^^^^^^^^
 
 error[E0587]: type has conflicting packed and align representation hints
-  --> $DIR/conflicting-repr-hints.rs:40:1
+  --> $DIR/conflicting-repr-hints.rs:48:1
    |
 LL | / union X {
-LL | |     i: i32
+LL | |
+LL | |     i: i32,
 LL | | }
    | |_^
 
 error[E0587]: type has conflicting packed and align representation hints
-  --> $DIR/conflicting-repr-hints.rs:46:1
+  --> $DIR/conflicting-repr-hints.rs:55:1
    |
 LL | / union Y {
-LL | |     i: i32
+LL | |
+LL | |     i: i32,
 LL | | }
    | |_^
 
 error[E0587]: type has conflicting packed and align representation hints
-  --> $DIR/conflicting-repr-hints.rs:52:1
+  --> $DIR/conflicting-repr-hints.rs:62:1
    |
 LL | / union Z {
-LL | |     i: i32
+LL | |
+LL | |     i: i32,
 LL | | }
    | |_^
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0566, E0587.
 For more information about an error, try `rustc --explain E0566`.
index 79ba93130a73aa003ccc79c92ccbbdb09baca41c..d6b399acb733097ecfdf9658622d638c857ec697 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for type `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope
   --> $DIR/issue-18343.rs:7:7
    |
 LL | struct Obj<F> where F: FnMut() -> u32 {
index a44b97184153832988234b9070c5e25e5035ad5f..f9dfdddad9d469060b340ee17fb85481a2619dde 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for type `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
   --> $DIR/issue-2392.rs:36:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -12,7 +12,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (o_closure.closure)();
    |     ^                 ^
 
-error[E0599]: no method named `not_closure` found for type `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
   --> $DIR/issue-2392.rs:38:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -23,7 +23,7 @@ LL |     o_closure.not_closure();
    |               |
    |               field, not a method
 
-error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
   --> $DIR/issue-2392.rs:42:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -37,7 +37,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (o_func.closure)();
    |     ^              ^
 
-error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
+error[E0599]: no method named `boxed_closure` found for struct `BoxedObj` in the current scope
   --> $DIR/issue-2392.rs:45:14
    |
 LL | struct BoxedObj {
@@ -51,7 +51,7 @@ help: to call the function stored in `boxed_closure`, surround the field access
 LL |     (boxed_fn.boxed_closure)();
    |     ^                      ^
 
-error[E0599]: no method named `boxed_closure` found for type `BoxedObj` in the current scope
+error[E0599]: no method named `boxed_closure` found for struct `BoxedObj` in the current scope
   --> $DIR/issue-2392.rs:48:19
    |
 LL | struct BoxedObj {
@@ -65,7 +65,7 @@ help: to call the function stored in `boxed_closure`, surround the field access
 LL |     (boxed_closure.boxed_closure)();
    |     ^                           ^
 
-error[E0599]: no method named `closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
   --> $DIR/issue-2392.rs:53:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (w.wrap.closure)();
    |     ^              ^
 
-error[E0599]: no method named `not_closure` found for type `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
   --> $DIR/issue-2392.rs:55:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -90,7 +90,7 @@ LL |     w.wrap.not_closure();
    |            |
    |            field, not a method
 
-error[E0599]: no method named `closure` found for type `Obj<std::boxed::Box<(dyn std::ops::FnOnce() -> u32 + 'static)>>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj<std::boxed::Box<(dyn std::ops::FnOnce() -> u32 + 'static)>>` in the current scope
   --> $DIR/issue-2392.rs:58:24
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -104,7 +104,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (check_expression().closure)();
    |     ^                          ^
 
-error[E0599]: no method named `f1` found for type `FuncContainer` in the current scope
+error[E0599]: no method named `f1` found for struct `FuncContainer` in the current scope
   --> $DIR/issue-2392.rs:64:31
    |
 LL | struct FuncContainer {
@@ -118,7 +118,7 @@ help: to call the function stored in `f1`, surround the field access with parent
 LL |             ((*self.container).f1)(1);
    |             ^                    ^
 
-error[E0599]: no method named `f2` found for type `FuncContainer` in the current scope
+error[E0599]: no method named `f2` found for struct `FuncContainer` in the current scope
   --> $DIR/issue-2392.rs:65:31
    |
 LL | struct FuncContainer {
@@ -132,7 +132,7 @@ help: to call the function stored in `f2`, surround the field access with parent
 LL |             ((*self.container).f2)(1);
    |             ^                    ^
 
-error[E0599]: no method named `f3` found for type `FuncContainer` in the current scope
+error[E0599]: no method named `f3` found for struct `FuncContainer` in the current scope
   --> $DIR/issue-2392.rs:66:31
    |
 LL | struct FuncContainer {
index b2f7894ba0560927ea1e3f7d172fb539b42f021f..a8d97bdfe2fb564ee95296e3f9aa9e2336f694ef 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `example` found for type `Example` in the current scope
+error[E0599]: no method named `example` found for struct `Example` in the current scope
   --> $DIR/issue-32128.rs:12:10
    |
 LL | struct Example {
index af29a9963e1f2eae25a8df363f5a0b429bd2f7f8..c109896e825be2ff9eb78806f0382676dc8c40fa 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for type `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
+error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
   --> $DIR/issue-33784.rs:27:7
    |
 LL |     p.closure();
@@ -9,7 +9,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (p.closure)();
    |     ^         ^
 
-error[E0599]: no method named `fn_ptr` found for type `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
+error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
   --> $DIR/issue-33784.rs:29:7
    |
 LL |     q.fn_ptr();
@@ -20,7 +20,7 @@ help: to call the function stored in `fn_ptr`, surround the field access with pa
 LL |     (q.fn_ptr)();
    |     ^        ^
 
-error[E0599]: no method named `c_fn_ptr` found for type `&D` in the current scope
+error[E0599]: no method named `c_fn_ptr` found for reference `&D` in the current scope
   --> $DIR/issue-33784.rs:32:7
    |
 LL |     s.c_fn_ptr();
index 97c949e32e341f43d3d63ae2a21dc0fa80a6dcfc..82cb235d47a7d8c06e34f416e19191ea9b3866ac 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `dog_age` found for type `animal::Dog` in the current scope
+error[E0599]: no method named `dog_age` found for struct `animal::Dog` in the current scope
   --> $DIR/private-field.rs:16:23
    |
 LL |     pub struct Dog {
index 47b090cb886783da762f369c8d999d49b9357e6c..19e7d2036bfc88ece09d605e7e1063452ca33dd3 100644 (file)
@@ -4,7 +4,7 @@ error[E0107]: wrong number of const arguments: expected 0, found 1
 LL |     let _: u32 = 5i32.try_into::<32>().unwrap();
    |                                  ^^ unexpected const argument
 
-error[E0599]: no method named `f` found for type `S` in the current scope
+error[E0599]: no method named `f` found for struct `S` in the current scope
   --> $DIR/invalid-const-arg-for-type-param.rs:7:7
    |
 LL | struct S;
index 1de6bafd293cf6013aa06c9257193cd7263e26dc..64aeb46894d169b63303972a07371c471d5498aa 100644 (file)
@@ -1,7 +1,10 @@
-// build-fail
+// build-pass
+
+#![warn(const_err)]
 
 fn main() {
-    &{[1, 2, 3][4]};
-    //~^ ERROR index out of bounds
-    //~| ERROR reaching this expression at runtime will panic or abort
+    &{ [1, 2, 3][4] };
+    //~^ WARN index out of bounds
+    //~| WARN reaching this expression at runtime will panic or abort
+    //~| WARN erroneous constant used [const_err]
 }
index f3ef16659dd3eeba5ef7eb62de8c5cbb54d47ffd..50ad8e83e905cc0ad842642cc1986511d0ebb74f 100644 (file)
@@ -1,18 +1,26 @@
-error: index out of bounds: the len is 3 but the index is 4
-  --> $DIR/array-literal-index-oob.rs:4:7
+warning: index out of bounds: the len is 3 but the index is 4
+  --> $DIR/array-literal-index-oob.rs:6:8
    |
-LL |     &{[1, 2, 3][4]};
-   |       ^^^^^^^^^^^^
+LL |     &{ [1, 2, 3][4] };
+   |        ^^^^^^^^^^^^
    |
-   = note: `#[deny(const_err)]` on by default
+note: lint level defined here
+  --> $DIR/array-literal-index-oob.rs:3:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
-  --> $DIR/array-literal-index-oob.rs:4:7
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/array-literal-index-oob.rs:6:8
    |
-LL |     &{[1, 2, 3][4]};
-   |     --^^^^^^^^^^^^-
-   |       |
-   |       indexing out of bounds: the len is 3 but the index is 4
+LL |     &{ [1, 2, 3][4] };
+   |     ---^^^^^^^^^^^^--
+   |        |
+   |        indexing out of bounds: the len is 3 but the index is 4
 
-error: aborting due to 2 previous errors
+warning: erroneous constant used
+  --> $DIR/array-literal-index-oob.rs:6:5
+   |
+LL |     &{ [1, 2, 3][4] };
+   |     ^^^^^^^^^^^^^^^^^ referenced constant has errors
 
index 96f67c92a5e93f02f977e7888405a951f2ef4312..2058d2e218473b925ca224333fcc1effa6beee25 100644 (file)
@@ -10,4 +10,5 @@
 fn main() {
     println!("{}", FOO);
     //~^ ERROR
+    //~| WARN erroneous constant used [const_err]
 }
index ec18f8f011d61efe2d1eb1972a421e4439ebc55e..b5f5f84cf3894ddb57e0fc5b41e041883b1b87ac 100644 (file)
@@ -18,6 +18,12 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{}", FOO);
    |                    ^^^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/conditional_array_execution.rs:11:20
+   |
+LL |     println!("{}", FOO);
+   |                    ^^^ referenced constant has errors
+
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
index 9369702f1721c1eec4a15b5b7343ef135c70c4b4..9300d9576de1d76a3615ff4b775c824f5fbf1cd8 100644 (file)
@@ -14,6 +14,7 @@ fn main() {
     match -128i8 {
         NEG_NEG_128 => println!("A"),
         //~^ ERROR could not evaluate constant pattern
+        //~| ERROR could not evaluate constant pattern
         _ => println!("B"),
     }
 }
index 13f00c47f6c1be43a22a896452da696b68904769..26728cf5415821de775d3fd8ea580a16de60bcf5 100644 (file)
@@ -4,5 +4,11 @@ error: could not evaluate constant pattern
 LL |         NEG_NEG_128 => println!("A"),
    |         ^^^^^^^^^^^
 
-error: aborting due to previous error
+error: could not evaluate constant pattern
+  --> $DIR/const-eval-overflow-2.rs:15:9
+   |
+LL |         NEG_NEG_128 => println!("A"),
+   |         ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
index a5f04d088b61147ba0f7911445881a1396033cea..81f53826d810348c27d247f0b3c4ae2411cca566 100644 (file)
@@ -4,7 +4,9 @@
 #![feature(const_fn)]
 #![allow(const_err)]
 
-fn double(x: usize) -> usize { x * 2 }
+fn double(x: usize) -> usize {
+    x * 2
+}
 const X: fn(usize) -> usize = double;
 
 const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
index 19f37fa00795ce9a54066288dc165f881c51f180..f99505c30901d77c814eea77b541f9c962545312 100644 (file)
@@ -1,11 +1,11 @@
 warning: skipping const checks
-  --> $DIR/const_fn_ptr_fail2.rs:11:5
+  --> $DIR/const_fn_ptr_fail2.rs:13:5
    |
 LL |     x(y)
    |     ^^^^
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_fn_ptr_fail2.rs:18:5
+  --> $DIR/const_fn_ptr_fail2.rs:20:5
    |
 LL |     assert_eq!(Y, 4);
    |     ^^^^^^^^^^^-^^^^^
@@ -15,7 +15,7 @@ LL |     assert_eq!(Y, 4);
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/const_fn_ptr_fail2.rs:20:5
+  --> $DIR/const_fn_ptr_fail2.rs:22:5
    |
 LL |     assert_eq!(Z, 4);
    |     ^^^^^^^^^^^-^^^^^
index 849c81ad449b5ee6af85d7f159ad0728d2c1008a..9109307632b595f60de4d1dd7995786809e4516f 100644 (file)
@@ -7,11 +7,13 @@ const fn foo(x: u32) -> u32 {
 }
 
 fn main() {
-    const X: u32 = 0-1;
+    const X: u32 = 0 - 1;
     //~^ WARN any use of this value will cause
-    const Y: u32 = foo(0-1);
+    const Y: u32 = foo(0 - 1);
     //~^ WARN any use of this value will cause
     println!("{} {}", X, Y);
     //~^ ERROR evaluation of constant expression failed
     //~| ERROR evaluation of constant expression failed
+    //~| WARN erroneous constant used [const_err]
+    //~| WARN erroneous constant used [const_err]
 }
index a1b3a05ed41696801c53b3ab483b4b82eace0a85..23b54d954c65874c0d6e412915d2ac98b4c79c42 100644 (file)
@@ -1,8 +1,8 @@
 warning: any use of this value will cause an error
   --> $DIR/issue-43197.rs:10:20
    |
-LL |     const X: u32 = 0-1;
-   |     ---------------^^^-
+LL |     const X: u32 = 0 - 1;
+   |     ---------------^^^^^-
    |                    |
    |                    attempt to subtract with overflow
    |
@@ -15,8 +15,8 @@ LL | #![warn(const_err)]
 warning: any use of this value will cause an error
   --> $DIR/issue-43197.rs:12:24
    |
-LL |     const Y: u32 = foo(0-1);
-   |     -------------------^^^--
+LL |     const Y: u32 = foo(0 - 1);
+   |     -------------------^^^^^--
    |                        |
    |                        attempt to subtract with overflow
 
@@ -26,12 +26,24 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{} {}", X, Y);
    |                       ^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/issue-43197.rs:14:23
+   |
+LL |     println!("{} {}", X, Y);
+   |                       ^ referenced constant has errors
+
 error[E0080]: evaluation of constant expression failed
   --> $DIR/issue-43197.rs:14:26
    |
 LL |     println!("{} {}", X, Y);
    |                          ^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/issue-43197.rs:14:26
+   |
+LL |     println!("{} {}", X, Y);
+   |                          ^ referenced constant has errors
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index 7da9256bb398fae4415699a4fc6a734727edf450..f9194709dc0b7c58e2925a5580d5a96d66c7939b 100644 (file)
@@ -25,5 +25,5 @@ impl Foo for u16 {
 
 fn main() {
     println!("{}", <Bar<u16, u8> as Foo>::AMT);
-    //~^ ERROR E0080
+    //~^ ERROR evaluation of constant expression failed [E0080]
 }
index e589126a9429c065a67906fe135e4e4a391d98cd..5c3635e4650cd4ee059bf16fb854fc84c73006aa 100644 (file)
@@ -12,11 +12,13 @@ impl Unsigned for U8 {
 struct Sum<A,B>(A,B);
 
 impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A,B> {
-    const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error
+    const MAX: u8 = A::MAX + B::MAX;
+    //~^ ERROR any use of this value will cause an error [const_err]
 }
 
 fn foo<T>(_: T) -> &'static u8 {
-    &Sum::<U8,U8>::MAX //~ ERROR E0080
+    &Sum::<U8,U8>::MAX
+    //~^ ERROR E0080
 }
 
 fn main() {
index f8b017e4b53a172c0c53d5b6442aeffc67b4076c..2e5167a99a2c638abe4d04709be5a72760e3e8d6 100644 (file)
@@ -9,7 +9,7 @@ LL |     const MAX: u8 = A::MAX + B::MAX;
    = note: `#[deny(const_err)]` on by default
 
 error[E0080]: evaluation of constant expression failed
-  --> $DIR/issue-50814.rs:19:5
+  --> $DIR/issue-50814.rs:20:5
    |
 LL |     &Sum::<U8,U8>::MAX
    |     ^-----------------
index 2eed8ca7d322cb68dd17e9ea130375aca553ca5c..fee232185d29a93559f1a59058116a6139c76fc6 100644 (file)
@@ -1,20 +1,22 @@
-// build-fail
+// build-pass
 // compile-flags: -O
 
-#![deny(const_err)]
+#![warn(const_err)]
 
 fn main() {
     println!("{}", 0u32 - 1);
     let _x = 0u32 - 1;
-    //~^ ERROR const_err
-    println!("{}", 1/(1-1));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(1-1);
-    //~^ ERROR const_err
-    println!("{}", 1/(false as u32));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(false as u32);
-    //~^ ERROR const_err
+    //~^ WARN const_err
+    println!("{}", 1 / (1 - 1));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (1 - 1);
+    //~^ WARN const_err
+    println!("{}", 1 / (false as u32));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (false as u32);
+    //~^ WARN const_err
 }
index 8f17ef05f2356760247a66c81e40ac81cca009ac..4de22fdf4ab1e4627d510fee7687bc45a7baa68d 100644 (file)
@@ -1,4 +1,4 @@
-error: this expression will panic at runtime
+warning: this expression will panic at runtime
   --> $DIR/promoted_errors.rs:8:14
    |
 LL |     let _x = 0u32 - 1;
@@ -7,44 +7,54 @@ LL |     let _x = 0u32 - 1;
 note: lint level defined here
   --> $DIR/promoted_errors.rs:4:9
    |
-LL | #![deny(const_err)]
+LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
-error: attempt to divide by zero
+warning: attempt to divide by zero
   --> $DIR/promoted_errors.rs:10:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
+warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:10:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:13:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:10:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ referenced constant has errors
+
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors.rs:14:14
    |
-LL |     let _x = 1/(1-1);
-   |              ^^^^^^^
+LL |     let _x = 1 / (1 - 1);
+   |              ^^^^^^^^^^^
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:15:20
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors.rs:16:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors.rs:15:20
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:16:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:18:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:16:20
    |
-LL |     let _x = 1/(false as u32);
-   |              ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
-error: aborting due to 7 previous errors
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors.rs:20:14
+   |
+LL |     let _x = 1 / (false as u32);
+   |              ^^^^^^^^^^^^^^^^^^
 
index ae680b4f1072ee4b6da3165d7adf026ba3515ac6..41a989d91c5d3f13407a9560d34abeaed015e21f 100644 (file)
@@ -1,21 +1,23 @@
-// build-fail
+// build-pass
 // compile-flags: -C overflow-checks=on -O
 
-#![deny(const_err)]
+#![warn(const_err)]
 
 fn main() {
     println!("{}", 0u32 - 1);
-    //~^ ERROR attempt to subtract with overflow
+    //~^ WARN attempt to subtract with overflow
     let _x = 0u32 - 1;
-    //~^ ERROR attempt to subtract with overflow
-    println!("{}", 1/(1-1));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(1-1);
-    //~^ ERROR const_err
-    println!("{}", 1/(false as u32));
-    //~^ ERROR attempt to divide by zero [const_err]
-    //~| ERROR const_err
-    let _x = 1/(false as u32);
-    //~^ ERROR const_err
+    //~^ WARN attempt to subtract with overflow
+    println!("{}", 1 / (1 - 1));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (1 - 1);
+    //~^ WARN const_err
+    println!("{}", 1 / (false as u32));
+    //~^ WARN attempt to divide by zero [const_err]
+    //~| WARN const_err
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (false as u32);
+    //~^ WARN const_err
 }
index 60a3cba6e1ff5e65b6f29228816438b01acece77..4f7ba8bf385d3c036d18ee05de861ee988691f25 100644 (file)
@@ -1,4 +1,4 @@
-error: attempt to subtract with overflow
+warning: attempt to subtract with overflow
   --> $DIR/promoted_errors2.rs:7:20
    |
 LL |     println!("{}", 0u32 - 1);
@@ -7,50 +7,60 @@ LL |     println!("{}", 0u32 - 1);
 note: lint level defined here
   --> $DIR/promoted_errors2.rs:4:9
    |
-LL | #![deny(const_err)]
+LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
-error: attempt to subtract with overflow
+warning: attempt to subtract with overflow
   --> $DIR/promoted_errors2.rs:9:14
    |
 LL |     let _x = 0u32 - 1;
    |              ^^^^^^^^
 
-error: attempt to divide by zero
+warning: attempt to divide by zero
   --> $DIR/promoted_errors2.rs:11:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
+warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors2.rs:11:20
    |
-LL |     println!("{}", 1/(1-1));
-   |                    ^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:14:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors2.rs:11:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ referenced constant has errors
+
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors2.rs:15:14
    |
-LL |     let _x = 1/(1-1);
-   |              ^^^^^^^
+LL |     let _x = 1 / (1 - 1);
+   |              ^^^^^^^^^^^
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:16:20
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors2.rs:17:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^
 
-error: reaching this expression at runtime will panic or abort
-  --> $DIR/promoted_errors2.rs:16:20
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors2.rs:17:20
    |
-LL |     println!("{}", 1/(false as u32));
-   |                    ^^^^^^^^^^^^^^^^ dividing by zero
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
 
-error: attempt to divide by zero
-  --> $DIR/promoted_errors2.rs:19:14
+warning: erroneous constant used
+  --> $DIR/promoted_errors2.rs:17:20
    |
-LL |     let _x = 1/(false as u32);
-   |              ^^^^^^^^^^^^^^^^
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
 
-error: aborting due to 8 previous errors
+warning: attempt to divide by zero
+  --> $DIR/promoted_errors2.rs:21:14
+   |
+LL |     let _x = 1 / (false as u32);
+   |              ^^^^^^^^^^^^^^^^^^
 
index 45ce040fb9eef8b127713987f54ed26670e0d657..87136a109db3502a4a6ddd1b677f5a79e9c46f5b 100644 (file)
@@ -5,6 +5,7 @@ fn main() {
     match n {
         0..=10 => {},
         10..=BAR => {}, //~ ERROR could not evaluate constant pattern
+                        //~| ERROR could not evaluate constant pattern
         _ => {},
     }
 }
index b72a5b80afa8d08b9e2279e518022b588e90ec95..17f8744ed9fd707b789e5691b901a7b5c3a02768 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ref_to_int_match.rs:24:1
+  --> $DIR/ref_to_int_match.rs:25:1
    |
 LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes
@@ -12,6 +12,12 @@ error: could not evaluate constant pattern
 LL |         10..=BAR => {},
    |              ^^^
 
-error: aborting due to 2 previous errors
+error: could not evaluate constant pattern
+  --> $DIR/ref_to_int_match.rs:7:14
+   |
+LL |         10..=BAR => {},
+   |              ^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index 80d80a986751e948983c7a61e56eb74b19a600a9..ea9fffa883ea5e83fb739323123e01531bd7d44a 100644 (file)
@@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
 LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
 LL | |     let out_of_bounds_ptr = &ptr[255];
-   | |                             ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1
+   | |                             ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 9 which has size 1
 LL | |     mem::transmute(out_of_bounds_ptr)
 LL | | } };
    | |____-
diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs
new file mode 100644 (file)
index 0000000..7ced248
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {}
+
+#[cfg(FALSE)]
+fn container() {
+    const unsafe WhereIsFerris Now() {}
+    //~^ ERROR expected one of `extern` or `fn`
+}
diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr
new file mode 100644 (file)
index 0000000..5ec9e2a
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected one of `extern` or `fn`, found `WhereIsFerris`
+  --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs:5:18
+   |
+LL |     const unsafe WhereIsFerris Now() {}
+   |                  ^^^^^^^^^^^^^ expected one of `extern` or `fn`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs
new file mode 100644 (file)
index 0000000..1886bfc
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {}
+
+#[cfg(FALSE)]
+fn container() {
+    const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
+    //~^ ERROR expected `fn`
+    //~| ERROR `const extern fn` definitions are unstable
+}
diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr
new file mode 100644 (file)
index 0000000..cf71ed4
--- /dev/null
@@ -0,0 +1,18 @@
+error: expected `fn`, found `PUT_ANYTHING_YOU_WANT_HERE`
+  --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:25
+   |
+LL |     const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `fn`
+
+error[E0658]: `const extern fn` definitions are unstable
+  --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:5
+   |
+LL |     const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
+   |     ^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/64926
+   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index 2d4175ea8eb7da4c4af5bbd19768664e08e89683..df793d7dd7ec947a4833a7e8d1dd4eb44f60b36c 100644 (file)
@@ -4,17 +4,21 @@ error[E0015]: calls in constant functions are limited to constant functions, tup
 LL |     random()
    |     ^^^^^^^^
 
-error[E0013]: constant functions cannot refer to statics, use a constant instead
+error[E0013]: constant functions cannot refer to statics
   --> $DIR/const-fn-not-safe-for-const.rs:20:5
    |
 LL |     Y
    |     ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
-error[E0013]: constant functions cannot refer to statics, use a constant instead
+error[E0013]: constant functions cannot refer to statics
   --> $DIR/const-fn-not-safe-for-const.rs:25:6
    |
 LL |     &Y
    |      ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error: aborting due to 3 previous errors
 
index 33abfec02a87a68dfa938a1d5e62928fe8a120bb..99006a20b1bcba56dfe6275b847724ea47185cc1 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 
 struct Foo {
     x: usize
index 7887fd12e5764a2f497c4b795617b911a57b11b6..6bbbdd972a26c102b243a275b71352ed823d4815 100644 (file)
@@ -3,7 +3,6 @@
 // check-pass
 
 #![feature(const_if_match)]
-#![feature(const_fn)]
 
 enum E {
     A,
index 95096723b3c95f2e3009851146b06b5a160b633e..21e3f2af15ad6280ce4ca9b38300f7a023126f5f 100644 (file)
@@ -1,5 +1,5 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate-const-if-match.rs:109:1
+  --> $DIR/feature-gate-const-if-match.rs:108:1
    |
 LL | / fn main() {
 LL | |     let _ = [0; {
index e4b65257531fdacbd999bfb03b86755822c40d18..00576d50ac66b46f3af78f3fc08de759b9436ea6 100644 (file)
@@ -6,7 +6,6 @@
 
 #![feature(rustc_attrs)]
 #![cfg_attr(if_match, feature(const_if_match))]
-#![feature(const_fn)]
 
 const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
     5
index e846ee4ab6a41bb1ac87db7deb64da6ebd462bc5..d3c6a51923ffb54317d6315399c92c61ba520b6e 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:11:16
+  --> $DIR/feature-gate-const-if-match.rs:10:16
    |
 LL |   const _: i32 = if true {
    |  ________________^
@@ -13,7 +13,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:17:16
+  --> $DIR/feature-gate-const-if-match.rs:16:16
    |
 LL |   const _: i32 = if let Some(true) = Some(false) {
    |  ________________^
@@ -27,7 +27,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:23:16
+  --> $DIR/feature-gate-const-if-match.rs:22:16
    |
 LL |   const _: i32 = match 1 {
    |  ________________^
@@ -41,7 +41,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:30:13
+  --> $DIR/feature-gate-const-if-match.rs:29:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL |     let x = if true { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:32:13
+  --> $DIR/feature-gate-const-if-match.rs:31:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL |     let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:34:5
+  --> $DIR/feature-gate-const-if-match.rs:33:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:39:13
+  --> $DIR/feature-gate-const-if-match.rs:38:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     let x = if true { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:41:13
+  --> $DIR/feature-gate-const-if-match.rs:40:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +86,7 @@ LL |     let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:43:5
+  --> $DIR/feature-gate-const-if-match.rs:42:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL |     if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:48:5
+  --> $DIR/feature-gate-const-if-match.rs:47:5
    |
 LL |     if true { 5 } else { 6 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL |     if true { 5 } else { 6 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:52:5
+  --> $DIR/feature-gate-const-if-match.rs:51:5
    |
 LL | /     if let Some(true) = a {
 LL | |         0
@@ -117,7 +117,7 @@ LL | |     }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:60:5
+  --> $DIR/feature-gate-const-if-match.rs:59:5
    |
 LL | /     match i {
 LL | |         i if i > 10 => i,
@@ -130,7 +130,7 @@ LL | |     }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:91:17
+  --> $DIR/feature-gate-const-if-match.rs:90:17
    |
 LL |         let x = if y { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL |         let x = if y { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:93:17
+  --> $DIR/feature-gate-const-if-match.rs:92:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +148,7 @@ LL |         let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:95:9
+  --> $DIR/feature-gate-const-if-match.rs:94:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL |         if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:111:17
+  --> $DIR/feature-gate-const-if-match.rs:110:17
    |
 LL |         let x = if false { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@ LL |         let x = if false { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:113:17
+  --> $DIR/feature-gate-const-if-match.rs:112:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -175,7 +175,7 @@ LL |         let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:115:9
+  --> $DIR/feature-gate-const-if-match.rs:114:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +184,7 @@ LL |         if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:68:21
+  --> $DIR/feature-gate-const-if-match.rs:67:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL |     const IF: i32 = if true { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:71:25
+  --> $DIR/feature-gate-const-if-match.rs:70:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,7 +202,7 @@ LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:74:24
+  --> $DIR/feature-gate-const-if-match.rs:73:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -211,7 +211,7 @@ LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:79:21
+  --> $DIR/feature-gate-const-if-match.rs:78:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ LL |     const IF: i32 = if true { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:82:25
+  --> $DIR/feature-gate-const-if-match.rs:81:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@ LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:85:24
+  --> $DIR/feature-gate-const-if-match.rs:84:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -238,7 +238,7 @@ LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/feature-gate-const-if-match.rs:115:21
+  --> $DIR/feature-gate-const-if-match.rs:114:21
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |                     ^
index 4b20a2124c356aa516a4400281f93f462a0f8e56..8cee2a54f56d3e4c08b1aeeeb272a068e9364959 100644 (file)
@@ -4,7 +4,6 @@
 
 #![feature(const_if_match)]
 #![feature(const_panic)]
-#![feature(const_fn)]
 
 const X: i32 = {
     let mut x = 0;
index bb0fce66c4d899e280e32ec945cbac2bea1e997a..823605ff034f10c8ca1c25bb2b53c6da78c021c8 100644 (file)
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_if_match, const_fn)]
+#![feature(const_if_match)]
 
 enum Foo {
     Prob,
index d66c4f47d03ee79289d4c8e3bf49017f558a0a62..5adb2fa54edc41614dbc106c4ab04a6e7ddf4b36 100644 (file)
@@ -17,6 +17,7 @@ macro_rules! mac {
         enum E {
             $( $v = $s::V, )*
             //~^ ERROR mismatched types
+            //~| ERROR mismatched types
         }
     }
 }
index 848ccf94da2b65164d56039b2097624c9576a026..9935f88e5b57718b524430f66a498b5b96b0fe30 100644 (file)
@@ -15,6 +15,23 @@ help: you can convert an `i32` to `isize` and panic if the converted value would
 LL |             $( $v = $s::V.try_into().unwrap(), )*
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/enum-discr-type-err.rs:18:21
+   |
+LL |               $( $v = $s::V, )*
+   |                       ^^^^^ expected `isize`, found `i32`
+...
+LL | / mac! {
+LL | |     A = F,
+LL | |     B = T,
+LL | | }
+   | |_- in this macro invocation
+   |
+help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
+   |
+LL |             $( $v = $s::V.try_into().unwrap(), )*
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 1c13bfceb6cc28c56793b830707baca6ba60d682..1e495438e836cde041550816c42937d560bcc265 100644 (file)
@@ -10,6 +10,7 @@ fn main() {
     match C {
         C => {}
         //~^ ERROR to use a constant of type `S` in a pattern, `S` must be annotated with
+        //~| ERROR to use a constant of type `S` in a pattern, `S` must be annotated with
     }
     const K: &T = &T;
     match K { //~ ERROR non-exhaustive patterns: `&T` not covered
index bf0bd3aca97a4bf26b1809057c42dc51c72a2ee0..b25ac09ab121144d1a1ce146d30f85373aff2c05 100644 (file)
@@ -5,7 +5,7 @@ LL |         C => {}
    |         ^
 
 error[E0004]: non-exhaustive patterns: `&T` not covered
-  --> $DIR/match_ice.rs:15:11
+  --> $DIR/match_ice.rs:16:11
    |
 LL | struct T;
    | --------- `T` defined here
@@ -15,6 +15,12 @@ LL |     match K {
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error: aborting due to 2 previous errors
+error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/match_ice.rs:11:9
+   |
+LL |         C => {}
+   |         ^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
index e07db3ffba25edd3de2d08aff01e753276bb70b3..edbf0e02d8de24df9dd8aecb150fa7f8662dfe39 100644 (file)
@@ -28,6 +28,7 @@
 static mut MUTABLE: u32 = 0;
 const READ_MUT: u32 = unsafe { MUTABLE }; //~ WARN any use of this value will cause an error
 //~^ WARN skipping const checks
+//~| WARN skipping const checks
 
 // ok some day perhaps
 const READ_IMMUT: &usize = { //~ ERROR it is undefined behavior to use this value
index eae76c1389b62327a147760e3abbe89b7113680f..243efbbaa76af224c236bac4332eee0e20e47448 100644 (file)
@@ -29,7 +29,13 @@ LL | const READ_MUT: u32 = unsafe { MUTABLE };
    |                                ^^^^^^^
 
 warning: skipping const checks
-  --> $DIR/const_refers_to_static.rs:35:6
+  --> $DIR/const_refers_to_static.rs:29:32
+   |
+LL | const READ_MUT: u32 = unsafe { MUTABLE };
+   |                                ^^^^^^^
+
+warning: skipping const checks
+  --> $DIR/const_refers_to_static.rs:36:6
    |
 LL |     &FOO
    |      ^^^
@@ -84,7 +90,7 @@ LL | const READ_MUT: u32 = unsafe { MUTABLE };
    |                                constant accesses static
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/const_refers_to_static.rs:33:1
+  --> $DIR/const_refers_to_static.rs:34:1
    |
 LL | / const READ_IMMUT: &usize = {
 LL | |     static FOO: usize = 0;
index 3493b7c54c43b4773bf440a7f927305976a7c040..88418e57acddaef394bea355a32b946f511e29df 100644 (file)
@@ -10,7 +10,7 @@ error: internal compiler error: mutable allocation in constant
 LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:347:17
+thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:346:17
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 error: internal compiler error: unexpected panic
index 32a713ebaa44ee8946eee755ceea976b0eda9b3d..cfb57d21ceec5ffc10a05f1e9490faa7351285c9 100644 (file)
@@ -11,5 +11,7 @@ fn foo() {}
 //~^ WARN any use of this value will cause an error
 
 fn main() {
-    println!("{:?}", C); //~ ERROR: evaluation of constant expression failed
+    println!("{:?}", C);
+    //~^ ERROR: evaluation of constant expression failed
+    //~| WARN: erroneous constant used [const_err]
 }
index 75f532a81bdc3f6ea0d0721fa38cc168a96804f7..6a7df858febcf38d863a4e8d2b934e68bfa83571 100644 (file)
@@ -24,6 +24,12 @@ error[E0080]: evaluation of constant expression failed
 LL |     println!("{:?}", C);
    |                      ^ referenced constant has errors
 
+warning: erroneous constant used
+  --> $DIR/non_const_fn.rs:14:22
+   |
+LL |     println!("{:?}", C);
+   |                      ^ referenced constant has errors
+
 error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
index 2fb9977f4d700a87d0fed2afab0fbc2ec5fc5f06..599d1d79e7555fcd9ac6958b364c8ff296ccf8d5 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no associated item named `HOST_SIZE` found for type `Foo<A, B>` in the current scope
+error[E0599]: no associated item named `HOST_SIZE` found for struct `Foo<A, B>` in the current scope
   --> $DIR/too_generic_eval_ice.rs:7:19
    |
 LL | pub struct Foo<A, B>(A, B);
index b5d2b4396f9a9de08e86e0e831f4da76ed200ae9..2817abfcaa8de80de2d4639afa8c225f357f98c1 100644 (file)
@@ -8,6 +8,7 @@
 fn main() {
     match &b""[..] {
         ZST => {} //~ ERROR could not evaluate constant pattern
+                  //~| ERROR could not evaluate constant pattern
     }
 }
 
index 5f84204f4086a7edb85320804d7b4c992c493c39..296a55ef16076c9ef5e4d59a251f3f7aa6d6cf64 100644 (file)
@@ -1,5 +1,5 @@
 error: any use of this value will cause an error
-  --> $DIR/transmute-size-mismatch-before-typeck.rs:14:29
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:15:29
    |
 LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
    | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^---
@@ -15,7 +15,7 @@ LL |         ZST => {}
    |         ^^^
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/transmute-size-mismatch-before-typeck.rs:14:29
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:15:29
    |
 LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
    |                             ^^^^^^^^^^^^^^^^^^^
@@ -23,6 +23,12 @@ LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
    = note: source type: `usize` (word size)
    = note: target type: `&'static [u8]` (2 * word size)
 
-error: aborting due to 3 previous errors
+error: could not evaluate constant pattern
+  --> $DIR/transmute-size-mismatch-before-typeck.rs:10:9
+   |
+LL |         ZST => {}
+   |         ^^^
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0512`.
index 5d779355400ccf6c0ee8040a568776999191c96a..2a41f708c2b87be80dc709ddd19b0b6050e6a014 100644 (file)
@@ -7,13 +7,15 @@
 
 fn main() {
     let x: &'static () = &();
-    assert_eq!(x as *const () as usize, 1);
+    assert_ne!(x as *const () as usize, 1);
     let x: &'static Foo = &Foo;
-    assert_eq!(x as *const Foo as usize, 4);
+    assert_ne!(x as *const Foo as usize, 4);
 
     // statics must have a unique address
     assert_ne!(&FOO as *const Foo as usize, 4);
 
-    assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
-    assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+    // FIXME this two tests should be assert_eq!
+    // this stopped working since we are promoting to constants instead of statics
+    assert_ne!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
+    assert_ne!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
 }
index 054bd0914d31c300fb5e638f8455d4ab47913d39..c95e8d239d2b9d211e97105ad4501099ef816808 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `clone` found for type `Foo` in the current scope
+error[E0599]: no method named `clone` found for struct `Foo` in the current scope
   --> $DIR/copy-a-resource.rs:18:16
    |
 LL | struct Foo {
index 6175b7df1107ad78029a5ffc4f4231a2d105a05b..b2edc1a1f66ca8b3c9d2e1e1f7cae8193e41ab9f 100644 (file)
@@ -3,6 +3,7 @@
 
 trait Foo<X = Box<dyn Foo>> {
     //~^ ERROR cycle detected
+    //~| ERROR cycle detected
 }
 
 fn main() { }
index e89d25742a0acfd589c0dd0a8e8e09d3521809e1..6b38d85302e66f308c94157803f96c2b5d2738fa 100644 (file)
@@ -11,6 +11,19 @@ note: cycle used when collecting item types in top-level module
 LL | trait Foo<X = Box<dyn Foo>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0391]: cycle detected when processing `Foo::X`
+  --> $DIR/cycle-trait-default-type-trait.rs:4:23
+   |
+LL | trait Foo<X = Box<dyn Foo>> {
+   |                       ^^^
+   |
+   = note: ...which again requires processing `Foo::X`, completing the cycle
+note: cycle used when collecting item types in top-level module
+  --> $DIR/cycle-trait-default-type-trait.rs:4:1
+   |
+LL | trait Foo<X = Box<dyn Foo>> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/deduplicate-diagnostics-2.deduplicate.stderr b/src/test/ui/deduplicate-diagnostics-2.deduplicate.stderr
new file mode 100644 (file)
index 0000000..7a28c64
--- /dev/null
@@ -0,0 +1,28 @@
+warning: floating-point types cannot be used in patterns
+  --> $DIR/deduplicate-diagnostics-2.rs:7:9
+   |
+LL |         1.0 => {}
+   |         ^^^
+   |
+   = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+warning: floating-point types cannot be used in patterns
+  --> $DIR/deduplicate-diagnostics-2.rs:11:9
+   |
+LL |         2.0 => {}
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+warning: floating-point types cannot be used in patterns
+  --> $DIR/deduplicate-diagnostics-2.rs:7:9
+   |
+LL |         1.0 => {}
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
diff --git a/src/test/ui/deduplicate-diagnostics-2.duplicate.stderr b/src/test/ui/deduplicate-diagnostics-2.duplicate.stderr
new file mode 100644 (file)
index 0000000..4fff3a8
--- /dev/null
@@ -0,0 +1,37 @@
+warning: floating-point types cannot be used in patterns
+  --> $DIR/deduplicate-diagnostics-2.rs:7:9
+   |
+LL |         1.0 => {}
+   |         ^^^
+   |
+   = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+warning: floating-point types cannot be used in patterns
+  --> $DIR/deduplicate-diagnostics-2.rs:11:9
+   |
+LL |         2.0 => {}
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+warning: floating-point types cannot be used in patterns
+  --> $DIR/deduplicate-diagnostics-2.rs:7:9
+   |
+LL |         1.0 => {}
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+warning: floating-point types cannot be used in patterns
+  --> $DIR/deduplicate-diagnostics-2.rs:11:9
+   |
+LL |         2.0 => {}
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
diff --git a/src/test/ui/deduplicate-diagnostics-2.rs b/src/test/ui/deduplicate-diagnostics-2.rs
new file mode 100644 (file)
index 0000000..f46a7c0
--- /dev/null
@@ -0,0 +1,17 @@
+// build-pass
+// revisions: duplicate deduplicate
+//[deduplicate] compile-flags: -Z deduplicate-diagnostics=yes
+
+fn main() {
+    match 0.0 {
+        1.0 => {} //~ WARNING floating-point types cannot be used in patterns
+                  //~| WARNING this was previously accepted
+                  //~| WARNING floating-point types cannot be used in patterns
+                  //~| WARNING this was previously accepted
+        2.0 => {} //~ WARNING floating-point types cannot be used in patterns
+                  //~| WARNING this was previously accepted
+                  //[duplicate]~| WARNING floating-point types cannot be used in patterns
+                  //[duplicate]~| WARNING this was previously accepted
+        _ => {}
+    }
+}
index 1acfce506229f522f4bd21a5937b853272f4e62e..5df2c687bddc2ea78b7712f4b3e79bc6dfa1f73b 100644 (file)
@@ -1,8 +1,15 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:8:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
 error: cannot find derive macro `Unresolved` in this scope
   --> $DIR/deduplicate-diagnostics.rs:4:10
    |
 LL | #[derive(Unresolved)]
    |          ^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0452`.
index 325da3b5d915bb67232e751a01dbc1a9cfd1bc5a..3b100b59995f067811351df595c5e32037a842b9 100644 (file)
@@ -1,3 +1,9 @@
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:8:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
 error: cannot find derive macro `Unresolved` in this scope
   --> $DIR/deduplicate-diagnostics.rs:4:10
    |
@@ -10,5 +16,18 @@ error: cannot find derive macro `Unresolved` in this scope
 LL | #[derive(Unresolved)]
    |          ^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:8:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/deduplicate-diagnostics.rs:8:8
+   |
+LL | #[deny("literal")]
+   |        ^^^^^^^^^ bad attribute argument
+
+error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0452`.
index 4a1f503d757a50d806cb4eed24f38a9f9341f5bd..c5d41ff2fdac3888241390ce946bc64353002ddb 100644 (file)
@@ -1,8 +1,11 @@
 // revisions: duplicate deduplicate
-//[duplicate] compile-flags: -Z deduplicate-diagnostics=no
+//[deduplicate] compile-flags: -Z deduplicate-diagnostics=yes
 
 #[derive(Unresolved)] //~ ERROR cannot find derive macro `Unresolved` in this scope
                       //[duplicate]~| ERROR cannot find derive macro `Unresolved` in this scope
 struct S;
 
+#[deny("literal")] //~ ERROR malformed lint attribute input
+                   //[duplicate]~| ERROR malformed lint attribute input
+                   //[duplicate]~| ERROR malformed lint attribute input
 fn main() {}
index 038de80508ac23962fb97fdb7238994603160320..2083a1d65220f75d47aea86cff24fcbae9368106 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `clone` found for type `Bar<NotClone>` in the current scope
+error[E0599]: no method named `clone` found for struct `Bar<NotClone>` in the current scope
   --> $DIR/derive-assoc-type-not-impl.rs:18:30
    |
 LL | struct Bar<T: Foo> {
index 2a5d09d4bb7ee3943f076c5577090b90e452ee16..beef639462ed39699475edd673e9e0f0f156f8f5 100644 (file)
 #[derive(PartialOrd,PartialEq)]
 enum Enum {
    A {
-     x: Error //~ ERROR
+     x: Error //~ ERROR can't compare `Error` with `Error`
+              //~| ERROR can't compare `Error` with `Error`
+              //~| ERROR can't compare `Error` with `Error`
+              //~| ERROR can't compare `Error` with `Error`
+              //~| ERROR can't compare `Error` with `Error`
    }
 }
 
index 3f669c20176aa1d52de514603d7518a9e670330b..80b896f4f043e4f95d1fd88680d9b0455492295f 100644 (file)
@@ -7,6 +7,42 @@ LL |      x: Error
    = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
-error: aborting due to previous error
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum-struct-variant.rs:13:6
+   |
+LL |      x: Error
+   |      ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum-struct-variant.rs:13:6
+   |
+LL |      x: Error
+   |      ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum-struct-variant.rs:13:6
+   |
+LL |      x: Error
+   |      ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum-struct-variant.rs:13:6
+   |
+LL |      x: Error
+   |      ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index e69c18200d138748bd5a88ab5f39e8c7caf8bebe..b02828da0d27688e9654cfe441b5edc06ae50078 100644 (file)
 #[derive(PartialOrd,PartialEq)]
 enum Enum {
    A(
-     Error //~ ERROR
+     Error //~ ERROR can't compare `Error` with `Error`
+           //~| ERROR can't compare `Error` with `Error`
+           //~| ERROR can't compare `Error` with `Error`
+           //~| ERROR can't compare `Error` with `Error`
+           //~| ERROR can't compare `Error` with `Error`
      )
 }
 
index a78af9e9cf8e43fae74a0bf50aaa49f3b1599f22..f12038fb867a7fa106ae2e2cd3d4871b85398bf4 100644 (file)
@@ -7,6 +7,42 @@ LL |      Error
    = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
-error: aborting due to previous error
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum.rs:13:6
+   |
+LL |      Error
+   |      ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum.rs:13:6
+   |
+LL |      Error
+   |      ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum.rs:13:6
+   |
+LL |      Error
+   |      ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-enum.rs:13:6
+   |
+LL |      Error
+   |      ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index b5d1df932c5395b01a3782395456f8f24afea079..bfcfc3d5dfdd7003b673d42bb96d9d40a6cf1697 100644 (file)
@@ -9,7 +9,11 @@
 
 #[derive(PartialOrd,PartialEq)]
 struct Struct {
-    x: Error //~ ERROR
+    x: Error //~ ERROR can't compare `Error` with `Error`
+             //~| ERROR can't compare `Error` with `Error`
+             //~| ERROR can't compare `Error` with `Error`
+             //~| ERROR can't compare `Error` with `Error`
+             //~| ERROR can't compare `Error` with `Error`
 }
 
 fn main() {}
index 8e85f1a01ffe6a2e3a40d9f74faf45e3e4eca777..dbb014752ec01ae91e1e1d030bd4b57b7cf86fb1 100644 (file)
@@ -7,6 +7,42 @@ LL |     x: Error
    = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
-error: aborting due to previous error
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-struct.rs:12:5
+   |
+LL |     x: Error
+   |     ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-struct.rs:12:5
+   |
+LL |     x: Error
+   |     ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-struct.rs:12:5
+   |
+LL |     x: Error
+   |     ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-struct.rs:12:5
+   |
+LL |     x: Error
+   |     ^^^^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 7dfb33b78e545242ba2299592c8ab3ebbfb52e0f..c8bdd6423a0233efd0875dc06e2a51e338bf7518 100644 (file)
@@ -9,7 +9,11 @@
 
 #[derive(PartialOrd,PartialEq)]
 struct Struct(
-    Error //~ ERROR
+    Error //~ ERROR can't compare `Error` with `Error`
+          //~| ERROR can't compare `Error` with `Error`
+          //~| ERROR can't compare `Error` with `Error`
+          //~| ERROR can't compare `Error` with `Error`
+          //~| ERROR can't compare `Error` with `Error`
 );
 
 fn main() {}
index bf915781aa5ce6ab72978c10255751a4c084f647..f6f1694bbf01e70b2ea0948ba4d26e3513286eda 100644 (file)
@@ -7,6 +7,42 @@ LL |     Error
    = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
-error: aborting due to previous error
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-tuple-struct.rs:12:5
+   |
+LL |     Error
+   |     ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-tuple-struct.rs:12:5
+   |
+LL |     Error
+   |     ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-tuple-struct.rs:12:5
+   |
+LL |     Error
+   |     ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Error` with `Error`
+  --> $DIR/derives-span-PartialOrd-tuple-struct.rs:12:5
+   |
+LL |     Error
+   |     ^^^^^ no implementation for `Error < Error` and `Error > Error`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Error`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 52659bd11e0808cf090d2fa33fd427a45a881e7a..95d440420b065739f1b989a74598bf253a82bf21 100644 (file)
@@ -1,9 +1,11 @@
 #[derive(Send)]
 //~^ ERROR cannot find derive macro `Send` in this scope
+//~| ERROR cannot find derive macro `Send` in this scope
 struct Test;
 
 #[derive(Sync)]
 //~^ ERROR cannot find derive macro `Sync` in this scope
+//~| ERROR cannot find derive macro `Sync` in this scope
 struct Test1;
 
 pub fn main() {}
index b18df3511817db7400d45c8e70fd84eb7546880b..74ca37287d23210d9889161d6ec0fd99ad55d3e3 100644 (file)
@@ -1,15 +1,39 @@
 error: cannot find derive macro `Sync` in this scope
-  --> $DIR/deriving-bounds.rs:5:10
+  --> $DIR/deriving-bounds.rs:6:10
    |
 LL | #[derive(Sync)]
    |          ^^^^
    |
 note: unsafe traits like `Sync` should be implemented explicitly
-  --> $DIR/deriving-bounds.rs:5:10
+  --> $DIR/deriving-bounds.rs:6:10
    |
 LL | #[derive(Sync)]
    |          ^^^^
 
+error: cannot find derive macro `Sync` in this scope
+  --> $DIR/deriving-bounds.rs:6:10
+   |
+LL | #[derive(Sync)]
+   |          ^^^^
+   |
+note: unsafe traits like `Sync` should be implemented explicitly
+  --> $DIR/deriving-bounds.rs:6:10
+   |
+LL | #[derive(Sync)]
+   |          ^^^^
+
+error: cannot find derive macro `Send` in this scope
+  --> $DIR/deriving-bounds.rs:1:10
+   |
+LL | #[derive(Send)]
+   |          ^^^^
+   |
+note: unsafe traits like `Send` should be implemented explicitly
+  --> $DIR/deriving-bounds.rs:1:10
+   |
+LL | #[derive(Send)]
+   |          ^^^^
+
 error: cannot find derive macro `Send` in this scope
   --> $DIR/deriving-bounds.rs:1:10
    |
@@ -22,5 +46,5 @@ note: unsafe traits like `Send` should be implemented explicitly
 LL | #[derive(Send)]
    |          ^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
index f4a6f3fd62a05666513111af0b5c152e4852ba5a..d1af5b458cc0ada803bc3cd1659c52c5511bb6f5 100644 (file)
@@ -1,5 +1,10 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 #[derive(Eqr)]
 //~^ ERROR cannot find derive macro `Eqr` in this scope
+//~| ERROR cannot find derive macro `Eqr` in this scope
 struct Foo;
 
 pub fn main() {}
index 1b8e689c753f31a2c7ca18d12806be1d3f7c4fe2..ead131323246ad01541afc7bd621a2b28f7b3caa 100644 (file)
@@ -1,8 +1,24 @@
 error: cannot find derive macro `Eqr` in this scope
-  --> $DIR/deriving-meta-unknown-trait.rs:1:10
+  --> $DIR/deriving-meta-unknown-trait.rs:5:10
    |
 LL | #[derive(Eqr)]
    |          ^^^ help: a derive macro with a similar name exists: `Eq`
+   | 
+  ::: $SRC_DIR/libcore/cmp.rs:LL:COL
+   |
+LL | pub macro Eq($item:item) {
+   | ------------------------ similarly named derive macro `Eq` defined here
+
+error: cannot find derive macro `Eqr` in this scope
+  --> $DIR/deriving-meta-unknown-trait.rs:5:10
+   |
+LL | #[derive(Eqr)]
+   |          ^^^ help: a derive macro with a similar name exists: `Eq`
+   | 
+  ::: $SRC_DIR/libcore/cmp.rs:LL:COL
+   |
+LL | pub macro Eq($item:item) {
+   | ------------------------ similarly named derive macro `Eq` defined here
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
index c7098d4b563bb1a65b6820b158ec70126be2b042..1173eca640fc39ab844251ee95316cfcaefbd83d 100644 (file)
@@ -1,4 +1,5 @@
 #[derive(FromPrimitive)] //~ ERROR cannot find derive macro `FromPrimitive` in this scope
+                         //~| ERROR cannot find derive macro `FromPrimitive` in this scope
 enum Foo {}
 
 fn main() {}
index d1b444976ddcce954c97020cddf0376af484f33b..ca64c9ee732cb3c65de202ce96a3c2cd9ffede25 100644 (file)
@@ -4,5 +4,11 @@ error: cannot find derive macro `FromPrimitive` in this scope
 LL | #[derive(FromPrimitive)]
    |          ^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: cannot find derive macro `FromPrimitive` in this scope
+  --> $DIR/deriving-primitive.rs:1:10
+   |
+LL | #[derive(FromPrimitive)]
+   |          ^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
index 7e7ba59dca8169f73af3637f5467bb2c94bd53ca..3f912f7ffc63e5630e6e0ffb214a692006f47dde 100644 (file)
@@ -2,25 +2,25 @@ fn main() {
     match 0u8 {
         [u8]::AssocItem => {}
         //~^ ERROR missing angle brackets in associated item path
-        //~| ERROR no associated item named `AssocItem` found for type `[u8]` in the current scope
+        //~| ERROR no associated item named `AssocItem` found
         (u8, u8)::AssocItem => {}
         //~^ ERROR missing angle brackets in associated item path
-        //~| ERROR no associated item named `AssocItem` found for type `(u8, u8)` in the current sco
+        //~| ERROR no associated item named `AssocItem` found
         _::AssocItem => {}
         //~^ ERROR missing angle brackets in associated item path
-        //~| ERROR no associated item named `AssocItem` found for type `_` in the current scope
+        //~| ERROR no associated item named `AssocItem` found
     }
     match &0u8 {
         &(u8,)::AssocItem => {}
         //~^ ERROR missing angle brackets in associated item path
-        //~| ERROR no associated item named `AssocItem` found for type `(u8,)` in the current scope
+        //~| ERROR no associated item named `AssocItem` found
     }
 }
 
 macro_rules! pat {
     ($ty: ty) => ($ty::AssocItem)
     //~^ ERROR missing angle brackets in associated item path
-    //~| ERROR no associated item named `AssocItem` found for type `u8` in the current scope
+    //~| ERROR no associated item named `AssocItem` found
 }
 macro_rules! ty {
     () => (u8)
@@ -31,6 +31,6 @@ fn check_macros() {
         pat!(u8) => {}
         ty!()::AssocItem => {}
         //~^ ERROR missing angle brackets in associated item path
-        //~| ERROR no associated item named `AssocItem` found for type `u8` in the current scope
+        //~| ERROR no associated item named `AssocItem` found
     }
 }
index 59b865437a2e0f724c7b3505e009d71b225c40dc..3f1946b94f64b5c6f7b33ae789fd06c2fefbf226 100644 (file)
@@ -37,13 +37,13 @@ LL |     ($ty: ty) => ($ty::AssocItem)
 LL |         pat!(u8) => {}
    |         -------- in this macro invocation
 
-error[E0599]: no associated item named `AssocItem` found for type `[u8]` in the current scope
+error[E0599]: no associated item named `AssocItem` found for slice `[u8]` in the current scope
   --> $DIR/bad-assoc-pat.rs:3:15
    |
 LL |         [u8]::AssocItem => {}
    |               ^^^^^^^^^ associated item not found in `[u8]`
 
-error[E0599]: no associated item named `AssocItem` found for type `(u8, u8)` in the current scope
+error[E0599]: no associated item named `AssocItem` found for tuple `(u8, u8)` in the current scope
   --> $DIR/bad-assoc-pat.rs:6:19
    |
 LL |         (u8, u8)::AssocItem => {}
@@ -55,7 +55,7 @@ error[E0599]: no associated item named `AssocItem` found for type `_` in the cur
 LL |         _::AssocItem => {}
    |            ^^^^^^^^^ associated item not found in `_`
 
-error[E0599]: no associated item named `AssocItem` found for type `(u8,)` in the current scope
+error[E0599]: no associated item named `AssocItem` found for tuple `(u8,)` in the current scope
   --> $DIR/bad-assoc-pat.rs:14:17
    |
 LL |         &(u8,)::AssocItem => {}
index ea21592997bfeed95d67a69a5ac36ac2ebc4a481..60633c6930cdfb8dd7a615a21bc3944f809c4560 100644 (file)
@@ -35,5 +35,5 @@ impl S {
 }
 
 fn main() {
-    S.hello_method(); //~ no method named `hello_method` found for type `S` in the current scope
+    S.hello_method(); //~ no method named `hello_method` found
 }
index d1e995013cb93708fdf345f1c18a5c08fe6f458a..072e61f6a3cd179e85979f045ccbfeb2dca5ff23 100644 (file)
@@ -56,7 +56,7 @@ error: missing `fn`, `type`, or `const` for associated-item declaration
 LL |     pub hello_method(&self) {
    |        ^ missing `fn`, `type`, or `const`
 
-error[E0599]: no method named `hello_method` found for type `S` in the current scope
+error[E0599]: no method named `hello_method` found for struct `S` in the current scope
   --> $DIR/issue-40006.rs:38:7
    |
 LL | struct S;
index 189335520543331b5aea5c52951a28cd83ed0e37..e4e94bb9492371c811fb2a0ccc56fef040e673df 100644 (file)
@@ -1,8 +1,8 @@
 fn main() {
     (0..13).collect<Vec<i32>>();
-    //~^ ERROR chained comparison
+    //~^ ERROR comparison operators cannot be chained
     Vec<i32>::new();
-    //~^ ERROR chained comparison
+    //~^ ERROR comparison operators cannot be chained
     (0..13).collect<Vec<i32>();
-    //~^ ERROR chained comparison
+    //~^ ERROR comparison operators cannot be chained
 }
index 749d1093ccab83246740db429f47a8043da4a967..f952136a7bfe36b8b1031acbf17606dfa9259e4f 100644 (file)
@@ -1,15 +1,23 @@
-error: chained comparison operators require parentheses
+error: comparison operators cannot be chained
   --> $DIR/issue-40396.rs:2:20
    |
 LL |     (0..13).collect<Vec<i32>>();
    |                    ^^^^^
    |
+help: split the comparison into two...
+   |
+LL |     (0..13).collect < Vec && Vec <i32>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     ((0..13).collect < Vec) <i32>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 help: use `::<...>` instead of `<...>` to specify type arguments
    |
 LL |     (0..13).collect::<Vec<i32>>();
    |                    ^^
 
-error: chained comparison operators require parentheses
+error: comparison operators cannot be chained
   --> $DIR/issue-40396.rs:4:8
    |
 LL |     Vec<i32>::new();
@@ -20,12 +28,20 @@ help: use `::<...>` instead of `<...>` to specify type arguments
 LL |     Vec::<i32>::new();
    |        ^^
 
-error: chained comparison operators require parentheses
+error: comparison operators cannot be chained
   --> $DIR/issue-40396.rs:6:20
    |
 LL |     (0..13).collect<Vec<i32>();
    |                    ^^^^^
    |
+help: split the comparison into two...
+   |
+LL |     (0..13).collect < Vec && Vec <i32>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     ((0..13).collect < Vec) <i32>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 help: use `::<...>` instead of `<...>` to specify type arguments
    |
 LL |     (0..13).collect::<Vec<i32>();
index 44421b077fa26eb2c0e75f664c07be4d45cbd76f..467daef63f6a660b015b84006e342902e2e07e38 100644 (file)
@@ -5,8 +5,10 @@ fn test_and() {
     let b = false;
 
     let _ = a and b; //~ ERROR `and` is not a logical operator
+                     //~| ERROR `and` is not a logical operator
 
     if a and b { //~ ERROR `and` is not a logical operator
+                 //~| ERROR `and` is not a logical operator
         println!("both");
     }
 
@@ -18,8 +20,10 @@ fn test_or() {
     let b = false;
 
     let _ = a or b; //~ ERROR `or` is not a logical operator
+                    //~| ERROR `or` is not a logical operator
 
     if a or b { //~ ERROR `or` is not a logical operator
+                //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -28,6 +32,7 @@ fn test_and_par() {
     let a = true;
     let b = false;
     if (a and b) {  //~ ERROR `and` is not a logical operator
+                    //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -36,6 +41,7 @@ fn test_or_par() {
     let a = true;
     let b = false;
     if (a or b) {  //~ ERROR `or` is not a logical operator
+                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
@@ -44,6 +50,7 @@ fn test_while_and() {
     let a = true;
     let b = false;
     while a and b {  //~ ERROR `and` is not a logical operator
+                     //~| ERROR `and` is not a logical operator
         println!("both");
     }
 }
@@ -52,6 +59,7 @@ fn test_while_or() {
     let a = true;
     let b = false;
     while a or b { //~ ERROR `or` is not a logical operator
+                   //~| ERROR `or` is not a logical operator
         println!("both");
     }
 }
index 528c62f501e0d1bf65bcad255050b235f1255559..e8731cf238ec40b56bd74a0328d39d7b87e986cc 100644 (file)
@@ -7,7 +7,23 @@ LL |     let _ = a and b;
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15
+   |
+LL |     let _ = a and b;
+   |               ^^^ help: use `&&` to perform logical conjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
+error: `and` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10
+   |
+LL |     if a and b {
+   |          ^^^ help: use `&&` to perform logical conjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
+error: `and` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10
    |
 LL |     if a and b {
    |          ^^^ help: use `&&` to perform logical conjunction
@@ -15,7 +31,7 @@ LL |     if a and b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15
    |
 LL |     let _ = a or b;
    |               ^^ help: use `||` to perform logical disjunction
@@ -23,7 +39,23 @@ LL |     let _ = a or b;
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15
+   |
+LL |     let _ = a or b;
+   |               ^^ help: use `||` to perform logical disjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
+error: `or` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10
+   |
+LL |     if a or b {
+   |          ^^ help: use `||` to perform logical disjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
+error: `or` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10
    |
 LL |     if a or b {
    |          ^^ help: use `||` to perform logical disjunction
@@ -31,15 +63,31 @@ LL |     if a or b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11
    |
 LL |     if (a and b) {
    |           ^^^ help: use `&&` to perform logical conjunction
    |
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
+error: `and` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11
+   |
+LL |     if (a and b) {
+   |           ^^^ help: use `&&` to perform logical conjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
+error: `or` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11
+   |
+LL |     if (a or b) {
+   |           ^^ help: use `||` to perform logical disjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11
    |
 LL |     if (a or b) {
    |           ^^ help: use `||` to perform logical disjunction
@@ -47,15 +95,31 @@ LL |     if (a or b) {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error: `and` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13
    |
 LL |     while a and b {
    |             ^^^ help: use `&&` to perform logical conjunction
    |
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
+error: `and` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13
+   |
+LL |     while a and b {
+   |             ^^^ help: use `&&` to perform logical conjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
+error: `or` is not a logical operator
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13
+   |
+LL |     while a or b {
+   |             ^^ help: use `||` to perform logical disjunction
+   |
+   = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+
 error: `or` is not a logical operator
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13
    |
 LL |     while a or b {
    |             ^^ help: use `||` to perform logical disjunction
@@ -63,13 +127,13 @@ LL |     while a or b {
    = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33
+  --> $DIR/issue-54109-and_instead_of_ampersands.rs:15:33
    |
 LL |     let _recovery_witness: () = 0;
    |                            --   ^ expected `()`, found integer
    |                            |
    |                            expected due to this
 
-error: aborting due to 9 previous errors
+error: aborting due to 17 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index ef0904c1a2dbfe4a6af2dc8ea4144967ddfbed10..6e2b1abd1370f462735dc29e3250614323874323 100644 (file)
@@ -2,5 +2,5 @@
 
 fn main() {
     T::new();
-    //~^ ERROR no function or associated item named `new` found for type `T` in the current scope
+    //~^ ERROR no function or associated item named `new` found
 }
index 5189ffa62d1ba23446eb46c849f4fa2af97a3699..fd7fdb4f7226c6eb0c4afbc42d29d17f7d443e65 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no function or associated item named `new` found for type `T` in the current scope
+error[E0599]: no function or associated item named `new` found for struct `T` in the current scope
   --> $DIR/dont-suggest-private-trait-method.rs:4:8
    |
 LL | struct T;
index 1a38d3d7601b815ce68d028b46263928c97d1d4e..f4144277f16bee48d3b60925152847308c0ccf11 100644 (file)
@@ -22,8 +22,8 @@ fn main() {
     let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1`
     let xe1 = XEmpty1();
     //~^ ERROR expected function, tuple struct or tuple variant, found struct `XEmpty1`
-    let xe3 = XE::Empty3; //~ ERROR no variant or associated item named `Empty3` found for type
-    let xe3 = XE::Empty3(); //~ ERROR no variant or associated item named `Empty3` found for type
+    let xe3 = XE::Empty3; //~ ERROR no variant or associated item named `Empty3` found for enum
+    let xe3 = XE::Empty3(); //~ ERROR no variant or associated item named `Empty3` found for enum
 
-    XE::Empty1 {}; //~ ERROR no variant `Empty1` in enum `empty_struct::XE`
+    XE::Empty1 {}; //~ ERROR no variant named `Empty1` found for enum `empty_struct::XE`
 }
index f427c1ba0adfb3636c6bac161187192d30a384c7..9da3a5f5bdb3d053297b450bddbe1277d4829544 100644 (file)
@@ -9,6 +9,11 @@ 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
 
 error[E0423]: expected function, tuple struct or tuple variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-expr.rs:16:14
@@ -21,6 +26,11 @@ 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
 
 error[E0423]: expected value, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-expr.rs:18:14
@@ -48,6 +58,11 @@ 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
 
 error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-expr.rs:23:15
@@ -57,8 +72,13 @@ 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
 
-error[E0599]: no variant or associated item named `Empty3` found for type `empty_struct::XE` in the current scope
+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
    |
 LL |     let xe3 = XE::Empty3;
@@ -67,7 +87,7 @@ LL |     let xe3 = XE::Empty3;
    |                   variant or associated item not found in `empty_struct::XE`
    |                   help: there is a variant with a similar name: `XEmpty3`
 
-error[E0599]: no variant or associated item named `Empty3` found for type `empty_struct::XE` in the current scope
+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:26:19
    |
 LL |     let xe3 = XE::Empty3();
@@ -76,7 +96,7 @@ LL |     let xe3 = XE::Empty3();
    |                   variant or associated item not found in `empty_struct::XE`
    |                   help: there is a variant with a similar name: `XEmpty3`
 
-error: no variant `Empty1` in enum `empty_struct::XE`
+error[E0599]: no variant named `Empty1` found for enum `empty_struct::XE`
   --> $DIR/empty-struct-braces-expr.rs:28:9
    |
 LL |     XE::Empty1 {};
index 9b5f31157d1bbce4b0f987d4f18b7389cf60fe67..0ff21c91b78fd25980a09bb4490cf02491e9c1fd 100644 (file)
@@ -15,6 +15,11 @@ 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
 
 error: aborting due to 2 previous errors
 
index 0b3c9ae51519e748e0e544b9e168e8a90ebecfe7..80c29db8d9b77a8d67fa6e741a50f234cda1a6e0 100644 (file)
@@ -9,6 +9,11 @@ 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
 
 error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-pat-2.rs:18:9
@@ -18,6 +23,11 @@ LL |         XEmpty1() => ()
    |         |
    |         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
 
 error[E0532]: expected tuple struct or tuple variant, found struct `Empty1`
   --> $DIR/empty-struct-braces-pat-2.rs:21:9
@@ -30,6 +40,11 @@ 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
 
 error[E0532]: expected tuple struct or tuple variant, found struct `XEmpty1`
   --> $DIR/empty-struct-braces-pat-2.rs:24:9
@@ -39,6 +54,11 @@ LL |         XEmpty1(..) => ()
    |         |
    |         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
 
 error: aborting due to 4 previous errors
 
index 785396c448bb05629560d29ff5ac6d17b14781b4..05439b39ea39dfe80e321b4dc2dead35cc412c5a 100644 (file)
@@ -15,6 +15,11 @@ 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
 
 error[E0532]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
   --> $DIR/empty-struct-braces-pat-3.rs:25:9
@@ -33,6 +38,11 @@ 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
 
 error: aborting due to 4 previous errors
 
index cfbb468e5e6331e863320082e88e4f4777faf9af..9388ed2665710d7896ce47cff1e9142284f523c7 100644 (file)
@@ -33,6 +33,11 @@ LL |         XE::XEmpty5 => (),
    |         |   |
    |         |   help: a unit variant with a similar name exists: `XEmpty4`
    |         did you mean `XE::XEmpty5( /* fields */ )`?
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:7:5
+   |
+LL |     XEmpty4,
+   |     ------- similarly named unit variant `XEmpty4` defined here
 
 error: aborting due to 4 previous errors
 
index fd41a6ed382842e1a9e29a8cca4f28ce84c3717a..8ee14a3d01d899ccde72f5d933f0d85b55f5c15b 100644 (file)
@@ -3,24 +3,44 @@ error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
    |
 LL |         Empty2() => ()
    |         ^^^^^^ 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
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
   --> $DIR/empty-struct-unit-pat.rs:24:9
    |
 LL |         XEmpty2() => ()
    |         ^^^^^^^ 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
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
   --> $DIR/empty-struct-unit-pat.rs:28:9
    |
 LL |         Empty2(..) => ()
    |         ^^^^^^ 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
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
   --> $DIR/empty-struct-unit-pat.rs:32:9
    |
 LL |         XEmpty2(..) => ()
    |         ^^^^^^^ 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
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
   --> $DIR/empty-struct-unit-pat.rs:37:9
@@ -35,6 +55,11 @@ LL |         XE::XEmpty4() => (),
    |         ^^^^-------
    |             |
    |             help: a tuple variant with a similar name exists: `XEmpty5`
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:8:5
+   |
+LL |     XEmpty5(),
+   |     --------- similarly named tuple variant `XEmpty5` defined here
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
   --> $DIR/empty-struct-unit-pat.rs:46:9
@@ -49,6 +74,11 @@ LL |         XE::XEmpty4(..) => (),
    |         ^^^^-------
    |             |
    |             help: a tuple variant with a similar name exists: `XEmpty5`
+   | 
+  ::: $DIR/auxiliary/empty-struct.rs:8:5
+   |
+LL |     XEmpty5(),
+   |     --------- similarly named tuple variant `XEmpty5` defined here
 
 error: aborting due to 8 previous errors
 
index 58d856b7c9d233d9af3c105ce8cf2281994f3004..a5d8f87261b2b5da3d20201f1d386fc9e8d0431b 100644 (file)
@@ -2,5 +2,6 @@ fn main() {
     match 5u32 {
         1000 ..= 5 => {}
         //~^ ERROR lower range bound must be less than or equal to upper
+        //~| ERROR lower range bound must be less than or equal to upper
     }
 }
index db8161d8fd5d8f5d1a6d0e63d6eba10f32c4f076..8a6114024b630d90bdec4c2c304c6b20d2b98beb 100644 (file)
@@ -4,6 +4,12 @@ error[E0030]: lower range bound must be less than or equal to upper
 LL |         1000 ..= 5 => {}
    |         ^^^^ lower bound larger than upper bound
 
-error: aborting due to previous error
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/E0030.rs:3:9
+   |
+LL |         1000 ..= 5 => {}
+   |         ^^^^ lower bound larger than upper bound
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0030`.
index 940b9f693cade298f393834155c91732f85d5f1e..4e5a6c9301467a1f21ba725b9aa050bdb6e19aa7 100644 (file)
@@ -1,4 +1,8 @@
 #![allow(foo = "")] //~ ERROR E0452
-
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
+                    //~| ERROR E0452
 fn main() {
 }
index 7f074168f8e02c42c67bca54f4d1866741c8092a..30c11e3274e1c5049e1f70ce914ab75718e79512 100644 (file)
@@ -4,6 +4,36 @@ error[E0452]: malformed lint attribute input
 LL | #![allow(foo = "")]
    |          ^^^^^^^^ bad attribute argument
 
-error: aborting due to previous error
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/E0452.rs:1:10
+   |
+LL | #![allow(foo = "")]
+   |          ^^^^^^^^ bad attribute argument
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0452`.
index 46fa04843ea03d6ce0fde890912ebb54e122dc62..69155b0688bc04db05d712d0535b82ee07934a4a 100644 (file)
@@ -2,5 +2,7 @@
 
 #[allow(non_snake_case)]
 //~^ ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case)
+//~| ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case)
+//~| ERROR allow(non_snake_case) overruled by outer forbid(non_snake_case)
 fn main() {
 }
index 03cc756d6ac004f7ea405dae179fc218d4ae8d6f..138e8483461c9e461a33a53437820e5868f6e649 100644 (file)
@@ -7,6 +7,24 @@ LL |
 LL | #[allow(non_snake_case)]
    |         ^^^^^^^^^^^^^^ overruled by previous forbid
 
-error: aborting due to previous error
+error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case)
+  --> $DIR/E0453.rs:3:9
+   |
+LL | #![forbid(non_snake_case)]
+   |           -------------- `forbid` level set here
+LL | 
+LL | #[allow(non_snake_case)]
+   |         ^^^^^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(non_snake_case) overruled by outer forbid(non_snake_case)
+  --> $DIR/E0453.rs:3:9
+   |
+LL | #![forbid(non_snake_case)]
+   |           -------------- `forbid` level set here
+LL | 
+LL | #[allow(non_snake_case)]
+   |         ^^^^^^^^^^^^^^ overruled by previous forbid
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index b09f5df5201b1b39aebb3fbfd78046a42aa41fa3..3bf428676105d383d48a1798cf33bbb0df604760 100644 (file)
@@ -1,5 +1,6 @@
 // repr currently doesn't support literals
 #[repr("C")] //~ ERROR E0565
+             //~| ERROR E0565
 struct A {  }
 
 fn main() {  }
index 6ed90c0ae4ffe10e97ed190a0cea077e17ed65e3..aa0951528e1ed5764e246a0c49d48d8029fc1bb7 100644 (file)
@@ -4,6 +4,12 @@ error[E0565]: meta item in `repr` must be an identifier
 LL | #[repr("C")]
    |        ^^^
 
-error: aborting due to previous error
+error[E0565]: meta item in `repr` must be an identifier
+  --> $DIR/E0565.rs:2:8
+   |
+LL | #[repr("C")]
+   |        ^^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0565`.
index d1e7e3f47442fcbd522e40dc487e519839a00410..0bbf9a6080349f4a0d4f6f135803f3538024fcd8 100644 (file)
@@ -1,10 +1,10 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/E0586.rs:3:22
+  --> $DIR/E0586.rs:3:19
    |
 LL |     let x = &tmp[1..=];
-   |                      ^
+   |                   ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: aborting due to previous error
 
index 89bfccf2fbc56f1cdd5d798b57f16adc904c61c1..a78a003661d6f96e507aa640793eb264f6c3862a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no associated item named `NotEvenReal` found for type `Foo` in the current scope
+error[E0599]: no associated item named `NotEvenReal` found for struct `Foo` in the current scope
   --> $DIR/E0599.rs:4:20
    |
 LL | struct Foo;
index 8636004102618a13e53617a05769bd0e724e1444..70137cb166206e6d508eb49c1dd6ff504cbcc97a 100644 (file)
@@ -2,6 +2,14 @@ error[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
 
-error: aborting due to previous error
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0602`.
index 73571a375b5f64fad49e6d84ba553cbb452f74f4..6b80d99b3afe9a534c7f133dd20dfaed5fbe645c 100644 (file)
@@ -20,7 +20,7 @@ LL |     x += 2;
    |
    = note: an implementation of `std::ops::AddAssign` might be missing for `&str`
 
-error[E0599]: no method named `z` found for type `&str` in the current scope
+error[E0599]: no method named `z` found for reference `&str` in the current scope
   --> $DIR/error-festival.rs:16:7
    |
 LL |     x.z();
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.rs b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.rs
deleted file mode 100644 (file)
index d97b693..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(exclusive_range_pattern)]
-
-fn main() {
-    match [5..4, 99..105, 43..44] {
-        [_, 99.., _] => {},
-        //~^ ERROR `X..` range patterns are not supported
-        //~| ERROR mismatched types
-        _ => {},
-    }
-}
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr
deleted file mode 100644 (file)
index 76ae724..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: `X..` range patterns are not supported
-  --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13
-   |
-LL |         [_, 99.., _] => {},
-   |             ^^^^ help: try using the maximum value for the type: `99..MAX`
-
-error[E0308]: mismatched types
-  --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13
-   |
-LL |     match [5..4, 99..105, 43..44] {
-   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
-LL |         [_, 99.., _] => {},
-   |             ^^ expected struct `std::ops::Range`, found integer
-   |
-   = note: expected struct `std::ops::Range<{integer}>`
-                found type `{integer}`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.rs b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.rs
deleted file mode 100644 (file)
index 09f459c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(exclusive_range_pattern)]
-
-fn main() {
-    match [5..4, 99..105, 43..44] {
-        [_, 99..] => {},
-        //~^ ERROR `X..` range patterns are not supported
-        //~| ERROR pattern requires 2 elements but array has 3
-        //~| ERROR mismatched types
-        _ => {},
-    }
-}
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr
deleted file mode 100644 (file)
index 5c96f80..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-error: `X..` range patterns are not supported
-  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13
-   |
-LL |         [_, 99..] => {},
-   |             ^^^^ help: try using the maximum value for the type: `99..MAX`
-
-error[E0527]: pattern requires 2 elements but array has 3
-  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:9
-   |
-LL |         [_, 99..] => {},
-   |         ^^^^^^^^^ expected 3 elements
-
-error[E0308]: mismatched types
-  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13
-   |
-LL |     match [5..4, 99..105, 43..44] {
-   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
-LL |         [_, 99..] => {},
-   |             ^^ expected struct `std::ops::Range`, found integer
-   |
-   = note: expected struct `std::ops::Range<{integer}>`
-                found type `{integer}`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0527.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs
deleted file mode 100644 (file)
index 1557f59..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#![feature(exclusive_range_pattern)]
-
-fn main() {
-    match [5..4, 99..105, 43..44] {
-        [..9, 99..100, _] => {},
-        //~^ ERROR `..X` range patterns are not supported
-        //~| ERROR mismatched types
-        //~| ERROR mismatched types
-        //~| ERROR mismatched types
-        _ => {},
-    }
-}
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr
deleted file mode 100644 (file)
index 17e1032..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-error: `..X` range patterns are not supported
-  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:10
-   |
-LL |         [..9, 99..100, _] => {},
-   |          ^^^ help: try using the minimum value for the type: `MIN..9`
-
-error[E0308]: mismatched types
-  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12
-   |
-LL |     match [5..4, 99..105, 43..44] {
-   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
-LL |         [..9, 99..100, _] => {},
-   |            ^ expected struct `std::ops::Range`, found integer
-   |
-   = note: expected struct `std::ops::Range<{integer}>`
-                found type `{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15
-   |
-LL |     match [5..4, 99..105, 43..44] {
-   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
-LL |         [..9, 99..100, _] => {},
-   |               ^^  --- this is of type `{integer}`
-   |               |
-   |               expected struct `std::ops::Range`, found integer
-   |
-   = note: expected struct `std::ops::Range<{integer}>`
-                found type `{integer}`
-
-error[E0308]: mismatched types
-  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:19
-   |
-LL |     match [5..4, 99..105, 43..44] {
-   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
-LL |         [..9, 99..100, _] => {},
-   |               --  ^^^ expected struct `std::ops::Range`, found integer
-   |               |
-   |               this is of type `{integer}`
-   |
-   = note: expected struct `std::ops::Range<{integer}>`
-                found type `{integer}`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
index 2e258d687d38533862e1c2abb5a9074314b4bed1..32b45ee10ad6f1c823a13d272419a20dcde6f077 100644 (file)
@@ -1,6 +1,11 @@
 error[E0308]: mismatched types
   --> $DIR/extern-types-distinct-types.rs:9:5
    |
+LL |     type A;
+   |     ------- the found foreign type
+LL |     type B;
+   |     ------- the expected foreign type
+...
 LL |     r
    |     ^ expected extern type `B`, found extern type `A`
    |
index 0d804f012bcc3dec031460a641b2d03799bf73c3..92c5c2025022e772351ee2e9ffc86b68b16730d5 100644 (file)
@@ -12,7 +12,7 @@
 // the change when it happens.
 //
 // At the time of authoring, the attributes here are listed in the
-// order that they occur in libsyntax/feature_gate.rs.
+// order that they occur in `librustc_feature`.
 //
 // Any builtin attributes that:
 //
index 5f276f6b65ebcf23792086ef54320faef1800f4f..3276309f745c2c0403a0c33edfad1c30d7a7b6ad 100644 (file)
@@ -3,14 +3,17 @@
 mod derive {
     #[derive(x3300)]
     //~^ ERROR cannot find derive macro `x3300` in this scope
+    //~| ERROR cannot find derive macro `x3300` in this scope
     union U { f: i32 }
 
     #[derive(x3300)]
     //~^ ERROR cannot find derive macro `x3300` in this scope
+    //~| ERROR cannot find derive macro `x3300` in this scope
     enum E { }
 
     #[derive(x3300)]
     //~^ ERROR cannot find derive macro `x3300` in this scope
+    //~| ERROR cannot find derive macro `x3300` in this scope
     struct S;
 }
 
index f14591c85e62e3a16bbf2ed6e4af74ab02bec521..ab16591734471ebc9d464ef8c10967479347ec12 100644 (file)
@@ -1,11 +1,29 @@
 error: cannot find derive macro `x3300` in this scope
-  --> $DIR/issue-43106-gating-of-derive-2.rs:12:14
+  --> $DIR/issue-43106-gating-of-derive-2.rs:14:14
    |
 LL |     #[derive(x3300)]
    |              ^^^^^
 
 error: cannot find derive macro `x3300` in this scope
-  --> $DIR/issue-43106-gating-of-derive-2.rs:8:14
+  --> $DIR/issue-43106-gating-of-derive-2.rs:14:14
+   |
+LL |     #[derive(x3300)]
+   |              ^^^^^
+
+error: cannot find derive macro `x3300` in this scope
+  --> $DIR/issue-43106-gating-of-derive-2.rs:9:14
+   |
+LL |     #[derive(x3300)]
+   |              ^^^^^
+
+error: cannot find derive macro `x3300` in this scope
+  --> $DIR/issue-43106-gating-of-derive-2.rs:9:14
+   |
+LL |     #[derive(x3300)]
+   |              ^^^^^
+
+error: cannot find derive macro `x3300` in this scope
+  --> $DIR/issue-43106-gating-of-derive-2.rs:4:14
    |
 LL |     #[derive(x3300)]
    |              ^^^^^
@@ -16,5 +34,5 @@ error: cannot find derive macro `x3300` in this scope
 LL |     #[derive(x3300)]
    |              ^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
 
index 60873f9cc7581c7ae64b01e03568a86588d241be..a01d85515a8b72da5ef7ef2a39dba1a3669af84e 100644 (file)
@@ -18,6 +18,7 @@ mod inner { #![rustc_deprecated()] }
 
     #[rustc_deprecated()] struct S;
     //~^ ERROR stability attributes may not be used outside of the standard library
+    //~| ERROR stability attributes may not be used outside of the standard library
 
     #[rustc_deprecated()] type T = S;
     //~^ ERROR stability attributes may not be used outside of the standard library
index 8c6c26f7b2d819d7c48f9f4ece2e926e6e80080e..3c4dcfec02b12df493aea1f811352de148882121 100644 (file)
@@ -29,17 +29,23 @@ LL |     #[rustc_deprecated()] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:22:5
+  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:19:5
+   |
+LL |     #[rustc_deprecated()] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:23:5
    |
 LL |     #[rustc_deprecated()] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:25:5
+  --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
    |
 LL |     #[rustc_deprecated()] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0734`.
index e3ac2749306ab164e6293581647e2bb1c12da297..73ff965307fd72d3fad5823ea0ad135d2c5d93fa 100644 (file)
@@ -18,6 +18,7 @@ mod inner { #![stable()] }
 
     #[stable()] struct S;
     //~^ ERROR stability attributes may not be used outside of the standard library
+    //~| ERROR stability attributes may not be used outside of the standard library
 
     #[stable()] type T = S;
     //~^ ERROR stability attributes may not be used outside of the standard library
index 09dabd293ff97bf01dd24dda456e04f756583d75..2573db1d684d9670d5bac1fbdbb67c5270d39828 100644 (file)
@@ -29,17 +29,23 @@ LL |     #[stable()] struct S;
    |     ^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-stable.rs:22:5
+  --> $DIR/issue-43106-gating-of-stable.rs:19:5
+   |
+LL |     #[stable()] struct S;
+   |     ^^^^^^^^^^^
+
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/issue-43106-gating-of-stable.rs:23:5
    |
 LL |     #[stable()] type T = S;
    |     ^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-stable.rs:25:5
+  --> $DIR/issue-43106-gating-of-stable.rs:26:5
    |
 LL |     #[stable()] impl S { }
    |     ^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0734`.
index 8d519c3106c5ec068d6511c597ee8278b233bfef..d8339b00c12d2459221eb59705d909dc2a3e6c90 100644 (file)
@@ -18,6 +18,7 @@ mod inner { #![unstable()] }
 
     #[unstable()] struct S;
     //~^ ERROR stability attributes may not be used outside of the standard library
+    //~| ERROR stability attributes may not be used outside of the standard library
 
     #[unstable()] type T = S;
     //~^ ERROR stability attributes may not be used outside of the standard library
index 49da2c59580e7e1d86447902dccdf363b1e60f89..500675e054c3f02346c2a1e4677cebbb90842c1f 100644 (file)
@@ -29,17 +29,23 @@ LL |     #[unstable()] struct S;
    |     ^^^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-unstable.rs:22:5
+  --> $DIR/issue-43106-gating-of-unstable.rs:19:5
+   |
+LL |     #[unstable()] struct S;
+   |     ^^^^^^^^^^^^^
+
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/issue-43106-gating-of-unstable.rs:23:5
    |
 LL |     #[unstable()] type T = S;
    |     ^^^^^^^^^^^^^
 
 error[E0734]: stability attributes may not be used outside of the standard library
-  --> $DIR/issue-43106-gating-of-unstable.rs:25:5
+  --> $DIR/issue-43106-gating-of-unstable.rs:26:5
    |
 LL |     #[unstable()] impl S { }
    |     ^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0734`.
index 9d68d3ec4f52a426976b60ea5ffd4f5e66d960b5..4e6e293846c6e08e2dc387db12d3bf35c8d88680 100644 (file)
@@ -1,2 +1,3 @@
 #[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
+                          //~| ERROR: `#[doc(include)]` is experimental
 fn main() {}
index 683c0ad217426b08e31eb5e3ce8cd9c243918d97..05340184033e9e4a9f6ffa30c5c065a7f1ce2c9e 100644 (file)
@@ -7,6 +7,15 @@ LL | #[doc(include="asdf.md")]
    = note: for more information, see https://github.com/rust-lang/rust/issues/44732
    = help: add `#![feature(external_doc)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error[E0658]: `#[doc(include)]` is experimental
+  --> $DIR/feature-gate-external_doc.rs:1:1
+   |
+LL | #[doc(include="asdf.md")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/44732
+   = help: add `#![feature(external_doc)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 1a7b9c990fa642bc58b9382aaba509eee130bed4..b124e9b2f4d7133a9a427c5826ad096025e05cd8 100644 (file)
@@ -1,4 +1,6 @@
 #![warn(nonstandard_style, reason = "the standard should be respected")]
 //~^ ERROR lint reasons are experimental
+//~| ERROR lint reasons are experimental
+//~| ERROR lint reasons are experimental
 
 fn main() {}
index 390a1bf580f6f403884dbf7fa0d4397885354f2b..08ba9d0d3a313200479a2031cf2baa5e64094332 100644 (file)
@@ -7,6 +7,24 @@ LL | #![warn(nonstandard_style, reason = "the standard should be respected")]
    = note: for more information, see https://github.com/rust-lang/rust/issues/54503
    = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error[E0658]: lint reasons are experimental
+  --> $DIR/feature-gate-lint-reasons.rs:1:28
+   |
+LL | #![warn(nonstandard_style, reason = "the standard should be respected")]
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/54503
+   = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
+
+error[E0658]: lint reasons are experimental
+  --> $DIR/feature-gate-lint-reasons.rs:1:28
+   |
+LL | #![warn(nonstandard_style, reason = "the standard should be respected")]
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/54503
+   = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 9d28f437415c9f78f77bb0dee0f5e20c5065f0c9..1e4a404fa25a7055bce48dfb142aa1874c4cfc96 100644 (file)
@@ -1,7 +1,7 @@
 #[repr(simd)] //~ error: SIMD types are experimental
 struct Foo(u64, u64);
 
-#[repr(C)] //~ warn: conflicting representation hints
+#[repr(C)] //~ ERROR conflicting representation hints
 #[repr(simd)] //~ error: SIMD types are experimental
 struct Bar(u64, u64);
 
index 02c8400e03e8202258163d9d2cbfbd1fcd176394..37a7bd0b1294dba95665c666dfb2bf954258f8ca 100644 (file)
@@ -16,7 +16,7 @@ LL | #[repr(simd)]
    = note: for more information, see https://github.com/rust-lang/rust/issues/27731
    = help: add `#![feature(repr_simd)]` to the crate attributes to enable
 
-warning[E0566]: conflicting representation hints
+error[E0566]: conflicting representation hints
   --> $DIR/feature-gate-repr-simd.rs:4:8
    |
 LL | #[repr(C)]
@@ -24,7 +24,7 @@ LL | #[repr(C)]
 LL | #[repr(simd)]
    |        ^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0566, E0658.
 For more information about an error, try `rustc --explain E0566`.
diff --git a/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.rs b/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.rs
deleted file mode 100644 (file)
index 3b972c1..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#![sanitizer_runtime] //~ ERROR the `#[sanitizer_runtime]` attribute is
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.stderr b/src/test/ui/feature-gates/feature-gate-sanitizer-runtime.stderr
deleted file mode 100644 (file)
index b13ec21..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: the `#[sanitizer_runtime]` attribute is used to identify crates that contain the runtime of a sanitizer and will never be stable
-  --> $DIR/feature-gate-sanitizer-runtime.rs:1:1
-   |
-LL | #![sanitizer_runtime]
-   | ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(sanitizer_runtime)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 4c157a05a5e050fcc992adbde7cba4d0677258e8..bf87aea0d4c1ab847001dd46e04e6383eb532198 100644 (file)
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/auto-trait-regions.rs:44:24
+  --> $DIR/auto-trait-regions.rs:45:24
    |
 LL |         let a = A(&mut true, &mut true, No);
    |                        ^^^^                - temporary value is freed at the end of this statement
@@ -12,7 +12,7 @@ LL |         assert_foo(a);
    = note: consider using a `let` binding to create a longer lived value
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/auto-trait-regions.rs:44:35
+  --> $DIR/auto-trait-regions.rs:45:35
    |
 LL |         let a = A(&mut true, &mut true, No);
    |                                   ^^^^     - temporary value is freed at the end of this statement
@@ -31,7 +31,7 @@ LL |     assert_foo(gen);
    |     ^^^^^^^^^^^^^^^
 
 error: higher-ranked subtype error
-  --> $DIR/auto-trait-regions.rs:48:5
+  --> $DIR/auto-trait-regions.rs:49:5
    |
 LL |     assert_foo(gen);
    |     ^^^^^^^^^^^^^^^
index 46d72899438576137f587c1d2a17476cd5cc35c4..dbd8965dcf0d0e94ee857c881ffec1e3f900249f 100644 (file)
@@ -29,6 +29,7 @@ fn main() {
     };
     assert_foo(gen);
     //~^ ERROR implementation of `Foo` is not general enough
+    //~| ERROR implementation of `Foo` is not general enough
 
     // Allow impls which matches any lifetime
     let x = &OnlyFooIfRef(No);
@@ -47,4 +48,5 @@ fn main() {
     };
     assert_foo(gen);
     //~^ ERROR not general enough
+    //~| ERROR not general enough
 }
index dab4d348ceb604a03572e4c63b80f62a2359afac..29a3907d93c84bc6ad2156281c3018d636f3bbe2 100644 (file)
@@ -11,7 +11,31 @@ LL |     assert_foo(gen);
    = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
 
 error: implementation of `Foo` is not general enough
-  --> $DIR/auto-trait-regions.rs:48:5
+  --> $DIR/auto-trait-regions.rs:30:5
+   |
+LL | auto trait Foo {}
+   | ----------------- trait `Foo` defined here
+...
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo` would have to be implemented for the type `&'0 OnlyFooIfStaticRef`, for any lifetime `'0`...
+   = note: ...but `Foo` is actually implemented for the type `&'1 OnlyFooIfStaticRef`, for some specific lifetime `'1`
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:49:5
+   |
+LL | auto trait Foo {}
+   | ----------------- trait `Foo` defined here
+...
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^ implementation of `Foo` is not general enough
+   |
+   = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
+
+error: implementation of `Foo` is not general enough
+  --> $DIR/auto-trait-regions.rs:49:5
    |
 LL | auto trait Foo {}
    | ----------------- trait `Foo` defined here
@@ -22,5 +46,5 @@ LL |     assert_foo(gen);
    = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
    = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.rs b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.rs
new file mode 100644 (file)
index 0000000..3f4c178
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    match [5..4, 99..105, 43..44] {
+        [_, 99.., _] => {},
+        //~^ ERROR mismatched types
+        _ => {},
+    }
+}
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr
new file mode 100644 (file)
index 0000000..a6f8563
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision.rs:6:13
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [_, 99.., _] => {},
+   |             ^^ expected struct `std::ops::Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.rs b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.rs
new file mode 100644 (file)
index 0000000..dedc854
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    match [5..4, 99..105, 43..44] {
+        [_, 99..] => {},
+        //~^ ERROR pattern requires 2 elements but array has 3
+        //~| ERROR mismatched types
+        _ => {},
+    }
+}
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr
new file mode 100644 (file)
index 0000000..4e0102c
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0527]: pattern requires 2 elements but array has 3
+  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:6:9
+   |
+LL |         [_, 99..] => {},
+   |         ^^^^^^^^^ expected 3 elements
+
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:6:13
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [_, 99..] => {},
+   |             ^^ expected struct `std::ops::Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0527.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.rs b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.rs
new file mode 100644 (file)
index 0000000..6a9b562
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    match [5..4, 99..105, 43..44] {
+        [..9, 99..100, _] => {},
+        //~^ ERROR mismatched types
+        //~| ERROR mismatched types
+        //~| ERROR mismatched types
+        _ => {},
+    }
+}
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr
new file mode 100644 (file)
index 0000000..665eef2
--- /dev/null
@@ -0,0 +1,40 @@
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:12
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [..9, 99..100, _] => {},
+   |            ^ expected struct `std::ops::Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:15
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [..9, 99..100, _] => {},
+   |               ^^  --- this is of type `{integer}`
+   |               |
+   |               expected struct `std::ops::Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:19
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [..9, 99..100, _] => {},
+   |               --  ^^^ expected struct `std::ops::Range`, found integer
+   |               |
+   |               this is of type `{integer}`
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.rs b/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.rs
new file mode 100644 (file)
index 0000000..1733012
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(exclusive_range_pattern)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn foo() {
+    if let ..=5 = 0 {}
+    //~^ ERROR half-open range patterns are unstable
+    if let ...5 = 0 {}
+    //~^ ERROR half-open range patterns are unstable
+    //~| ERROR range-to patterns with `...` are not allowed
+    if let ..5 = 0 {}
+    //~^ ERROR half-open range patterns are unstable
+    if let 5.. = 0 {}
+    //~^ ERROR half-open range patterns are unstable
+    if let 5..= = 0 {}
+    //~^ ERROR half-open range patterns are unstable
+    //~| ERROR inclusive range with no end
+    if let 5... = 0 {}
+    //~^ ERROR half-open range patterns are unstable
+    //~| ERROR inclusive range with no end
+}
diff --git a/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.stderr b/src/test/ui/half-open-range-patterns/feature-gate-half-open-range-patterns.stderr
new file mode 100644 (file)
index 0000000..99db339
--- /dev/null
@@ -0,0 +1,80 @@
+error: range-to patterns with `...` are not allowed
+  --> $DIR/feature-gate-half-open-range-patterns.rs:9:12
+   |
+LL |     if let ...5 = 0 {}
+   |            ^^^ help: use `..=` instead
+
+error[E0586]: inclusive range with no end
+  --> $DIR/feature-gate-half-open-range-patterns.rs:16:13
+   |
+LL |     if let 5..= = 0 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/feature-gate-half-open-range-patterns.rs:19:13
+   |
+LL |     if let 5... = 0 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0658]: half-open range patterns are unstable
+  --> $DIR/feature-gate-half-open-range-patterns.rs:7:12
+   |
+LL |     if let ..=5 = 0 {}
+   |            ^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67264
+   = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
+
+error[E0658]: half-open range patterns are unstable
+  --> $DIR/feature-gate-half-open-range-patterns.rs:9:12
+   |
+LL |     if let ...5 = 0 {}
+   |            ^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67264
+   = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
+
+error[E0658]: half-open range patterns are unstable
+  --> $DIR/feature-gate-half-open-range-patterns.rs:12:12
+   |
+LL |     if let ..5 = 0 {}
+   |            ^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67264
+   = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
+
+error[E0658]: half-open range patterns are unstable
+  --> $DIR/feature-gate-half-open-range-patterns.rs:14:12
+   |
+LL |     if let 5.. = 0 {}
+   |            ^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67264
+   = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
+
+error[E0658]: half-open range patterns are unstable
+  --> $DIR/feature-gate-half-open-range-patterns.rs:16:12
+   |
+LL |     if let 5..= = 0 {}
+   |            ^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67264
+   = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
+
+error[E0658]: half-open range patterns are unstable
+  --> $DIR/feature-gate-half-open-range-patterns.rs:19:12
+   |
+LL |     if let 5... = 0 {}
+   |            ^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67264
+   = help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0586, E0658.
+For more information about an error, try `rustc --explain E0586`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs
new file mode 100644 (file)
index 0000000..7cddf5f
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    let "a".. = "a"; //~ ERROR only char and numeric types are allowed in range patterns
+    let .."a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns
+    let ..="a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr
new file mode 100644 (file)
index 0000000..68ca363
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0029]: only char and numeric types are allowed in range patterns
+  --> $DIR/half-open-range-pats-bad-types.rs:5:9
+   |
+LL |     let "a".. = "a";
+   |         ^^^ this is of type `&'static str` but it should be `char` or numeric
+
+error[E0029]: only char and numeric types are allowed in range patterns
+  --> $DIR/half-open-range-pats-bad-types.rs:6:11
+   |
+LL |     let .."a" = "a";
+   |           ^^^ this is of type `&'static str` but it should be `char` or numeric
+
+error[E0029]: only char and numeric types are allowed in range patterns
+  --> $DIR/half-open-range-pats-bad-types.rs:7:12
+   |
+LL |     let ..="a" = "a";
+   |            ^^^ this is of type `&'static str` but it should be `char` or numeric
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0029`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs
new file mode 100644 (file)
index 0000000..b135891
--- /dev/null
@@ -0,0 +1,168 @@
+// Test various non-exhaustive matches for `X..`, `..=X` and `..X` ranges.
+
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+#![allow(illegal_floating_point_literal_pattern)]
+
+fn main() {}
+
+macro_rules! m {
+    ($s:expr, $($t:tt)+) => {
+        match $s { $($t)+ => {} }
+    }
+}
+
+fn floats() {
+    m!(0f32, core::f32::NEG_INFINITY..); //~ ERROR non-exhaustive patterns: `_` not covered
+    m!(0f32, ..core::f32::INFINITY); //~ ERROR non-exhaustive patterns: `_` not covered
+}
+
+fn khar() {
+    const ALMOST_MAX: char = '\u{10fffe}';
+    const ALMOST_MIN: char = '\u{1}';
+    const VAL: char = 'a';
+    const VAL_1: char = 'b';
+    const VAL_2: char = 'c';
+    m!('a', ..core::char::MAX); //~ ERROR non-exhaustive patterns
+    m!('a', ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+    m!('a', ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+    m!('a', ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+    m!('a', ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+    m!('a', ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+}
+
+mod unsigned {
+    fn u8() {
+        const ALMOST_MAX: u8 = core::u8::MAX - 1;
+        const ALMOST_MIN: u8 = core::u8::MIN + 1;
+        const VAL: u8 = 42;
+        const VAL_1: u8 = VAL + 1;
+        const VAL_2: u8 = VAL + 2;
+        m!(0, ..core::u8::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u16() {
+        const ALMOST_MAX: u16 = core::u16::MAX - 1;
+        const ALMOST_MIN: u16 = core::u16::MIN + 1;
+        const VAL: u16 = 42;
+        const VAL_1: u16 = VAL + 1;
+        const VAL_2: u16 = VAL + 2;
+        m!(0, ..core::u16::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u32() {
+        const ALMOST_MAX: u32 = core::u32::MAX - 1;
+        const ALMOST_MIN: u32 = core::u32::MIN + 1;
+        const VAL: u32 = 42;
+        const VAL_1: u32 = VAL + 1;
+        const VAL_2: u32 = VAL + 2;
+        m!(0, ..core::u32::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u64() {
+        const ALMOST_MAX: u64 = core::u64::MAX - 1;
+        const ALMOST_MIN: u64 = core::u64::MIN + 1;
+        const VAL: u64 = 42;
+        const VAL_1: u64 = VAL + 1;
+        const VAL_2: u64 = VAL + 2;
+        m!(0, ..core::u64::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u128() {
+        const ALMOST_MAX: u128 = core::u128::MAX - 1;
+        const ALMOST_MIN: u128 = core::u128::MIN + 1;
+        const VAL: u128 = 42;
+        const VAL_1: u128 = VAL + 1;
+        const VAL_2: u128 = VAL + 2;
+        m!(0, ..core::u128::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+}
+
+mod signed {
+    fn i8() {
+        const ALMOST_MAX: i8 = core::i8::MAX - 1;
+        const ALMOST_MIN: i8 = core::i8::MIN + 1;
+        const VAL: i8 = 42;
+        const VAL_1: i8 = VAL + 1;
+        const VAL_2: i8 = VAL + 2;
+        m!(0, ..core::i8::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i16() {
+        const ALMOST_MAX: i16 = core::i16::MAX - 1;
+        const ALMOST_MIN: i16 = core::i16::MIN + 1;
+        const VAL: i16 = 42;
+        const VAL_1: i16 = VAL + 1;
+        const VAL_2: i16 = VAL + 2;
+        m!(0, ..core::i16::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i32() {
+        const ALMOST_MAX: i32 = core::i32::MAX - 1;
+        const ALMOST_MIN: i32 = core::i32::MIN + 1;
+        const VAL: i32 = 42;
+        const VAL_1: i32 = VAL + 1;
+        const VAL_2: i32 = VAL + 2;
+        m!(0, ..core::i32::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i64() {
+        const ALMOST_MAX: i64 = core::i64::MAX - 1;
+        const ALMOST_MIN: i64 = core::i64::MIN + 1;
+        const VAL: i64 = 42;
+        const VAL_1: i64 = VAL + 1;
+        const VAL_2: i64 = VAL + 2;
+        m!(0, ..core::i64::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i128() {
+        const ALMOST_MAX: i128 = core::i128::MAX - 1;
+        const ALMOST_MIN: i128 = core::i128::MIN + 1;
+        const VAL: i128 = 42;
+        const VAL_1: i128 = VAL + 1;
+        const VAL_2: i128 = VAL + 2;
+        m!(0, ..core::i128::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
new file mode 100644 (file)
index 0000000..26d0cf9
--- /dev/null
@@ -0,0 +1,547 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8
+   |
+LL |     m!(0f32, core::f32::NEG_INFINITY..);
+   |        ^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:17:8
+   |
+LL |     m!(0f32, ..core::f32::INFINITY);
+   |        ^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
+   |
+LL |     m!('a', ..core::char::MAX);
+   |        ^^^ pattern `'\u{10ffff}'` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
+   |
+LL |     m!('a', ..ALMOST_MAX);
+   |        ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `'\u{0}'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
+   |
+LL |     m!('a', ALMOST_MIN..);
+   |        ^^^ pattern `'\u{0}'` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
+   |
+LL |     m!('a', ..=ALMOST_MAX);
+   |        ^^^ pattern `'\u{10ffff}'` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `'b'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
+   |
+LL |     m!('a', ..=VAL | VAL_2..);
+   |        ^^^ pattern `'b'` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `'b'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:31:8
+   |
+LL |     m!('a', ..VAL_1 | VAL_2..);
+   |        ^^^ pattern `'b'` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
+   |
+LL |         m!(0, ..core::u8::MAX);
+   |            ^ pattern `std::u8::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `254u8..=std::u8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `254u8..=std::u8::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `0u8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0u8` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::u8::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43u8` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:46:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43u8` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
+   |
+LL |         m!(0, ..core::u16::MAX);
+   |            ^ pattern `std::u16::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `65534u16..=std::u16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `65534u16..=std::u16::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `0u16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0u16` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::u16::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43u16` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:59:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43u16` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
+   |
+LL |         m!(0, ..core::u32::MAX);
+   |            ^ pattern `std::u32::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `4294967294u32..=std::u32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `4294967294u32..=std::u32::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `0u32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0u32` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::u32::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43u32` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:72:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43u32` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
+   |
+LL |         m!(0, ..core::u64::MAX);
+   |            ^ pattern `std::u64::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `18446744073709551614u64..=std::u64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `18446744073709551614u64..=std::u64::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `0u64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0u64` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::u64::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43u64` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:85:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43u64` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
+   |
+LL |         m!(0, ..core::u128::MAX);
+   |            ^ pattern `std::u128::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454u128..=std::u128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `340282366920938463463374607431768211454u128..=std::u128::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `0u128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0u128` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::u128::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43u128` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43u128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:98:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43u128` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
+   |
+LL |         m!(0, ..core::i8::MAX);
+   |            ^ pattern `std::i8::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `126i8..=std::i8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `126i8..=std::i8::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i8::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `std::i8::MIN` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::i8::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43i8` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:114:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43i8` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
+   |
+LL |         m!(0, ..core::i16::MAX);
+   |            ^ pattern `std::i16::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `32766i16..=std::i16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `32766i16..=std::i16::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i16::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `std::i16::MIN` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::i16::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43i16` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:127:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43i16` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
+   |
+LL |         m!(0, ..core::i32::MAX);
+   |            ^ pattern `std::i32::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `2147483646i32..=std::i32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `2147483646i32..=std::i32::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i32::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `std::i32::MIN` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::i32::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43i32` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:140:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43i32` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
+   |
+LL |         m!(0, ..core::i64::MAX);
+   |            ^ pattern `std::i64::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `9223372036854775806i64..=std::i64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `9223372036854775806i64..=std::i64::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i64::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `std::i64::MIN` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::i64::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43i64` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:153:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43i64` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
+   |
+LL |         m!(0, ..core::i128::MAX);
+   |            ^ pattern `std::i128::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726i128..=std::i128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `170141183460469231731687303715884105726i128..=std::i128::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i128::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `std::i128::MIN` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `std::i128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `std::i128::MAX` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43i128` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `43i128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:166:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43i128` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 68 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs
new file mode 100644 (file)
index 0000000..efac0df
--- /dev/null
@@ -0,0 +1,49 @@
+// check-pass
+
+// Test various exhaustive matches for `X..`, `..=X` and `..X` ranges.
+
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {}
+
+macro_rules! m {
+    ($s:expr, $($t:tt)+) => {
+        match $s { $($t)+ => {} }
+    }
+}
+
+macro_rules! test_int {
+    ($s:expr, $min:path, $max:path) => {
+        m!($s, $min..);
+        m!($s, $min..5 | 5..);
+        m!($s, ..5 | 5..);
+        m!($s, ..=4 | 5..);
+        m!($s, ..=$max);
+        m!($s, ..$max | $max);
+        m!(($s, true), (..5, true) | (5.., true) | ($min.., false));
+    }
+}
+
+fn unsigned_int() {
+    test_int!(0u8, core::u8::MIN, core::u8::MAX);
+    test_int!(0u16, core::u16::MIN, core::u16::MAX);
+    test_int!(0u32, core::u32::MIN, core::u32::MAX);
+    test_int!(0u64, core::u64::MIN, core::u64::MAX);
+    test_int!(0u128, core::u128::MIN, core::u128::MAX);
+}
+
+fn signed_int() {
+    test_int!(0i8, core::i8::MIN, core::i8::MAX);
+    test_int!(0i16, core::i16::MIN, core::i16::MAX);
+    test_int!(0i32, core::i32::MIN, core::i32::MAX);
+    test_int!(0i64, core::i64::MIN, core::i64::MAX);
+    test_int!(0i128, core::i128::MIN, core::i128::MAX);
+}
+
+fn khar() {
+    m!('a', ..=core::char::MAX);
+    m!('a', '\u{0}'..);
+    m!('a', ..='\u{D7FF}' | '\u{E000}'..);
+    m!('a', ..'\u{D7FF}' | '\u{D7FF}' | '\u{E000}'..);
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.rs
new file mode 100644 (file)
index 0000000..904efda
--- /dev/null
@@ -0,0 +1,54 @@
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+#![allow(illegal_floating_point_literal_pattern)]
+
+macro_rules! m {
+    ($s:expr, $($t:tt)+) => {
+        match $s { $($t)+ => {} }
+    }
+}
+
+fn main() {
+    m!(0, ..core::u8::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::u16::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::u32::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::u64::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::u128::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+
+    m!(0, ..core::i8::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::i16::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::i32::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::i64::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..core::i128::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+
+    m!(0f32, ..core::f32::NEG_INFINITY);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0f64, ..core::f64::NEG_INFINITY);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+
+    m!('a', ..'\u{0}');
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.stderr
new file mode 100644 (file)
index 0000000..b536e1b
--- /dev/null
@@ -0,0 +1,159 @@
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:12:11
+   |
+LL |     m!(0, ..core::u8::MIN);
+   |           ^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:15:11
+   |
+LL |     m!(0, ..core::u16::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:18:11
+   |
+LL |     m!(0, ..core::u32::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:21:11
+   |
+LL |     m!(0, ..core::u64::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:24:11
+   |
+LL |     m!(0, ..core::u128::MIN);
+   |           ^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:28:11
+   |
+LL |     m!(0, ..core::i8::MIN);
+   |           ^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:31:11
+   |
+LL |     m!(0, ..core::i16::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:34:11
+   |
+LL |     m!(0, ..core::i32::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:37:11
+   |
+LL |     m!(0, ..core::i64::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:40:11
+   |
+LL |     m!(0, ..core::i128::MIN);
+   |           ^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:44:14
+   |
+LL |     m!(0f32, ..core::f32::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:47:14
+   |
+LL |     m!(0f64, ..core::f64::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:51:13
+   |
+LL |     m!('a', ..'\u{0}');
+   |             ^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:12:11
+   |
+LL |     m!(0, ..core::u8::MIN);
+   |           ^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:15:11
+   |
+LL |     m!(0, ..core::u16::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:18:11
+   |
+LL |     m!(0, ..core::u32::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:21:11
+   |
+LL |     m!(0, ..core::u64::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:24:11
+   |
+LL |     m!(0, ..core::u128::MIN);
+   |           ^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:28:11
+   |
+LL |     m!(0, ..core::i8::MIN);
+   |           ^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:31:11
+   |
+LL |     m!(0, ..core::i16::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:34:11
+   |
+LL |     m!(0, ..core::i32::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:37:11
+   |
+LL |     m!(0, ..core::i64::MIN);
+   |           ^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:40:11
+   |
+LL |     m!(0, ..core::i128::MIN);
+   |           ^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:44:14
+   |
+LL |     m!(0f32, ..core::f32::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:47:14
+   |
+LL |     m!(0f64, ..core::f64::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-hair-lower-empty.rs:51:13
+   |
+LL |     m!('a', ..'\u{0}');
+   |             ^^^^^^^^^
+
+error: aborting due to 26 previous errors
+
+For more information about this error, try `rustc --explain E0579`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
new file mode 100644 (file)
index 0000000..daed775
--- /dev/null
@@ -0,0 +1,32 @@
+// Test that `...X` range-to patterns are syntactically invalid.
+//
+// See https://github.com/rust-lang/rust/pull/67258#issuecomment-565656155
+// for the reason why. To summarize, we might want to introduce `...expr` as
+// an expression form for splatting (or "untupling") in an expression context.
+// While there is no syntactic ambiguity with `...X` in a pattern context,
+// there's a potential confusion factor here, and we would prefer to keep patterns
+// and expressions in-sync. As such, we do not allow `...X` in patterns either.
+
+#![feature(half_open_range_patterns)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    match scrutinee {
+        ...X => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...0 => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...'a' => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...0.0f32 => {} //~ ERROR range-to patterns with `...` are not allowed
+    }
+}
+
+fn syntax2() {
+    macro_rules! mac {
+        ($e:expr) => {
+            let ...$e; //~ ERROR range-to patterns with `...` are not allowed
+        }
+    }
+
+    mac!(0);
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
new file mode 100644 (file)
index 0000000..ba2e7ea
--- /dev/null
@@ -0,0 +1,35 @@
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:17:9
+   |
+LL |         ...X => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:18:9
+   |
+LL |         ...0 => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:19:9
+   |
+LL |         ...'a' => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:20:9
+   |
+LL |         ...0.0f32 => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:27:17
+   |
+LL |             let ...$e;
+   |                 ^^^ help: use `..=` instead
+...
+LL |     mac!(0);
+   |     -------- in this macro invocation
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
new file mode 100644 (file)
index 0000000..9ace0c3
--- /dev/null
@@ -0,0 +1,26 @@
+// Test `X...` and `X..=` range patterns not being allowed syntactically.
+// FIXME(Centril): perhaps these should be semantic restrictions.
+
+#![feature(half_open_range_patterns)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn foo() {
+    if let 0... = 1 {} //~ ERROR inclusive range with no end
+    if let 0..= = 1 {} //~ ERROR inclusive range with no end
+    const X: u8 = 0;
+    if let X... = 1 {} //~ ERROR inclusive range with no end
+    if let X..= = 1 {} //~ ERROR inclusive range with no end
+}
+
+fn bar() {
+    macro_rules! mac {
+        ($e:expr) => {
+            let $e...; //~ ERROR inclusive range with no end
+            let $e..=; //~ ERROR inclusive range with no end
+        }
+    }
+
+    mac!(0);
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
new file mode 100644 (file)
index 0000000..2bdb8ea
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:10:13
+   |
+LL |     if let 0... = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:11:13
+   |
+LL |     if let 0..= = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:13:13
+   |
+LL |     if let X... = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:14:13
+   |
+LL |     if let X..= = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:20:19
+   |
+LL |             let $e...;
+   |                   ^^^ help: use `..` instead
+...
+LL |     mac!(0);
+   |     -------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:21:19
+   |
+LL |             let $e..=;
+   |                   ^^^ help: use `..` instead
+...
+LL |     mac!(0);
+   |     -------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0586`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
new file mode 100644 (file)
index 0000000..f054bbe
--- /dev/null
@@ -0,0 +1,26 @@
+#![feature(half_open_range_patterns)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    match &0 {
+        &0.. | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        &0..= | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        //~| ERROR inclusive range with no end
+        &0... | _ => {}
+        //~^ ERROR inclusive range with no end
+    }
+
+    match &0 {
+        &..0 | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        &..=0 | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        &...0 | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        //~| ERROR range-to patterns with `...` are not allowed
+    }
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
new file mode 100644 (file)
index 0000000..a5f7c39
--- /dev/null
@@ -0,0 +1,55 @@
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:10
+   |
+LL |         &0.. | _ => {}
+   |          ^^^ help: add parentheses to clarify the precedence: `(0 ..)`
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:10:11
+   |
+LL |         &0..= | _ => {}
+   |           ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:10:10
+   |
+LL |         &0..= | _ => {}
+   |          ^^^^ help: add parentheses to clarify the precedence: `(0 ..=)`
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:13:11
+   |
+LL |         &0... | _ => {}
+   |           ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:18:10
+   |
+LL |         &..0 | _ => {}
+   |          ^^^ help: add parentheses to clarify the precedence: `(..0)`
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10
+   |
+LL |         &..=0 | _ => {}
+   |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:22:10
+   |
+LL |         &...0 | _ => {}
+   |          ^^^ help: use `..=` instead
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:22:10
+   |
+LL |         &...0 | _ => {}
+   |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0586`.
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
new file mode 100644 (file)
index 0000000..416c59a
--- /dev/null
@@ -0,0 +1,160 @@
+// run-pass
+
+// Test half-open range patterns against their expression equivalents
+// via `.contains(...)` and make sure the dynamic semantics match.
+
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+#![allow(illegal_floating_point_literal_pattern)]
+#![allow(unreachable_patterns)]
+
+macro_rules! yes {
+    ($scrutinee:expr, $($t:tt)+) => {
+        {
+            let m = match $scrutinee { $($t)+ => true, _ => false, };
+            let c = ($($t)+).contains(&$scrutinee);
+            assert_eq!(m, c);
+            m
+        }
+    }
+}
+
+fn range_to_inclusive() {
+    // `..=X` (`RangeToInclusive`-equivalent):
+    //---------------------------------------
+
+    // u8; `..=X`
+    assert!(yes!(core::u8::MIN, ..=core::u8::MIN));
+    assert!(yes!(core::u8::MIN, ..=5));
+    assert!(yes!(5u8, ..=5));
+    assert!(!yes!(6u8, ..=5));
+
+    // i16; `..=X`
+    assert!(yes!(core::i16::MIN, ..=core::i16::MIN));
+    assert!(yes!(core::i16::MIN, ..=0));
+    assert!(yes!(core::i16::MIN, ..=-5));
+    assert!(yes!(-5, ..=-5));
+    assert!(!yes!(-4, ..=-5));
+
+    // char; `..=X`
+    assert!(yes!('\u{0}', ..='\u{0}'));
+    assert!(yes!('\u{0}', ..='a'));
+    assert!(yes!('a', ..='a'));
+    assert!(!yes!('b', ..='a'));
+
+    // f32; `..=X`
+    assert!(yes!(core::f32::NEG_INFINITY, ..=core::f32::NEG_INFINITY));
+    assert!(yes!(core::f32::NEG_INFINITY, ..=1.0f32));
+    assert!(yes!(1.5f32, ..=1.5f32));
+    assert!(!yes!(1.6f32, ..=-1.5f32));
+
+    // f64; `..=X`
+    assert!(yes!(core::f64::NEG_INFINITY, ..=core::f64::NEG_INFINITY));
+    assert!(yes!(core::f64::NEG_INFINITY, ..=1.0f64));
+    assert!(yes!(1.5f64, ..=1.5f64));
+    assert!(!yes!(1.6f64, ..=-1.5f64));
+}
+
+fn range_to() {
+    // `..X` (`RangeTo`-equivalent):
+    //-----------------------------
+
+    // u8; `..X`
+    assert!(yes!(0u8, ..1));
+    assert!(yes!(0u8, ..5));
+    assert!(!yes!(5u8, ..5));
+    assert!(!yes!(6u8, ..5));
+
+    // u8; `..X`
+    const NU8: u8 = core::u8::MIN + 1;
+    assert!(yes!(core::u8::MIN, ..NU8));
+    assert!(yes!(0u8, ..5));
+    assert!(!yes!(5u8, ..5));
+    assert!(!yes!(6u8, ..5));
+
+    // i16; `..X`
+    const NI16: i16 = core::i16::MIN + 1;
+    assert!(yes!(core::i16::MIN, ..NI16));
+    assert!(yes!(core::i16::MIN, ..5));
+    assert!(yes!(-6, ..-5));
+    assert!(!yes!(-5, ..-5));
+
+    // char; `..X`
+    assert!(yes!('\u{0}', ..'\u{1}'));
+    assert!(yes!('\u{0}', ..'a'));
+    assert!(yes!('a', ..'b'));
+    assert!(!yes!('a', ..'a'));
+    assert!(!yes!('b', ..'a'));
+
+    // f32; `..X`
+    assert!(yes!(core::f32::NEG_INFINITY, ..1.0f32));
+    assert!(!yes!(1.5f32, ..1.5f32));
+    const E32: f32 = 1.5f32 + core::f32::EPSILON;
+    assert!(yes!(1.5f32, ..E32));
+    assert!(!yes!(1.6f32, ..1.5f32));
+
+    // f64; `..X`
+    assert!(yes!(core::f64::NEG_INFINITY, ..1.0f64));
+    assert!(!yes!(1.5f64, ..1.5f64));
+    const E64: f64 = 1.5f64 + core::f64::EPSILON;
+    assert!(yes!(1.5f64, ..E64));
+    assert!(!yes!(1.6f64, ..1.5f64));
+}
+
+fn range_from() {
+    // `X..` (`RangeFrom`-equivalent):
+    //--------------------------------
+
+    // u8; `X..`
+    assert!(yes!(core::u8::MIN, core::u8::MIN..));
+    assert!(yes!(core::u8::MAX, core::u8::MIN..));
+    assert!(!yes!(core::u8::MIN, 1..));
+    assert!(!yes!(4, 5..));
+    assert!(yes!(5, 5..));
+    assert!(yes!(6, 5..));
+    assert!(yes!(core::u8::MAX, core::u8::MAX..));
+
+    // i16; `X..`
+    assert!(yes!(core::i16::MIN, core::i16::MIN..));
+    assert!(yes!(core::i16::MAX, core::i16::MIN..));
+    const NI16: i16 = core::i16::MIN + 1;
+    assert!(!yes!(core::i16::MIN, NI16..));
+    assert!(!yes!(-4, 5..));
+    assert!(yes!(-4, -4..));
+    assert!(yes!(-3, -4..));
+    assert!(yes!(core::i16::MAX, core::i16::MAX..));
+
+    // char; `X..`
+    assert!(yes!('\u{0}', '\u{0}'..));
+    assert!(yes!(core::char::MAX, '\u{0}'..));
+    assert!(yes!('a', 'a'..));
+    assert!(yes!('b', 'a'..));
+    assert!(!yes!('a', 'b'..));
+    assert!(yes!(core::char::MAX, core::char::MAX..));
+
+    // f32; `X..`
+    assert!(yes!(core::f32::NEG_INFINITY, core::f32::NEG_INFINITY..));
+    assert!(yes!(core::f32::INFINITY, core::f32::NEG_INFINITY..));
+    assert!(!yes!(core::f32::NEG_INFINITY, 1.0f32..));
+    assert!(yes!(core::f32::INFINITY, 1.0f32..));
+    assert!(!yes!(1.0f32 - core::f32::EPSILON, 1.0f32..));
+    assert!(yes!(1.0f32, 1.0f32..));
+    assert!(yes!(core::f32::INFINITY, 1.0f32..));
+    assert!(yes!(core::f32::INFINITY, core::f32::INFINITY..));
+
+    // f64; `X..`
+    assert!(yes!(core::f64::NEG_INFINITY, core::f64::NEG_INFINITY..));
+    assert!(yes!(core::f64::INFINITY, core::f64::NEG_INFINITY..));
+    assert!(!yes!(core::f64::NEG_INFINITY, 1.0f64..));
+    assert!(yes!(core::f64::INFINITY, 1.0f64..));
+    assert!(!yes!(1.0f64 - core::f64::EPSILON, 1.0f64..));
+    assert!(yes!(1.0f64, 1.0f64..));
+    assert!(yes!(core::f64::INFINITY, 1.0f64..));
+    assert!(yes!(core::f64::INFINITY, core::f64::INFINITY..));
+}
+
+fn main() {
+    range_to_inclusive();
+    range_to();
+    range_from();
+}
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
new file mode 100644 (file)
index 0000000..8bb98d3
--- /dev/null
@@ -0,0 +1,30 @@
+// check-pass
+
+// Test the parsing of half-open ranges.
+
+#![feature(exclusive_range_pattern)]
+#![feature(half_open_range_patterns)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    match scrutinee {
+        X.. | 0.. | 'a'.. | 0.0f32.. => {}
+        ..=X | ..X => {}
+        ..=0 | ..0 => {}
+        ..='a' | ..'a' => {}
+        ..=0.0f32 | ..0.0f32 => {}
+    }
+}
+
+fn syntax2() {
+    macro_rules! mac {
+        ($e:expr) => {
+            match 0u8 { ..$e => {}, _ => {} }
+            match 0u8 { ..=$e => {}, _ => {} }
+            match 0u8 { $e.. => {}, _ => {} }
+        }
+    }
+    mac!(42u8);
+}
diff --git a/src/test/ui/half-open-range-patterns/pat-tuple-4.rs b/src/test/ui/half-open-range-patterns/pat-tuple-4.rs
new file mode 100644 (file)
index 0000000..bd79536
--- /dev/null
@@ -0,0 +1,13 @@
+// check-pass
+
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    const PAT: u8 = 1;
+
+    match 0 {
+        (.. PAT) => {}
+        _ => {}
+    }
+}
diff --git a/src/test/ui/half-open-range-patterns/pat-tuple-5.rs b/src/test/ui/half-open-range-patterns/pat-tuple-5.rs
new file mode 100644 (file)
index 0000000..613d907
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    const PAT: u8 = 1;
+
+    match (0, 1) {
+        (PAT ..) => {} //~ ERROR mismatched types
+    }
+}
diff --git a/src/test/ui/half-open-range-patterns/pat-tuple-5.stderr b/src/test/ui/half-open-range-patterns/pat-tuple-5.stderr
new file mode 100644 (file)
index 0000000..307ad71
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/pat-tuple-5.rs:8:10
+   |
+LL |     match (0, 1) {
+   |           ------ this expression has type `({integer}, {integer})`
+LL |         (PAT ..) => {}
+   |          ^^^ expected tuple, found `u8`
+   |
+   = note: expected tuple `({integer}, {integer})`
+               found type `u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index afa07cc60eb84839bd92e6891c0b03104684f51e..303c0cc645e38262d42966cd1bf2f7b0e5f47e2e 100644 (file)
@@ -39,6 +39,7 @@ LL | |     // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
 ...  |
 LL | |     foo_hrtb_bar_not(&mut t);
    | |     ------------------------ recursive call site
+LL | |
 LL | | }
    | |_^ cannot return without recursing
    |
@@ -62,7 +63,7 @@ LL |     foo_hrtb_bar_not(&mut t);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: function cannot return without recursing
-  --> $DIR/hrtb-perfect-forwarding.rs:49:1
+  --> $DIR/hrtb-perfect-forwarding.rs:50:1
    |
 LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
 LL | |     where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
index 63db695f7e67cf79b81ba81e3918b1f97fd39f28..0303a764c12def1154c80a48ffa058418ffe630c 100644 (file)
@@ -44,6 +44,7 @@ fn foo_hrtb_bar_not<'b,T>(mut t: T)
     // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where
     // clause only specifies `T : Bar<&'b isize>`.
     foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types
+                              //~| ERROR mismatched types
 }
 
 fn foo_hrtb_bar_hrtb<T>(mut t: T)
index 9bc8cd67a82afad16ca7cdcc13345de90f940bd4..1ceb0c99e90e9b0319fcbb3b15fe66b39cd963f6 100644 (file)
@@ -7,6 +7,15 @@ LL |     foo_hrtb_bar_not(&mut t);
    = note: expected type `Bar<&'a isize>`
               found type `Bar<&'b isize>`
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/hrtb-perfect-forwarding.rs:46:5
+   |
+LL |     foo_hrtb_bar_not(&mut t);
+   |     ^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `Bar<&'a isize>`
+              found type `Bar<&'b isize>`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index cd1272da2a66ee8102912859c03b7587e33b06f9..c736c5479f848a47a0b9cd05927477795f280dc6 100644 (file)
@@ -11,10 +11,46 @@ LL |     let filter = map.filter(|x: &_| true);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:116:17
+  --> $DIR/issue-30786.rs:114:18
+   |
+LL |     let filter = map.filter(|x: &_| true);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-30786.rs:114:18
+   |
+LL |     let filter = map.filter(|x: &_| true);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-30786.rs:114:18
+   |
+LL |     let filter = map.filter(|x: &_| true);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-30786.rs:119:17
+   |
+LL |     let count = filter.count(); // Assert that we still have a valid stream.
+   |                 ^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-30786.rs:119:17
+   |
+LL |     let count = filter.count(); // Assert that we still have a valid stream.
+   |                 ^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-30786.rs:119:17
+   |
+LL |     let count = filter.count(); // Assert that we still have a valid stream.
+   |                 ^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-30786.rs:119:17
    |
 LL |     let count = filter.count(); // Assert that we still have a valid stream.
    |                 ^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 9 previous errors
 
index 34d6b19f602f7d60c60caaba7bea48c2c0266c32..c656f8430653629be8124a5b4114d9276921454a 100644 (file)
@@ -113,7 +113,12 @@ fn main() {
     //[migrate]~| NOTE  implementation of `Stream` is not general enough
     let filter = map.filter(|x: &_| true);
     //[nll]~^ ERROR higher-ranked subtype error
+    //[nll]~| ERROR higher-ranked subtype error
+    //[nll]~| ERROR higher-ranked subtype error
+    //[nll]~| ERROR higher-ranked subtype error
     let count = filter.count(); // Assert that we still have a valid stream.
     //[nll]~^ ERROR higher-ranked subtype error
-
+    //[nll]~| ERROR higher-ranked subtype error
+    //[nll]~| ERROR higher-ranked subtype error
+    //[nll]~| ERROR higher-ranked subtype error
 }
index 736369dab83549237717f2561db9d710ce96256a..5d75f5034bc65d078f9956fb9107d61f8927ae2c 100644 (file)
@@ -15,7 +15,7 @@ LL |     fn f() { ::bar::m!(); }
 LL |         Vec::new();
    |         ^^^ use of undeclared type or module `Vec`
 
-error[E0599]: no method named `clone` found for type `()` in the current scope
+error[E0599]: no method named `clone` found for unit type `()` in the current scope
   --> $DIR/no_implicit_prelude.rs:12:12
    |
 LL |     fn f() { ::bar::m!(); }
index a116c5b38ce97a00b42e5a4d1234e2ce47fd88e4..15c4acbc939bc8f2527c61837df55c1cc6efd6bc 100644 (file)
@@ -14,7 +14,7 @@ mod bar {
 }
 
 mod baz {
-    pub macro m() { ().f() } //~ ERROR no method named `f` found for type `()` in the current scope
+    pub macro m() { ().f() } //~ ERROR no method named `f` found
     fn f() { ::bar::m!(); }
 }
 
index c3ce484edf7a95a13c719eeb0f8c02c1e92135e9..8e3609292a7f9c2a1230992581aec8b54d1cdb87 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `f` found for type `()` in the current scope
+error[E0599]: no method named `f` found for unit type `()` in the current scope
   --> $DIR/trait_items.rs:17:24
    |
 LL |     fn f() { ::baz::m!(); }
index 1c601bc3c34eaff144bca7db1920fcd0be9866b7..a6012835f441e1d75dc6a0a8d1dbcf2536175a81 100644 (file)
@@ -12,6 +12,7 @@ fn main() {
 fn cycle1() -> impl Clone {
     //~^ ERROR cycle detected
     //~| ERROR cycle detected
+    //~| ERROR cycle detected
     send(cycle2().clone());
     //~^ ERROR cannot be sent between threads safely
 
index d11941fee18249cf74ee46113ad55b96df3a7176..0ebaac8945050ecd9d8fa97722092f989c4b88a2 100644 (file)
@@ -11,12 +11,12 @@ LL | fn cycle1() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
 note: ...which requires processing `cycle2::{{opaque}}#0`...
-  --> $DIR/auto-trait-leak.rs:21:16
+  --> $DIR/auto-trait-leak.rs:22:16
    |
 LL | fn cycle2() -> impl Clone {
    |                ^^^^^^^^^^
 note: ...which requires processing `cycle2`...
-  --> $DIR/auto-trait-leak.rs:21:1
+  --> $DIR/auto-trait-leak.rs:22:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,12 +47,47 @@ LL | fn cycle1() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
 note: ...which requires processing `cycle2::{{opaque}}#0`...
-  --> $DIR/auto-trait-leak.rs:21:16
+  --> $DIR/auto-trait-leak.rs:22:16
    |
 LL | fn cycle2() -> impl Clone {
    |                ^^^^^^^^^^
 note: ...which requires processing `cycle2`...
-  --> $DIR/auto-trait-leak.rs:21:1
+  --> $DIR/auto-trait-leak.rs:22:1
+   |
+LL | fn cycle2() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle
+note: cycle used when checking item types in top-level module
+  --> $DIR/auto-trait-leak.rs:1:1
+   |
+LL | / use std::cell::Cell;
+LL | | use std::rc::Rc;
+LL | |
+LL | | fn send<T: Send>(_: T) {}
+...  |
+LL | |     Rc::new(String::from("foo"))
+LL | | }
+   | |_^
+
+error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0`
+  --> $DIR/auto-trait-leak.rs:12:16
+   |
+LL | fn cycle1() -> impl Clone {
+   |                ^^^^^^^^^^
+   |
+note: ...which requires processing `cycle1`...
+  --> $DIR/auto-trait-leak.rs:12:1
+   |
+LL | fn cycle1() -> impl Clone {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
+note: ...which requires processing `cycle2::{{opaque}}#0`...
+  --> $DIR/auto-trait-leak.rs:22:16
+   |
+LL | fn cycle2() -> impl Clone {
+   |                ^^^^^^^^^^
+note: ...which requires processing `cycle2`...
+  --> $DIR/auto-trait-leak.rs:22:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -70,18 +105,21 @@ LL | | }
    | |_^
 
 error[E0277]: `std::rc::Rc<std::string::String>` cannot be sent between threads safely
-  --> $DIR/auto-trait-leak.rs:15:5
+  --> $DIR/auto-trait-leak.rs:16:5
    |
 LL | fn send<T: Send>(_: T) {}
    |    ----    ---- required by this bound in `send`
 ...
 LL |     send(cycle2().clone());
    |     ^^^^ `std::rc::Rc<std::string::String>` cannot be sent between threads safely
+...
+LL | fn cycle2() -> impl Clone {
+   |                ---------- within this `impl std::clone::Clone`
    |
    = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
    = note: required because it appears within the type `impl std::clone::Clone`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0277, E0391.
 For more information about an error, try `rustc --explain E0277`.
index d163e1dff7ac981cd284aa37c16ef1f20506ace6..a93b3dbc71b60c7b5a4302dd1db175cd38cd931c 100644 (file)
@@ -1,6 +1,9 @@
 error[E0277]: `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
   --> $DIR/auto-trait-leak2.rs:13:5
    |
+LL | fn before() -> impl Fn(i32) {
+   |                ------------ within this `impl std::ops::Fn<(i32,)>`
+...
 LL | fn send<T: Send>(_: T) {}
    |    ----    ---- required by this bound in `send`
 ...
@@ -19,6 +22,9 @@ LL | fn send<T: Send>(_: T) {}
 ...
 LL |     send(after());
    |     ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+...
+LL | fn after() -> impl Fn(i32) {
+   |               ------------ within this `impl std::ops::Fn<(i32,)>`
    |
    = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
    = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
index 644d26b34060c94e7c9384ff43b5ef43b83d9d92..1605f3434cf5ade5269a9a656a17971492c0cb48 100644 (file)
@@ -6,19 +6,19 @@ LL | #![feature(impl_trait_in_bindings)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
+error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope
   --> $DIR/bindings-opaque.rs:11:17
    |
 LL |     let _ = FOO.count_ones();
    |                 ^^^^^^^^^^ method not found in `impl std::marker::Copy`
 
-error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
+error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope
   --> $DIR/bindings-opaque.rs:13:17
    |
 LL |     let _ = BAR.count_ones();
    |                 ^^^^^^^^^^ method not found in `impl std::marker::Copy`
 
-error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
+error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope
   --> $DIR/bindings-opaque.rs:15:17
    |
 LL |     let _ = foo.count_ones();
index 312976b72d20e26d29e055b5d9bcea2624cd177b..b882514f61609361c9478ffc6a0d39de9f09e669 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/equality2.rs:25:18
    |
+LL | fn hide<T: Foo>(x: T) -> impl Foo {
+   |                          -------- the found opaque type
+...
 LL |     let _: u32 = hide(0_u32);
    |            ---   ^^^^^^^^^^^ expected `u32`, found opaque type
    |            |
@@ -12,6 +15,9 @@ LL |     let _: u32 = hide(0_u32);
 error[E0308]: mismatched types
   --> $DIR/equality2.rs:31:18
    |
+LL | fn hide<T: Foo>(x: T) -> impl Foo {
+   |                          -------- the found opaque type
+...
 LL |     let _: i32 = Leak::leak(hide(0_i32));
    |            ---   ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
    |            |
@@ -25,6 +31,12 @@ LL |     let _: i32 = Leak::leak(hide(0_i32));
 error[E0308]: mismatched types
   --> $DIR/equality2.rs:38:10
    |
+LL | fn hide<T: Foo>(x: T) -> impl Foo {
+   |                          --------
+   |                          |
+   |                          the expected opaque type
+   |                          the found opaque type
+...
 LL |     x = (x.1,
    |          ^^^ expected `u32`, found `i32`
    |
@@ -34,6 +46,12 @@ LL |     x = (x.1,
 error[E0308]: mismatched types
   --> $DIR/equality2.rs:41:10
    |
+LL | fn hide<T: Foo>(x: T) -> impl Foo {
+   |                          --------
+   |                          |
+   |                          the expected opaque type
+   |                          the found opaque type
+...
 LL |          x.0);
    |          ^^^ expected `i32`, found `u32`
    |
index 2bff01be9b813a4e515297abd07d9cd9a14747f8..41f48cb56933e3f7434b03741061859d09ad29ec 100644 (file)
@@ -18,5 +18,5 @@ fn main() {
     let f1 = Bar;
 
     f1.foo(1usize);
-    //~^ error: method named `foo` found for type `Bar` in the current scope
+    //~^ error: method named `foo` found for struct `Bar` in the current scope
 }
index 441191beaf588002d2def67298bb35f718a6c292..57417975474f7fe718b76bc15f7f081ccbcb48e1 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `Bar` in the current scope
+error[E0599]: no method named `foo` found for struct `Bar` in the current scope
   --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:20:8
    |
 LL | struct Bar;
index fb870d6c6f0764fa739c8fccce82ec7c2c5f024e..7f2eb0c21e61df5f5961d2989a1616c65ed200e5 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `is_empty` found for type `Foo` in the current scope
+error[E0599]: no method named `is_empty` found for struct `Foo` in the current scope
   --> $DIR/method-suggestion-no-duplication.rs:7:15
    |
 LL | struct Foo;
index c912873a6c05c5193ec48ff98ddcb27f6c27a538..c8abc2d8f8ee05d359b9f7a09fdc2e1f78fd6a1d 100644 (file)
@@ -25,7 +25,7 @@ fn main() {
     //~|items from traits can only be used if the trait is in scope
     std::rc::Rc::new(&mut Box::new(&1u32)).method();
     //~^items from traits can only be used if the trait is in scope
-    //~| ERROR no method named `method` found for type
+    //~| ERROR no method named `method` found for struct
 
     'a'.method();
     //~^ ERROR no method named
index f0a03e1be82ac5e7c48d16725fc9e7fd8e5cf927..da25617e18759c08da121adaa650cc6b6ca3b605 100644 (file)
@@ -16,7 +16,7 @@ LL | use no_method_suggested_traits::qux::PrivPub;
 LL | use no_method_suggested_traits::Reexported;
    |
 
-error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&u32>>` in the current scope
+error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&u32>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:26:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method();
@@ -46,7 +46,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
 LL | use foo::Bar;
    |
 
-error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
+error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:32:43
    |
 LL |         fn method(&self) {}
@@ -78,7 +78,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
 LL | use no_method_suggested_traits::foo::PubPub;
    |
 
-error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&i32>>` in the current scope
+error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&i32>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:37:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method();
@@ -90,7 +90,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
 LL | use no_method_suggested_traits::foo::PubPub;
    |
 
-error[E0599]: no method named `method` found for type `Foo` in the current scope
+error[E0599]: no method named `method` found for struct `Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:40:9
    |
 LL | struct Foo;
@@ -106,7 +106,7 @@ LL |     Foo.method();
            candidate #3: `no_method_suggested_traits::qux::PrivPub`
            candidate #4: `no_method_suggested_traits::Reexported`
 
-error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope
+error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:42:43
    |
 LL |     std::rc::Rc::new(&mut Box::new(&Foo)).method();
@@ -129,7 +129,7 @@ LL |     1u64.method2();
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
            candidate #1: `foo::Bar`
 
-error[E0599]: no method named `method2` found for type `std::rc::Rc<&mut std::boxed::Box<&u64>>` in the current scope
+error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&u64>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:47:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1u64)).method2();
@@ -139,7 +139,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&1u64)).method2();
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
            candidate #1: `foo::Bar`
 
-error[E0599]: no method named `method2` found for type `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:50:37
    |
 LL |     no_method_suggested_traits::Foo.method2();
@@ -149,7 +149,7 @@ LL |     no_method_suggested_traits::Foo.method2();
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
            candidate #1: `foo::Bar`
 
-error[E0599]: no method named `method2` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:52:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
@@ -159,7 +159,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).metho
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
            candidate #1: `foo::Bar`
 
-error[E0599]: no method named `method2` found for type `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:54:40
    |
 LL |     no_method_suggested_traits::Bar::X.method2();
@@ -169,7 +169,7 @@ LL |     no_method_suggested_traits::Bar::X.method2();
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
            candidate #1: `foo::Bar`
 
-error[E0599]: no method named `method2` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:56:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
@@ -179,7 +179,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).me
    = note: the following trait defines an item `method2`, perhaps you need to implement it:
            candidate #1: `foo::Bar`
 
-error[E0599]: no method named `method3` found for type `Foo` in the current scope
+error[E0599]: no method named `method3` found for struct `Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:59:9
    |
 LL | struct Foo;
@@ -192,7 +192,7 @@ LL |     Foo.method3();
    = note: the following trait defines an item `method3`, perhaps you need to implement it:
            candidate #1: `no_method_suggested_traits::foo::PubPub`
 
-error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope
+error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:61:43
    |
 LL |     std::rc::Rc::new(&mut Box::new(&Foo)).method3();
@@ -202,7 +202,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&Foo)).method3();
    = note: the following trait defines an item `method3`, perhaps you need to implement it:
            candidate #1: `no_method_suggested_traits::foo::PubPub`
 
-error[E0599]: no method named `method3` found for type `Bar` in the current scope
+error[E0599]: no method named `method3` found for enum `Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:63:12
    |
 LL | enum Bar { X }
@@ -215,7 +215,7 @@ LL |     Bar::X.method3();
    = note: the following trait defines an item `method3`, perhaps you need to implement it:
            candidate #1: `no_method_suggested_traits::foo::PubPub`
 
-error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&Bar>>` in the current scope
+error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:65:46
    |
 LL |     std::rc::Rc::new(&mut Box::new(&Bar::X)).method3();
@@ -231,31 +231,31 @@ error[E0599]: no method named `method3` found for type `usize` in the current sc
 LL |     1_usize.method3();
    |             ^^^^^^^ method not found in `usize`
 
-error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&usize>>` in the current scope
+error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&usize>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:70:47
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1_usize)).method3();
    |                                               ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&usize>>`
 
-error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Foo` in the current scope
+error[E0599]: no method named `method3` found for struct `no_method_suggested_traits::Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:71:37
    |
 LL |     no_method_suggested_traits::Foo.method3();
    |                                     ^^^^^^^ method not found in `no_method_suggested_traits::Foo`
 
-error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope
+error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:72:71
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
    |                                                                       ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>`
 
-error[E0599]: no method named `method3` found for type `no_method_suggested_traits::Bar` in the current scope
+error[E0599]: no method named `method3` found for enum `no_method_suggested_traits::Bar` in the current scope
   --> $DIR/no-method-suggested-traits.rs:74:40
    |
 LL |     no_method_suggested_traits::Bar::X.method3();
    |                                        ^^^^^^^ method not found in `no_method_suggested_traits::Bar`
 
-error[E0599]: no method named `method3` found for type `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope
+error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:75:74
    |
 LL |     std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
index 9c6750fd48c2650c3d1347c4b95628447b3dc9ef..c1f048897d9eae7aed38ba84fcdc43a13b33c8ed 100644 (file)
@@ -3,6 +3,8 @@
 
 #[non_existent] //~ ERROR cannot determine resolution for the attribute macro `non_existent`
 #[derive(NonExistent)] //~ ERROR cannot determine resolution for the derive macro `NonExistent`
+                       //~| ERROR cannot determine resolution for the derive macro `NonExistent`
+                       //~| ERROR cannot determine resolution for the derive macro `NonExistent`
 struct S;
 
 fn main() {}
index aa103ba01e34e52ff11883c071f4bf87438add59..07de3d95902efa10090592a6f28f735b7751f31a 100644 (file)
@@ -29,6 +29,22 @@ LL | #[non_existent]
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to 4 previous errors
+error: cannot determine resolution for the derive macro `NonExistent`
+  --> $DIR/issue-55457.rs:5:10
+   |
+LL | #[derive(NonExistent)]
+   |          ^^^^^^^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the derive macro `NonExistent`
+  --> $DIR/issue-55457.rs:5:10
+   |
+LL | #[derive(NonExistent)]
+   |          ^^^^^^^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0432`.
index 29e9b8ec841f54661233112fcbb236606490a9df..37fe0eceed6b8c4641f1d517557922f9150b0049 100644 (file)
@@ -26,6 +26,7 @@ mod inner1 {
 }
 
 exported!(); //~ ERROR `exported` is ambiguous
+             //~| ERROR `exported` is ambiguous
 
 mod inner2 {
     define_exported!();
index 7d013828bd90857603388ce5092c3ba751bb933a..c9498fed6a58eff3fa3d53bd4836054e0f707eaa 100644 (file)
@@ -21,8 +21,31 @@ LL | use inner1::*;
    |     ^^^^^^^^^
    = help: consider adding an explicit import of `exported` to disambiguate
 
+error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+  --> $DIR/local-modularized-tricky-fail-1.rs:28:1
+   |
+LL | exported!();
+   | ^^^^^^^^ ambiguous name
+   |
+note: `exported` could refer to the macro defined here
+  --> $DIR/local-modularized-tricky-fail-1.rs:5:5
+   |
+LL | /     macro_rules! exported {
+LL | |         () => ()
+LL | |     }
+   | |_____^
+...
+LL |       define_exported!();
+   |       ------------------- in this macro invocation
+note: `exported` could also refer to the macro imported here
+  --> $DIR/local-modularized-tricky-fail-1.rs:22:5
+   |
+LL | use inner1::*;
+   |     ^^^^^^^^^
+   = help: consider adding an explicit import of `exported` to disambiguate
+
 error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
-  --> $DIR/local-modularized-tricky-fail-1.rs:35:5
+  --> $DIR/local-modularized-tricky-fail-1.rs:36:5
    |
 LL |     panic!();
    |     ^^^^^ ambiguous name
@@ -41,7 +64,7 @@ LL |       define_panic!();
    = help: use `crate::panic` to refer to this macro unambiguously
 
 error[E0659]: `include` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
-  --> $DIR/local-modularized-tricky-fail-1.rs:46:1
+  --> $DIR/local-modularized-tricky-fail-1.rs:47:1
    |
 LL | include!();
    | ^^^^^^^ ambiguous name
@@ -59,6 +82,6 @@ LL |       define_include!();
    |       ------------------ in this macro invocation
    = help: use `crate::include` to refer to this macro unambiguously
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0659`.
index f2a22ad620b1111004fe4893436494d2b13fe7a8..f39711898cdf005943d19018225f5cbee999fe34 100644 (file)
@@ -14,6 +14,7 @@ mod m1 {
 mod m2 {
     use two_macros::*;
     m! { //~ ERROR ambiguous
+         //~| ERROR ambiguous
         use foo::m;
     }
 }
index 3b9e6feebd7e37f53e41266128222ddd4d4bf5cb..27b34fe0c01fa8ab4ca548bb4f25e373ad09e088 100644 (file)
@@ -5,7 +5,25 @@ LL |     m! {
    |     ^ ambiguous name
    |
 note: `m` could refer to the macro imported here
-  --> $DIR/macros.rs:17:13
+  --> $DIR/macros.rs:18:13
+   |
+LL |         use foo::m;
+   |             ^^^^^^
+note: `m` could also refer to the macro imported here
+  --> $DIR/macros.rs:15:9
+   |
+LL |     use two_macros::*;
+   |         ^^^^^^^^^^^^^
+   = help: consider adding an explicit import of `m` to disambiguate
+
+error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+  --> $DIR/macros.rs:16:5
+   |
+LL |     m! {
+   |     ^ ambiguous name
+   |
+note: `m` could refer to the macro imported here
+  --> $DIR/macros.rs:18:13
    |
 LL |         use foo::m;
    |             ^^^^^^
@@ -17,23 +35,23 @@ LL |     use two_macros::*;
    = help: consider adding an explicit import of `m` to disambiguate
 
 error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
-  --> $DIR/macros.rs:29:9
+  --> $DIR/macros.rs:30:9
    |
 LL |         m! {
    |         ^ ambiguous name
    |
 note: `m` could refer to the macro imported here
-  --> $DIR/macros.rs:30:17
+  --> $DIR/macros.rs:31:17
    |
 LL |             use two_macros::n as m;
    |                 ^^^^^^^^^^^^^^^^^^
 note: `m` could also refer to the macro imported here
-  --> $DIR/macros.rs:22:9
+  --> $DIR/macros.rs:23:9
    |
 LL |     use two_macros::m;
    |         ^^^^^^^^^^^^^
    = help: use `self::m` to refer to this macro unambiguously
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0659`.
index 6345af001112f16a2a71d9cbd1da2df91e442fc5..21e5c03eb1605b254f76db7f8ef7bccefc56e51e 100644 (file)
@@ -1,4 +1,4 @@
-// Make sure that invalid ranges generate an error during HIR lowering, not an ICE
+// Make sure that invalid ranges generate an error during parsing, not an ICE
 
 pub fn main() {
     ..;
@@ -6,12 +6,12 @@ pub fn main() {
     ..1;
     0..1;
     ..=; //~ERROR inclusive range with no end
-         //~^HELP bounded at the end
+         //~^HELP use `..` instead
 }
 
 fn _foo1() {
     ..=1;
     0..=1;
     0..=; //~ERROR inclusive range with no end
-          //~^HELP bounded at the end
+          //~^HELP use `..` instead
 }
index 091fe37c7a1f7223de6f5bbfa3b15dd5cbec439c..ea2ab0f299d1b9f3c759e9e3f6e43ab06f6c0508 100644 (file)
@@ -1,18 +1,18 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/impossible_range.rs:8:8
+  --> $DIR/impossible_range.rs:8:5
    |
 LL |     ..=;
-   |        ^
+   |     ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/impossible_range.rs:15:9
+  --> $DIR/impossible_range.rs:15:6
    |
 LL |     0..=;
-   |         ^
+   |      ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: aborting due to 2 previous errors
 
index f4567554d0dbbe160d701dd2834f56019d877257..8c59fbd530129d5e4bbd04927a6f8b09b03963d5 100644 (file)
@@ -37,7 +37,7 @@ LL |     Foo.bar();
    |
    = help: consider adding a `#![recursion_limit="256"]` attribute to your crate
 
-error[E0599]: no method named `bar` found for type `Foo` in the current scope
+error[E0599]: no method named `bar` found for struct `Foo` in the current scope
   --> $DIR/infinite-autoderef.rs:26:9
    |
 LL | struct Foo;
diff --git a/src/test/ui/internal/internal-unstable-const.rs b/src/test/ui/internal/internal-unstable-const.rs
new file mode 100644 (file)
index 0000000..ce306c8
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![feature(const_if_match)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+const fn foo() -> i32 {
+    if true { 4 } else { 5 } //~ loops and conditional expressions are not stable in const fn
+}
+
+fn main() {}
diff --git a/src/test/ui/internal/internal-unstable-const.stderr b/src/test/ui/internal/internal-unstable-const.stderr
new file mode 100644 (file)
index 0000000..58bbe79
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0723]: loops and conditional expressions are not stable in const fn
+  --> $DIR/internal-unstable-const.rs:7:5
+   |
+LL |     if true { 4 } else { 5 }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/invalid_const_promotion.rs b/src/test/ui/invalid_const_promotion.rs
deleted file mode 100644 (file)
index 5d7664c..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// run-pass
-
-#![allow(unused_mut)]
-// ignore-wasm32
-// ignore-emscripten
-// ignore-sgx no processes
-
-// compile-flags: -C debug_assertions=yes
-
-#![stable(feature = "rustc", since = "1.0.0")]
-#![feature(const_fn, rustc_private, staged_api, rustc_attrs)]
-#![allow(const_err)]
-
-extern crate libc;
-
-use std::env;
-use std::process::{Command, Stdio};
-
-// this will panic in debug mode and overflow in release mode
-//
-// NB we give bar an unused argument because otherwise memoization
-// of the const fn kicks in, causing a different code path in the
-// compiler to be executed (see PR #66294).
-#[stable(feature = "rustc", since = "1.0.0")]
-#[rustc_const_stable(feature = "rustc", since = "1.0.0")]
-#[rustc_promotable]
-const fn bar(_: bool) -> usize { 0 - 1 }
-
-fn foo() {
-    let _: &'static _ = &bar(true);
-}
-
-#[cfg(unix)]
-fn check_status(status: std::process::ExitStatus)
-{
-    use std::os::unix::process::ExitStatusExt;
-
-    assert!(status.signal() == Some(libc::SIGILL)
-            || status.signal() == Some(libc::SIGTRAP)
-            || status.signal() == Some(libc::SIGABRT));
-}
-
-#[cfg(not(unix))]
-fn check_status(status: std::process::ExitStatus)
-{
-    assert!(!status.success());
-}
-
-fn main() {
-    let args: Vec<String> = env::args().collect();
-    if args.len() > 1 && args[1] == "test" {
-        foo();
-        return;
-    }
-
-    let mut p = Command::new(&args[0])
-        .stdout(Stdio::piped())
-        .stdin(Stdio::piped())
-        .arg("test").output().unwrap();
-    check_status(p.status);
-}
index 80ca051ceff0df2f2529b89dd6d013e2b854dac6..666fb6ab2bbb1580cd06ad2cde864711531a5e65 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `&b::B` in the current scope
+error[E0599]: no method named `foo` found for reference `&b::B` in the current scope
   --> $DIR/issue-10465.rs:17:15
    |
 LL |             b.foo();
index cdb261a238e5654a1caf812a44d0dfe5c24a4b07..2f31636f8adf9ba3404a678d240c3e7fafa59ef0 100644 (file)
@@ -12,7 +12,7 @@ LL |         self.iter()
    = help: type parameters must be constrained to match other types
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
-error[E0599]: no method named `iter` found for type `&G` in the current scope
+error[E0599]: no method named `iter` found for reference `&G` in the current scope
   --> $DIR/issue-13853.rs:27:23
    |
 LL |     for node in graph.iter() {
index 3e5e25a9f6d1f28e94125fee7510e61978fdee9e..9864c0840d87859a1535a5d42389b5cab3f6ee51 100644 (file)
@@ -3,6 +3,8 @@ warning[E0170]: pattern binding `A` is named the same as one of the variants of
    |
 LL |             A => "A",
    |             ^ help: to match on the variant, qualify the path: `E::A`
+   |
+   = note: `#[warn(bindings_with_variant_name)]` on by default
 
 warning[E0170]: pattern binding `B` is named the same as one of the variants of the type `E`
   --> $DIR/issue-14221.rs:15:13
index dbfdad25e5be875e02b271261934c63ff8dff853..c93a03cdec66a00de224b8be617079397650f384 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 use foo::MyEnum::Result;
 use foo::NoResult; // Through a re-export
 
index f3242919e0105fa5d52869ab1e5d76d3d69bac44..2d532cdb9d8a9f53e886f4c2786bfe4088799671 100644 (file)
@@ -1,8 +1,13 @@
 error[E0573]: expected type, found variant `NoResult`
-  --> $DIR/issue-17546.rs:12:17
+  --> $DIR/issue-17546.rs:16:17
    |
 LL |     fn new() -> NoResult<MyEnum, String> {
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   | 
+  ::: $SRC_DIR/libcore/result.rs:LL:COL
+   |
+LL | pub enum Result<T, E> {
+   | --------------------- similarly named enum `Result` defined here
    |
 help: try using the variant's enum
    |
@@ -14,7 +19,7 @@ LL |     fn new() -> Result<MyEnum, String> {
    |                 ^^^^^^
 
 error[E0573]: expected type, found variant `Result`
-  --> $DIR/issue-17546.rs:22:17
+  --> $DIR/issue-17546.rs:26:17
    |
 LL |     fn new() -> Result<foo::MyEnum, String> {
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type
@@ -32,7 +37,7 @@ LL |     use std::result::Result;
      and 1 other candidate
 
 error[E0573]: expected type, found variant `Result`
-  --> $DIR/issue-17546.rs:28:13
+  --> $DIR/issue-17546.rs:32:13
    |
 LL | fn new() -> Result<foo::MyEnum, String> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type
@@ -50,10 +55,15 @@ LL | use std::result::Result;
      and 1 other candidate
 
 error[E0573]: expected type, found variant `NoResult`
-  --> $DIR/issue-17546.rs:33:15
+  --> $DIR/issue-17546.rs:37:15
    |
 LL | fn newer() -> NoResult<foo::MyEnum, String> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | 
+  ::: $SRC_DIR/libcore/result.rs:LL:COL
+   |
+LL | pub enum Result<T, E> {
+   | --------------------- similarly named enum `Result` defined here
    |
 help: try using the variant's enum
    |
index 97657f8848155bf5bc584202e88912114971d3e9..9355c8ab15256f7e993d81e57b4a7ea1e77b3faa 100644 (file)
@@ -4,6 +4,7 @@
 static mut S: usize = 3;
 const C2: &'static mut usize = unsafe { &mut S };
 //~^ ERROR: constants cannot refer to statics
+//~| ERROR: constants cannot refer to statics
 //~| ERROR: references in constants may only refer to immutable values
 
 fn main() {}
index 7e4a62ac96957482ed612afbb68297f1e44a69eb..e45d8b6c740e0cf909ee28051d982cb8cc070fc9 100644 (file)
@@ -7,11 +7,21 @@ LL | const C1: &'static mut [usize] = &mut [];
    = note: for more information, see https://github.com/rust-lang/rust/issues/57349
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0013]: constants cannot refer to statics, use a constant instead
+error[E0013]: constants cannot refer to statics
   --> $DIR/issue-17718-const-bad-values.rs:5:46
    |
 LL | const C2: &'static mut usize = unsafe { &mut S };
    |                                              ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/issue-17718-const-bad-values.rs:5:46
+   |
+LL | const C2: &'static mut usize = unsafe { &mut S };
+   |                                              ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0658]: references in constants may only refer to immutable values
   --> $DIR/issue-17718-const-bad-values.rs:5:41
@@ -22,7 +32,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S };
    = note: for more information, see https://github.com/rust-lang/rust/issues/57349
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0013, E0658.
 For more information about an error, try `rustc --explain E0013`.
index 27aad9c03cebea8c02834171349fbe9fb42d2e4b..e3c3b369ffb320418a9df9558aa176d1ee1ae0eb 100644 (file)
@@ -1,20 +1,26 @@
-error[E0013]: constants cannot refer to statics, use a constant instead
+error[E0013]: constants cannot refer to statics
   --> $DIR/issue-17718-references.rs:9:29
    |
 LL | const T2: &'static usize = &S;
    |                             ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
-error[E0013]: constants cannot refer to statics, use a constant instead
+error[E0013]: constants cannot refer to statics
   --> $DIR/issue-17718-references.rs:14:19
    |
 LL | const T6: usize = S;
    |                   ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
-error[E0013]: constants cannot refer to statics, use a constant instead
+error[E0013]: constants cannot refer to statics
   --> $DIR/issue-17718-references.rs:19:33
    |
 LL | const T10: Struct = Struct { a: S };
    |                                 ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error: aborting due to 3 previous errors
 
index 6d52156b3d2de2e9dac6e54df40cb14de7aef8d3..f712a2eedb7e9cdb095ad83c20fb752ee11ba689 100644 (file)
@@ -1,7 +1,6 @@
 pub fn main() {
     const z: &'static isize = {
         static p: isize = 3;
-        &p
-        //~^ ERROR constants cannot refer to statics, use a constant instead
+        &p //~ ERROR constants cannot refer to statics
     };
 }
index d58822f16eb35b419d092ea65b9c0cc37d6041cd..4fc3ca78f961c4e086df6ec297d38f5f22883c55 100644 (file)
@@ -1,8 +1,10 @@
-error[E0013]: constants cannot refer to statics, use a constant instead
+error[E0013]: constants cannot refer to statics
   --> $DIR/issue-18118-2.rs:4:10
    |
 LL |         &p
    |          ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error: aborting due to previous error
 
index 1ab13477e37ed9a6a43e6a085f1f0d3dde2808d7..01e5313fcc1d928705318f8bf82bc87e1b826ab8 100644 (file)
@@ -3,6 +3,8 @@ warning[E0170]: pattern binding `Bar` is named the same as one of the variants o
    |
 LL | Bar if true
    | ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
+   |
+   = note: `#[warn(bindings_with_variant_name)]` on by default
 
 warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
   --> $DIR/issue-19100.rs:22:1
index c15c5392fac2590147df668ed903a6f1ec23f5d5..b6847cd755c3fb7de03da89b275a43193598383d 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `homura` found for type `&'static str` in the current scope
+error[E0599]: no method named `homura` found for reference `&'static str` in the current scope
   --> $DIR/issue-19521.rs:2:8
    |
 LL |     "".homura()();
index fe920c1693982649a7af5a46ec2265bf0ed09f32..b412d7bc70436ea150aaf295aac3e70e2216ee72 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `kaname` found for type `Homura` in the current scope
+error[E0599]: no method named `kaname` found for struct `Homura` in the current scope
   --> $DIR/issue-19692.rs:4:40
    |
 LL | struct Homura;
index ef4b1581fd874f900d31bdfbe4ce82c8e9f6d09e..d0e15cb393ae8b851d51da5747538174a4d5aa04 100644 (file)
@@ -28,6 +28,7 @@ impl<'a> Publisher<'a> for MyStruct<'a> {
     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
         // Not obvious, but there is an implicit lifetime here -------^
         //~^^ ERROR cannot infer
+        //~| ERROR cannot infer
         //~| ERROR mismatched types
         //~| ERROR mismatched types
         //
index c7fd134a129decdd7352545c9946fd7fedb4a70d..a4ea1cd9834c89986fe24346e3a90cf134379b5b 100644 (file)
@@ -102,7 +102,49 @@ LL | |     }
    = note: expected  `Publisher<'_>`
               found  `Publisher<'_>`
 
-error: aborting due to 3 previous errors
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/issue-20831-debruijn.rs:28:5
+   |
+LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+LL | |         // Not obvious, but there is an implicit lifetime here -------^
+LL | |
+LL | |
+...  |
+LL | |         self.sub = t;
+LL | |     }
+   | |_____^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 28:5...
+  --> $DIR/issue-20831-debruijn.rs:28:5
+   |
+LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+LL | |         // Not obvious, but there is an implicit lifetime here -------^
+LL | |
+LL | |
+...  |
+LL | |         self.sub = t;
+LL | |     }
+   | |_____^
+note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the impl at 26:6...
+  --> $DIR/issue-20831-debruijn.rs:26:6
+   |
+LL | impl<'a> Publisher<'a> for MyStruct<'a> {
+   |      ^^
+note: ...so that the types are compatible
+  --> $DIR/issue-20831-debruijn.rs:28:5
+   |
+LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+LL | |         // Not obvious, but there is an implicit lifetime here -------^
+LL | |
+LL | |
+...  |
+LL | |         self.sub = t;
+LL | |     }
+   | |_____^
+   = note: expected  `Publisher<'_>`
+              found  `Publisher<'_>`
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0308, E0495.
 For more information about an error, try `rustc --explain E0308`.
index 4e5cace525787e41ab27914af6c6ae3954c7c0fc..efde16167b71b9f85e3f8ed1a8240fb81e296441 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `to_string` found for type `*const u8` in the current scope
+error[E0599]: no method named `to_string` found for raw pointer `*const u8` in the current scope
   --> $DIR/issue-21596.rs:4:22
    |
 LL |     println!("{}", z.to_string());
index 98a354b1bd0fc5f5f7b337c5ed034d777de63725..dfd84b9a79d404e701c79d068ddfb13c8efbbf9b 100644 (file)
@@ -2,7 +2,7 @@ enum Delicious {
     Pie      = 0x1,
     Apple    = 0x2,
     ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
-    //~^ ERROR no variant or associated item named `PIE` found for type `Delicious`
+    //~^ ERROR no variant or associated item named `PIE` found
 }
 
 fn main() {}
index 72038ea20a3fae86b269f5060ca868f2c359cc93..584b05ec44d3fed5b1ce957a7c45a44b87090245 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no variant or associated item named `PIE` found for type `Delicious` in the current scope
+error[E0599]: no variant or associated item named `PIE` found for enum `Delicious` in the current scope
   --> $DIR/issue-22933-2.rs:4:55
    |
 LL | enum Delicious {
index 8518ed34aee9f7e3aebddbf5099db47000f87543..fbcce4b8344670a0039973a2dad54e32d9f710e8 100644 (file)
@@ -1,4 +1,4 @@
 const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR no associated item named `MIN` found for type `u8`
+//~^ ERROR no associated item named `MIN` found
 
 fn main() {}
index 7c15598448d7fe6ccd01a16ff1f81cd874918934..92f4c546440ab7f053ac3e73a19dc2de676ad419 100644 (file)
@@ -7,7 +7,7 @@ fn use_token(token: &Token) { unimplemented!() }
 
 fn main() {
     use_token(&Token::Homura); //~ ERROR no variant or associated item named `Homura`
-    Struct::method(); //~ ERROR no function or associated item named `method` found for type
-    Struct::method; //~ ERROR no function or associated item named `method` found for type
-    Struct::Assoc; //~ ERROR no associated item named `Assoc` found for type `Struct` in
+    Struct::method(); //~ ERROR no function or associated item named `method` found
+    Struct::method; //~ ERROR no function or associated item named `method` found
+    Struct::Assoc; //~ ERROR no associated item named `Assoc` found
 }
index 699e41156fa808e463690e04cbbc941895f3fa63..89f70fda786eabdb80dbc420857c617da0bbabbe 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no variant or associated item named `Homura` found for type `Token` in the current scope
+error[E0599]: no variant or associated item named `Homura` found for enum `Token` in the current scope
   --> $DIR/issue-23173.rs:9:23
    |
 LL | enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ }
@@ -7,7 +7,7 @@ LL | enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ }
 LL |     use_token(&Token::Homura);
    |                       ^^^^^^ variant or associated item not found in `Token`
 
-error[E0599]: no function or associated item named `method` found for type `Struct` in the current scope
+error[E0599]: no function or associated item named `method` found for struct `Struct` in the current scope
   --> $DIR/issue-23173.rs:10:13
    |
 LL | struct Struct {
@@ -16,7 +16,7 @@ LL | struct Struct {
 LL |     Struct::method();
    |             ^^^^^^ function or associated item not found in `Struct`
 
-error[E0599]: no function or associated item named `method` found for type `Struct` in the current scope
+error[E0599]: no function or associated item named `method` found for struct `Struct` in the current scope
   --> $DIR/issue-23173.rs:11:13
    |
 LL | struct Struct {
@@ -25,7 +25,7 @@ LL | struct Struct {
 LL |     Struct::method;
    |             ^^^^^^ function or associated item not found in `Struct`
 
-error[E0599]: no associated item named `Assoc` found for type `Struct` in the current scope
+error[E0599]: no associated item named `Assoc` found for struct `Struct` in the current scope
   --> $DIR/issue-23173.rs:12:13
    |
 LL | struct Struct {
index 157f20d22d8ae85d00b7b8306c2c054989d6993d..09f9ebccf250547fdff98f8e22ec2e9979bf8408 100644 (file)
@@ -1,5 +1,5 @@
 pub enum SomeEnum {
-    B = SomeEnum::A, //~ ERROR no variant or associated item named `A` found for type `SomeEnum`
+    B = SomeEnum::A, //~ ERROR no variant or associated item named `A` found
 }
 
 fn main() {}
index 97100ed375374b70c5bbdec22d18c6366291aa92..a81b459a34cbeb08ada5c259507044bc96e2a666 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no variant or associated item named `A` found for type `SomeEnum` in the current scope
+error[E0599]: no variant or associated item named `A` found for enum `SomeEnum` in the current scope
   --> $DIR/issue-23217.rs:2:19
    |
 LL | pub enum SomeEnum {
index b0e729a59eb22921ef751bd0b89c9fd5e07fb40a..036c05fc848cf37fc0dbd8c8f91cc634489fc954 100644 (file)
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-24036.rs:3:9
    |
+LL |     let mut x = |c| c + 1;
+   |                 --------- the expected closure
 LL |     x = |c| c + 1;
    |         ^^^^^^^^^ expected closure, found a different closure
    |
index adad6c35a3f67e5bd75780dacc32edd76e669821..ea042a6c76bb474905870f161133726a778b1475 100644 (file)
@@ -1,6 +1,6 @@
 macro_rules! foo {
     ($e:expr) => { $e.foo() }
-    //~^ ERROR no method named `foo` found for type `i32` in the current scope
+    //~^ ERROR no method named `foo` found
 }
 
 fn main() {
@@ -8,5 +8,5 @@ fn main() {
     foo!(a);
 
     foo!(1i32.foo());
-    //~^ ERROR no method named `foo` found for type `i32` in the current scope
+    //~^ ERROR no method named `foo` found
 }
index c9ede03003434a3f490c2fd5cd42a7f6454112cf..aa720fd45895a88f2096a059ce49dcce141bb64a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `clone` found for type `C` in the current scope
+error[E0599]: no method named `clone` found for struct `C` in the current scope
   --> $DIR/issue-2823.rs:13:16
    |
 LL | struct C {
index e315317c98a6c7fb646be3d80a527b9796a31fd4..77bc829209440b40bf68151c9e369fdeef41cc86 100644 (file)
@@ -4,7 +4,7 @@ error[E0191]: the value of the associated type `Output` (from trait `std::ops::B
 LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
    |                 ^^^^^^ help: specify the associated type: `BitXor<Output = Type>`
 
-error[E0599]: no function or associated item named `bitor` found for type `dyn std::ops::BitXor<_>` in the current scope
+error[E0599]: no function or associated item named `bitor` found for trait object `dyn std::ops::BitXor<_>` in the current scope
   --> $DIR/issue-28344.rs:4:25
    |
 LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
@@ -19,7 +19,7 @@ error[E0191]: the value of the associated type `Output` (from trait `std::ops::B
 LL |     let g = BitXor::bitor;
    |             ^^^^^^ help: specify the associated type: `BitXor<Output = Type>`
 
-error[E0599]: no function or associated item named `bitor` found for type `dyn std::ops::BitXor<_>` in the current scope
+error[E0599]: no function or associated item named `bitor` found for trait object `dyn std::ops::BitXor<_>` in the current scope
   --> $DIR/issue-28344.rs:8:21
    |
 LL |     let g = BitXor::bitor;
index 4d286be1e3302ae0e8bb3db6efd4bd123fb5897c..c543ef9b0e3d8466b024cab48a009f1e62ca1001 100644 (file)
@@ -2,6 +2,6 @@
 
 pub trait Foo {}
 impl Foo for [u8; usize::BYTES] {}
-//~^ ERROR no associated item named `BYTES` found for type `usize`
+//~^ ERROR no associated item named `BYTES` found
 
 fn main() { }
index 438a4c521b198f8dcfeaa185f07f826eb77fc8f9..f874b00db0b49b8b1c44458d1ec8a2b60265117a 100644 (file)
@@ -5,7 +5,7 @@ fn main() {
 
     a + a; //~ ERROR cannot add `A` to `A`
 
-    a - a; //~ ERROR cannot substract `A` from `A`
+    a - a; //~ ERROR cannot subtract `A` from `A`
 
     a * a; //~ ERROR cannot multiply `A` to `A`
 
index 2ef571b576f891377cd5c6fe3532c590a9197f9a..b63e168caf1964a9edebaaecffa991f5e02fbc6c 100644 (file)
@@ -8,7 +8,7 @@ LL |     a + a;
    |
    = note: an implementation of `std::ops::Add` might be missing for `A`
 
-error[E0369]: cannot substract `A` from `A`
+error[E0369]: cannot subtract `A` from `A`
   --> $DIR/issue-28837.rs:8:7
    |
 LL |     a - a;
index 6493565d2164719b9b51cf36c6cf35c469b78b0e..f0a1e2d006179e0949b4e5abedc2dc8345b4aa97 100644 (file)
@@ -5,7 +5,7 @@ fn main(){
     foo(|| {
         match Foo::Bar(1) {
             Foo::Baz(..) => (),
-            //~^ ERROR no variant or associated item named `Baz` found for type `Foo`
+            //~^ ERROR no variant or associated item named `Baz` found
             _ => (),
         }
     });
index 7411896443dfe80d153807fd8a884ef8a3409ea9..2736ee881d564869dd981245ff54acf5aaf96246 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no variant or associated item named `Baz` found for type `Foo` in the current scope
+error[E0599]: no variant or associated item named `Baz` found for enum `Foo` in the current scope
   --> $DIR/issue-28971.rs:7:18
    |
 LL | enum Foo {
index 1cd3f84f7a2270ec54df1c7817df02dbfa64707d..dd2784841758cfcbec14d49636bdcd8f723b10ac 100644 (file)
@@ -13,7 +13,7 @@ fn func() -> Ret {
 
 fn main() {
     Obj::func.x();
-    //~^ ERROR no method named `x` found for type `fn() -> Ret {Obj::func}` in the current scope
+    //~^ ERROR no method named `x` found
     func.x();
-    //~^ ERROR no method named `x` found for type `fn() -> Ret {func}` in the current scope
+    //~^ ERROR no method named `x` found
 }
index c537c6118f3a8cbb609c9fa5b7768d5fc6004e48..fff20248b70d5638dbcf1d2298149adfcd9ffe30 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `x` found for type `fn() -> Ret {Obj::func}` in the current scope
+error[E0599]: no method named `x` found for fn item `fn() -> Ret {Obj::func}` in the current scope
   --> $DIR/issue-29124.rs:15:15
    |
 LL |     Obj::func.x();
@@ -6,7 +6,7 @@ LL |     Obj::func.x();
    |
    = note: Obj::func is a function, perhaps you wish to call it
 
-error[E0599]: no method named `x` found for type `fn() -> Ret {func}` in the current scope
+error[E0599]: no method named `x` found for fn item `fn() -> Ret {func}` in the current scope
   --> $DIR/issue-29124.rs:17:10
    |
 LL |     func.x();
index 4fc32e0de8d57d43687753537ecc67e729ff1210..705355d91bf3cfb68d63922c63493c862406acb3 100644 (file)
@@ -5,5 +5,5 @@
 
 fn main() {
     let ug = Graph::<i32, i32>::new_undirected();
-    //~^ ERROR no function or associated item named `new_undirected` found for type
+    //~^ ERROR no function or associated item named `new_undirected` found
 }
index 32bbd4d03d6d7558037430a0e45371abb527d482..bc6731601f095644e8ee8088d939dd641efd58ae 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no function or associated item named `new_undirected` found for type `issue_30123_aux::Graph<i32, i32>` in the current scope
+error[E0599]: no function or associated item named `new_undirected` found for struct `issue_30123_aux::Graph<i32, i32>` in the current scope
   --> $DIR/issue-30123.rs:7:33
    |
 LL |     let ug = Graph::<i32, i32>::new_undirected();
index d762d6f2b3d5ed2b79e02d5273295a78a67f7e0f..ac1b5235f442384ce60e2aa8747c803e17d91d0f 100644 (file)
@@ -3,6 +3,8 @@ warning[E0170]: pattern binding `Nil` is named the same as one of the variants o
    |
 LL |         Nil => true,
    |         ^^^ help: to match on the variant, qualify the path: `Stack::Nil`
+   |
+   = note: `#[warn(bindings_with_variant_name)]` on by default
 
 error: unreachable pattern
   --> $DIR/issue-30302.rs:15:9
index 38cf3c4f930e8a84a5c1d8c0701aae0623e12dab..a614b96ac1439cc853144cff4bffaeab4f905364 100644 (file)
@@ -7,7 +7,7 @@ LL |         .cloned()
    = note:   expected type `u8`
            found reference `&_`
 
-error[E0599]: no method named `collect` found for type `std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope
+error[E0599]: no method named `collect` found for struct `std::iter::Cloned<std::iter::TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope
   --> $DIR/issue-31173.rs:14:10
    |
 LL |         .collect();
index ee099069f02414152b8ddfb3654ef6d80a3ebd08..3e6cf446da3f7213b3d7af883918fc1467afc206 100644 (file)
@@ -7,5 +7,6 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
 fn main() {
     size_of_copy::<dyn Misc + Copy>();
     //~^ ERROR only auto traits can be used as additional traits in a trait object
+    //~| ERROR only auto traits can be used as additional traits in a trait object
     //~| ERROR the trait bound `dyn Misc: std::marker::Copy` is not satisfied
 }
index e3564e867017451ced460d043bc06eaa556c40e9..450c37f456a80b471a05a2ba6503c9ef841ec099 100644 (file)
@@ -9,6 +9,17 @@ LL |     size_of_copy::<dyn Misc + Copy>();
    |                        first non-auto trait
    |                        trait alias used in trait object type (first use)
 
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/issue-32963.rs:8:31
+   |
+LL |     size_of_copy::<dyn Misc + Copy>();
+   |                        ----   ^^^^
+   |                        |      |
+   |                        |      additional non-auto trait
+   |                        |      trait alias used in trait object type (additional use)
+   |                        first non-auto trait
+   |                        trait alias used in trait object type (first use)
+
 error[E0277]: the trait bound `dyn Misc: std::marker::Copy` is not satisfied
   --> $DIR/issue-32963.rs:8:5
    |
@@ -18,7 +29,7 @@ LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
 LL |     size_of_copy::<dyn Misc + Copy>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `dyn Misc`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0225, E0277.
 For more information about an error, try `rustc --explain E0225`.
index 147fb3fa8cf330bd527e56b9a39da7b557aabb2d..2713f47ad2ff6b88f49251e4e66c58a39b4bd04a 100644 (file)
@@ -1,5 +1,6 @@
 #[derive(Clone,
          Sync, //~ ERROR cannot find derive macro `Sync` in this scope
+               //~| ERROR cannot find derive macro `Sync` in this scope
          Copy)]
 enum Foo {}
 
index 78e7202077498ee7b01967e62d73e5f55fa7563e..2a9ba5ba71b8fe0d5d5454293c4154252cf45809 100644 (file)
@@ -10,5 +10,17 @@ note: unsafe traits like `Sync` should be implemented explicitly
 LL |          Sync,
    |          ^^^^
 
-error: aborting due to previous error
+error: cannot find derive macro `Sync` in this scope
+  --> $DIR/issue-33571.rs:2:10
+   |
+LL |          Sync,
+   |          ^^^^
+   |
+note: unsafe traits like `Sync` should be implemented explicitly
+  --> $DIR/issue-33571.rs:2:10
+   |
+LL |          Sync,
+   |          ^^^^
+
+error: aborting due to 2 previous errors
 
index 09c499452adb687b737843c63ed5c2d4bc8c33e8..de544afae73b2bc3fc6a188e9da2068b04b8e57d 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
-    let baz = ().foo(); //~ ERROR no method named `foo` found for type `()` in the current scope
+    let baz = ().foo(); //~ ERROR no method named `foo` found
     <i32 as std::str::FromStr>::from_str(&baz); // No complaints about `str` being unsized
 }
index e6b74d262c340d4f04985e24d1206579378e8296..bbd8042d1cd6b4eb7f23b8e4e130d76b74cae43f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `()` in the current scope
+error[E0599]: no method named `foo` found for unit type `()` in the current scope
   --> $DIR/issue-33575.rs:2:18
    |
 LL |     let baz = ().foo();
index fc2c3679e13b8c3ef67d9db03b9d36592f73a4bc..632ddb91b36fda42dfb848f21a4daf6b3d97efa5 100644 (file)
@@ -4,7 +4,7 @@ enum S {
 
 fn bug(l: S) {
     match l {
-        S::B {} => {}, //~ ERROR no variant `B` in enum `S`
+        S::B {} => {}, //~ ERROR no variant named `B` found for enum `S`
     }
 }
 
index 194bb2bfab8ae29d532aff3f1a62515cfa96639c..f9a25b69ff6210120212f96d52df10a2982e6ef5 100644 (file)
@@ -1,4 +1,4 @@
-error: no variant `B` in enum `S`
+error[E0599]: no variant named `B` found for enum `S`
   --> $DIR/issue-34209.rs:7:12
    |
 LL | enum S {
@@ -9,3 +9,4 @@ LL |         S::B {} => {},
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0599`.
index 13e627a492f404d4cb9eb9d9ca8313257e042a0c..625fcb0a6f607a211b9c95c5a59be5cfdba82bfd 100644 (file)
@@ -1,5 +1,9 @@
 #[derive(PartialEq)] struct Comparable;
 #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
 //~^ ERROR can't compare `Comparable`
+//~| ERROR can't compare `Comparable`
+//~| ERROR can't compare `Comparable`
+//~| ERROR can't compare `Comparable`
+//~| ERROR can't compare `Comparable`
 
 fn main() {}
index c57f80cd4091c1f3d99c407cf5d040857e563b11..9e1734899bdd27b9e7527b5d49b1603c5b2dbc9d 100644 (file)
@@ -7,6 +7,42 @@ LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
    = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable`
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
-error: aborting due to previous error
+error[E0277]: can't compare `Comparable` with `Comparable`
+  --> $DIR/issue-34229.rs:2:46
+   |
+LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
+   |                                              ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Comparable` with `Comparable`
+  --> $DIR/issue-34229.rs:2:46
+   |
+LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
+   |                                              ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Comparable` with `Comparable`
+  --> $DIR/issue-34229.rs:2:46
+   |
+LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
+   |                                              ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `Comparable` with `Comparable`
+  --> $DIR/issue-34229.rs:2:46
+   |
+LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable);
+   |                                              ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index e34b5c9a0f47e3a7b84a3902ce756769ce4808d1..afe4d42edd8c8da6ec5b6931f4eb6aee65417c48 100644 (file)
@@ -7,5 +7,5 @@ fn main () {
     //~| 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 for type `()` in the current scope
+    //~^ ERROR no method named `iter` found
 }
index 3055e316a082a381197317e563b7dc2601956aca..c52ea4ef9daa9c744782e74094b946aaa68438fb 100644 (file)
@@ -43,7 +43,7 @@ LL |     let sr: Vec<(u32, _, _) = vec![];
    |             |
    |             cannot assign to this expression
 
-error[E0599]: no method named `iter` found for type `()` in the current scope
+error[E0599]: no method named `iter` found for unit type `()` in the current scope
   --> $DIR/issue-34334.rs:9:36
    |
 LL |     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
index b381203856e925a6ead03990b06868d2840345a0..a998f95d306cb05d8fbd946b55072704fcde30c1 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `is_subset` found for type `&std::collections::HashSet<T>` in the current scope
+error[E0599]: no method named `is_subset` found for reference `&std::collections::HashSet<T>` in the current scope
   --> $DIR/issue-35677.rs:4:10
    |
 LL |     this.is_subset(other)
index 1102f3c4640a188a3b0adb5785b4a11cc25cdb60..58f44f42524bc2cf9777298504af0e93fe0205f4 100644 (file)
@@ -1,4 +1,5 @@
 #![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
                  //~| ERROR cannot determine resolution for the derive macro `Copy`
+                 //~| ERROR cannot determine resolution for the derive macro `Copy`
 
 fn main() {}
index b5db98f306bd32e10e3e6dc6a04a80e1dd92a14b..98b41b07ea98a43818c3beab18b4e19ec8cf75dd 100644 (file)
@@ -12,5 +12,13 @@ LL | #![derive(Copy)]
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to 2 previous errors
+error: cannot determine resolution for the derive macro `Copy`
+  --> $DIR/issue-36617.rs:1:11
+   |
+LL | #![derive(Copy)]
+   |           ^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: aborting due to 3 previous errors
 
index 844a2dc00698efa7043eda3566e1a7999843e9ea..0817c51ee4eabccd1fd7666e077590c66654c67f 100644 (file)
@@ -7,7 +7,7 @@ pub fn boom() -> bool {
         return 1+1 == 2
     }
     pub fn chirp(&self) {
-        self.boom(); //~ ERROR no method named `boom` found for type `&Obj` in the current scope
+        self.boom(); //~ ERROR no method named `boom` found
     }
 }
 
index b98bc572a397c6c87cbf8b6ed148beb919fe5b1f..6ca2deee377a3690e52c01f34cd0006172143543 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `boom` found for type `&Obj` in the current scope
+error[E0599]: no method named `boom` found for reference `&Obj` in the current scope
   --> $DIR/issue-3707.rs:10:14
    |
 LL |         self.boom();
index 60a8793b4e6be0811e2f6e473865a3ac054c88b7..3d28f1936b47fd4d1de50df3d256b7cfab873641 100644 (file)
@@ -1,5 +1,5 @@
 fn foo<T: Iterator>() {
-    T::Item; //~ ERROR no associated item named `Item` found for type `T` in the current scope
+    T::Item; //~ ERROR no associated item named `Item` found
 }
 
 fn main() { }
index 603d42ca35e0b2598b1d52bf26096d0b4a7271b1..0022065a32c3d98a762f227926e139b62158b73e 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no associated item named `Item` found for type `T` in the current scope
+error[E0599]: no associated item named `Item` found for type parameter `T` in the current scope
   --> $DIR/issue-38919.rs:2:8
    |
 LL |     T::Item;
index 8b173e1b50c1e9ebcc4e2046c8ccf70fbe875542..2f6e676538e963a8e24af9c793a3ceb341976322 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `exec` found for type `&mut std::process::Command` in the current scope
+error[E0599]: no method named `exec` found for mutable reference `&mut std::process::Command` in the current scope
   --> $DIR/issue-39175.rs:15:39
    |
 LL |     Command::new("echo").arg("hello").exec();
index 5af48ca4c0dbc9f1a598ebdd9f789b8dc249612f..3a75956af528012fdc8a16fb3db0b5d5925f6dd1 100644 (file)
@@ -12,7 +12,7 @@ fn dim() -> usize {
 
 pub struct Vector<T, D: Dim> {
     entries: [T; D::dim()],
-    //~^ ERROR no function or associated item named `dim` found for type `D` in the current scope
+    //~^ ERROR no function or associated item named `dim` found
     _dummy: D,
 }
 
index b945b5e665459fd626e4d8fe6a9230a27c756a4e..0554b232c248b7f1189d4584c77cd0bc72db0c61 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no function or associated item named `dim` found for type `D` in the current scope
+error[E0599]: no function or associated item named `dim` found for type parameter `D` in the current scope
   --> $DIR/issue-39559.rs:14:21
    |
 LL |     entries: [T; D::dim()],
index 1a4775fc9600f136a09619e6f0511c8968e768ae..8cf841f9371215a254302992dcdbd3984431fb0c 100644 (file)
@@ -1,26 +1,22 @@
 // run-pass
-#![allow(non_snake_case)]
-
 // ignore-emscripten FIXME(#45351)
 
 #![feature(repr_simd, platform_intrinsics)]
 
-#[repr(C)] //~ WARNING conflicting representation hints
 #[repr(simd)]
 #[derive(Copy, Clone, Debug)]
-pub struct char3(pub i8, pub i8, pub i8);
+pub struct Char3(pub i8, pub i8, pub i8);
 
-#[repr(C)]  //~ WARNING conflicting representation hints
 #[repr(simd)]
 #[derive(Copy, Clone, Debug)]
-pub struct short3(pub i16, pub i16, pub i16);
+pub struct Short3(pub i16, pub i16, pub i16);
 
 extern "platform-intrinsic" {
     fn simd_cast<T, U>(x: T) -> U;
 }
 
 fn main() {
-    let cast: short3 = unsafe { simd_cast(char3(10, -3, -9)) };
+    let cast: Short3 = unsafe { simd_cast(Char3(10, -3, -9)) };
 
     println!("{:?}", cast);
 }
diff --git a/src/test/ui/issues/issue-39720.stderr b/src/test/ui/issues/issue-39720.stderr
deleted file mode 100644 (file)
index 8121ed2..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-warning[E0566]: conflicting representation hints
-  --> $DIR/issue-39720.rs:8:8
-   |
-LL | #[repr(C)]
-   |        ^
-LL | #[repr(simd)]
-   |        ^^^^
-
-warning[E0566]: conflicting representation hints
-  --> $DIR/issue-39720.rs:13:8
-   |
-LL | #[repr(C)]
-   |        ^
-LL | #[repr(simd)]
-   |        ^^^^
-
index 4e00915683a2d5eccdd1c8cc5de8370e7c02720e..a5ed5b87051e798ad5d8185d3a2efc4ab7524eee 100644 (file)
@@ -20,6 +20,6 @@ fn to_string(&self) -> String {
 
 fn main() {
     let p = Point::new(0.0, 0.0);
-    //~^ ERROR no function or associated item named `new` found for type `Point`
+    //~^ ERROR no function or associated item named `new` found for struct `Point`
     println!("{}", p.to_string());
 }
index ee07a410a9c863ced5729c2b79480fd4fa26ef99..63282e8d86d7b32ebf60ca25bec48bcca8ffacca 100644 (file)
@@ -7,7 +7,7 @@ LL | |         Point { x: x, y: y }
 LL | |     }
    | |_____^ not a member of trait `ToString_`
 
-error[E0599]: no function or associated item named `new` found for type `Point` in the current scope
+error[E0599]: no function or associated item named `new` found for struct `Point` in the current scope
   --> $DIR/issue-3973.rs:22:20
    |
 LL | struct Point {
index 60fdf7c3e8a479b18b5e7355cb941a6f4fc6fd50..5b95a7379135556a855c37a4d8033f45abc17b96 100644 (file)
@@ -1,6 +1,7 @@
 // Matching against float literals should result in a linter error
 
 #![feature(exclusive_range_pattern)]
+#![feature(half_open_range_patterns)]
 #![allow(unused)]
 #![forbid(illegal_floating_point_literal_pattern)]
 
@@ -12,23 +13,53 @@ fn main() {
                    //~| ERROR floating-point types cannot be used in patterns
                    //~| WARNING this was previously accepted by the compiler but is being
         5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns
+                      //~| ERROR floating-point types cannot be used in patterns
+                      //~| WARNING hard error
                       //~| WARNING hard error
         -5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
+                    //~| ERROR floating-point types cannot be used in patterns
+                    //~| WARNING hard error
                     //~| WARNING hard error
         1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns
                            //~| WARNING hard error
                            //~| ERROR floating-point types cannot be used in patterns
                            //~| WARNING hard error
+                           //~| ERROR floating-point types cannot be used in patterns
+                           //~| WARNING hard error
+                           //~| ERROR floating-point types cannot be used in patterns
+                           //~| WARNING hard error
         39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns
+                             //~| ERROR floating-point types cannot be used in patterns
                              //~| WARNING hard error
                              //~| ERROR floating-point types cannot be used in patterns
+                             //~| ERROR floating-point types cannot be used in patterns
+                             //~| WARNING hard error
+                             //~| WARNING hard error
                              //~| WARNING hard error
+
+        ..71.0 => {}
+        //~^ ERROR floating-point types cannot be used in patterns
+        //~| ERROR floating-point types cannot be used in patterns
+        //~| WARNING hard error
+        //~| WARNING this was previously accepted by the compiler
+        ..=72.0 => {}
+        //~^ ERROR floating-point types cannot be used in patterns
+        //~| ERROR floating-point types cannot be used in patterns
+        //~| WARNING hard error
+        //~| WARNING this was previously accepted by the compiler
+        71.0.. => {}
+        //~^ ERROR floating-point types cannot be used in patterns
+        //~| ERROR floating-point types cannot be used in patterns
+        //~| WARNING hard error
+        //~| WARNING this was previously accepted by the compiler
         _ => {},
     };
     let y = 5.0;
     // Same for tuples
     match (x, 5) {
         (3.14, 1) => {}, //~ ERROR floating-point types cannot be used
+                         //~| ERROR floating-point types cannot be used
+                         //~| WARNING hard error
                          //~| WARNING hard error
         _ => {},
     }
@@ -36,6 +67,8 @@ fn main() {
     struct Foo { x: f32 };
     match (Foo { x }) {
         Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used
+                              //~| ERROR floating-point types cannot be used
+                              //~| WARNING hard error
                               //~| WARNING hard error
         _ => {},
     }
index c334742cfc4a46f4f2d7cc9f12f9b69ad769d0b1..1ff58153c88649fc4fc3a0d257b4208bc5d37332 100644 (file)
@@ -1,11 +1,11 @@
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:10:9
+  --> $DIR/issue-41255.rs:11:9
    |
 LL |         5.0 => {},
    |         ^^^
    |
 note: lint level defined here
-  --> $DIR/issue-41255.rs:5:11
+  --> $DIR/issue-41255.rs:6:11
    |
 LL | #![forbid(illegal_floating_point_literal_pattern)]
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL | #![forbid(illegal_floating_point_literal_pattern)]
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:14:9
+  --> $DIR/issue-41255.rs:15:9
    |
 LL |         5.0f32 => {},
    |         ^^^^^^
@@ -22,7 +22,7 @@ LL |         5.0f32 => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:16:10
+  --> $DIR/issue-41255.rs:19:10
    |
 LL |         -5.0 => {},
    |          ^^^
@@ -31,7 +31,7 @@ LL |         -5.0 => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:18:9
+  --> $DIR/issue-41255.rs:23:9
    |
 LL |         1.0 .. 33.0 => {},
    |         ^^^
@@ -40,7 +40,7 @@ LL |         1.0 .. 33.0 => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:18:16
+  --> $DIR/issue-41255.rs:23:16
    |
 LL |         1.0 .. 33.0 => {},
    |                ^^^^
@@ -49,7 +49,7 @@ LL |         1.0 .. 33.0 => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:22:9
+  --> $DIR/issue-41255.rs:31:9
    |
 LL |         39.0 ..= 70.0 => {},
    |         ^^^^
@@ -58,7 +58,7 @@ LL |         39.0 ..= 70.0 => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:22:18
+  --> $DIR/issue-41255.rs:31:18
    |
 LL |         39.0 ..= 70.0 => {},
    |                  ^^^^
@@ -67,7 +67,34 @@ LL |         39.0 ..= 70.0 => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:31:10
+  --> $DIR/issue-41255.rs:40:11
+   |
+LL |         ..71.0 => {}
+   |           ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:45:12
+   |
+LL |         ..=72.0 => {}
+   |            ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:50:9
+   |
+LL |         71.0.. => {}
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:60:10
    |
 LL |         (3.14, 1) => {},
    |          ^^^^
@@ -76,7 +103,7 @@ LL |         (3.14, 1) => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:38:18
+  --> $DIR/issue-41255.rs:69:18
    |
 LL |         Foo { x: 2.0 } => {},
    |                  ^^^
@@ -85,7 +112,7 @@ LL |         Foo { x: 2.0 } => {},
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: floating-point types cannot be used in patterns
-  --> $DIR/issue-41255.rs:10:9
+  --> $DIR/issue-41255.rs:11:9
    |
 LL |         5.0 => {},
    |         ^^^
@@ -93,5 +120,104 @@ LL |         5.0 => {},
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
-error: aborting due to 10 previous errors
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:15:9
+   |
+LL |         5.0f32 => {},
+   |         ^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:19:10
+   |
+LL |         -5.0 => {},
+   |          ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:23:9
+   |
+LL |         1.0 .. 33.0 => {},
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:23:16
+   |
+LL |         1.0 .. 33.0 => {},
+   |                ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:31:9
+   |
+LL |         39.0 ..= 70.0 => {},
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:31:18
+   |
+LL |         39.0 ..= 70.0 => {},
+   |                  ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:40:11
+   |
+LL |         ..71.0 => {}
+   |           ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:45:12
+   |
+LL |         ..=72.0 => {}
+   |            ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:50:9
+   |
+LL |         71.0.. => {}
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:60:10
+   |
+LL |         (3.14, 1) => {},
+   |          ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-41255.rs:69:18
+   |
+LL |         Foo { x: 2.0 } => {},
+   |                  ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: aborting due to 24 previous errors
 
index 16facc5a78f8d8ccab8081387a913a4b084c9f4a..10cde21abd7660db8e95f0b8de36815084ab6aaf 100644 (file)
@@ -25,5 +25,5 @@ fn size_hint(&self) -> (usize, Option<usize>) { (std::usize::MAX, None) }
 fn main() {
     let a = iterate(0, |x| x+1);
     println!("{:?}", a.iter().take(10).collect::<Vec<usize>>());
-    //~^ ERROR no method named `iter` found for type `Iterate<{integer}
+    //~^ ERROR no method named `iter` found
 }
index 0e1d55c339eb4437b7eee548e883727c1be7d7d4..09d5594f73f06bd360f1eea195d23d3317cc1794 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `iter` found for type `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope
+error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope
   --> $DIR/issue-41880.rs:27:24
    |
 LL | pub struct Iterate<T, F> {
index 763bb9ae0ea9c8853677538c72fba0d98f8541e4..82cdc20df2fbdd08ec6fff8bffb95998f98fa9fc 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no associated item named `String` found for type `std::string::String` in the current scope
+error[E0599]: no associated item named `String` found for struct `std::string::String` in the current scope
   --> $DIR/issue-42880.rs:4:22
    |
 LL |     let f = |&Value::String(_)| ();
index f61b65baac4198e1278ad94c7498cbeaa2564e28..231af76fc932d024adc62b3b3e2cec5b084f7c54 100644 (file)
@@ -8,6 +8,7 @@ fn main() {
     match 1 {
         NUM => unimplemented!(),
         //~^ ERROR could not evaluate constant pattern
+        //~| ERROR could not evaluate constant pattern
         _ => unimplemented!(),
     }
 }
index e3609c57dcec524a1a7313f4546abdd87a795f96..1a7b67b563d52cefd3ac24afc94ff9caf40e4f74 100644 (file)
@@ -20,6 +20,12 @@ error: could not evaluate constant pattern
 LL |         NUM => unimplemented!(),
    |         ^^^
 
-error: aborting due to 3 previous errors
+error: could not evaluate constant pattern
+  --> $DIR/issue-43105.rs:9:9
+   |
+LL |         NUM => unimplemented!(),
+   |         ^^^
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0015`.
index f4f4dce7682fa51913b417046260be5ce18f4f2f..ce667a5006e6f31aebdf9bdc0e50b6132c29871f 100644 (file)
@@ -8,5 +8,5 @@
 extern crate xcrate_issue_43189_b;
 fn main() {
     ().a();
-    //~^ ERROR no method named `a` found for type `()` in the current scope [E0599]
+    //~^ ERROR no method named `a` found
 }
index 4dae6c1cd158e49a94dd47c7df5359c67cb68ad4..3f63cb8e78fbaf5cc8935c6be1a96411260f5604 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `a` found for type `()` in the current scope
+error[E0599]: no method named `a` found for unit type `()` in the current scope
   --> $DIR/issue-43189.rs:10:8
    |
 LL |     ().a();
index 8b1343b1326b455d507daf43033cee04150b627c..7c8bf299db5819a54cae5b1235222b5f6cff0267 100644 (file)
@@ -1,6 +1,7 @@
 #![feature(use_extern_macros)]
 trait Foo {}
 #[derive(Foo::Anything)] //~ ERROR failed to resolve: partially resolved path in a derive macro
+                         //~| ERROR failed to resolve: partially resolved path in a derive macro
 struct S;
 
 fn main() {}
index 9c88d3b87c907c64a7281f5df649b3362e652b77..2ffa15264b66df02da64b1734e6b6a0b9dd5efb3 100644 (file)
@@ -4,6 +4,12 @@ error[E0433]: failed to resolve: partially resolved path in a derive macro
 LL | #[derive(Foo::Anything)]
    |          ^^^^^^^^^^^^^ partially resolved path in a derive macro
 
-error: aborting due to previous error
+error[E0433]: failed to resolve: partially resolved path in a derive macro
+  --> $DIR/issue-46101.rs:3:10
+   |
+LL | #[derive(Foo::Anything)]
+   |          ^^^^^^^^^^^^^ partially resolved path in a derive macro
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
index 97da984d4afd0d63e3619805d78d1a9656b1d537..3258ee92a74222ec60c36dd0d3ed4f30912deb84 100644 (file)
@@ -1,12 +1,10 @@
-// check-pass
-
-#[repr(C,u8)] //~ WARNING conflicting representation hints
+#[repr(C, u8)] //~ ERROR conflicting representation hints
 enum Foo {
     A,
     B,
 }
 
-#[repr(C)] //~ WARNING conflicting representation hints
+#[repr(C)] //~ ERROR conflicting representation hints
 #[repr(u8)]
 enum Bar {
     A,
index 16bcec0c7bb3a9c06e0eb7dc5c1155abee2c1d6f..c807f644fd310371cd1e1cab557d3248635cb0da 100644 (file)
@@ -1,14 +1,17 @@
-warning[E0566]: conflicting representation hints
-  --> $DIR/issue-47094.rs:3:8
+error[E0566]: conflicting representation hints
+  --> $DIR/issue-47094.rs:1:8
    |
-LL | #[repr(C,u8)]
-   |        ^ ^^
+LL | #[repr(C, u8)]
+   |        ^  ^^
 
-warning[E0566]: conflicting representation hints
-  --> $DIR/issue-47094.rs:9:8
+error[E0566]: conflicting representation hints
+  --> $DIR/issue-47094.rs:7:8
    |
 LL | #[repr(C)]
    |        ^
 LL | #[repr(u8)]
    |        ^^
 
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0566`.
index 24c61425b8e29e2b7cce1e00efff8fd10eb616b1..5b6b8f8de18e23a057605d4229bd27291ba956cf 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
     let _result = &Some(42).as_deref();
-//~^ ERROR no method named `as_deref` found for type `std::option::Option<{integer}>`
+//~^ ERROR no method named `as_deref` found for enum `std::option::Option<{integer}>`
 }
index 0eb7bf0247565d5a4bfd61ff34811520d40e904e..f91f6e891ed90ceb5cd5f1b835aaef4b210dbe59 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `as_deref` found for type `std::option::Option<{integer}>` in the current scope
+error[E0599]: no method named `as_deref` found for enum `std::option::Option<{integer}>` in the current scope
   --> $DIR/option-as_deref.rs:2:29
    |
 LL |     let _result = &Some(42).as_deref();
index 67ad73f58477396e6801f47bf01f1860c6fa3e8f..c5fe6ea82cb0e6e8a423f16db13ac9eb417602af 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
     let _result = &mut Some(42).as_deref_mut();
-//~^ ERROR no method named `as_deref_mut` found for type `std::option::Option<{integer}>`
+//~^ ERROR no method named `as_deref_mut` found for enum `std::option::Option<{integer}>`
 }
index 845ddb52319c722a043faa2f54e6e862ca0b3e15..583236345cac17f5cdefa2be8bd90bbfe7d5c7c2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `as_deref_mut` found for type `std::option::Option<{integer}>` in the current scope
+error[E0599]: no method named `as_deref_mut` found for enum `std::option::Option<{integer}>` in the current scope
   --> $DIR/option-as_deref_mut.rs:2:33
    |
 LL |     let _result = &mut Some(42).as_deref_mut();
index 5e016748770dc98ebade3318b8134c9759e31dc4..fae11fe62b16c35c782a502f5f596f7eb73f79d4 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `as_deref` found for type `std::result::Result<{integer}, _>` in the current scope
+error[E0599]: no method named `as_deref` found for enum `std::result::Result<{integer}, _>` in the current scope
   --> $DIR/result-as_deref.rs:4:27
    |
 LL |     let _result = &Ok(42).as_deref();
index 6dc13da548b1246a81e3597ea23b3e6cb9225f48..1d98361c46198f2640dc9718a85ee03972a83c42 100644 (file)
@@ -1,8 +1,8 @@
-error[E0599]: no method named `as_deref_err` found for type `std::result::Result<_, {integer}>` in the current scope
+error[E0599]: no method named `as_deref_err` found for enum `std::result::Result<_, {integer}>` in the current scope
   --> $DIR/result-as_deref_err.rs:4:28
    |
 LL |     let _result = &Err(41).as_deref_err();
-   |                            ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_ok`
+   |                            ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut`
    |
    = note: the method `as_deref_err` exists but the following trait bounds were not satisfied:
            `{integer} : std::ops::Deref`
index f21e97388b6f4084b2453c4db26ac83d64fc8510..2c6231fb3b5890c98afca37f57edd41c9f55e05a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `as_deref_mut` found for type `std::result::Result<{integer}, _>` in the current scope
+error[E0599]: no method named `as_deref_mut` found for enum `std::result::Result<{integer}, _>` in the current scope
   --> $DIR/result-as_deref_mut.rs:4:31
    |
 LL |     let _result = &mut Ok(42).as_deref_mut();
index 44c0c954eeeca414dd1a5f1d6bbde25f707d5853..950a050ea9f81aa93fe11e6a1a7882e5b8a19950 100644 (file)
@@ -1,8 +1,8 @@
-error[E0599]: no method named `as_deref_mut_err` found for type `std::result::Result<_, {integer}>` in the current scope
+error[E0599]: no method named `as_deref_mut_err` found for enum `std::result::Result<_, {integer}>` in the current scope
   --> $DIR/result-as_deref_mut_err.rs:4:32
    |
 LL |     let _result = &mut Err(41).as_deref_mut_err();
-   |                                ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut_ok`
+   |                                ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut`
    |
    = note: the method `as_deref_mut_err` exists but the following trait bounds were not satisfied:
            `{integer} : std::ops::DerefMut`
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.rs
deleted file mode 100644 (file)
index 54b695a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(inner_deref)]
-
-fn main() {
-    let _result = &mut Ok(42).as_deref_mut_ok();
-//~^ ERROR no method named `as_deref_mut_ok` found
-}
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_ok.stderr
deleted file mode 100644 (file)
index b8369c9..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0599]: no method named `as_deref_mut_ok` found for type `std::result::Result<{integer}, _>` in the current scope
-  --> $DIR/result-as_deref_mut_ok.rs:4:31
-   |
-LL |     let _result = &mut Ok(42).as_deref_mut_ok();
-   |                               ^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut_err`
-   |
-   = note: the method `as_deref_mut_ok` exists but the following trait bounds were not satisfied:
-           `{integer} : std::ops::DerefMut`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.rs
deleted file mode 100644 (file)
index ebb0500..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(inner_deref)]
-
-fn main() {
-    let _result = &Ok(42).as_deref_ok();
-//~^ ERROR no method named `as_deref_ok` found
-}
diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_ok.stderr
deleted file mode 100644 (file)
index b26705a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0599]: no method named `as_deref_ok` found for type `std::result::Result<{integer}, _>` in the current scope
-  --> $DIR/result-as_deref_ok.rs:4:27
-   |
-LL |     let _result = &Ok(42).as_deref_ok();
-   |                           ^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_err`
-   |
-   = note: the method `as_deref_ok` exists but the following trait bounds were not satisfied:
-           `{integer} : std::ops::Deref`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0599`.
index 31dbb75ec1cc4582c1d7291e5b7057c09083488c..deb63872f6968c44f976912a544c357c1f3ae266 100644 (file)
@@ -2,6 +2,7 @@
 //~^ ERROR the trait `Copy` may not be implemented for this type
 struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
 //~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR cannot find type `NotDefined` in this scope
 //~| ERROR `i32` is not an iterator
 
 fn main() {}
index 9022bfae509f5a61ce5d64f2f84f2f0c2e6976f3..2b92664d57772143db6446c90165bd2094e0b87e 100644 (file)
@@ -4,6 +4,12 @@ error[E0412]: cannot find type `NotDefined` in this scope
 LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
    |            ^^^^^^^^^^ not found in this scope
 
+error[E0412]: cannot find type `NotDefined` in this scope
+  --> $DIR/issue-50480.rs:3:12
+   |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+   |            ^^^^^^^^^^ not found in this scope
+
 error[E0277]: `i32` is not an iterator
   --> $DIR/issue-50480.rs:3:24
    |
@@ -24,7 +30,7 @@ LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
    |                                                 |
    |                                                 this field does not implement `Copy`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0204, E0277, E0412.
 For more information about an error, try `rustc --explain E0204`.
index e6737662088f2081e569a6f595aaa16886cc4186..5bf0579030ad01a341ba7e1596741e2600ec2679 100644 (file)
@@ -8,5 +8,5 @@ fn foo(self: Box<isize>) { }
 
 fn main() {
     (&5isize as &dyn Foo).foo();
-    //~^ ERROR: no method named `foo` found for type `&dyn Foo` in the current scope
+    //~^ ERROR: no method named `foo` found for reference `&dyn Foo` in the current scope
 }
index 5034e6d538e3e307e66031b772b34cd9ad65575e..4680c8b131c50a77e4e46b373b2f6835e60de580 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `&dyn Foo` in the current scope
+error[E0599]: no method named `foo` found for reference `&dyn Foo` in the current scope
   --> $DIR/issue-5153.rs:10:27
    |
 LL |     (&5isize as &dyn Foo).foo();
index c69145c1fe8336d22369a6ca551db770cdcf557b..502825e9766e3d90af04bd09c311cdfccecbdc26 100644 (file)
@@ -1,8 +1,10 @@
-error[E0013]: constants cannot refer to statics, use a constant instead
+error[E0013]: constants cannot refer to statics
   --> $DIR/issue-52060.rs:4:26
    |
 LL | static B: [u32; 1] = [0; A.len()];
    |                          ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-52060.rs:4:26
index 0751b0a635b3e03072d2f2e4b43ca1308548a111..b5d55141b7509bc1649c60e41652ade6d0c614bf 100644 (file)
@@ -10,6 +10,7 @@ macro_rules! impl_add {
             fn $n() {
                 S::f::<i64>();
                 //~^ ERROR wrong number of type arguments
+                //~| ERROR wrong number of type arguments
             }
         )*
     }
index 9fbffaf39e5515cbfad729f3db83690421774cd2..21e41574a46838ebd3b30bf21f6d6babcc50ecff 100644 (file)
@@ -7,6 +7,15 @@ LL |                 S::f::<i64>();
 LL | impl_add!(a b);
    | --------------- in this macro invocation
 
-error: aborting due to previous error
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/issue-53251.rs:11:24
+   |
+LL |                 S::f::<i64>();
+   |                        ^^^ unexpected type argument
+...
+LL | impl_add!(a b);
+   | --------------- in this macro invocation
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
index 3830ad4b1e3ae317348558a4527e0f133c86acaf..5222e3ee95d5945bd52330be98219e17896356ec 100644 (file)
@@ -4,7 +4,7 @@ error[E0616]: field `inner` of struct `std::sync::Mutex` is private
 LL |     let _ = test.comps.inner.lock().unwrap();
    |             ^^^^^^^^^^^^^^^^
 
-error[E0599]: no method named `unwrap` found for type `std::sys_common::mutex::MutexGuard<'_>` in the current scope
+error[E0599]: no method named `unwrap` found for struct `std::sys_common::mutex::MutexGuard<'_>` in the current scope
   --> $DIR/issue-54062.rs:10:37
    |
 LL |     let _ = test.comps.inner.lock().unwrap();
index c4000c8a9d41ef72c86342e7599e8862d0aae512..e762b7bc0c89953489b640cdd48a06facc32562b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `f` found for type `fn(&u8)` in the current scope
+error[E0599]: no method named `f` found for fn pointer `fn(&u8)` in the current scope
   --> $DIR/issue-57362-1.rs:20:7
    |
 LL |     a.f();
index 2e713cc0ab508cacc862c7caa4c700a3698f95e1..3528084f6ceb4fc02d88faa5914c0bd1e046ef55 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no function or associated item named `make_g` found for type `for<'r> fn(&'r ())` in the current scope
+error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'r> fn(&'r ())` in the current scope
   --> $DIR/issue-57362-2.rs:22:25
    |
 LL |     let x = <fn (&())>::make_g();
index ef0d66d7ad6d122437262c25e0d8902ba486a8fe..70a7c38b8342582b2930ff035e31b474645add44 100644 (file)
@@ -11,9 +11,13 @@ LL |     const SIZE: usize;
    |     ------------------ required by `Foo::SIZE`
 LL | 
 LL |     fn new(slice: &[u8; Foo::SIZE]) -> Self;
-   |                         ^^^^^^^^^ cannot infer type
+   |                         ^^^^^^^^^
+   |                         |
+   |                         cannot infer type
+   |                         help: use the fully qualified path to an implementation: `<Type as Foo>::SIZE`
    |
    = note: cannot resolve `_: Foo`
+   = note: associated constants cannot be accessed directly on a `trait`, they can only be accessed through a specific `impl`
 
 error: aborting due to 2 previous errors
 
index bbdfebe1577c7e65c7f2d7171b2fa6f26589b254..b253c135b8c529fa4c883b8956c142d81af5c464 100644 (file)
@@ -18,5 +18,5 @@ fn main() {
     Trait::exists(());
     // no object safety error
     Trait::nonexistent(());
-    //~^ ERROR no function or associated item named `nonexistent` found for type `dyn Trait`
+    //~^ ERROR no function or associated item named `nonexistent` found
 }
index 07f2a046b2dbbbcab2639babcc243fca79a0779f..5e98cfadf8ae7500b8730fa6f8a95c3250eca9ae 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no function or associated item named `nonexistent` found for type `dyn Trait` in the current scope
+error[E0599]: no function or associated item named `nonexistent` found for trait object `dyn Trait` in the current scope
   --> $DIR/issue-58734.rs:20:12
    |
 LL |     Trait::nonexistent(());
index e98a4d0e491a3a1a9c9664db3889937de2c21cfd..8ab47a4af1d2e92952ce4c3a40100bbea4ff410d 100644 (file)
@@ -4,5 +4,6 @@
 
 trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
 //~^ ERROR associated type `Res` not found for `Self`
+//~| ERROR associated type `Res` not found for `Self`
 
 fn main() {}
index fb1de9759c5cf5fca6f2224579c4f9f8dd6c9e62..53cdb8b1baf4cacdbc278e2f234b9084187fb7a3 100644 (file)
@@ -4,6 +4,12 @@ error[E0220]: associated type `Res` not found for `Self`
 LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
    |                                                    ^^^ associated type `Res` not found
 
-error: aborting due to previous error
+error[E0220]: associated type `Res` not found for `Self`
+  --> $DIR/issue-59029-1.rs:5:52
+   |
+LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
+   |                                                    ^^^ associated type `Res` not found
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0220`.
index 20e84ec364b65bbcbb75f9bdf0e0f1fde3b3403e..cfd02183cb4a8724a06bd935fbf44ae1ea9836ad 100644 (file)
@@ -1,5 +1,6 @@
+// error-pattern:this file contains an unclosed delimiter
+// error-pattern:xpected `{`, found `macro_rules`
+
 fn main() {}
 
 fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
-//~^ ERROR expected `{`, found `macro_rules`
-//~ ERROR this file contains an unclosed delimiter
index 692bfe02275a8114c5dadf0d860f651545049d29..935d3842cdf6120299f42537bf487e1df044452d 100644 (file)
@@ -1,18 +1,60 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/issue-62554.rs:5:52
+  --> $DIR/issue-62554.rs:6:89
    |
 LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
-   |               -                       -         -                  -                  - unclosed delimiter
-   |               |                       |         |                  |
+   |               -                       -         -                  -                  - ^
+   |               |                       |         |                  |                  |
+   |               |                       |         |                  |                  unclosed delimiter
+   |               |                       |         |                  unclosed delimiter
+   |               |                       |         unclosed delimiter
+   |               unclosed delimiter      unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-62554.rs:6:89
+   |
+LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
+   |               -                       -         -                  -                  - ^
+   |               |                       |         |                  |                  |
+   |               |                       |         |                  |                  unclosed delimiter
+   |               |                       |         |                  unclosed delimiter
+   |               |                       |         unclosed delimiter
+   |               unclosed delimiter      unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-62554.rs:6:89
+   |
+LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
+   |               -                       -         -                  -                  - ^
+   |               |                       |         |                  |                  |
+   |               |                       |         |                  |                  unclosed delimiter
+   |               |                       |         |                  unclosed delimiter
+   |               |                       |         unclosed delimiter
+   |               unclosed delimiter      unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-62554.rs:6:89
+   |
+LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
+   |               -                       -         -                  -                  - ^
+   |               |                       |         |                  |                  |
+   |               |                       |         |                  |                  unclosed delimiter
+   |               |                       |         |                  unclosed delimiter
+   |               |                       |         unclosed delimiter
+   |               unclosed delimiter      unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-62554.rs:6:89
+   |
+LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
+   |               -                       -         -                  -                  - ^
+   |               |                       |         |                  |                  |
+   |               |                       |         |                  |                  unclosed delimiter
    |               |                       |         |                  unclosed delimiter
    |               |                       |         unclosed delimiter
    |               unclosed delimiter      unclosed delimiter
-LL |
-LL |
-   |                                                    ^
 
 error: expected `{`, found `macro_rules`
-  --> $DIR/issue-62554.rs:3:23
+  --> $DIR/issue-62554.rs:6:23
    |
 LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
    |                 --    ^^^^^^^^^^^ expected `{`
@@ -22,10 +64,8 @@ LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s
 help: try placing this code inside a block
    |
 LL | fn foo(u: u8) { if u8 { macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
-LL |
-LL |
 LL |  }
    |
 
-error: aborting due to 2 previous errors
+error: aborting due to 6 previous errors
 
index f1b2de8d8b36f21525c215c166aacb68e840251c..e7a244e9df576619b61c7f964ce2cedad4d07931 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `bar` found for type `Foo` in the current scope
+error[E0599]: no method named `bar` found for struct `Foo` in the current scope
   --> $DIR/issue-64430.rs:7:9
    |
 LL | pub struct Foo;
index e0eaafdfc2f2213e3bb1da7166d2ce0615b99eaf..018ce0459fd6f21794251af2a8bf3aab56bf31f4 100644 (file)
@@ -5,7 +5,7 @@ trait Foo {
 trait Bar {}
 
 fn do_stuff<T : Bar>(t : T) {
-    t.foo() //~ ERROR no method named `foo` found for type `T` in the current scope
+    t.foo() //~ ERROR no method named `foo` found
 }
 
 fn main() {}
index 24bf60abf6a7828adc4bc4b650e18638ce7efa50..4807a0930e7d02e733b79d148bdbedde68410939 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `T` in the current scope
+error[E0599]: no method named `foo` found for type parameter `T` in the current scope
   --> $DIR/issue-65284-suggest-generic-trait-bound.rs:8:7
    |
 LL |     t.foo()
diff --git a/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.rs b/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.rs
new file mode 100644 (file)
index 0000000..3c49a5a
--- /dev/null
@@ -0,0 +1,6 @@
+pub struct Foo {
+    pub bar: Vec<i32>ö
+    //~^ ERROR expected `,`, or `}`, found `ö`
+} //~ ERROR expected `:`, found `}`
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.stderr b/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.stderr
new file mode 100644 (file)
index 0000000..ef365a6
--- /dev/null
@@ -0,0 +1,17 @@
+error: expected `,`, or `}`, found `ö`
+  --> $DIR/issue-68000-unicode-ident-after-missing-comma.rs:2:22
+   |
+LL |     pub bar: Vec<i32>ö
+   |                      ^ help: try adding a comma: `,`
+
+error: expected `:`, found `}`
+  --> $DIR/issue-68000-unicode-ident-after-missing-comma.rs:4:1
+   |
+LL |     pub bar: Vec<i32>ö
+   |                       - expected `:`
+LL |
+LL | }
+   | ^ unexpected token
+
+error: aborting due to 2 previous errors
+
index b4af3581a0de07b44c64fcf1d653e33850a4a049..325137327b26926492c0e2e9d6cc8e7e6c2ec0e3 100644 (file)
@@ -17,7 +17,9 @@ fn main() {
 
     match [x, 1.0] {
         [NAN, _] => {}, //~ ERROR floating-point types cannot be used
-        //~^ WARN this was previously accepted by the compiler but is being phased out
+                        //~| ERROR floating-point types cannot be used
+        //~| WARN this was previously accepted by the compiler but is being phased out
+        //~| WARN this was previously accepted by the compiler but is being phased out
         _ => {},
     };
 }
index ab4467e5135ed256cbcb20f75b21ca2342869fd9..f4188dc3566c2b435d0e390b17973fb903622479 100644 (file)
@@ -30,5 +30,14 @@ LL |         NAN => {},
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
-error: aborting due to 3 previous errors
+error: floating-point types cannot be used in patterns
+  --> $DIR/issue-6804.rs:19:10
+   |
+LL |         [NAN, _] => {},
+   |          ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-68091-unicode-ident-after-if.rs b/src/test/ui/issues/issue-68091-unicode-ident-after-if.rs
new file mode 100644 (file)
index 0000000..00f90cc
--- /dev/null
@@ -0,0 +1,9 @@
+macro_rules! x {
+    ($($c:tt)*) => {
+        $($c)ö* {} //~ ERROR missing condition for `if` expression
+    };             //~| ERROR mismatched types
+}
+
+fn main() {
+    x!(if);
+}
diff --git a/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr b/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr
new file mode 100644 (file)
index 0000000..8d1a03a
--- /dev/null
@@ -0,0 +1,18 @@
+error: missing condition for `if` expression
+  --> $DIR/issue-68091-unicode-ident-after-if.rs:3:14
+   |
+LL |         $($c)ö* {}
+   |              ^ expected if condition here
+
+error[E0308]: mismatched types
+  --> $DIR/issue-68091-unicode-ident-after-if.rs:3:17
+   |
+LL |         $($c)ö* {}
+   |                 ^^ expected `bool`, found `()`
+...
+LL |     x!(if);
+   |     ------- in this macro invocation
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs
new file mode 100644 (file)
index 0000000..1a90b47
--- /dev/null
@@ -0,0 +1,9 @@
+macro_rules! x {
+    ($($c:tt)*) => {
+        $($c)ö* //~ ERROR macro expansion ends with an incomplete expression: expected expression
+    };
+}
+
+fn main() {
+    x!(!);
+}
diff --git a/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr
new file mode 100644 (file)
index 0000000..0b9c364
--- /dev/null
@@ -0,0 +1,8 @@
+error: macro expansion ends with an incomplete expression: expected expression
+  --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:3:14
+   |
+LL |         $($c)ö*
+   |              ^ expected expression
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-68103.rs b/src/test/ui/issues/issue-68103.rs
new file mode 100644 (file)
index 0000000..e775678
--- /dev/null
@@ -0,0 +1,6 @@
+// check-pass
+
+pub extern crate self as name;
+pub use name::name as bug;
+
+fn main() {}
index 5221f2c529bc691928dbde0d7967d54195b493e6..1571cd2bbf68356cea14be42d15fb54c4c729289 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 struct Foo {
     x: isize
 }
index 9320943a82766ed62b865c8b30e092bbc462e556..94f489e209e32e87560364094deaf2a1067fa877 100644 (file)
@@ -1,8 +1,13 @@
 error[E0412]: cannot find type `Fo` in this scope
-  --> $DIR/issue-7607-1.rs:5:6
+  --> $DIR/issue-7607-1.rs:9:6
    |
 LL | impl Fo {
    |      ^^ help: a trait with a similar name exists: `Fn`
+   | 
+  ::: $SRC_DIR/libcore/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args>: FnMut<Args> {
+   | ------------------------------- similarly named trait `Fn` defined here
 
 error: aborting due to previous error
 
index 7add8afee437f54c956ffa91038e9c61e94af5f9..d3dcb3380bbccbf89baa5f640e1cf2a75ee572c7 100644 (file)
@@ -4,5 +4,5 @@
 
 fn main() {
     Foo::bar();
-    //~^ ERROR no function or associated item named `bar` found for type `Foo`
+    //~^ ERROR no function or associated item named `bar` found for struct `Foo`
 }
index bbeab405e293502d17a567c5514c3c8ca86de98e..73e13c65cf37f23e51b388d8d87eb752fcce38cb 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no function or associated item named `bar` found for type `Foo` in the current scope
+error[E0599]: no function or associated item named `bar` found for struct `Foo` in the current scope
   --> $DIR/issue-7950.rs:6:10
    |
 LL | struct Foo;
index 40b67f8fe8cd70145a710dd180cf7f334678f3fe..39640e373991f06c0030031f7140f14c7f7699d1 100644 (file)
@@ -5,7 +5,9 @@ LL | fn bar<F:FnOnce() + Send>(_: F) { }
    |    ---              ---- required by this bound in `bar`
 ...
 LL |     bar(move|| foo(x));
-   |     ^^^ `std::rc::Rc<usize>` cannot be sent between threads safely
+   |     ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`
+   |     |
+   |     `std::rc::Rc<usize>` cannot be sent between threads safely
    |
    = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<usize>`
    = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc<usize>]`
index a7843a930119a222f6968f014171060903218a1e..6bb0877e9b9bafe463240d81eebbe565591808bb 100644 (file)
@@ -9,7 +9,7 @@ help: possible better candidate is found in another module, you can import it in
 LL | use T;
    |
 
-error[E0599]: no function or associated item named `f` found for type `Foo` in the current scope
+error[E0599]: no function or associated item named `f` found for type parameter `Foo` in the current scope
   --> $DIR/lexical-scopes.rs:10:10
    |
 LL |     Foo::f();
index 082b5430bf471081c475d64f85a1208b547b749e..13b28e8830b62bd11fc28f2c4e0e4a441745b133 100644 (file)
@@ -2,5 +2,7 @@
 
 #[allow(deprecated)]
 //~^ ERROR allow(deprecated) overruled by outer forbid(deprecated)
+//~| ERROR allow(deprecated) overruled by outer forbid(deprecated)
+//~| ERROR allow(deprecated) overruled by outer forbid(deprecated)
 fn main() {
 }
index 6e1e2b3e1478b2d0436d37b440caca5645bed910..bf138c317e93d79289a36e8a46757e3fc87969b1 100644 (file)
@@ -7,6 +7,24 @@ LL |
 LL | #[allow(deprecated)]
    |         ^^^^^^^^^^ overruled by previous forbid
 
-error: aborting due to previous error
+error[E0453]: allow(deprecated) overruled by outer forbid(deprecated)
+  --> $DIR/lint-forbid-attr.rs:3:9
+   |
+LL | #![forbid(deprecated)]
+   |           ---------- `forbid` level set here
+LL | 
+LL | #[allow(deprecated)]
+   |         ^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(deprecated) overruled by outer forbid(deprecated)
+  --> $DIR/lint-forbid-attr.rs:3:9
+   |
+LL | #![forbid(deprecated)]
+   |           ---------- `forbid` level set here
+LL | 
+LL | #[allow(deprecated)]
+   |         ^^^^^^^^^^ overruled by previous forbid
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 150685c3186aac7756fced721e12f0ef634a4c49..821470c86860a4a9ab82fa0f94596445c30cff97 100644 (file)
@@ -1,5 +1,7 @@
 // compile-flags: -F deprecated
 
 #[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated)
+                     //~| ERROR allow(deprecated) overruled by outer forbid(deprecated)
+                     //~| ERROR allow(deprecated) overruled by outer forbid(deprecated)
 fn main() {
 }
index bece4775abb934b74e6cd39b51095a441a0a8283..89a4445d80068301db2d5be79d51c5bfb8f45fb9 100644 (file)
@@ -6,6 +6,22 @@ LL | #[allow(deprecated)]
    |
    = note: `forbid` lint level was set on command line
 
-error: aborting due to previous error
+error[E0453]: allow(deprecated) overruled by outer forbid(deprecated)
+  --> $DIR/lint-forbid-cmdline.rs:3:9
+   |
+LL | #[allow(deprecated)]
+   |         ^^^^^^^^^^ overruled by previous forbid
+   |
+   = note: `forbid` lint level was set on command line
+
+error[E0453]: allow(deprecated) overruled by outer forbid(deprecated)
+  --> $DIR/lint-forbid-cmdline.rs:3:9
+   |
+LL | #[allow(deprecated)]
+   |         ^^^^^^^^^^ overruled by previous forbid
+   |
+   = note: `forbid` lint level was set on command line
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 0d327677d5469923805047d75a67060d96c9c25d..cf5570753d85d37e12a13b81d796705a46bdea8c 100644 (file)
@@ -1,4 +1,8 @@
 #![deny = "foo"] //~ ERROR malformed `deny` attribute input
 #![allow(bar = "baz")] //~ ERROR malformed lint attribute
-
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
+                       //~| ERROR malformed lint attribute
 fn main() { }
index f4876290ddb5d16f5cc4dc9e25168d42f13a02ec..6dc8d4984445e1e1fefa1edbd137321d3e3062e0 100644 (file)
@@ -4,12 +4,42 @@ error[E0452]: malformed lint attribute input
 LL | #![allow(bar = "baz")]
    |          ^^^^^^^^^^^ bad attribute argument
 
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+
 error: malformed `deny` attribute input
   --> $DIR/lint-malformed.rs:1:1
    |
 LL | #![deny = "foo"]
    | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
 
-error: aborting due to 2 previous errors
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/lint-malformed.rs:2:10
+   |
+LL | #![allow(bar = "baz")]
+   |          ^^^^^^^^^^^ bad attribute argument
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0452`.
index 69b0d2675c22d663991b6012ca1f203943ea5b43..b4ab5f5ee62ddee302c9aae215b1593f79f21ef3 100644 (file)
@@ -2,6 +2,18 @@ warning: lint `raw_pointer_derive` has been removed: `using derive with raw poin
    |
    = note: requested on the command line with `-D raw_pointer_derive`
 
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
+   |
+   = note: requested on the command line with `-D raw_pointer_derive`
+
 error: unused variable: `unused`
   --> $DIR/lint-removed-cmdline.rs:12:17
    |
index c978981a5c2ed0c879867b3935ddaa50b9224d8c..6401d9b77e007fa025756a69eddc7ad07cd175e7 100644 (file)
@@ -2,6 +2,18 @@ warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
    = note: requested on the command line with `-D bare_trait_object`
 
+warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = note: requested on the command line with `-D bare_trait_object`
+
+warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = note: requested on the command line with `-D bare_trait_object`
+
+warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
+   |
+   = note: requested on the command line with `-D bare_trait_object`
+
 error: unused variable: `unused`
   --> $DIR/lint-renamed-cmdline.rs:8:17
    |
index 0585fec99b418c37ee7270587f62dbd65b70f4f4..0bac9bb3d99cd94dbc3b05ae021cd383418a8620 100644 (file)
@@ -97,10 +97,13 @@ fn test() {
         struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
         struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
         //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
+        //~| WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
         type A = dyn TraitWithAssociatedTypes<
             TypeUnstable = u8,
             TypeDeprecated = u16,
             //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated'
+            //~| WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated'
+            //~| WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated'
         >;
 
         let _ = DeprecatedStruct { //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct'
index 62380135b333b029475fd057433ab0074960ba74..650373c90bcf27576bca7854a0f6893ce772b1ce 100644 (file)
@@ -77,241 +77,241 @@ LL | ...   <Foo as Trait>::trait_deprecated_unstable_text(&foo);
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedStruct': text
-  --> $DIR/lint-stability-deprecated.rs:106:17
+  --> $DIR/lint-stability-deprecated.rs:109:17
    |
 LL |         let _ = DeprecatedStruct {
    |                 ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedUnstableStruct': text
-  --> $DIR/lint-stability-deprecated.rs:109:17
+  --> $DIR/lint-stability-deprecated.rs:112:17
    |
 LL |         let _ = DeprecatedUnstableStruct {
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedUnitStruct': text
-  --> $DIR/lint-stability-deprecated.rs:116:17
+  --> $DIR/lint-stability-deprecated.rs:119:17
    |
 LL |         let _ = DeprecatedUnitStruct;
    |                 ^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedUnstableUnitStruct': text
-  --> $DIR/lint-stability-deprecated.rs:117:17
+  --> $DIR/lint-stability-deprecated.rs:120:17
    |
 LL |         let _ = DeprecatedUnstableUnitStruct;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Enum::DeprecatedVariant': text
-  --> $DIR/lint-stability-deprecated.rs:121:17
+  --> $DIR/lint-stability-deprecated.rs:124:17
    |
 LL |         let _ = Enum::DeprecatedVariant;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Enum::DeprecatedUnstableVariant': text
-  --> $DIR/lint-stability-deprecated.rs:122:17
+  --> $DIR/lint-stability-deprecated.rs:125:17
    |
 LL |         let _ = Enum::DeprecatedUnstableVariant;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedTupleStruct': text
-  --> $DIR/lint-stability-deprecated.rs:126:17
+  --> $DIR/lint-stability-deprecated.rs:129:17
    |
 LL |         let _ = DeprecatedTupleStruct (1);
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedUnstableTupleStruct': text
-  --> $DIR/lint-stability-deprecated.rs:127:17
+  --> $DIR/lint-stability-deprecated.rs:130:17
    |
 LL |         let _ = DeprecatedUnstableTupleStruct (1);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:136:25
+  --> $DIR/lint-stability-deprecated.rs:139:25
    |
 LL |         macro_test_arg!(deprecated_text());
    |                         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::deprecated_unstable_text': text
-  --> $DIR/lint-stability-deprecated.rs:137:25
+  --> $DIR/lint-stability-deprecated.rs:140:25
    |
 LL |         macro_test_arg!(deprecated_unstable_text());
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:138:41
+  --> $DIR/lint-stability-deprecated.rs:141:41
    |
 LL |         macro_test_arg!(macro_test_arg!(deprecated_text()));
    |                                         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:143:9
+  --> $DIR/lint-stability-deprecated.rs:146:9
    |
 LL |         Trait::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:145:9
+  --> $DIR/lint-stability-deprecated.rs:148:9
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:147:9
+  --> $DIR/lint-stability-deprecated.rs:150:9
    |
 LL |         Trait::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:149:9
+  --> $DIR/lint-stability-deprecated.rs:152:9
    |
 LL |         <Foo as Trait>::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
-  --> $DIR/lint-stability-deprecated.rs:151:9
+  --> $DIR/lint-stability-deprecated.rs:154:9
    |
 LL |         Trait::trait_deprecated_unstable(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
-  --> $DIR/lint-stability-deprecated.rs:153:9
+  --> $DIR/lint-stability-deprecated.rs:156:9
    |
 LL |         <Foo as Trait>::trait_deprecated_unstable(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
-  --> $DIR/lint-stability-deprecated.rs:155:9
+  --> $DIR/lint-stability-deprecated.rs:158:9
    |
 LL | ...   Trait::trait_deprecated_unstable_text(&foo);
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
-  --> $DIR/lint-stability-deprecated.rs:157:9
+  --> $DIR/lint-stability-deprecated.rs:160:9
    |
 LL | ...   <Foo as Trait>::trait_deprecated_unstable_text(&foo);
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedTrait': text
-  --> $DIR/lint-stability-deprecated.rs:185:10
+  --> $DIR/lint-stability-deprecated.rs:188:10
    |
 LL |     impl DeprecatedTrait for S {}
    |          ^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedTrait': text
-  --> $DIR/lint-stability-deprecated.rs:187:25
+  --> $DIR/lint-stability-deprecated.rs:190:25
    |
 LL |     trait LocalTrait2 : DeprecatedTrait { }
    |                         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'inheritance::inherited_stability::unstable_mod::deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:206:9
+  --> $DIR/lint-stability-deprecated.rs:209:9
    |
 LL |         unstable_mod::deprecated();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:328:9
+  --> $DIR/lint-stability-deprecated.rs:331:9
    |
 LL |         deprecated();
    |         ^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:333:9
+  --> $DIR/lint-stability-deprecated.rs:336:9
    |
 LL |         Trait::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:335:9
+  --> $DIR/lint-stability-deprecated.rs:338:9
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:337:9
+  --> $DIR/lint-stability-deprecated.rs:340:9
    |
 LL |         deprecated_text();
    |         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:342:9
+  --> $DIR/lint-stability-deprecated.rs:345:9
    |
 LL |         Trait::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:344:9
+  --> $DIR/lint-stability-deprecated.rs:347:9
    |
 LL |         <Foo as Trait>::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::DeprecatedStruct': text
-  --> $DIR/lint-stability-deprecated.rs:382:17
+  --> $DIR/lint-stability-deprecated.rs:385:17
    |
 LL |         let _ = DeprecatedStruct {
    |                 ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::DeprecatedUnitStruct': text
-  --> $DIR/lint-stability-deprecated.rs:389:17
+  --> $DIR/lint-stability-deprecated.rs:392:17
    |
 LL |         let _ = DeprecatedUnitStruct;
    |                 ^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Enum::DeprecatedVariant': text
-  --> $DIR/lint-stability-deprecated.rs:393:17
+  --> $DIR/lint-stability-deprecated.rs:396:17
    |
 LL |         let _ = Enum::DeprecatedVariant;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::DeprecatedTupleStruct': text
-  --> $DIR/lint-stability-deprecated.rs:397:17
+  --> $DIR/lint-stability-deprecated.rs:400:17
    |
 LL |         let _ = DeprecatedTupleStruct (1);
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:404:9
+  --> $DIR/lint-stability-deprecated.rs:407:9
    |
 LL |         Trait::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:406:9
+  --> $DIR/lint-stability-deprecated.rs:409:9
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:408:9
+  --> $DIR/lint-stability-deprecated.rs:411:9
    |
 LL |         Trait::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:410:9
+  --> $DIR/lint-stability-deprecated.rs:413:9
    |
 LL |         <Foo as Trait>::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::test_fn_body::fn_in_body': text
-  --> $DIR/lint-stability-deprecated.rs:437:9
+  --> $DIR/lint-stability-deprecated.rs:440:9
    |
 LL |         fn_in_body();
    |         ^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::DeprecatedTrait': text
-  --> $DIR/lint-stability-deprecated.rs:457:10
+  --> $DIR/lint-stability-deprecated.rs:460:10
    |
 LL |     impl DeprecatedTrait for S { }
    |          ^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::DeprecatedTrait': text
-  --> $DIR/lint-stability-deprecated.rs:459:24
+  --> $DIR/lint-stability-deprecated.rs:462:24
    |
 LL |     trait LocalTrait : DeprecatedTrait { }
    |                        ^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::MethodTester::test_method_body::fn_in_body': text
-  --> $DIR/lint-stability-deprecated.rs:445:13
+  --> $DIR/lint-stability-deprecated.rs:448:13
    |
 LL |             fn_in_body();
    |             ^^^^^^^^^^
@@ -323,7 +323,7 @@ LL |         struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
    |                                                ^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
-  --> $DIR/lint-stability-deprecated.rs:102:13
+  --> $DIR/lint-stability-deprecated.rs:103:13
    |
 LL |             TypeDeprecated = u16,
    |             ^^^^^^^^^^^^^^^^^^^^
@@ -449,188 +449,206 @@ LL | ...   <Foo>::trait_deprecated_unstable_text(&foo);
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedStruct::i': text
-  --> $DIR/lint-stability-deprecated.rs:107:13
+  --> $DIR/lint-stability-deprecated.rs:110:13
    |
 LL |             i: 0
    |             ^^^^
 
 warning: use of deprecated item 'lint_stability::DeprecatedUnstableStruct::i': text
-  --> $DIR/lint-stability-deprecated.rs:111:13
+  --> $DIR/lint-stability-deprecated.rs:114:13
    |
 LL |             i: 0
    |             ^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:142:13
+  --> $DIR/lint-stability-deprecated.rs:145:13
    |
 LL |         foo.trait_deprecated();
    |             ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:144:9
+  --> $DIR/lint-stability-deprecated.rs:147:9
    |
 LL |         <Foo>::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:146:13
+  --> $DIR/lint-stability-deprecated.rs:149:13
    |
 LL |         foo.trait_deprecated_text();
    |             ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:148:9
+  --> $DIR/lint-stability-deprecated.rs:151:9
    |
 LL |         <Foo>::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
-  --> $DIR/lint-stability-deprecated.rs:150:13
+  --> $DIR/lint-stability-deprecated.rs:153:13
    |
 LL |         foo.trait_deprecated_unstable();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
-  --> $DIR/lint-stability-deprecated.rs:152:9
+  --> $DIR/lint-stability-deprecated.rs:155:9
    |
 LL |         <Foo>::trait_deprecated_unstable(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
-  --> $DIR/lint-stability-deprecated.rs:154:13
+  --> $DIR/lint-stability-deprecated.rs:157:13
    |
 LL |         foo.trait_deprecated_unstable_text();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
-  --> $DIR/lint-stability-deprecated.rs:156:9
+  --> $DIR/lint-stability-deprecated.rs:159:9
    |
 LL | ...   <Foo>::trait_deprecated_unstable_text(&foo);
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:173:13
+  --> $DIR/lint-stability-deprecated.rs:176:13
    |
 LL |         foo.trait_deprecated();
    |             ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:174:13
+  --> $DIR/lint-stability-deprecated.rs:177:13
    |
 LL |         foo.trait_deprecated_text();
    |             ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
-  --> $DIR/lint-stability-deprecated.rs:175:13
+  --> $DIR/lint-stability-deprecated.rs:178:13
    |
 LL |         foo.trait_deprecated_unstable();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
-  --> $DIR/lint-stability-deprecated.rs:176:13
+  --> $DIR/lint-stability-deprecated.rs:179:13
    |
 LL |         foo.trait_deprecated_unstable_text();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:329:13
+  --> $DIR/lint-stability-deprecated.rs:332:13
    |
 LL |         foo.method_deprecated();
    |             ^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:330:9
+  --> $DIR/lint-stability-deprecated.rs:333:9
    |
 LL |         Foo::method_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:331:9
+  --> $DIR/lint-stability-deprecated.rs:334:9
    |
 LL |         <Foo>::method_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:332:13
+  --> $DIR/lint-stability-deprecated.rs:335:13
    |
 LL |         foo.trait_deprecated();
    |             ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:334:9
+  --> $DIR/lint-stability-deprecated.rs:337:9
    |
 LL |         <Foo>::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:338:13
+  --> $DIR/lint-stability-deprecated.rs:341:13
    |
 LL |         foo.method_deprecated_text();
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:339:9
+  --> $DIR/lint-stability-deprecated.rs:342:9
    |
 LL |         Foo::method_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:340:9
+  --> $DIR/lint-stability-deprecated.rs:343:9
    |
 LL |         <Foo>::method_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:341:13
+  --> $DIR/lint-stability-deprecated.rs:344:13
    |
 LL |         foo.trait_deprecated_text();
    |             ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:343:9
+  --> $DIR/lint-stability-deprecated.rs:346:9
    |
 LL |         <Foo>::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::DeprecatedStruct::i': text
-  --> $DIR/lint-stability-deprecated.rs:384:13
+  --> $DIR/lint-stability-deprecated.rs:387:13
    |
 LL |             i: 0
    |             ^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:403:13
+  --> $DIR/lint-stability-deprecated.rs:406:13
    |
 LL |         foo.trait_deprecated();
    |             ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:405:9
+  --> $DIR/lint-stability-deprecated.rs:408:9
    |
 LL |         <Foo>::trait_deprecated(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:407:13
+  --> $DIR/lint-stability-deprecated.rs:410:13
    |
 LL |         foo.trait_deprecated_text();
    |             ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:409:9
+  --> $DIR/lint-stability-deprecated.rs:412:9
    |
 LL |         <Foo>::trait_deprecated_text(&foo);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
-  --> $DIR/lint-stability-deprecated.rs:426:13
+  --> $DIR/lint-stability-deprecated.rs:429:13
    |
 LL |         foo.trait_deprecated();
    |             ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
-  --> $DIR/lint-stability-deprecated.rs:427:13
+  --> $DIR/lint-stability-deprecated.rs:430:13
    |
 LL |         foo.trait_deprecated_text();
    |             ^^^^^^^^^^^^^^^^^^^^^
 
+warning: use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
+  --> $DIR/lint-stability-deprecated.rs:98:48
+   |
+LL |         struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
+   |                                                ^^^^^^^^^^^^^^^^^
+
+warning: use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
+  --> $DIR/lint-stability-deprecated.rs:103:13
+   |
+LL |             TypeDeprecated = u16,
+   |             ^^^^^^^^^^^^^^^^^^^^
+
+warning: use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
+  --> $DIR/lint-stability-deprecated.rs:103:13
+   |
+LL |             TypeDeprecated = u16,
+   |             ^^^^^^^^^^^^^^^^^^^^
+
index c2cbf5feaada4d8c08f93f6d7d79e582180c847a..3a78ed2ceea151d0e154fdab161548500e0e9044 100644 (file)
@@ -6,6 +6,30 @@ warning: lint `private_no_mangle_statics` has been removed: `no longer a warning
    |
    = note: requested on the command line with `-F private_no_mangle_statics`
 
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported`
+   |
+   = note: requested on the command line with `-F private_no_mangle_fns`
+
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported`
+   |
+   = note: requested on the command line with `-F private_no_mangle_statics`
+
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported`
+   |
+   = note: requested on the command line with `-F private_no_mangle_fns`
+
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported`
+   |
+   = note: requested on the command line with `-F private_no_mangle_statics`
+
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported`
+   |
+   = note: requested on the command line with `-F private_no_mangle_fns`
+
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported`
+   |
+   = note: requested on the command line with `-F private_no_mangle_statics`
+
 error: const items should never be `#[no_mangle]`
   --> $DIR/lint-unexported-no-mangle.rs:9:1
    |
index 58fdae3333ca172dcc2e4e2ec21e103b5122e3ad..27e7ee7fc03bd9afe3f65adb081b5e950f01dedd 100644 (file)
@@ -7,6 +7,24 @@ error[E0602]: unknown lint: `dead_cod`
    = help: did you mean: `dead_code`
    = note: requested on the command line with `-D dead_cod`
 
-error: aborting due to 2 previous errors
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error[E0602]: unknown lint: `bogus`
+   |
+   = note: requested on the command line with `-D bogus`
+
+error[E0602]: unknown lint: `dead_cod`
+   |
+   = help: did you mean: `dead_code`
+   = note: requested on the command line with `-D dead_cod`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0602`.
index f614d5d71f88cdc0afcfa02e7082e02cf10873b6..b937832ac622ddf02dc556c83edeba89ba003f99 100644 (file)
@@ -3,6 +3,8 @@ warning[E0170]: pattern binding `Foo` is named the same as one of the variants o
    |
 LL |         Foo => {}
    |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
+   |
+   = note: `#[warn(bindings_with_variant_name)]` on by default
 
 warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
index 950533cca1a98fd9e4dfffc60445b6a710f25beb..2a38565f60364fc38ea043bc64b8d2a90378e4b0 100644 (file)
@@ -7,12 +7,18 @@
 #![forbid(unused, non_snake_case)]
 
 #[allow(unused_variables)] //~ ERROR overruled
+                           //~| ERROR overruled
+                           //~| ERROR overruled
 fn foo() {}
 
 #[allow(unused)] //~ ERROR overruled
+                 //~| ERROR overruled
+                 //~| ERROR overruled
 fn bar() {}
 
 #[allow(nonstandard_style)] //~ ERROR overruled
+                            //~| ERROR overruled
+                            //~| ERROR overruled
 fn main() {
     println!("hello forbidden world")
 }
index 310a5d88f8c1cd790bae6bacd53e6ca1f31a29d6..b2e638e7af978b1210710ee3a69bea3b07e6ee23 100644 (file)
@@ -8,7 +8,7 @@ LL | #[allow(unused_variables)]
    |         ^^^^^^^^^^^^^^^^ overruled by previous forbid
 
 error[E0453]: allow(unused) overruled by outer forbid(unused)
-  --> $DIR/outer-forbid.rs:12:9
+  --> $DIR/outer-forbid.rs:14:9
    |
 LL | #![forbid(unused, non_snake_case)]
    |           ------ `forbid` level set here
@@ -17,7 +17,7 @@ LL | #[allow(unused)]
    |         ^^^^^^ overruled by previous forbid
 
 error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case)
-  --> $DIR/outer-forbid.rs:15:9
+  --> $DIR/outer-forbid.rs:19:9
    |
 LL | #![forbid(unused, non_snake_case)]
    |                   -------------- `forbid` level set here
@@ -25,6 +25,60 @@ LL | #![forbid(unused, non_snake_case)]
 LL | #[allow(nonstandard_style)]
    |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
 
-error: aborting due to 3 previous errors
+error[E0453]: allow(unused_variables) overruled by outer forbid(unused)
+  --> $DIR/outer-forbid.rs:9:9
+   |
+LL | #![forbid(unused, non_snake_case)]
+   |           ------ `forbid` level set here
+LL | 
+LL | #[allow(unused_variables)]
+   |         ^^^^^^^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(unused) overruled by outer forbid(unused)
+  --> $DIR/outer-forbid.rs:14:9
+   |
+LL | #![forbid(unused, non_snake_case)]
+   |           ------ `forbid` level set here
+...
+LL | #[allow(unused)]
+   |         ^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case)
+  --> $DIR/outer-forbid.rs:19:9
+   |
+LL | #![forbid(unused, non_snake_case)]
+   |                   -------------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(unused_variables) overruled by outer forbid(unused)
+  --> $DIR/outer-forbid.rs:9:9
+   |
+LL | #![forbid(unused, non_snake_case)]
+   |           ------ `forbid` level set here
+LL | 
+LL | #[allow(unused_variables)]
+   |         ^^^^^^^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(unused) overruled by outer forbid(unused)
+  --> $DIR/outer-forbid.rs:14:9
+   |
+LL | #![forbid(unused, non_snake_case)]
+   |           ------ `forbid` level set here
+...
+LL | #[allow(unused)]
+   |         ^^^^^^ overruled by previous forbid
+
+error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case)
+  --> $DIR/outer-forbid.rs:19:9
+   |
+LL | #![forbid(unused, non_snake_case)]
+   |                   -------------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 21c2ddd5ef7ce2c051980d174e88fe4a9d1ff0d6..03cf0679fce9414d5360994b58cc9582b8a18e34 100644 (file)
@@ -2,24 +2,70 @@
 
 #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
 //~^ ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| NOTE reason must be a string literal
+//~| NOTE reason must be a string literal
 //~| NOTE reason must be a string literal
 #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
 //~^ ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| NOTE reason must be a string literal
+//~| NOTE reason must be a string literal
 //~| NOTE reason must be a string literal
 #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
 //~^ ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
 //~^ ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
 //~^ ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
+//~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
 //~^ ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| NOTE reason in lint attribute must come last
+//~| NOTE reason in lint attribute must come last
 //~| NOTE reason in lint attribute must come last
 #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
 //~^ ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| ERROR malformed lint attribute
+//~| NOTE reason in lint attribute must come last
+//~| NOTE reason in lint attribute must come last
 //~| NOTE reason in lint attribute must come last
 #![warn(missing_copy_implementations, reason)]
 //~^ WARN unknown lint
index 3f925f19ef18e7e9bf32cdde70de06173b65e057..a84167fed12d039222e7a1fa1ea6ff1bf922a000 100644 (file)
@@ -5,49 +5,187 @@ LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
    |                                                          ^ reason must be a string literal
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:6:40
+  --> $DIR/reasons-erroneous.rs:10:40
    |
 LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:9:29
+  --> $DIR/reasons-erroneous.rs:17:29
    |
 LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:12:23
+  --> $DIR/reasons-erroneous.rs:17:29
+   |
+LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:30:23
    |
 LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:15:36
+  --> $DIR/reasons-erroneous.rs:30:23
+   |
+LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:43:36
+   |
+LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:43:36
    |
 LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:18:44
+  --> $DIR/reasons-erroneous.rs:56:44
    |
 LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
    |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:21:25
+  --> $DIR/reasons-erroneous.rs:63:25
    |
 LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
 warning: unknown lint: `reason`
-  --> $DIR/reasons-erroneous.rs:24:39
+  --> $DIR/reasons-erroneous.rs:70:39
    |
 LL | #![warn(missing_copy_implementations, reason)]
    |                                       ^^^^^^
    |
    = note: `#[warn(unknown_lints)]` on by default
 
-error: aborting due to 7 previous errors
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:3:58
+   |
+LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
+   |                                                          ^ reason must be a string literal
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:10:40
+   |
+LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:17:29
+   |
+LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:17:29
+   |
+LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:30:23
+   |
+LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:30:23
+   |
+LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:43:36
+   |
+LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:43:36
+   |
+LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:56:44
+   |
+LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:63:25
+   |
+LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:3:58
+   |
+LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
+   |                                                          ^ reason must be a string literal
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:10:40
+   |
+LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:17:29
+   |
+LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:17:29
+   |
+LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:30:23
+   |
+LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:30:23
+   |
+LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:43:36
+   |
+LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:43:36
+   |
+LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:56:44
+   |
+LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
+
+error[E0452]: malformed lint attribute input
+  --> $DIR/reasons-erroneous.rs:63:25
+   |
+LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
+
+error: aborting due to 30 previous errors
 
 For more information about this error, try `rustc --explain E0452`.
index 19ab76707d40802d64eaae67944ee535ee61764d..6a71176aabb15db8197c609a1cf4d80335292ba5 100644 (file)
@@ -3,6 +3,8 @@
 #![forbid(
     unsafe_code,
     //~^ NOTE `forbid` level set here
+    //~| NOTE `forbid` level set here
+    //~| NOTE `forbid` level set here
     reason = "our errors & omissions insurance policy doesn't cover unsafe Rust"
 )]
 
@@ -13,7 +15,13 @@ fn main() {
 
     #[allow(unsafe_code)]
     //~^ ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code)
+    //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code)
+    //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code)
     //~| NOTE overruled by previous forbid
+    //~| NOTE overruled by previous forbid
+    //~| NOTE overruled by previous forbid
+    //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust
+    //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust
     //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust
     unsafe {
         *a_billion_dollar_mistake
index ea09e591cba0f41799834977655ae2f9e4fa976e..0954edea7378c8c32152b0660fab70b5066b21ea 100644 (file)
@@ -1,5 +1,5 @@
 error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code)
-  --> $DIR/reasons-forbidden.rs:14:13
+  --> $DIR/reasons-forbidden.rs:16:13
    |
 LL |     unsafe_code,
    |     ----------- `forbid` level set here
@@ -9,6 +9,28 @@ LL |     #[allow(unsafe_code)]
    |
    = note: our errors & omissions insurance policy doesn't cover unsafe Rust
 
-error: aborting due to previous error
+error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code)
+  --> $DIR/reasons-forbidden.rs:16:13
+   |
+LL |     unsafe_code,
+   |     ----------- `forbid` level set here
+...
+LL |     #[allow(unsafe_code)]
+   |             ^^^^^^^^^^^ overruled by previous forbid
+   |
+   = note: our errors & omissions insurance policy doesn't cover unsafe Rust
+
+error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code)
+  --> $DIR/reasons-forbidden.rs:16:13
+   |
+LL |     unsafe_code,
+   |     ----------- `forbid` level set here
+...
+LL |     #[allow(unsafe_code)]
+   |             ^^^^^^^^^^^ overruled by previous forbid
+   |
+   = note: our errors & omissions insurance policy doesn't cover unsafe Rust
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 33de3d5184b1fa20073abe15e269e9038b2bef61..c1a4e32a6dcbcd842f4bb64bb4e4c15ba6a0df42 100644 (file)
@@ -1,6 +1,8 @@
 #[derive(
     core::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `core`
+                          //~| ERROR could not find `RustcDecodable` in `core`
     core::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `core`
+                          //~| ERROR could not find `RustcDecodable` in `core`
 )]
 #[core::bench] //~ ERROR could not find `bench` in `core`
 #[core::global_allocator] //~ ERROR could not find `global_allocator` in `core`
@@ -10,7 +12,9 @@
 
 #[derive(
     std::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `std`
+                         //~| ERROR could not find `RustcDecodable` in `std`
     std::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `std`
+                         //~| ERROR could not find `RustcDecodable` in `std`
 )]
 #[std::bench] //~ ERROR could not find `bench` in `std`
 #[std::global_allocator] //~ ERROR could not find `global_allocator` in `std`
index 6de689076b8490a99d3b8beb09c8d93dbd6442df..9831e46ec30a1c3cf66e54f90f1b16e6e41ab619 100644 (file)
@@ -1,23 +1,23 @@
 error[E0433]: failed to resolve: could not find `bench` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:5:9
+  --> $DIR/builtin-std-paths-fail.rs:7:9
    |
 LL | #[core::bench]
    |         ^^^^^ could not find `bench` in `core`
 
 error[E0433]: failed to resolve: could not find `global_allocator` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:6:9
+  --> $DIR/builtin-std-paths-fail.rs:8:9
    |
 LL | #[core::global_allocator]
    |         ^^^^^^^^^^^^^^^^ could not find `global_allocator` in `core`
 
 error[E0433]: failed to resolve: could not find `test_case` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:7:9
+  --> $DIR/builtin-std-paths-fail.rs:9:9
    |
 LL | #[core::test_case]
    |         ^^^^^^^^^ could not find `test_case` in `core`
 
 error[E0433]: failed to resolve: could not find `test` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:8:9
+  --> $DIR/builtin-std-paths-fail.rs:10:9
    |
 LL | #[core::test]
    |         ^^^^ could not find `test` in `core`
@@ -29,47 +29,71 @@ LL |     core::RustcDecodable,
    |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
 
 error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
-  --> $DIR/builtin-std-paths-fail.rs:3:11
+  --> $DIR/builtin-std-paths-fail.rs:4:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:4:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:2:11
    |
 LL |     core::RustcDecodable,
    |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
 
 error[E0433]: failed to resolve: could not find `bench` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:15:8
+  --> $DIR/builtin-std-paths-fail.rs:19:8
    |
 LL | #[std::bench]
    |        ^^^^^ could not find `bench` in `std`
 
 error[E0433]: failed to resolve: could not find `global_allocator` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:16:8
+  --> $DIR/builtin-std-paths-fail.rs:20:8
    |
 LL | #[std::global_allocator]
    |        ^^^^^^^^^^^^^^^^ could not find `global_allocator` in `std`
 
 error[E0433]: failed to resolve: could not find `test_case` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:17:8
+  --> $DIR/builtin-std-paths-fail.rs:21:8
    |
 LL | #[std::test_case]
    |        ^^^^^^^^^ could not find `test_case` in `std`
 
 error[E0433]: failed to resolve: could not find `test` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:18:8
+  --> $DIR/builtin-std-paths-fail.rs:22:8
    |
 LL | #[std::test]
    |        ^^^^ could not find `test` in `std`
 
 error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:12:10
+  --> $DIR/builtin-std-paths-fail.rs:14:10
+   |
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:16:10
+   |
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:16:10
    |
 LL |     std::RustcDecodable,
    |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
 
 error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
-  --> $DIR/builtin-std-paths-fail.rs:13:10
+  --> $DIR/builtin-std-paths-fail.rs:14:10
    |
 LL |     std::RustcDecodable,
    |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
 
-error: aborting due to 12 previous errors
+error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/macros/issue-68058.rs b/src/test/ui/macros/issue-68058.rs
new file mode 100644 (file)
index 0000000..24da262
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+
+macro_rules! foo {
+    ($doc: expr) => {
+        fn f() {
+            #[doc = $doc]
+            ()
+        }
+    };
+}
+
+foo!("doc");
+
+fn main() {}
index 1ddc419d302acf81e042f20c48ab57779dbaf9ec..b2892f3b6c239fc10815bcb18dbeff9187c03dfe 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 fn main() {
     printlx!("oh noes!"); //~ ERROR cannot find
 }
index ce2e1985b38cee8ff420f79393e2984c601b9d7a..00afbde8932fca2426c64030396dc52b9f037a1a 100644 (file)
@@ -1,8 +1,13 @@
 error: cannot find macro `printlx` in this scope
-  --> $DIR/macro-name-typo.rs:2:5
+  --> $DIR/macro-name-typo.rs:6:5
    |
 LL |     printlx!("oh noes!");
    |     ^^^^^^^ help: a macro with a similar name exists: `println`
+   | 
+  ::: $SRC_DIR/libstd/macros.rs:LL:COL
+   |
+LL | macro_rules! println {
+   | -------------------- similarly named macro `println` defined here
 
 error: aborting due to previous error
 
index 68eb350a95614772327aae1e335f4c4204c8f3f4..3c3948ca3c36129acb7612ed5db8b3dbd3f46108 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 fn main() {
     inline!(); //~ ERROR cannot find macro `inline` in this scope
 }
index ec00760de6c6f3ac53106233c499983b6097f8ed..536459067437dc58d1a8e9260fe14face3755040 100644 (file)
@@ -1,8 +1,13 @@
 error: cannot find macro `inline` in this scope
-  --> $DIR/macro-path-prelude-fail-3.rs:2:5
+  --> $DIR/macro-path-prelude-fail-3.rs:6:5
    |
 LL |     inline!();
    |     ^^^^^^ help: a macro with a similar name exists: `line`
+   | 
+  ::: $SRC_DIR/libcore/macros/mod.rs:LL:COL
+   |
+LL |     macro_rules! line {
+   |     ----------------- similarly named macro `line` defined here
 
 error: aborting due to previous error
 
index 8b4e90a5798f15a4b70c6cc6f72a68800e061828..74fb519cc82ffe6be0ce4a10c582bd89490d9caa 100644 (file)
@@ -3,6 +3,11 @@ error: cannot find macro `macro_two` in this scope
    |
 LL |     macro_two!();
    |     ^^^^^^^^^ help: a macro with a similar name exists: `macro_one`
+   | 
+  ::: $DIR/auxiliary/two_macros.rs:2:1
+   |
+LL | macro_rules! macro_one { () => ("one") }
+   | ---------------------- similarly named macro `macro_one` defined here
 
 error: aborting due to previous error
 
index 14d23be059c87d18fd9049debd5dc2dafefd7b70..8ed911cbca71839aaaaacdf3206acf199d1c8853 100644 (file)
@@ -1,4 +1,5 @@
 #[derive(::Absolute)] //~ ERROR failed to resolve
+                      //~| ERROR failed to resolve
 struct S;
 
 fn main() {}
index 711fa4dd405bc0c4def9e9f4671e36f1316c5d06..c53971e245fdb1656c842dc60cfbb7ff4701be59 100644 (file)
@@ -4,6 +4,12 @@ error[E0433]: failed to resolve: maybe a missing crate `Absolute`?
 LL | #[derive(::Absolute)]
    |            ^^^^^^^^ maybe a missing crate `Absolute`?
 
-error: aborting due to previous error
+error[E0433]: failed to resolve: maybe a missing crate `Absolute`?
+  --> $DIR/meta-item-absolute-path.rs:1:12
+   |
+LL | #[derive(::Absolute)]
+   |            ^^^^^^^^ maybe a missing crate `Absolute`?
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0433`.
index 19e6e12958bf3e6ac0d7a9b75831d3d6ce3212c9..792664e1db82c180a1766351c42cba8a40472e0c 100644 (file)
@@ -6,16 +6,19 @@ fn main() {
         _ => { }
     };
     //~^^^ ERROR lower range bound must be less than or equal to upper
+    //~| ERROR lower range bound must be less than or equal to upper
 
     match 5 {
         0 .. 0 => { }
         _ => { }
     };
     //~^^^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
 
     match 5u64 {
         0xFFFF_FFFF_FFFF_FFFF ..= 1 => { }
         _ => { }
     };
     //~^^^ ERROR lower range bound must be less than or equal to upper
+    //~| ERROR lower range bound must be less than or equal to upper
 }
index 52a2bf2b34aa668f3e5b3e2e678ab9304cf0fa85..7a0852d7e6ce68137c17b229767d84b09d9aacff 100644 (file)
@@ -5,18 +5,36 @@ LL |         6 ..= 1 => { }
    |         ^ lower bound larger than upper bound
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/match-range-fail-2.rs:11:9
+  --> $DIR/match-range-fail-2.rs:12:9
    |
 LL |         0 .. 0 => { }
    |         ^
 
 error[E0030]: lower range bound must be less than or equal to upper
-  --> $DIR/match-range-fail-2.rs:17:9
+  --> $DIR/match-range-fail-2.rs:19:9
    |
 LL |         0xFFFF_FFFF_FFFF_FFFF ..= 1 => { }
    |         ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound
 
-error: aborting due to 3 previous errors
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/match-range-fail-2.rs:5:9
+   |
+LL |         6 ..= 1 => { }
+   |         ^ lower bound larger than upper bound
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/match-range-fail-2.rs:12:9
+   |
+LL |         0 .. 0 => { }
+   |         ^
+
+error[E0030]: lower range bound must be less than or equal to upper
+  --> $DIR/match-range-fail-2.rs:19:9
+   |
+LL |         0xFFFF_FFFF_FFFF_FFFF ..= 1 => { }
+   |         ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound
+
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0030, E0579.
 For more information about an error, try `rustc --explain E0030`.
index e0dec0a4a705f52256d60a7e8ecdad2422165786..5ff4b412667c23ad249784d6d757cc6e7907d0b7 100644 (file)
@@ -15,6 +15,6 @@ fn main() {
 
     let y = Foo;
     y.zero()
-     .take()    //~ ERROR no method named `take` found for type `Foo` in the current scope
+     .take()    //~ ERROR no method named `take` found
      .one(0);
 }
index 94c27b7d17865abee9dc5e8cff7fb8bb5cc993c1..7efdd91708a80618bd0b206e233b4a613db76f7c 100644 (file)
@@ -25,7 +25,7 @@ LL |     fn two(self, _: isize, _: isize) -> Foo { self }
 LL |      .two(0);
    |       ^^^ expected 2 parameters
 
-error[E0599]: no method named `take` found for type `Foo` in the current scope
+error[E0599]: no method named `take` found for struct `Foo` in the current scope
   --> $DIR/method-call-err-msg.rs:18:7
    |
 LL | pub struct Foo;
diff --git a/src/test/ui/mir/issue-67947.rs b/src/test/ui/mir/issue-67947.rs
new file mode 100644 (file)
index 0000000..79e75e6
--- /dev/null
@@ -0,0 +1,7 @@
+struct Bug {
+    A: [(); { *"" }.len()],
+    //~^ ERROR: cannot move a value of type str
+    //~| ERROR: cannot move out of a shared reference
+}
+
+fn main() {}
diff --git a/src/test/ui/mir/issue-67947.stderr b/src/test/ui/mir/issue-67947.stderr
new file mode 100644 (file)
index 0000000..d526218
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0161]: cannot move a value of type str: the size of str cannot be statically determined
+  --> $DIR/issue-67947.rs:2:13
+   |
+LL |     A: [(); { *"" }.len()],
+   |             ^^^^^^^
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/issue-67947.rs:2:15
+   |
+LL |     A: [(); { *"" }.len()],
+   |               ^^^ move occurs because value has type `str`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0161, E0507.
+For more information about an error, try `rustc --explain E0161`.
index da018aa89482c58cdf9a4318973389713ee0e213..f8d677b99d6934a2462c8380e5b5048bf6d6534c 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `count` found for type `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope
+error[E0599]: no method named `count` found for struct `std::iter::Filter<std::iter::Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope
   --> $DIR/issue-36053-2.rs:7:55
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
index 83cea168465154d54b6b8ca6a582b444939c4e0b..58ceaffc96400f2dcce4292a9100f626fdbb1214 100644 (file)
@@ -3,5 +3,5 @@
 fn main() {
     let a: Result<(), Foo> = Ok(());
     a.unwrap();
-    //~^ ERROR no method named `unwrap` found for type `std::result::Result<(), Foo>`
+    //~^ ERROR no method named `unwrap` found
 }
index 865092e4e9ccccc385d99dbc30934e5f9c9d0cb5..bbfb00050566a4d289f27743ea1837c591eaa954 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `unwrap` found for type `std::result::Result<(), Foo>` in the current scope
+error[E0599]: no method named `unwrap` found for enum `std::result::Result<(), Foo>` in the current scope
   --> $DIR/method-help-unsatisfied-bound.rs:5:7
    |
 LL |     a.unwrap();
index 0484661a2e1543f8888bdf741313e104b9e0deab..13d727de441cb8cef49e2d5546725c2a196269c8 100644 (file)
@@ -24,6 +24,11 @@ error[E0423]: expected value, found type alias `xm1::S`
    |
 LL |     check(xm1::S);
    |           ^^^^^^
+   | 
+  ::: $DIR/auxiliary/namespace-mix.rs:3:5
+   |
+LL |     pub struct TS();
+   |     ---------------- similarly named tuple struct `TS` defined here
    |
    = note: can't use a type alias as a constructor
 help: a tuple struct with a similar name exists
@@ -64,6 +69,11 @@ error[E0423]: expected value, found struct variant `xm7::V`
    |
 LL |     check(xm7::V);
    |           ^^^^^^ did you mean `xm7::V { /* fields */ }`?
+   | 
+  ::: $DIR/auxiliary/namespace-mix.rs:7:9
+   |
+LL |         TV(),
+   |         ---- similarly named tuple variant `TV` defined here
    |
 help: a tuple variant with a similar name exists
    |
index d46f0e61793f35ce713c8d9246d0587cebdbcabb..d6426d2cfabfda31785f8dbccf1f5f8696b3daba 100644 (file)
@@ -11,5 +11,5 @@ fn bind<B, F>(&self, mut f: F) where F: FnMut(A) -> Vec<B> {
 }
 fn main() {
     ["hi"].bind(|x| [x] );
-    //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope
+    //~^ ERROR no method named `bind` found
 }
index 8ce2ba033321e2e28caec3836bea032654484492..9645244751dabe6e8c23c2800517ae74a7c33e6f 100644 (file)
@@ -6,7 +6,7 @@ LL |         for elt in self { r = r + f(*elt); }
    |
    = help: the trait `std::ops::Add<std::vec::Vec<B>>` is not implemented for `()`
 
-error[E0599]: no method named `bind` found for type `[&str; 1]` in the current scope
+error[E0599]: no method named `bind` found for array `[&str; 1]` in the current scope
   --> $DIR/issue-2149.rs:13:12
    |
 LL |     ["hi"].bind(|x| [x] );
index 8cb690a35c874fef541483a04633c0c65b9e0925..65946ee8a20cf8588ca193830159779fa497e307 100644 (file)
@@ -1,13 +1,20 @@
 error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
   --> $DIR/no-send-res-ports.rs:29:5
    |
-LL |     thread::spawn(move|| {
-   |     ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
+LL |       thread::spawn(move|| {
+   |  _____^^^^^^^^^^^^^_-
+   | |     |
+   | |     `std::rc::Rc<()>` cannot be sent between threads safely
+LL | |
+LL | |         let y = x;
+LL | |         println!("{:?}", y);
+LL | |     });
+   | |_____- within this `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]`
    | 
   ::: $SRC_DIR/libstd/thread/mod.rs:LL:COL
    |
-LL |     F: Send + 'static,
-   |        ---- required by this bound in `std::thread::spawn`
+LL |       F: Send + 'static,
+   |          ---- required by this bound in `std::thread::spawn`
    |
    = help: within `[closure@$DIR/no-send-res-ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
    = note: required because it appears within the type `Port<()>`
index b05c29c0d40360ccbf8db0f8d8c7df036660f302..074ed66a261836c4e986e348dbdee4356849dd62 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `clone` found for type `libc::c_void` in the current scope
+error[E0599]: no method named `clone` found for enum `libc::c_void` in the current scope
   --> $DIR/non-copyable-void.rs:11:23
    |
 LL |         let _z = (*y).clone();
diff --git a/src/test/ui/non-ice-error-on-worker-io-fail.rs b/src/test/ui/non-ice-error-on-worker-io-fail.rs
new file mode 100644 (file)
index 0000000..8af1774
--- /dev/null
@@ -0,0 +1,37 @@
+// Issue #66530: We would ICE if someone compiled with `-o /dev/null`,
+// because we would try to generate auxiliary files in `/dev/` (which
+// at least the OS X file system rejects).
+//
+// An attempt to `-o` into a directory we cannot write into should indeed
+// be an error; but not an ICE.
+
+// compile-flags: -o /dev/null
+
+// The error-pattern check occurs *before* normalization, and the error patterns
+// are wildly different between build environments. So this is a cop-out (and we
+// rely on the checking of the normalized stderr output as our actual
+// "verification" of the diagnostic).
+
+// error-pattern: error
+
+// On Mac OS X, we get an error like the below
+// normalize-stderr-test "failed to write bytecode to /dev/null.non_ice_error_on_worker_io_fail.*" -> "io error modifying /dev/"
+
+// On Linux, we get an error like the below
+// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /dev/"
+
+// ignore-tidy-linelength
+// ignore-windows - this is a unix-specific test
+// ignore-emscripten - the file-system issues do not replicate here
+// ignore-wasm - the file-system issues do not replicate here
+// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu
+
+#![crate_type="lib"]
+
+#![cfg_attr(not(feature = "std"), no_std)]
+pub mod task {
+    pub mod __internal {
+        use crate::task::Waker;
+    }
+    pub use core::task::Waker;
+}
diff --git a/src/test/ui/non-ice-error-on-worker-io-fail.stderr b/src/test/ui/non-ice-error-on-worker-io-fail.stderr
new file mode 100644 (file)
index 0000000..f5601ad
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: io error modifying /dev/
+
+error: aborting due to previous error
+
index c1c50211381899c53909aafd76cce0f20e3311e0..6c3c4a6ac98884b7552ba53d1b08e51a3a765669 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `clone` found for type `Foo` in the current scope
+error[E0599]: no method named `clone` found for struct `Foo` in the current scope
   --> $DIR/noncopyable-class.rs:34:16
    |
 LL | struct Foo {
index b66391b83b8dbd7c8a2c053ded883efea0af2123..20c7f81cf5ef54a7de923b3570f10fec95fb8860 100644 (file)
@@ -1,8 +1,14 @@
 error[E0277]: the trait bound `S: std::clone::Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
   --> $DIR/not-clone-closure.rs:11:23
    |
-LL |     let hello = hello.clone();
-   |                       ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S`
+LL |       let hello = move || {
+   |  _________________-
+LL | |         println!("Hello {}", a.0);
+LL | |     };
+   | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
+LL | 
+LL |       let hello = hello.clone();
+   |                         ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S`
    |
    = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
 
index 2df628ecf8e500434226e3d1a6e9a871495b1f60..855894b4495c6baba701a7bece186aeb28e1ebc0 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `owned` found for type `&dyn Foo` in the current scope
+error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope
   --> $DIR/object-pointer-types.rs:11:7
    |
 LL |     x.owned();
@@ -8,7 +8,7 @@ LL |     x.owned();
    = note: the following trait defines an item `owned`, perhaps you need to implement it:
            candidate #1: `Foo`
 
-error[E0599]: no method named `owned` found for type `&mut dyn Foo` in the current scope
+error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope
   --> $DIR/object-pointer-types.rs:17:7
    |
 LL |     x.owned();
@@ -18,7 +18,7 @@ LL |     x.owned();
    = note: the following trait defines an item `owned`, perhaps you need to implement it:
            candidate #1: `Foo`
 
-error[E0599]: no method named `managed` found for type `std::boxed::Box<(dyn Foo + 'static)>` in the current scope
+error[E0599]: no method named `managed` found for struct `std::boxed::Box<(dyn Foo + 'static)>` in the current scope
   --> $DIR/object-pointer-types.rs:23:7
    |
 LL |     x.managed();
index f167b3595d92fe9d105a045b9999a9ad39bdfd9c..13759a2351997c5636c9b1fdaa32474dc0ba5dc2 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 // Test that the parser is error correcting missing idents. Despite a parsing
 // error (or two), we still run type checking (and don't get extra errors there).
 
index d593431d9781d4eada23dd71baaafa8abec7eafa..c54baf00b27f2c8ef395bd044f30e65f5a90ef67 100644 (file)
@@ -1,17 +1,17 @@
 error: unexpected token: `;`
-  --> $DIR/parse-error-correct.rs:8:15
+  --> $DIR/parse-error-correct.rs:6:15
    |
 LL |     let x = y.;
    |               ^
 
 error: unexpected token: `(`
-  --> $DIR/parse-error-correct.rs:9:15
+  --> $DIR/parse-error-correct.rs:7:15
    |
 LL |     let x = y.();
    |               ^
 
 error[E0618]: expected function, found `{integer}`
-  --> $DIR/parse-error-correct.rs:9:13
+  --> $DIR/parse-error-correct.rs:7:13
    |
 LL |     let y = 42;
    |         - `{integer}` defined here
@@ -22,7 +22,7 @@ LL |     let x = y.();
    |             call expression requires function
 
 error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
-  --> $DIR/parse-error-correct.rs:11:15
+  --> $DIR/parse-error-correct.rs:9:15
    |
 LL |     let x = y.foo;
    |               ^^^
index dcc0dc00a72eaf933716475228339d10aceb7de4..7e26b4f2b6a22273724d741c223fb23be7264856 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 // Test that we can recover from missing braces in the parser.
 
 trait Foo {
index 4d881918c40ccc79aa634313f99d0facd50e195d..f56060c3e356f6b41b31e373820f85349db2b503 100644 (file)
@@ -1,5 +1,5 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/parser-recovery-1.rs:15:54
+  --> $DIR/parser-recovery-1.rs:13:54
    |
 LL | trait Foo {
    |           - unclosed delimiter
@@ -13,19 +13,19 @@ LL | }
    |                                                      ^
 
 error: unexpected token: `;`
-  --> $DIR/parser-recovery-1.rs:12:15
+  --> $DIR/parser-recovery-1.rs:10:15
    |
 LL |     let x = y.;
    |               ^
 
 error[E0425]: cannot find function `foo` in this scope
-  --> $DIR/parser-recovery-1.rs:7:17
+  --> $DIR/parser-recovery-1.rs:5:17
    |
 LL |         let x = foo();
    |                 ^^^ not found in this scope
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/parser-recovery-1.rs:12:13
+  --> $DIR/parser-recovery-1.rs:10:13
    |
 LL |     let x = y.;
    |             ^ not found in this scope
index dc5be96cc6405fb152074cfac7aa4332af4b6131..48b22afffe7f04ae57a4f6fcc873255716f8f2c7 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 // Test that we can recover from mismatched braces in the parser.
 
 trait Foo {
index c48211d4064793e7948342dc45641725cf50c0a1..cd3da4c71f0b5685fbffd5d6b189e279c455f42a 100644 (file)
@@ -1,11 +1,11 @@
 error: unexpected token: `;`
-  --> $DIR/parser-recovery-2.rs:12:15
+  --> $DIR/parser-recovery-2.rs:10:15
    |
 LL |     let x = y.;
    |               ^
 
 error: mismatched closing delimiter: `)`
-  --> $DIR/parser-recovery-2.rs:8:5
+  --> $DIR/parser-recovery-2.rs:6:5
    |
 LL |     fn bar() {
    |              - unclosed delimiter
@@ -14,13 +14,13 @@ LL |     )
    |     ^ mismatched closing delimiter
 
 error[E0425]: cannot find function `foo` in this scope
-  --> $DIR/parser-recovery-2.rs:7:17
+  --> $DIR/parser-recovery-2.rs:5:17
    |
 LL |         let x = foo();
    |                 ^^^ not found in this scope
 
 error[E0425]: cannot find value `y` in this scope
-  --> $DIR/parser-recovery-2.rs:12:13
+  --> $DIR/parser-recovery-2.rs:10:13
    |
 LL |     let x = y.;
    |             ^ not found in this scope
index f1b028ea8de02ac93a482fc4ca9ae24d866351d7..20d3edf12517514475b8c8c077918ee1b7c99667 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 fn main() {
     let x = "\x80"; //~ ERROR may only be used
     let y = "\xff"; //~ ERROR may only be used
index 391677917580bee901285fca8bae5322c6cd6456..cf51b00cdc39aa5aa8356e51e34bbca7b3973380 100644 (file)
@@ -1,17 +1,17 @@
 error: this form of character escape may only be used with characters in the range [\x00-\x7f]
-  --> $DIR/ascii-only-character-escape.rs:4:14
+  --> $DIR/ascii-only-character-escape.rs:2:14
    |
 LL |     let x = "\x80";
    |              ^^^^
 
 error: this form of character escape may only be used with characters in the range [\x00-\x7f]
-  --> $DIR/ascii-only-character-escape.rs:5:14
+  --> $DIR/ascii-only-character-escape.rs:3:14
    |
 LL |     let y = "\xff";
    |              ^^^^
 
 error: this form of character escape may only be used with characters in the range [\x00-\x7f]
-  --> $DIR/ascii-only-character-escape.rs:6:14
+  --> $DIR/ascii-only-character-escape.rs:4:14
    |
 LL |     let z = "\xe2";
    |              ^^^^
index f6d2bee0e15600a300d1d8e4de5915ba78e7bfb3..118bff8144c7f6d33d178375eaed8e4d01b0cccb 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(half_open_range_patterns)]
+
 fn main() {}
 
 #[cfg(FALSE)] fn e() { let _ = box #![attr] 0; }
@@ -90,15 +92,15 @@ fn main() {}
 // note: requires parens in patterns to allow disambiguation
 
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
-//~^ ERROR `X..=` range patterns are not supported
+//~^ ERROR inclusive range with no end
 //~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
-//~^ ERROR `X..=` range patterns are not supported
+//~^ ERROR inclusive range with no end
 //~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
 //~^ ERROR unexpected token: `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
-//~^ ERROR `X..=` range patterns are not supported
+//~^ ERROR inclusive range with no end
 //~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 
 #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
index 0123006418a3a71545846f7bcc420649e7155a25..4775b9b7bc003593d9c76ca2a06268b5e060ceb8 100644 (file)
@@ -1,5 +1,5 @@
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:3:36
+  --> $DIR/attr-stmt-expr-attr-bad.rs:5:36
    |
 LL | #[cfg(FALSE)] fn e() { let _ = box #![attr] 0; }
    |                                    ^^^^^^^^
@@ -7,19 +7,19 @@ LL | #[cfg(FALSE)] fn e() { let _ = box #![attr] 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: expected expression, found `]`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:5:40
+  --> $DIR/attr-stmt-expr-attr-bad.rs:7:40
    |
 LL | #[cfg(FALSE)] fn e() { let _ = [#[attr]]; }
    |                                        ^ expected expression
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:7:35
+  --> $DIR/attr-stmt-expr-attr-bad.rs:9:35
    |
 LL | #[cfg(FALSE)] fn e() { let _ = foo#[attr](); }
    |                                   ^ expected one of 7 possible tokens
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:9:36
+  --> $DIR/attr-stmt-expr-attr-bad.rs:11:36
    |
 LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
    |                                    ^^^^^^^^
@@ -27,13 +27,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: expected expression, found `)`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:9:44
+  --> $DIR/attr-stmt-expr-attr-bad.rs:11:44
    |
 LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
    |                                            ^ expected expression
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:12:38
+  --> $DIR/attr-stmt-expr-attr-bad.rs:14:38
    |
 LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
    |                                      ^^^^^^^^
@@ -41,13 +41,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: expected expression, found `)`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:12:46
+  --> $DIR/attr-stmt-expr-attr-bad.rs:14:46
    |
 LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
    |                                              ^ expected expression
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:15:36
+  --> $DIR/attr-stmt-expr-attr-bad.rs:17:36
    |
 LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; }
    |                                    ^^^^^^^^
@@ -55,7 +55,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:17:33
+  --> $DIR/attr-stmt-expr-attr-bad.rs:19:33
    |
 LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; }
    |                                 ^^^^^^^^
@@ -63,7 +63,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:19:33
+  --> $DIR/attr-stmt-expr-attr-bad.rs:21:33
    |
 LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; }
    |                                 ^^^^^^^^
@@ -71,13 +71,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:21:34
+  --> $DIR/attr-stmt-expr-attr-bad.rs:23:34
    |
 LL | #[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; }
    |                                  ^ expected one of 7 possible tokens
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:23:35
+  --> $DIR/attr-stmt-expr-attr-bad.rs:25:35
    |
 LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; }
    |                                   ^^^^^^^^
@@ -85,7 +85,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:25:40
+  --> $DIR/attr-stmt-expr-attr-bad.rs:27:40
    |
 LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; }
    |                                        ^^^^^^^^
@@ -93,7 +93,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:27:35
+  --> $DIR/attr-stmt-expr-attr-bad.rs:29:35
    |
 LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; }
    |                                   ^^^^^^^^
@@ -101,7 +101,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:29:40
+  --> $DIR/attr-stmt-expr-attr-bad.rs:31:40
    |
 LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; }
    |                                        ^^^^^^^^
@@ -109,19 +109,19 @@ LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: expected expression, found `..`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:31:40
+  --> $DIR/attr-stmt-expr-attr-bad.rs:33:40
    |
 LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; }
    |                                        ^^ expected expression
 
 error: expected expression, found `..`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:33:40
+  --> $DIR/attr-stmt-expr-attr-bad.rs:35:40
    |
 LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..; }
    |                                        ^^ expected expression
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:35:41
+  --> $DIR/attr-stmt-expr-attr-bad.rs:37:41
    |
 LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; }
    |                                         ^^^^^^^^
@@ -129,7 +129,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:37:45
+  --> $DIR/attr-stmt-expr-attr-bad.rs:39:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
    |                                             ^^^^^^^^
@@ -137,13 +137,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: attributes are not yet allowed on `if` expressions
-  --> $DIR/attr-stmt-expr-attr-bad.rs:39:32
+  --> $DIR/attr-stmt-expr-attr-bad.rs:41:32
    |
 LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; }
    |                                ^^^^^^^
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:41:37
+  --> $DIR/attr-stmt-expr-attr-bad.rs:43:37
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
    |                                --   ^       --- help: try placing this code inside a block: `{ {}; }`
@@ -152,7 +152,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
    |                                this `if` expression has a condition, but no block
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:43:38
+  --> $DIR/attr-stmt-expr-attr-bad.rs:45:38
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
    |                                      ^^^^^^^^
@@ -160,13 +160,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:45:40
+  --> $DIR/attr-stmt-expr-attr-bad.rs:47:40
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
    |                                        ^ expected one of `.`, `;`, `?`, `else`, or an operator
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:47:45
+  --> $DIR/attr-stmt-expr-attr-bad.rs:49:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
    |                                             ^       --- help: try placing this code inside a block: `{ {}; }`
@@ -174,7 +174,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
    |                                             expected `{`
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:49:46
+  --> $DIR/attr-stmt-expr-attr-bad.rs:51:46
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
    |                                              ^^^^^^^^
@@ -182,13 +182,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: attributes are not yet allowed on `if` expressions
-  --> $DIR/attr-stmt-expr-attr-bad.rs:51:45
+  --> $DIR/attr-stmt-expr-attr-bad.rs:53:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
    |                                             ^^^^^^^
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:51:45
+  --> $DIR/attr-stmt-expr-attr-bad.rs:53:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
    |                                             ^       -------- help: try placing this code inside a block: `{ if 0 {}; }`
@@ -196,7 +196,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
    |                                             expected `{`
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:54:50
+  --> $DIR/attr-stmt-expr-attr-bad.rs:56:50
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
    |                                             --   ^       --- help: try placing this code inside a block: `{ {}; }`
@@ -205,7 +205,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
    |                                             this `if` expression has a condition, but no block
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:56:51
+  --> $DIR/attr-stmt-expr-attr-bad.rs:58:51
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
    |                                                   ^^^^^^^^
@@ -213,13 +213,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: attributes are not yet allowed on `if` expressions
-  --> $DIR/attr-stmt-expr-attr-bad.rs:58:32
+  --> $DIR/attr-stmt-expr-attr-bad.rs:60:32
    |
 LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; }
    |                                ^^^^^^^
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:60:45
+  --> $DIR/attr-stmt-expr-attr-bad.rs:62:45
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
    |                                --           ^       --- help: try placing this code inside a block: `{ {}; }`
@@ -228,7 +228,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
    |                                this `if` expression has a condition, but no block
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:62:46
+  --> $DIR/attr-stmt-expr-attr-bad.rs:64:46
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
    |                                              ^^^^^^^^
@@ -236,13 +236,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:64:48
+  --> $DIR/attr-stmt-expr-attr-bad.rs:66:48
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
    |                                                ^ expected one of `.`, `;`, `?`, `else`, or an operator
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:66:53
+  --> $DIR/attr-stmt-expr-attr-bad.rs:68:53
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
    |                                                     ^       --- help: try placing this code inside a block: `{ {}; }`
@@ -250,7 +250,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
    |                                                     expected `{`
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:68:54
+  --> $DIR/attr-stmt-expr-attr-bad.rs:70:54
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
    |                                                      ^^^^^^^^
@@ -258,13 +258,13 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: attributes are not yet allowed on `if` expressions
-  --> $DIR/attr-stmt-expr-attr-bad.rs:70:53
+  --> $DIR/attr-stmt-expr-attr-bad.rs:72:53
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
    |                                                     ^^^^^^^
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:70:53
+  --> $DIR/attr-stmt-expr-attr-bad.rs:72:53
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
    |                                                     ^       ---------------- help: try placing this code inside a block: `{ if let _ = 0 {}; }`
@@ -272,7 +272,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}
    |                                                     expected `{`
 
 error: expected `{`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:73:66
+  --> $DIR/attr-stmt-expr-attr-bad.rs:75:66
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
    |                                                     --           ^       --- help: try placing this code inside a block: `{ {}; }`
@@ -281,7 +281,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}
    |                                                     this `if` expression has a condition, but no block
 
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr-stmt-expr-attr-bad.rs:75:67
+  --> $DIR/attr-stmt-expr-attr-bad.rs:77:67
    |
 LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
    |                                                                   ^^^^^^^^
@@ -289,7 +289,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted following an outer attribute
-  --> $DIR/attr-stmt-expr-attr-bad.rs:78:32
+  --> $DIR/attr-stmt-expr-attr-bad.rs:80:32
    |
 LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; }
    |                        ------- ^^^^^^^^ not permitted following an outer attibute
@@ -299,7 +299,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted following an outer attribute
-  --> $DIR/attr-stmt-expr-attr-bad.rs:80:32
+  --> $DIR/attr-stmt-expr-attr-bad.rs:82:32
    |
 LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; }
    |                        ------- ^^^^^^^^ not permitted following an outer attibute
@@ -309,7 +309,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted following an outer attribute
-  --> $DIR/attr-stmt-expr-attr-bad.rs:82:32
+  --> $DIR/attr-stmt-expr-attr-bad.rs:84:32
    |
 LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
    |                        ------- ^^^^^^^^ not permitted following an outer attibute
@@ -319,7 +319,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted following an outer attribute
-  --> $DIR/attr-stmt-expr-attr-bad.rs:84:32
+  --> $DIR/attr-stmt-expr-attr-bad.rs:86:32
    |
 LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
    |                        ------- ^^^^^^^^ not permitted following an outer attibute
@@ -329,7 +329,7 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
 error: an inner attribute is not permitted following an outer attribute
-  --> $DIR/attr-stmt-expr-attr-bad.rs:86:32
+  --> $DIR/attr-stmt-expr-attr-bad.rs:88:32
    |
 LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
    |                        ------- ^^^^^^^^ not permitted following an outer attibute
@@ -338,83 +338,90 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
-error: `X..=` range patterns are not supported
-  --> $DIR/attr-stmt-expr-attr-bad.rs:92:34
+error[E0586]: inclusive range with no end
+  --> $DIR/attr-stmt-expr-attr-bad.rs:94:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
-   |                                  ^^^^ help: try using the maximum value for the type: `0..=MAX`
+   |                                   ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: expected one of `=>`, `if`, or `|`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:92:38
+  --> $DIR/attr-stmt-expr-attr-bad.rs:94:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
    |                                      ^ expected one of `=>`, `if`, or `|`
 
-error: `X..=` range patterns are not supported
-  --> $DIR/attr-stmt-expr-attr-bad.rs:95:34
+error[E0586]: inclusive range with no end
+  --> $DIR/attr-stmt-expr-attr-bad.rs:97:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
-   |                                  ^^^^ help: try using the maximum value for the type: `0..=MAX`
+   |                                   ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: expected one of `=>`, `if`, or `|`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:95:38
+  --> $DIR/attr-stmt-expr-attr-bad.rs:97:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
    |                                      ^ expected one of `=>`, `if`, or `|`
 
 error: unexpected token: `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:98:39
+  --> $DIR/attr-stmt-expr-attr-bad.rs:100:39
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
    |                                       ^
 
-error: `X..=` range patterns are not supported
-  --> $DIR/attr-stmt-expr-attr-bad.rs:100:34
+error[E0586]: inclusive range with no end
+  --> $DIR/attr-stmt-expr-attr-bad.rs:102:35
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
-   |                                  ^^^^ help: try using the maximum value for the type: `0..=MAX`
+   |                                   ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: expected one of `=>`, `if`, or `|`, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:100:38
+  --> $DIR/attr-stmt-expr-attr-bad.rs:102:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
    |                                      ^ expected one of `=>`, `if`, or `|`
 
 error: unexpected token: `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:104:34
+  --> $DIR/attr-stmt-expr-attr-bad.rs:106:34
    |
 LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
    |                                  ^
 
 error: expected one of `.`, `;`, `?`, or an operator, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:104:34
+  --> $DIR/attr-stmt-expr-attr-bad.rs:106:34
    |
 LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
    |                                  ^ expected one of `.`, `;`, `?`, or an operator
 
 error: unexpected token: `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:107:34
+  --> $DIR/attr-stmt-expr-attr-bad.rs:109:34
    |
 LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
    |                                  ^
 
 error: expected one of `.`, `;`, `?`, or an operator, found `#`
-  --> $DIR/attr-stmt-expr-attr-bad.rs:107:34
+  --> $DIR/attr-stmt-expr-attr-bad.rs:109:34
    |
 LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
    |                                  ^ expected one of `.`, `;`, `?`, or an operator
 
 error: expected statement after outer attribute
-  --> $DIR/attr-stmt-expr-attr-bad.rs:112:44
+  --> $DIR/attr-stmt-expr-attr-bad.rs:114:44
    |
 LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
    |                                            ^
 
 error: expected statement after outer attribute
-  --> $DIR/attr-stmt-expr-attr-bad.rs:114:45
+  --> $DIR/attr-stmt-expr-attr-bad.rs:116:45
    |
 LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } }
    |                                             ^
 
 error: aborting due to 57 previous errors
 
+For more information about this error, try `rustc --explain E0586`.
index 1c9b5973be7fe992bb92f21034bbb2a190781e64..11696b82bc9ac9b4f566bdb69bfebf8003b0c9d0 100644 (file)
@@ -1,7 +1,6 @@
-// compile-flags: -Z continue-parse-after-error
-
 // ignore-tidy-cr
 // ignore-tidy-tab
+
 fn main() {
     // these literals are just silly.
     ''';
index 8e96ea22771b830104e4a831cc5fbca4a49f5211..093978fd84d007851a4adc24459409d19e729a74 100644 (file)
@@ -1,11 +1,11 @@
 error: character constant must be escaped: '
-  --> $DIR/bad-char-literals.rs:7:6
+  --> $DIR/bad-char-literals.rs:6:6
    |
 LL |     ''';
    |      ^
 
 error: character constant must be escaped: \n
-  --> $DIR/bad-char-literals.rs:11:6
+  --> $DIR/bad-char-literals.rs:10:6
    |
 LL |       '
    |  ______^
@@ -13,13 +13,13 @@ LL | | ';
    | |_
 
 error: character constant must be escaped: \r
-  --> $DIR/bad-char-literals.rs:16:6
+  --> $DIR/bad-char-literals.rs:15:6
    |
 LL |     '\r';
    |      ^
 
 error: character constant must be escaped: \t
-  --> $DIR/bad-char-literals.rs:19:6
+  --> $DIR/bad-char-literals.rs:18:6
    |
 LL |     '    ';
    |      ^^^^
index 9122cb49ebc1a47731a634b6df8f0c9ee8436511..7a187a0518af9d7f404c031d1c3be8f25dbf175f 100644 (file)
@@ -8,6 +8,11 @@ struct S<
     T: ?for<'a> Trait, // OK
     T: Tr +, // OK
     T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
+
+    T: ?const Tr, // OK
+    T: ?const ?Tr, // OK
+    T: ?const Tr + 'a, // OK
+    T: ?const 'a, //~ ERROR `?const` may only modify trait bounds, not lifetime bounds
 >;
 
 fn main() {}
index 0b714e40a101233b985f9bb824d13be8265a8319..9a1f2ed398240f48f8da6b140af1848eee8b5fea 100644 (file)
@@ -4,5 +4,11 @@ error: `?` may only modify trait bounds, not lifetime bounds
 LL |     T: ?'a,
    |        ^
 
-error: aborting due to previous error
+error: `?const` may only modify trait bounds, not lifetime bounds
+  --> $DIR/bounds-type.rs:15:8
+   |
+LL |     T: ?const 'a,
+   |        ^^^^^^
+
+error: aborting due to 2 previous errors
 
index bd358af29843a45d7067194a8bfb5ce3b6f5fb23..dadf3971220f7054ae75af19ef90c11c6a3578b2 100644 (file)
@@ -1,6 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
-
 // ignore-tidy-tab
 
 static FOO: u8 = b'\f';  //~ ERROR unknown byte escape
index 58a5797b907761f3d9175de9582d4c24ea0feb35..53d50af88d33b84d2a8b75b99a98af06d084452a 100644 (file)
@@ -1,41 +1,41 @@
 error: unknown byte escape: f
-  --> $DIR/byte-literals.rs:6:21
+  --> $DIR/byte-literals.rs:3:21
    |
 LL | static FOO: u8 = b'\f';
    |                     ^ unknown byte escape
 
 error: unknown byte escape: f
-  --> $DIR/byte-literals.rs:9:8
+  --> $DIR/byte-literals.rs:6:8
    |
 LL |     b'\f';
    |        ^ unknown byte escape
 
 error: invalid character in numeric character escape: Z
-  --> $DIR/byte-literals.rs:10:10
+  --> $DIR/byte-literals.rs:7:10
    |
 LL |     b'\x0Z';
    |          ^
 
 error: byte constant must be escaped: \t
-  --> $DIR/byte-literals.rs:11:7
+  --> $DIR/byte-literals.rs:8:7
    |
 LL |     b'    ';
    |       ^^^^
 
 error: byte constant must be escaped: '
-  --> $DIR/byte-literals.rs:12:7
+  --> $DIR/byte-literals.rs:9:7
    |
 LL |     b''';
    |       ^
 
 error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte
-  --> $DIR/byte-literals.rs:13:7
+  --> $DIR/byte-literals.rs:10:7
    |
 LL |     b'é';
    |       ^
 
 error: unterminated byte constant
-  --> $DIR/byte-literals.rs:14:6
+  --> $DIR/byte-literals.rs:11:6
    |
 LL |     b'a
    |      ^^^^
index 8d8ee4da987176134799b5835c1c5ea3d91f4ae1..caffd9efbed37f9bcf964a9be40fd9f02bba1949 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 static FOO: &'static [u8] = b"\f";  //~ ERROR unknown byte escape
 
 pub fn main() {
index eeb2fcd12320bd2baa95e189c297eee336cc5879..ca964cd4b8f21e995c1cfc2b1e75af5849b249ac 100644 (file)
@@ -1,29 +1,29 @@
 error: unknown byte escape: f
-  --> $DIR/byte-string-literals.rs:3:32
+  --> $DIR/byte-string-literals.rs:1:32
    |
 LL | static FOO: &'static [u8] = b"\f";
    |                                ^ unknown byte escape
 
 error: unknown byte escape: f
-  --> $DIR/byte-string-literals.rs:6:8
+  --> $DIR/byte-string-literals.rs:4:8
    |
 LL |     b"\f";
    |        ^ unknown byte escape
 
 error: invalid character in numeric character escape: Z
-  --> $DIR/byte-string-literals.rs:7:10
+  --> $DIR/byte-string-literals.rs:5:10
    |
 LL |     b"\x0Z";
    |          ^
 
 error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte
-  --> $DIR/byte-string-literals.rs:8:7
+  --> $DIR/byte-string-literals.rs:6:7
    |
 LL |     b"é";
    |       ^
 
 error: unterminated double quote byte string
-  --> $DIR/byte-string-literals.rs:9:6
+  --> $DIR/byte-string-literals.rs:7:6
    |
 LL |       b"a
    |  ______^
diff --git a/src/test/ui/parser/chained-comparison-suggestion.rs b/src/test/ui/parser/chained-comparison-suggestion.rs
new file mode 100644 (file)
index 0000000..0431196
--- /dev/null
@@ -0,0 +1,40 @@
+// Check that we get nice suggestions when attempting a chained comparison.
+
+fn comp1() {
+    1 < 2 <= 3; //~ ERROR comparison operators cannot be chained
+    //~^ ERROR mismatched types
+}
+
+fn comp2() {
+    1 < 2 < 3; //~ ERROR comparison operators cannot be chained
+}
+
+fn comp3() {
+    1 <= 2 < 3; //~ ERROR comparison operators cannot be chained
+    //~^ ERROR mismatched types
+}
+
+fn comp4() {
+    1 <= 2 <= 3; //~ ERROR comparison operators cannot be chained
+    //~^ ERROR mismatched types
+}
+
+fn comp5() {
+    1 > 2 >= 3; //~ ERROR comparison operators cannot be chained
+    //~^ ERROR mismatched types
+}
+
+fn comp6() {
+    1 > 2 > 3; //~ ERROR comparison operators cannot be chained
+}
+
+fn comp7() {
+    1 >= 2 > 3; //~ ERROR comparison operators cannot be chained
+}
+
+fn comp8() {
+    1 >= 2 >= 3; //~ ERROR comparison operators cannot be chained
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/chained-comparison-suggestion.stderr b/src/test/ui/parser/chained-comparison-suggestion.stderr
new file mode 100644 (file)
index 0000000..5c10a45
--- /dev/null
@@ -0,0 +1,159 @@
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:4:7
+   |
+LL |     1 < 2 <= 3;
+   |       ^^^^^^
+   |
+help: split the comparison into two...
+   |
+LL |     1 < 2 && 2 <= 3;
+   |     ^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 < 2) <= 3;
+   |     ^^^^^^^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:9:7
+   |
+LL |     1 < 2 < 3;
+   |       ^^^^^
+   |
+   = help: use `::<...>` instead of `<...>` to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
+help: split the comparison into two...
+   |
+LL |     1 < 2 && 2 < 3;
+   |     ^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 < 2) < 3;
+   |     ^^^^^^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:13:7
+   |
+LL |     1 <= 2 < 3;
+   |       ^^^^^^
+   |
+help: split the comparison into two...
+   |
+LL |     1 <= 2 && 2 < 3;
+   |     ^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 <= 2) < 3;
+   |     ^^^^^^^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:18:7
+   |
+LL |     1 <= 2 <= 3;
+   |       ^^^^^^^
+   |
+help: split the comparison into two...
+   |
+LL |     1 <= 2 && 2 <= 3;
+   |     ^^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 <= 2) <= 3;
+   |     ^^^^^^^^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:23:7
+   |
+LL |     1 > 2 >= 3;
+   |       ^^^^^^
+   |
+help: split the comparison into two...
+   |
+LL |     1 > 2 && 2 >= 3;
+   |     ^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 > 2) >= 3;
+   |     ^^^^^^^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:28:7
+   |
+LL |     1 > 2 > 3;
+   |       ^^^^^
+   |
+   = help: use `::<...>` instead of `<...>` to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
+help: split the comparison into two...
+   |
+LL |     1 > 2 && 2 > 3;
+   |     ^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 > 2) > 3;
+   |     ^^^^^^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:32:7
+   |
+LL |     1 >= 2 > 3;
+   |       ^^^^^^
+   |
+   = help: use `::<...>` instead of `<...>` to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
+help: split the comparison into two...
+   |
+LL |     1 >= 2 && 2 > 3;
+   |     ^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 >= 2) > 3;
+   |     ^^^^^^^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/chained-comparison-suggestion.rs:36:7
+   |
+LL |     1 >= 2 >= 3;
+   |       ^^^^^^^
+   |
+help: split the comparison into two...
+   |
+LL |     1 >= 2 && 2 >= 3;
+   |     ^^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (1 >= 2) >= 3;
+   |     ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/chained-comparison-suggestion.rs:4:14
+   |
+LL |     1 < 2 <= 3;
+   |              ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/chained-comparison-suggestion.rs:13:14
+   |
+LL |     1 <= 2 < 3;
+   |              ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/chained-comparison-suggestion.rs:18:15
+   |
+LL |     1 <= 2 <= 3;
+   |               ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/chained-comparison-suggestion.rs:23:14
+   |
+LL |     1 > 2 >= 3;
+   |              ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/chained-comparison-suggestion.rs:36:15
+   |
+LL |     1 >= 2 >= 3;
+   |               ^ expected `bool`, found integer
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index c2a80e8fa15940fb98d401555860041f27002866..270c8b43dfd5e7d8527f67d1810888f9036a208a 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 impl ! {} // OK
 impl ! where u8: Copy {} // OK
 
index e929fa53620f66884b44e51a229eb9830b4e31a9..7c2a7937c5da7c15238467ce3a98f763e5a65028 100644 (file)
@@ -1,29 +1,29 @@
 error: missing `for` in a trait impl
-  --> $DIR/impl-parsing.rs:6:11
+  --> $DIR/impl-parsing.rs:4:11
    |
 LL | impl Trait Type {}
    |           ^ help: add `for` here
 
 error: missing `for` in a trait impl
-  --> $DIR/impl-parsing.rs:7:11
+  --> $DIR/impl-parsing.rs:5:11
    |
 LL | impl Trait .. {}
    |           ^ help: add `for` here
 
 error: expected a trait, found type
-  --> $DIR/impl-parsing.rs:8:6
+  --> $DIR/impl-parsing.rs:6:6
    |
 LL | impl ?Sized for Type {}
    |      ^^^^^^
 
 error: expected a trait, found type
-  --> $DIR/impl-parsing.rs:9:6
+  --> $DIR/impl-parsing.rs:7:6
    |
 LL | impl ?Sized for .. {}
    |      ^^^^^^
 
 error: expected `impl`, found `FAIL`
-  --> $DIR/impl-parsing.rs:11:16
+  --> $DIR/impl-parsing.rs:9:16
    |
 LL | default unsafe FAIL
    |                ^^^^ expected `impl`
index 53629973a1b5f002a873bffd4e110aba9354c9de..ab445a9329426cbc094b868182ae6a9b26d1652e 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 fn main() {
     let _ = b"\u{a66e}";
     //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string
index 5fabc1d7e4326643f6238fb2fc643bcb5ede6c10..b391ac75bf8d1129dcf7394f347c2564f8531421 100644 (file)
@@ -1,17 +1,17 @@
 error: unicode escape sequences cannot be used as a byte or in a byte string
-  --> $DIR/issue-23620-invalid-escapes.rs:4:15
+  --> $DIR/issue-23620-invalid-escapes.rs:2:15
    |
 LL |     let _ = b"\u{a66e}";
    |               ^^^^^^^^
 
 error: unicode escape sequences cannot be used as a byte or in a byte string
-  --> $DIR/issue-23620-invalid-escapes.rs:7:15
+  --> $DIR/issue-23620-invalid-escapes.rs:5:15
    |
 LL |     let _ = b'\u{a66e}';
    |               ^^^^^^^^
 
 error: incorrect unicode escape sequence
-  --> $DIR/issue-23620-invalid-escapes.rs:10:15
+  --> $DIR/issue-23620-invalid-escapes.rs:8:15
    |
 LL |     let _ = b'\u';
    |               ^^ incorrect unicode escape sequence
@@ -19,43 +19,43 @@ LL |     let _ = b'\u';
    = help: format of unicode escape sequences is `\u{...}`
 
 error: numeric character escape is too short
-  --> $DIR/issue-23620-invalid-escapes.rs:13:15
+  --> $DIR/issue-23620-invalid-escapes.rs:11:15
    |
 LL |     let _ = b'\x5';
    |               ^^^
 
 error: invalid character in numeric character escape: x
-  --> $DIR/issue-23620-invalid-escapes.rs:16:17
+  --> $DIR/issue-23620-invalid-escapes.rs:14:17
    |
 LL |     let _ = b'\xxy';
    |                 ^
 
 error: numeric character escape is too short
-  --> $DIR/issue-23620-invalid-escapes.rs:19:14
+  --> $DIR/issue-23620-invalid-escapes.rs:17:14
    |
 LL |     let _ = '\x5';
    |              ^^^
 
 error: invalid character in numeric character escape: x
-  --> $DIR/issue-23620-invalid-escapes.rs:22:16
+  --> $DIR/issue-23620-invalid-escapes.rs:20:16
    |
 LL |     let _ = '\xxy';
    |                ^
 
 error: unicode escape sequences cannot be used as a byte or in a byte string
-  --> $DIR/issue-23620-invalid-escapes.rs:25:15
+  --> $DIR/issue-23620-invalid-escapes.rs:23:15
    |
 LL |     let _ = b"\u{a4a4} \xf \u";
    |               ^^^^^^^^
 
 error: invalid character in numeric character escape:  
-  --> $DIR/issue-23620-invalid-escapes.rs:25:27
+  --> $DIR/issue-23620-invalid-escapes.rs:23:27
    |
 LL |     let _ = b"\u{a4a4} \xf \u";
    |                           ^
 
 error: incorrect unicode escape sequence
-  --> $DIR/issue-23620-invalid-escapes.rs:25:28
+  --> $DIR/issue-23620-invalid-escapes.rs:23:28
    |
 LL |     let _ = b"\u{a4a4} \xf \u";
    |                            ^^ incorrect unicode escape sequence
@@ -63,13 +63,13 @@ LL |     let _ = b"\u{a4a4} \xf \u";
    = help: format of unicode escape sequences is `\u{...}`
 
 error: invalid character in numeric character escape:  
-  --> $DIR/issue-23620-invalid-escapes.rs:30:17
+  --> $DIR/issue-23620-invalid-escapes.rs:28:17
    |
 LL |     let _ = "\xf \u";
    |                 ^
 
 error: incorrect unicode escape sequence
-  --> $DIR/issue-23620-invalid-escapes.rs:30:18
+  --> $DIR/issue-23620-invalid-escapes.rs:28:18
    |
 LL |     let _ = "\xf \u";
    |                  ^^ incorrect unicode escape sequence
@@ -77,7 +77,7 @@ LL |     let _ = "\xf \u";
    = help: format of unicode escape sequences is `\u{...}`
 
 error: incorrect unicode escape sequence
-  --> $DIR/issue-23620-invalid-escapes.rs:34:14
+  --> $DIR/issue-23620-invalid-escapes.rs:32:14
    |
 LL |     let _ = "\u8f";
    |              ^^--
index cfa19a2a310a279b3712c8baf6643d7107a5ac9f..0db06f636c3ec39e63bed76aa829a5179ade2053 100644 (file)
@@ -1,3 +1,4 @@
 "\u\\"
 //~^ ERROR incorrect unicode escape sequence
 //~| ERROR invalid trailing slash in literal
+//~| ERROR expected item, found `"\u\\"`
index 05c5c4d000a864f31b14af4c515aa6de859d6a72..f72174f8929b888b947d62b8d006b83a6d30c734 100644 (file)
@@ -12,5 +12,11 @@ error: invalid trailing slash in literal
 LL | "\u\"
    |     ^
 
-error: aborting due to 2 previous errors
+error: expected item, found `"\u\"`
+  --> $DIR/issue-62913.rs:1:1
+   |
+LL | "\u\"
+   | ^^^^^^ expected item
+
+error: aborting due to 3 previous errors
 
index 18bc51e7ba7cdf4713668d9c01e64559f319b274..1c5d0c6f8ab46fd5d9dce13c5af1a6819fc44b9e 100644 (file)
@@ -1,5 +1,5 @@
 // ignore-tidy-trailing-newlines
-// error-pattern: aborting due to 6 previous errors
+// error-pattern: aborting due to 7 previous errors
 
 fn main() {}
 
index e95e629957c26b0fc20ac2bab4e479cfb8c07137..95ee52d810ddcd85139b0870978257bea380b619 100644 (file)
@@ -9,6 +9,17 @@ LL |
 LL | 
    |  ^
 
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-62973.rs:8:2
+   |
+LL | fn p() { match s { v, E { [) {) }
+   |        -         - unclosed delimiter
+   |        |
+   |        unclosed delimiter
+LL | 
+LL | 
+   |  ^
+
 error: expected one of `,` or `}`, found `{`
   --> $DIR/issue-62973.rs:6:25
    |
@@ -60,5 +71,5 @@ LL | fn p() { match s { v, E { [) {) }
    |                              |
    |                              unclosed delimiter
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
index a7d10ca9320a6cee464fec063ba0de8454223bdc..8efb3c73f034f71a7a169d908854cd068a62508b 100644 (file)
@@ -1,6 +1,7 @@
 // check-pass
 
 #![feature(exclusive_range_pattern)]
+#![feature(half_open_range_patterns)]
 
 #![allow(ellipsis_inclusive_range_patterns)]
 
@@ -10,6 +11,11 @@ macro_rules! mac_expr {
             if let 2...$e = 3 {}
             if let 2..=$e = 3 {}
             if let 2..$e = 3 {}
+            if let ..$e = 3 {}
+            if let ..=$e = 3 {}
+            if let $e.. = 5 {}
+            if let $e..5 = 4 {}
+            if let $e..=5 = 4 {}
         }
     }
     mac_expr!(4);
index a5a8de85466bbccf5c549f3d538f82bf69ccc854..d5f5f1469f35a830acb1ba6b91f034f31e02b656 100644 (file)
@@ -1,3 +1,3 @@
-// error-pattern: aborting due to 5 previous errors
+// error-pattern: aborting due to 6 previous errors
 
 fn i(n{...,f #
index a6fb037b299f535f9755d29f2e27c6a2f234dd84..462fdf11f40a9ccae0a28a243ebe43178aafc70f 100644 (file)
@@ -7,6 +7,15 @@ LL | fn i(n{...,f #
    |     | unclosed delimiter
    |     unclosed delimiter
 
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-63135.rs:3:16
+   |
+LL | fn i(n{...,f #
+   |     - -        ^
+   |     | |
+   |     | unclosed delimiter
+   |     unclosed delimiter
+
 error: expected field pattern, found `...`
   --> $DIR/issue-63135.rs:3:8
    |
@@ -34,5 +43,5 @@ error: expected one of `:` or `|`, found `)`
 LL | fn i(n{...,f #
    |                ^ expected one of `:` or `|`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
index 1730adfa91419bea63b3a67ca56972406eb972f5..5ec143fae234479231dd52c8ff13f4d08a68b958 100644 (file)
@@ -1,3 +1,5 @@
+// ignore-tidy-linelength
+
 // The problem in #66357 was that the call trace:
 //
 // - parse_fn_block_decl
@@ -11,4 +13,4 @@
 
 fn f() { |[](* }
 //~^ ERROR expected one of `,` or `:`, found `(`
-//~| ERROR expected one of `)`, `-`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*`
+//~| ERROR expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*`
index 00d84e2afe353fcd3f84dfb16db0b90ca1296cf4..c3810999d239509f6100bfbbe04b387e5a94b8ef 100644 (file)
@@ -1,11 +1,11 @@
 error: expected one of `,` or `:`, found `(`
-  --> $DIR/issue-66357-unexpected-unreachable.rs:12:13
+  --> $DIR/issue-66357-unexpected-unreachable.rs:14:13
    |
 LL | fn f() { |[](* }
    |             ^ expected one of `,` or `:`
 
-error: expected one of `)`, `-`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*`
-  --> $DIR/issue-66357-unexpected-unreachable.rs:12:14
+error: expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*`
+  --> $DIR/issue-66357-unexpected-unreachable.rs:14:14
    |
 LL | fn f() { |[](* }
    |             -^ help: `)` may belong here
index 54d75ed682d0d13c6c5c76f6c7fe67b979de9a56..e7951cfd2d20cc2314ef754f690f4342e1aad4d0 100644 (file)
@@ -1,4 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
 static c3: char =
     '\x1' //~ ERROR: numeric character escape is too short
 ;
index 000d155c268336a46bf1468b72718bc817cf17ac..fcf4802f79bba85a8f853fd83fd1757a49dafbda 100644 (file)
@@ -1,23 +1,23 @@
 error: numeric character escape is too short
-  --> $DIR/lex-bad-char-literals-1.rs:3:6
+  --> $DIR/lex-bad-char-literals-1.rs:2:6
    |
 LL |     '\x1'
    |      ^^^
 
 error: numeric character escape is too short
-  --> $DIR/lex-bad-char-literals-1.rs:7:6
+  --> $DIR/lex-bad-char-literals-1.rs:6:6
    |
 LL |     "\x1"
    |      ^^^
 
 error: unknown character escape: \u{25cf}
-  --> $DIR/lex-bad-char-literals-1.rs:11:7
+  --> $DIR/lex-bad-char-literals-1.rs:10:7
    |
 LL |     '\●'
    |       ^ unknown character escape
 
 error: unknown character escape: \u{25cf}
-  --> $DIR/lex-bad-char-literals-1.rs:15:7
+  --> $DIR/lex-bad-char-literals-1.rs:14:7
    |
 LL |     "\●"
    |       ^ unknown character escape
index 70eafcb91dacb9c2a9de8cc307d68e550a5903fd..1580157210e6940c54d47319ff186ab812a6e3ba 100644 (file)
@@ -1,4 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
 fn main() {
     let _: char = '';
     //~^ ERROR: empty character literal
index e1ba3c3ee0f170a7eaaa2e9515a00d8c73616ff7..ee9aa869352990d480fdc87a6efe5f8b6b34e515 100644 (file)
@@ -1,17 +1,17 @@
 error: empty character literal
-  --> $DIR/lex-bad-char-literals-7.rs:3:20
+  --> $DIR/lex-bad-char-literals-7.rs:2:20
    |
 LL |     let _: char = '';
    |                    ^
 
 error: empty unicode escape (must have at least 1 hex digit)
-  --> $DIR/lex-bad-char-literals-7.rs:5:20
+  --> $DIR/lex-bad-char-literals-7.rs:4:20
    |
 LL |     let _: char = '\u{}';
    |                    ^^^^
 
 error: unterminated character literal
-  --> $DIR/lex-bad-char-literals-7.rs:12:13
+  --> $DIR/lex-bad-char-literals-7.rs:11:13
    |
 LL |     let _ = ' hello // here's a comment
    |             ^^^^^^^^
index b588b007ae92935ce04fd8676fea471f8e6d1f67..9a9f9c433e1d6f8f9c36593e1e12051f9b7355d3 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 // ignore-tidy-cr
 
 /// doc comment with bare CR: '\r'
index b0fe4b6acd48443a7d939b0900b69c3f7ed9edf8..598da6b930730aa90235d3cf8db6074f6803d511 100644 (file)
@@ -1,41 +1,41 @@
 error: bare CR not allowed in doc-comment
-  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:5:32
+  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:3:32
    |
 LL | /// doc comment with bare CR: '\r'
    |                                ^
 
 error: bare CR not allowed in block doc-comment
-  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:9:38
+  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:7:38
    |
 LL | /** block doc comment with bare CR: '\r' */
    |                                      ^
 
 error: bare CR not allowed in doc-comment
-  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:14:36
+  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:12:36
    |
 LL |     //! doc comment with bare CR: '\r'
    |                                    ^
 
 error: bare CR not allowed in block doc-comment
-  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:17:42
+  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:15:42
    |
 LL |     /*! block doc comment with bare CR: '\r' */
    |                                          ^
 
 error: bare CR not allowed in string, use \r instead
-  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:21:18
+  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:19:18
    |
 LL |     let _s = "foo\rbar";
    |                  ^
 
 error: bare CR not allowed in raw string
-  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:24:19
+  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:22:19
    |
 LL |     let _s = r"bar\rfoo";
    |                   ^
 
 error: unknown character escape: \r
-  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:27:19
+  --> $DIR/lex-bare-cr-string-literal-doc-comment.rs:25:19
    |
 LL |     let _s = "foo\\rbar";
    |                   ^ unknown character escape
index 4f7c5eea1d18342ebfc3ab12940242f5d4e254ff..c35236ce7934e96c3e26ce95f56fc436409f28df 100644 (file)
@@ -1,3 +1,3 @@
 // ignore-tidy-trailing-newlines
-// error-pattern: aborting due to 2 previous errors
+// error-pattern: aborting due to 3 previous errors
 fn main((ؼ
\ No newline at end of file
index c98b6bb6991c7af135430c2e761a7ac7d9556e0f..d67e7c88912a5ae2b9641eaf5019d5ebb9c7b593 100644 (file)
@@ -7,11 +7,20 @@ LL | fn main((ؼ
    |        |unclosed delimiter
    |        unclosed delimiter
 
+error: this file contains an unclosed delimiter
+  --> $DIR/missing_right_paren.rs:3:11
+   |
+LL | fn main((ؼ
+   |        -- ^
+   |        ||
+   |        |unclosed delimiter
+   |        unclosed delimiter
+
 error: expected one of `:` or `|`, found `)`
   --> $DIR/missing_right_paren.rs:3:11
    |
 LL | fn main((ؼ
    |           ^ expected one of `:` or `|`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/pat-tuple-4.rs b/src/test/ui/parser/pat-tuple-4.rs
deleted file mode 100644 (file)
index 2f03160..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-fn main() {
-    const PAT: u8 = 0;
-
-    match 0 {
-        (.. PAT) => {}
-        //~^ ERROR `..X` range patterns are not supported
-        //~| ERROR exclusive range pattern syntax is experimental
-    }
-}
-
-const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
diff --git a/src/test/ui/parser/pat-tuple-4.stderr b/src/test/ui/parser/pat-tuple-4.stderr
deleted file mode 100644 (file)
index 6c64290..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error: `..X` range patterns are not supported
-  --> $DIR/pat-tuple-4.rs:5:10
-   |
-LL |         (.. PAT) => {}
-   |          ^^^^^^ help: try using the minimum value for the type: `MIN..PAT`
-
-error[E0658]: exclusive range pattern syntax is experimental
-  --> $DIR/pat-tuple-4.rs:5:10
-   |
-LL |         (.. PAT) => {}
-   |          ^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/37854
-   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
-
-error[E0308]: mismatched types
-  --> $DIR/pat-tuple-4.rs:11:30
-   |
-LL | const RECOVERY_WITNESS: () = 0;
-   |                              ^ expected `()`, found integer
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0658.
-For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/pat-tuple-5.rs b/src/test/ui/parser/pat-tuple-5.rs
deleted file mode 100644 (file)
index 5334ef9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-fn main() {
-    const PAT: u8 = 0;
-
-    match (0, 1) {
-        (PAT ..) => {}
-        //~^ ERROR `X..` range patterns are not supported
-        //~| ERROR exclusive range pattern syntax is experimental
-        //~| ERROR mismatched types
-    }
-}
diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr
deleted file mode 100644 (file)
index 8ff4f94..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error: `X..` range patterns are not supported
-  --> $DIR/pat-tuple-5.rs:5:10
-   |
-LL |         (PAT ..) => {}
-   |          ^^^^^^ help: try using the maximum value for the type: `PAT..MAX`
-
-error[E0658]: exclusive range pattern syntax is experimental
-  --> $DIR/pat-tuple-5.rs:5:10
-   |
-LL |         (PAT ..) => {}
-   |          ^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/37854
-   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
-
-error[E0308]: mismatched types
-  --> $DIR/pat-tuple-5.rs:5:10
-   |
-LL |     match (0, 1) {
-   |           ------ this expression has type `({integer}, {integer})`
-LL |         (PAT ..) => {}
-   |          ^^^ expected tuple, found `u8`
-   |
-   = note: expected tuple `({integer}, {integer})`
-               found type `u8`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0658.
-For more information about an error, try `rustc --explain E0308`.
index bc61c5b49ea8712526120500c46a67008248e502..7c3b906b47f9f4b8723ccbba0ca8ca4065049596 100644 (file)
@@ -2,5 +2,5 @@
 
 pub fn main() {
     for _ in 1..= {} //~ERROR inclusive range with no end
-                     //~^HELP bounded at the end
+                     //~^HELP use `..` instead
 }
index 12b7edae79f52918cf1f4b326fd6028837e00b74..1dd479945968104d4c270154d978c91038e5b16f 100644 (file)
@@ -1,10 +1,10 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/range_inclusive.rs:4:19
+  --> $DIR/range_inclusive.rs:4:15
    |
 LL |     for _ in 1..= {}
-   |                   ^
+   |               ^^^ help: use `..` instead
    |
-   = help: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: aborting due to previous error
 
index 534afabdf777e30023b6ebae60771942822d6763..163c8ac66b022ae8eb4aac851d8adc71027e05bb 100644 (file)
@@ -1,5 +1,5 @@
 // ignore-tidy-cr
-// compile-flags: -Z continue-parse-after-error
+
 pub fn main() {
     br"a\r"; //~ ERROR bare CR not allowed in raw string
     br"é";  //~ ERROR raw byte string must be ASCII
index 260e108315973642bee25231146bc77780d777c7..e07ea6221d7c95637e7b103756d16164c2a5a81b 100644 (file)
@@ -4,6 +4,7 @@
 // 2. Or at least we have parser recovery if they don't.
 
 #![feature(exclusive_range_pattern)]
+#![feature(half_open_range_patterns)]
 #![deny(ellipsis_inclusive_range_patterns)]
 
 fn main() {}
@@ -55,70 +56,66 @@ fn inclusive2_from_to() {
 }
 
 fn exclusive_from() {
-    if let 0.. = 0 {} //~ ERROR `X..` range patterns are not supported
-    if let X.. = 0 {} //~ ERROR `X..` range patterns are not supported
-    if let true.. = 0 {} //~ ERROR `X..` range patterns are not supported
+    if let 0.. = 0 {}
+    if let X.. = 0 {}
+    if let true.. = 0 {}
     //~^ ERROR only char and numeric types
-    if let .0.. = 0 {} //~ ERROR `X..` range patterns are not supported
+    if let .0.. = 0 {}
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
 }
 
 fn inclusive_from() {
-    if let 0..= = 0 {} //~ ERROR `X..=` range patterns are not supported
-    if let X..= = 0 {} //~ ERROR `X..=` range patterns are not supported
-    if let true..= = 0 {} //~ ERROR `X..=` range patterns are not supported
+    if let 0..= = 0 {} //~ ERROR inclusive range with no end
+    if let X..= = 0 {} //~ ERROR inclusive range with no end
+    if let true..= = 0 {} //~ ERROR inclusive range with no end
     //~| ERROR only char and numeric types
-    if let .0..= = 0 {} //~ ERROR `X..=` range patterns are not supported
+    if let .0..= = 0 {} //~ ERROR inclusive range with no end
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
 }
 
 fn inclusive2_from() {
-    if let 0... = 0 {} //~ ERROR `X...` range patterns are not supported
-    //~^ ERROR `...` range patterns are deprecated
-    if let X... = 0 {} //~ ERROR `X...` range patterns are not supported
-    //~^ ERROR `...` range patterns are deprecated
-    if let true... = 0 {} //~ ERROR `X...` range patterns are not supported
-    //~^ ERROR `...` range patterns are deprecated
+    if let 0... = 0 {} //~ ERROR inclusive range with no end
+    if let X... = 0 {} //~ ERROR inclusive range with no end
+    if let true... = 0 {} //~ ERROR inclusive range with no end
     //~| ERROR only char and numeric types
-    if let .0... = 0 {} //~ ERROR `X...` range patterns are not supported
+    if let .0... = 0 {} //~ ERROR inclusive range with no end
     //~^ ERROR float literals must have an integer part
-    //~| ERROR `...` range patterns are deprecated
     //~| ERROR mismatched types
 }
 
 fn exclusive_to() {
-    if let ..0 = 0 {} //~ ERROR `..X` range patterns are not supported
-    if let ..Y = 0 {} //~ ERROR `..X` range patterns are not supported
-    if let ..true = 0 {} //~ ERROR `..X` range patterns are not supported
-    //~| ERROR only char and numeric types
-    if let .. .0 = 0 {} //~ ERROR `..X` range patterns are not supported
+    if let ..0 = 0 {}
+    if let ..Y = 0 {}
+    if let ..true = 0 {}
+    //~^ ERROR only char and numeric types
+    if let .. .0 = 0 {}
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
 }
 
 fn inclusive_to() {
-    if let ..=3 = 0 {} //~ ERROR `..=X` range patterns are not supported
-    if let ..=Y = 0 {} //~ ERROR `..=X` range patterns are not supported
-    if let ..=true = 0 {} //~ ERROR `..=X` range patterns are not supported
-    //~| ERROR only char and numeric types
-    if let ..=.0 = 0 {} //~ ERROR `..=X` range patterns are not supported
+    if let ..=3 = 0 {}
+    if let ..=Y = 0 {}
+    if let ..=true = 0 {}
+    //~^ ERROR only char and numeric types
+    if let ..=.0 = 0 {}
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
 }
 
 fn inclusive2_to() {
-    if let ...3 = 0 {} //~ ERROR `...X` range patterns are not supported
-    //~^ ERROR `...` range patterns are deprecated
-    if let ...Y = 0 {} //~ ERROR `...X` range patterns are not supported
-    //~^ ERROR `...` range patterns are deprecated
-    if let ...true = 0 {} //~ ERROR `...X` range patterns are not supported
-    //~^ ERROR `...` range patterns are deprecated
+    if let ...3 = 0 {}
+    //~^ ERROR range-to patterns with `...` are not allowed
+    if let ...Y = 0 {}
+    //~^ ERROR range-to patterns with `...` are not allowed
+    if let ...true = 0 {}
+    //~^ ERROR range-to patterns with `...` are not allowed
     //~| ERROR only char and numeric types
-    if let ....3 = 0 {} //~ ERROR `...X` range patterns are not supported
+    if let ....3 = 0 {}
     //~^ ERROR float literals must have an integer part
-    //~| ERROR `...` range patterns are deprecated
+    //~| ERROR range-to patterns with `...` are not allowed
     //~| ERROR mismatched types
 }
 
@@ -136,14 +133,13 @@ macro_rules! mac2 {
 
     macro_rules! mac {
         ($e:expr) => {
-            let ..$e; //~ ERROR `..X` range patterns are not supported
-            let ...$e; //~ ERROR `...X` range patterns are not supported
-            //~^ ERROR `...` range patterns are deprecated
-            let ..=$e; //~ ERROR `..=X` range patterns are not supported
-            let $e..; //~ ERROR `X..` range patterns are not supported
-            let $e...; //~ ERROR `X...` range patterns are not supported
-            //~^ ERROR `...` range patterns are deprecated
-            let $e..=; //~ ERROR `X..=` range patterns are not supported
+            let ..$e;
+            let ...$e;
+            //~^ ERROR range-to patterns with `...` are not allowed
+            let ..=$e;
+            let $e..;
+            let $e...; //~ ERROR inclusive range with no end
+            let $e..=; //~ ERROR inclusive range with no end
         }
     }
 
index 3fed64c191a8a2de52c518513935c66e64aa1cd6..f43f9bf3012183b870a61dcc7502e375d36f6a2e 100644 (file)
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:21:12
+  --> $DIR/recover-range-pats.rs:22:12
    |
 LL |     if let .0..Y = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:23:16
+  --> $DIR/recover-range-pats.rs:24:16
    |
 LL |     if let X.. .0 = 0 {}
    |                ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:34:12
+  --> $DIR/recover-range-pats.rs:35:12
    |
 LL |     if let .0..=Y = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:36:16
+  --> $DIR/recover-range-pats.rs:37:16
    |
 LL |     if let X..=.0 = 0 {}
    |                ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:49:12
+  --> $DIR/recover-range-pats.rs:50:12
    |
 LL |     if let .0...Y = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:52:17
+  --> $DIR/recover-range-pats.rs:53:17
    |
 LL |     if let X... .0 = 0 {}
    |                 ^^ help: must have an integer part: `0.0`
 
-error: `X..` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:58:12
-   |
-LL |     if let 0.. = 0 {}
-   |            ^^^ help: try using the maximum value for the type: `0..MAX`
-
-error: `X..` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:59:12
-   |
-LL |     if let X.. = 0 {}
-   |            ^^^ help: try using the maximum value for the type: `X..MAX`
-
-error: `X..` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:60:12
-   |
-LL |     if let true.. = 0 {}
-   |            ^^^^^^ help: try using the maximum value for the type: `true..MAX`
-
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:62:12
+  --> $DIR/recover-range-pats.rs:63:12
    |
 LL |     if let .0.. = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
-error: `X..` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:62:12
-   |
-LL |     if let .0.. = 0 {}
-   |            ^^^^ help: try using the maximum value for the type: `0.0..MAX`
-
-error: `X..=` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:68:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:69:13
    |
 LL |     if let 0..= = 0 {}
-   |            ^^^^ help: try using the maximum value for the type: `0..=MAX`
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: `X..=` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:69:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:70:13
    |
 LL |     if let X..= = 0 {}
-   |            ^^^^ help: try using the maximum value for the type: `X..=MAX`
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: `X..=` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:70:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:71:16
    |
 LL |     if let true..= = 0 {}
-   |            ^^^^^^^ help: try using the maximum value for the type: `true..=MAX`
+   |                ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:72:12
+  --> $DIR/recover-range-pats.rs:73:12
    |
 LL |     if let .0..= = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
-error: `X..=` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:72:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:73:14
    |
 LL |     if let .0..= = 0 {}
-   |            ^^^^^ help: try using the maximum value for the type: `0.0..=MAX`
+   |              ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: `X...` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:78:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:79:13
    |
 LL |     if let 0... = 0 {}
-   |            ^^^^ help: try using the maximum value for the type: `0...MAX`
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: `X...` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:80:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:80:13
    |
 LL |     if let X... = 0 {}
-   |            ^^^^ help: try using the maximum value for the type: `X...MAX`
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: `X...` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:82:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:81:16
    |
 LL |     if let true... = 0 {}
-   |            ^^^^^^^ help: try using the maximum value for the type: `true...MAX`
+   |                ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:85:12
+  --> $DIR/recover-range-pats.rs:83:12
    |
 LL |     if let .0... = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
-error: `X...` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:85:12
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:83:14
    |
 LL |     if let .0... = 0 {}
-   |            ^^^^^ help: try using the maximum value for the type: `0.0...MAX`
-
-error: `..X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:92:12
+   |              ^^^ help: use `..` instead
    |
-LL |     if let ..0 = 0 {}
-   |            ^^^ help: try using the minimum value for the type: `MIN..0`
-
-error: `..X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:93:12
-   |
-LL |     if let ..Y = 0 {}
-   |            ^^^ help: try using the minimum value for the type: `MIN..Y`
-
-error: `..X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:94:12
-   |
-LL |     if let ..true = 0 {}
-   |            ^^^^^^ help: try using the minimum value for the type: `MIN..true`
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:96:15
+  --> $DIR/recover-range-pats.rs:93:15
    |
 LL |     if let .. .0 = 0 {}
    |               ^^ help: must have an integer part: `0.0`
 
-error: `..X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:96:12
-   |
-LL |     if let .. .0 = 0 {}
-   |            ^^^^^ help: try using the minimum value for the type: `MIN..0.0`
-
-error: `..=X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:102:12
-   |
-LL |     if let ..=3 = 0 {}
-   |            ^^^^ help: try using the minimum value for the type: `MIN..=3`
-
-error: `..=X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:103:12
-   |
-LL |     if let ..=Y = 0 {}
-   |            ^^^^ help: try using the minimum value for the type: `MIN..=Y`
-
-error: `..=X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:104:12
-   |
-LL |     if let ..=true = 0 {}
-   |            ^^^^^^^ help: try using the minimum value for the type: `MIN..=true`
-
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:106:15
+  --> $DIR/recover-range-pats.rs:103:15
    |
 LL |     if let ..=.0 = 0 {}
    |               ^^ help: must have an integer part: `0.0`
 
-error: `..=X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:106:12
-   |
-LL |     if let ..=.0 = 0 {}
-   |            ^^^^^ help: try using the minimum value for the type: `MIN..=0.0`
-
-error: `...X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:112:12
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:109:12
    |
 LL |     if let ...3 = 0 {}
-   |            ^^^^ help: try using the minimum value for the type: `MIN...3`
+   |            ^^^ help: use `..=` instead
 
-error: `...X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:114:12
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:111:12
    |
 LL |     if let ...Y = 0 {}
-   |            ^^^^ help: try using the minimum value for the type: `MIN...Y`
+   |            ^^^ help: use `..=` instead
 
-error: `...X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:116:12
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:113:12
    |
 LL |     if let ...true = 0 {}
-   |            ^^^^^^^ help: try using the minimum value for the type: `MIN...true`
+   |            ^^^ help: use `..=` instead
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:119:15
+  --> $DIR/recover-range-pats.rs:116:15
    |
 LL |     if let ....3 = 0 {}
    |               ^^ help: must have an integer part: `0.3`
 
-error: `...X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:119:12
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:116:12
    |
 LL |     if let ....3 = 0 {}
-   |            ^^^^^ help: try using the minimum value for the type: `MIN...0.3`
-
-error: `..X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:139:17
-   |
-LL |             let ..$e;
-   |                 ^^ help: try using the minimum value for the type: `MIN..0`
-...
-LL |     mac!(0);
-   |     -------- in this macro invocation
+   |            ^^^ help: use `..=` instead
 
-error: `...X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:140:17
+error: range-to patterns with `...` are not allowed
+  --> $DIR/recover-range-pats.rs:137:17
    |
 LL |             let ...$e;
-   |                 ^^^ help: try using the minimum value for the type: `MIN...0`
+   |                 ^^^ help: use `..=` instead
 ...
 LL |     mac!(0);
    |     -------- in this macro invocation
 
-error: `..=X` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:142:17
-   |
-LL |             let ..=$e;
-   |                 ^^^ help: try using the minimum value for the type: `MIN..=0`
-...
-LL |     mac!(0);
-   |     -------- in this macro invocation
-
-error: `X..` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:143:19
-   |
-LL |             let $e..;
-   |                   ^^ help: try using the maximum value for the type: `0..MAX`
-...
-LL |     mac!(0);
-   |     -------- in this macro invocation
-
-error: `X...` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:144:19
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:141:19
    |
 LL |             let $e...;
-   |                   ^^^ help: try using the maximum value for the type: `0...MAX`
+   |                   ^^^ help: use `..` instead
 ...
 LL |     mac!(0);
    |     -------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: `X..=` range patterns are not supported
-  --> $DIR/recover-range-pats.rs:146:19
+error[E0586]: inclusive range with no end
+  --> $DIR/recover-range-pats.rs:142:19
    |
 LL |             let $e..=;
-   |                   ^^^ help: try using the maximum value for the type: `0..=MAX`
+   |                   ^^^ help: use `..` instead
 ...
 LL |     mac!(0);
    |     -------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:41:13
+  --> $DIR/recover-range-pats.rs:42:13
    |
 LL |     if let 0...3 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
    |
 note: lint level defined here
-  --> $DIR/recover-range-pats.rs:7:9
+  --> $DIR/recover-range-pats.rs:8:9
    |
 LL | #![deny(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:42:13
+  --> $DIR/recover-range-pats.rs:43:13
    |
 LL |     if let 0...Y = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:43:13
+  --> $DIR/recover-range-pats.rs:44:13
    |
 LL |     if let X...3 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:44:13
+  --> $DIR/recover-range-pats.rs:45:13
    |
 LL |     if let X...Y = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:45:16
+  --> $DIR/recover-range-pats.rs:46:16
    |
 LL |     if let true...Y = 0 {}
    |                ^^^ help: use `..=` for an inclusive range
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:47:13
+  --> $DIR/recover-range-pats.rs:48:13
    |
 LL |     if let X...true = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:49:14
+  --> $DIR/recover-range-pats.rs:50:14
    |
 LL |     if let .0...Y = 0 {}
    |              ^^^ help: use `..=` for an inclusive range
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:52:13
+  --> $DIR/recover-range-pats.rs:53:13
    |
 LL |     if let X... .0 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:78:13
-   |
-LL |     if let 0... = 0 {}
-   |             ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:80:13
-   |
-LL |     if let X... = 0 {}
-   |             ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:82:16
-   |
-LL |     if let true... = 0 {}
-   |                ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:85:14
-   |
-LL |     if let .0... = 0 {}
-   |              ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:112:12
-   |
-LL |     if let ...3 = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:114:12
-   |
-LL |     if let ...Y = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:116:12
-   |
-LL |     if let ...true = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:119:12
-   |
-LL |     if let ....3 = 0 {}
-   |            ^^^ help: use `..=` for an inclusive range
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:129:20
+  --> $DIR/recover-range-pats.rs:126:20
    |
 LL |             let $e1...$e2;
    |                    ^^^ help: use `..=` for an inclusive range
@@ -379,26 +252,8 @@ LL |             let $e1...$e2;
 LL |     mac2!(0, 1);
    |     ------------ in this macro invocation
 
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:140:17
-   |
-LL |             let ...$e;
-   |                 ^^^ help: use `..=` for an inclusive range
-...
-LL |     mac!(0);
-   |     -------- in this macro invocation
-
-error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:144:19
-   |
-LL |             let $e...;
-   |                   ^^^ help: use `..=` for an inclusive range
-...
-LL |     mac!(0);
-   |     -------- in this macro invocation
-
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:19:12
+  --> $DIR/recover-range-pats.rs:20:12
    |
 LL |     if let true..Y = 0 {}
    |            ^^^^  - this is of type `u8`
@@ -406,7 +261,7 @@ LL |     if let true..Y = 0 {}
    |            this is of type `bool` but it should be `char` or numeric
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:20:15
+  --> $DIR/recover-range-pats.rs:21:15
    |
 LL |     if let X..true = 0 {}
    |            -  ^^^^ this is of type `bool` but it should be `char` or numeric
@@ -414,7 +269,7 @@ LL |     if let X..true = 0 {}
    |            this is of type `u8`
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:21:12
+  --> $DIR/recover-range-pats.rs:22:12
    |
 LL |     if let .0..Y = 0 {}
    |            ^^  - this is of type `u8`
@@ -422,7 +277,7 @@ LL |     if let .0..Y = 0 {}
    |            expected integer, found floating-point number
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:23:16
+  --> $DIR/recover-range-pats.rs:24:16
    |
 LL |     if let X.. .0 = 0 {}
    |            -   ^^   - this expression has type `u8`
@@ -431,7 +286,7 @@ LL |     if let X.. .0 = 0 {}
    |            this is of type `u8`
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:32:12
+  --> $DIR/recover-range-pats.rs:33:12
    |
 LL |     if let true..=Y = 0 {}
    |            ^^^^   - this is of type `u8`
@@ -439,7 +294,7 @@ LL |     if let true..=Y = 0 {}
    |            this is of type `bool` but it should be `char` or numeric
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:33:16
+  --> $DIR/recover-range-pats.rs:34:16
    |
 LL |     if let X..=true = 0 {}
    |            -   ^^^^ this is of type `bool` but it should be `char` or numeric
@@ -447,7 +302,7 @@ LL |     if let X..=true = 0 {}
    |            this is of type `u8`
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:34:12
+  --> $DIR/recover-range-pats.rs:35:12
    |
 LL |     if let .0..=Y = 0 {}
    |            ^^   - this is of type `u8`
@@ -455,7 +310,7 @@ LL |     if let .0..=Y = 0 {}
    |            expected integer, found floating-point number
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:36:16
+  --> $DIR/recover-range-pats.rs:37:16
    |
 LL |     if let X..=.0 = 0 {}
    |            -   ^^   - this expression has type `u8`
@@ -464,7 +319,7 @@ LL |     if let X..=.0 = 0 {}
    |            this is of type `u8`
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:45:12
+  --> $DIR/recover-range-pats.rs:46:12
    |
 LL |     if let true...Y = 0 {}
    |            ^^^^   - this is of type `u8`
@@ -472,7 +327,7 @@ LL |     if let true...Y = 0 {}
    |            this is of type `bool` but it should be `char` or numeric
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:47:16
+  --> $DIR/recover-range-pats.rs:48:16
    |
 LL |     if let X...true = 0 {}
    |            -   ^^^^ this is of type `bool` but it should be `char` or numeric
@@ -480,7 +335,7 @@ LL |     if let X...true = 0 {}
    |            this is of type `u8`
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:49:12
+  --> $DIR/recover-range-pats.rs:50:12
    |
 LL |     if let .0...Y = 0 {}
    |            ^^   - this is of type `u8`
@@ -488,7 +343,7 @@ LL |     if let .0...Y = 0 {}
    |            expected integer, found floating-point number
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:52:17
+  --> $DIR/recover-range-pats.rs:53:17
    |
 LL |     if let X... .0 = 0 {}
    |            -    ^^   - this expression has type `u8`
@@ -497,78 +352,78 @@ LL |     if let X... .0 = 0 {}
    |            this is of type `u8`
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:60:12
+  --> $DIR/recover-range-pats.rs:61:12
    |
 LL |     if let true.. = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:62:12
+  --> $DIR/recover-range-pats.rs:63:12
    |
 LL |     if let .0.. = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:70:12
+  --> $DIR/recover-range-pats.rs:71:12
    |
 LL |     if let true..= = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:72:12
+  --> $DIR/recover-range-pats.rs:73:12
    |
 LL |     if let .0..= = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:82:12
+  --> $DIR/recover-range-pats.rs:81:12
    |
 LL |     if let true... = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:85:12
+  --> $DIR/recover-range-pats.rs:83:12
    |
 LL |     if let .0... = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:94:14
+  --> $DIR/recover-range-pats.rs:91:14
    |
 LL |     if let ..true = 0 {}
    |              ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:96:15
+  --> $DIR/recover-range-pats.rs:93:15
    |
 LL |     if let .. .0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:104:15
+  --> $DIR/recover-range-pats.rs:101:15
    |
 LL |     if let ..=true = 0 {}
    |               ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:106:15
+  --> $DIR/recover-range-pats.rs:103:15
    |
 LL |     if let ..=.0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
 error[E0029]: only char and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:116:15
+  --> $DIR/recover-range-pats.rs:113:15
    |
 LL |     if let ...true = 0 {}
    |               ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:119:15
+  --> $DIR/recover-range-pats.rs:116:15
    |
 LL |     if let ....3 = 0 {}
    |               ^^ expected integer, found floating-point number
 
-error: aborting due to 85 previous errors
+error: aborting due to 60 previous errors
 
-Some errors have detailed explanations: E0029, E0308.
+Some errors have detailed explanations: E0029, E0308, E0586.
 For more information about an error, try `rustc --explain E0029`.
index 9c7a25d589a1f9aafa988098042db58979b5dc5a..e27b03dddc5be56882eaf84089585bd4ceb9e98d 100644 (file)
@@ -3,24 +3,26 @@ fn f<T>() {}
 
 fn main() {
     false == false == false;
-    //~^ ERROR chained comparison operators require parentheses
+    //~^ ERROR comparison operators cannot be chained
 
     false == 0 < 2;
-    //~^ ERROR chained comparison operators require parentheses
+    //~^ ERROR comparison operators cannot be chained
     //~| ERROR mismatched types
     //~| ERROR mismatched types
 
     f<X>();
-    //~^ ERROR chained comparison operators require parentheses
+    //~^ ERROR comparison operators cannot be chained
     //~| HELP use `::<...>` instead of `<...>` to specify type arguments
 
     f<Result<Option<X>, Option<Option<X>>>(1, 2);
-    //~^ ERROR chained comparison operators require parentheses
+    //~^ ERROR comparison operators cannot be chained
+    //~| HELP split the comparison into two...
+    //~| ...or parenthesize one of the comparisons
     //~| HELP use `::<...>` instead of `<...>` to specify type arguments
 
     use std::convert::identity;
     let _ = identity<u8>;
-    //~^ ERROR chained comparison operators require parentheses
+    //~^ ERROR comparison operators cannot be chained
     //~| HELP use `::<...>` instead of `<...>` to specify type arguments
     //~| HELP or use `(...)` if you meant to specify fn arguments
 }
index bece9a388008c072a59927d0701288e316d18e2c..44edf2de7f8de22adccbaf1aa6c0168f4671c671 100644 (file)
@@ -1,16 +1,16 @@
-error: chained comparison operators require parentheses
+error: comparison operators cannot be chained
   --> $DIR/require-parens-for-chained-comparison.rs:5:11
    |
 LL |     false == false == false;
    |           ^^^^^^^^^^^
 
-error: chained comparison operators require parentheses
+error: comparison operators cannot be chained
   --> $DIR/require-parens-for-chained-comparison.rs:8:11
    |
 LL |     false == 0 < 2;
    |           ^^^^^^
 
-error: chained comparison operators require parentheses
+error: comparison operators cannot be chained
   --> $DIR/require-parens-for-chained-comparison.rs:13:6
    |
 LL |     f<X>();
@@ -21,19 +21,27 @@ help: use `::<...>` instead of `<...>` to specify type arguments
 LL |     f::<X>();
    |      ^^
 
-error: chained comparison operators require parentheses
+error: comparison operators cannot be chained
   --> $DIR/require-parens-for-chained-comparison.rs:17:6
    |
 LL |     f<Result<Option<X>, Option<Option<X>>>(1, 2);
    |      ^^^^^^^^
    |
+help: split the comparison into two...
+   |
+LL |     f < Result && Result <Option<X>, Option<Option<X>>>(1, 2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+help: ...or parenthesize one of the comparisons
+   |
+LL |     (f < Result) <Option<X>, Option<Option<X>>>(1, 2);
+   |     ^^^^^^^^^^^^^^
 help: use `::<...>` instead of `<...>` to specify type arguments
    |
 LL |     f::<Result<Option<X>, Option<Option<X>>>(1, 2);
    |      ^^
 
-error: chained comparison operators require parentheses
-  --> $DIR/require-parens-for-chained-comparison.rs:22:21
+error: comparison operators cannot be chained
+  --> $DIR/require-parens-for-chained-comparison.rs:24:21
    |
 LL |     let _ = identity<u8>;
    |                     ^^^^
index 1b8ed9f12b8804b7a6cb65f87b8fbb39dcb73cd2..6a3b2c1c60605ad9274487d2b46385cac5deea0c 100644 (file)
@@ -1,5 +1,3 @@
-// compile-flags: -Z continue-parse-after-error
-
 struct Foo {
     x: isize,
     y: isize,
index 8f32fb0eca106c595b2667726b01cd286511a714..306b4754d0d69a6ad46dc9d382359f14dd8a44a8 100644 (file)
@@ -1,17 +1,17 @@
 error: field expressions may not have generic arguments
-  --> $DIR/type-parameters-in-field-exprs.rs:13:10
+  --> $DIR/type-parameters-in-field-exprs.rs:11:10
    |
 LL |     f.x::<isize>;
    |          ^^^^^^^
 
 error: field expressions may not have generic arguments
-  --> $DIR/type-parameters-in-field-exprs.rs:15:10
+  --> $DIR/type-parameters-in-field-exprs.rs:13:10
    |
 LL |     f.x::<>;
    |          ^^
 
 error: field expressions may not have generic arguments
-  --> $DIR/type-parameters-in-field-exprs.rs:17:7
+  --> $DIR/type-parameters-in-field-exprs.rs:15:7
    |
 LL |     f.x::();
    |       ^^^^^
index 88eda9afec7eb853bc9f9e1301e63b8a56b3b145..559925c282f9ae2ac3b98e4d243aa40544f44152 100644 (file)
@@ -101,6 +101,7 @@ fn f2(ref mut a @ ref b: U) {}
         //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable
         //~| ERROR cannot borrow `a` as mutable because it is also borrowed as immutable
         //~| ERROR cannot move out of `b` in pattern guard
+        //~| ERROR cannot move out of `b` in pattern guard
         _ => {}
     }
     match Ok(U) {
@@ -108,6 +109,7 @@ fn f2(ref mut a @ ref b: U) {}
         //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable
         //~| ERROR cannot borrow `a` as immutable because it is also borrowed as mutable
         //~| ERROR cannot move out of `a` in pattern guard
+        //~| ERROR cannot move out of `a` in pattern guard
         _ => {}
     }
 
index b068a6125b670fded33ac94cb5520095c7d5d0d9..b5c26a1fa039945c21545307010619bfa0cbf28c 100644 (file)
@@ -191,7 +191,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    |                                 immutable borrow occurs here
 
 error: cannot borrow `a` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:107:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:108:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |         ---------^^^^^^-----^
@@ -200,7 +200,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false
    |         mutable borrow occurs here
 
 error: cannot borrow `a` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:107:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:108:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                 ---------^^^^^^^-----^
@@ -209,7 +209,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false
    |                                 mutable borrow occurs here
 
 error: cannot borrow `a` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:114:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:116:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -219,7 +219,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         immutable borrow occurs here
 
 error: cannot borrow `a` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:121:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -229,7 +229,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         immutable borrow occurs here
 
 error: cannot borrow `a` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:126:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:128:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -239,7 +239,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         immutable borrow occurs here
 
 error: cannot borrow `a` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:133:9
    |
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
@@ -359,8 +359,24 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
+error[E0507]: cannot move out of `b` in pattern guard
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:100:66
+   |
+LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+   |                                                                  ^ move occurs because `b` has type `&mut main::U`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `a` in pattern guard
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:108:66
+   |
+LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+   |                                                                  ^ move occurs because `a` has type `&mut std::result::Result<main::U, main::U>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
 error[E0507]: cannot move out of `a` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:107:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:108:66
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                                                  ^ move occurs because `a` has type `&mut std::result::Result<main::U, main::U>`, which does not implement the `Copy` trait
@@ -368,7 +384,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:18
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:121:18
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         ---------^^^^^^^^^------------
@@ -380,7 +396,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:29
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:121:29
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         --------------------^^^^^^^^^-
@@ -392,7 +408,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:126:18
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:128:18
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         ---------^^^^^^^^^------------
@@ -404,7 +420,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:126:29
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:128:29
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         --------------------^^^^^^^^^-
@@ -415,7 +431,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
 LL |     drop(a);
    |          - immutable borrow later used here
 
-error: aborting due to 43 previous errors
+error: aborting due to 45 previous errors
 
 Some errors have detailed explanations: E0502, E0507, E0594.
 For more information about an error, try `rustc --explain E0502`.
index 7a0f14425b746b22554a9ac1d2c15d40c50aa35a..7217fe1b02f4e1741ee466db8313b136fc272424 100644 (file)
@@ -1,4 +1,4 @@
-thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:LL:CC
+thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir_build/hair/pattern/_match.rs:LL:CC
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 error: internal compiler error: unexpected panic
index abb8d6907e76d85c957689f993387d7612293213..21218d9a17368d915a2ded626e73a59e9bb6df66 100644 (file)
@@ -3,6 +3,8 @@ warning[E0170]: pattern binding `Bar` is named the same as one of the variants o
    |
 LL |         Bar => {},
    |         ^^^ help: to match on the variant, qualify the path: `Foo::Bar`
+   |
+   = note: `#[warn(bindings_with_variant_name)]` on by default
 
 warning[E0170]: pattern binding `Baz` is named the same as one of the variants of the type `Foo`
   --> $DIR/issue-67776-match-same-name-enum-variant-refs.rs:19:9
index def6c62459e5a8698b9348ce9029157005667a30..5b3db2e57c8360f91a628887e3fbada78d5c0511 100644 (file)
@@ -18,7 +18,8 @@ fn foo(value: i32) -> Option<$name> {
     Pos = 1,
     Neg = -1,
     Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
-                   //~^ ERROR only char and numeric types are allowed in range patterns
+                   //~| ERROR arbitrary expressions aren't allowed in patterns
+                   //~| ERROR only char and numeric types are allowed in range patterns
 });
 
 fn main() {}
index 78768d282e7c44c1825afdefe05fa288325adba9..70dd1a9263f6f315689b9de73cfa499559f88eeb 100644 (file)
@@ -4,6 +4,12 @@ error: arbitrary expressions aren't allowed in patterns
 LL |     Arith = 1 + 1,
    |             ^^^^^
 
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/patkind-litrange-no-expr.rs:20:13
+   |
+LL |     Arith = 1 + 1,
+   |             ^^^^^
+
 error[E0029]: only char and numeric types are allowed in range patterns
   --> $DIR/patkind-litrange-no-expr.rs:20:13
    |
@@ -13,6 +19,6 @@ LL |                 $( $value ..= 42 => Some($name::$variant), )* // PatKind::R
 LL |     Arith = 1 + 1,
    |             ^^^^^ this is of type `_` but it should be `char` or numeric
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0029`.
index 7de7b7e79be44faf85c4b75fe98ff73dd672e40b..37c4ccda0f5e34ebfd4790c314cd56bf947fcab5 100644 (file)
@@ -34,11 +34,15 @@ fn main() {
       //~^ WARNING floating-point types cannot be used in patterns
       //~| WARNING floating-point types cannot be used in patterns
       //~| WARNING floating-point types cannot be used in patterns
+      //~| WARNING floating-point types cannot be used in patterns
+      //~| WARNING this was previously accepted by the compiler
       //~| WARNING this was previously accepted by the compiler
       //~| WARNING this was previously accepted by the compiler
       //~| WARNING this was previously accepted by the compiler
       0.02f64 => {} //~ ERROR unreachable pattern
       //~^ WARNING floating-point types cannot be used in patterns
+      //~| WARNING floating-point types cannot be used in patterns
+      //~| WARNING this was previously accepted by the compiler
       //~| WARNING this was previously accepted by the compiler
       _ => {}
     };
index c15186d2558f24402c0746132a7f3fbf4c3b1783..8412a113664c8e0959e4d765ab53de8c93ec61e3 100644 (file)
@@ -48,7 +48,7 @@ LL |       0.01f64 ..= 6.5f64 => {}
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 warning: floating-point types cannot be used in patterns
-  --> $DIR/match-range-fail-dominate.rs:40:7
+  --> $DIR/match-range-fail-dominate.rs:42:7
    |
 LL |       0.02f64 => {}
    |       ^^^^^^^
@@ -57,7 +57,7 @@ LL |       0.02f64 => {}
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: unreachable pattern
-  --> $DIR/match-range-fail-dominate.rs:40:7
+  --> $DIR/match-range-fail-dominate.rs:42:7
    |
 LL |       0.02f64 => {}
    |       ^^^^^^^
@@ -71,5 +71,23 @@ LL |       0.01f64 ..= 6.5f64 => {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
+warning: floating-point types cannot be used in patterns
+  --> $DIR/match-range-fail-dominate.rs:33:19
+   |
+LL |       0.01f64 ..= 6.5f64 => {}
+   |                   ^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+warning: floating-point types cannot be used in patterns
+  --> $DIR/match-range-fail-dominate.rs:42:7
+   |
+LL |       0.02f64 => {}
+   |       ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
 error: aborting due to 5 previous errors
 
index d376237c355d08fcfd31814ac19312bbd47b0089..fcf7b19572f1ff509b7897979a2dae2b10d1c70c 100644 (file)
@@ -131,6 +131,7 @@ fn test() {
     fn test2() {
         use bar::baz::{foo, bar};
         //~^ ERROR: module `baz` is private
+        //~| ERROR: module `baz` is private
 
         foo();
         bar();
index b647cc8ab8a834c53eeb73ba40d5d926eaeb0991..29f53cd0e35450e071e90dcd76af26f9ae4bc3ca 100644 (file)
@@ -5,13 +5,19 @@ LL |         use bar::baz::{foo, bar};
    |                  ^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:140:18
+  --> $DIR/privacy1.rs:132:18
+   |
+LL |         use bar::baz::{foo, bar};
+   |                  ^^^
+
+error[E0603]: module `baz` is private
+  --> $DIR/privacy1.rs:141:18
    |
 LL |         use bar::baz;
    |                  ^^^
 
 error[E0603]: module `i` is private
-  --> $DIR/privacy1.rs:164:20
+  --> $DIR/privacy1.rs:165:20
    |
 LL |     use self::foo::i::A;
    |                    ^
@@ -65,7 +71,7 @@ LL |         ::bar::baz::bar();
    |                ^^^
 
 error[E0603]: trait `B` is private
-  --> $DIR/privacy1.rs:156:17
+  --> $DIR/privacy1.rs:157:17
    |
 LL |     impl ::bar::B for f32 { fn foo() -> f32 { 1.0 } }
    |                 ^
@@ -100,7 +106,7 @@ error[E0624]: method `bar2` is private
 LL |         ::bar::baz::A.bar2();
    |                       ^^^^
 
-error: aborting due to 17 previous errors
+error: aborting due to 18 previous errors
 
 Some errors have detailed explanations: E0603, E0624.
 For more information about an error, try `rustc --explain E0603`.
index 3c42f24d5ff738e55f7232e8f4b68b9a83deec19..ad1052ada6084971e12f623b51cbe227e3eb3d54 100644 (file)
@@ -17,6 +17,8 @@ pub trait PubTr {
         //~^ WARN private trait `m::PrivTr` in public interface
         //~| WARN this was previously accepted
         //~| WARN private type `m::Priv` in public interface
+        //~| WARN private type `m::Priv` in public interface
+        //~| WARN this was previously accepted
         //~| WARN this was previously accepted
         type Alias1: PrivTr;
         type Alias2: PubTrAux1<Priv> = u8;
@@ -34,6 +36,7 @@ impl PubTr for u8 {
 
         type Exist = impl PrivTr;
         //~^ ERROR private trait `m::PrivTr` in public interface
+        //~| ERROR private trait `m::PrivTr` in public interface
         fn infer_exist() -> Self::Exist { Priv }
     }
 }
index 158862f9228cccf95ad08038ada914491a0b0780..3cc551cdeded63c9e6518385d41d236e64215685 100644 (file)
@@ -29,8 +29,23 @@ LL | |     }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
 
+warning: private type `m::Priv` in public interface (error E0446)
+  --> $DIR/private-in-public-assoc-ty.rs:16:5
+   |
+LL | /     pub trait PubTr {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |         fn infer_exist() -> Self::Exist;
+LL | |     }
+   | |_____^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
+
 error[E0446]: private type `m::Priv` in public interface
-  --> $DIR/private-in-public-assoc-ty.rs:25:9
+  --> $DIR/private-in-public-assoc-ty.rs:27:9
    |
 LL |     struct Priv;
    |     - `m::Priv` declared as private
@@ -39,7 +54,7 @@ LL |         type Alias4 = Priv;
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
 
 error[E0446]: private type `m::Priv` in public interface
-  --> $DIR/private-in-public-assoc-ty.rs:32:9
+  --> $DIR/private-in-public-assoc-ty.rs:34:9
    |
 LL |     struct Priv;
    |     - `m::Priv` declared as private
@@ -48,7 +63,16 @@ LL |         type Alias1 = Priv;
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
 
 error[E0445]: private trait `m::PrivTr` in public interface
-  --> $DIR/private-in-public-assoc-ty.rs:35:9
+  --> $DIR/private-in-public-assoc-ty.rs:37:9
+   |
+LL |     trait PrivTr {}
+   |     - `m::PrivTr` declared as private
+...
+LL |         type Exist = impl PrivTr;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
+
+error[E0445]: private trait `m::PrivTr` in public interface
+  --> $DIR/private-in-public-assoc-ty.rs:37:9
    |
 LL |     trait PrivTr {}
    |     - `m::PrivTr` declared as private
@@ -56,7 +80,7 @@ LL |     trait PrivTr {}
 LL |         type Exist = impl PrivTr;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0445, E0446.
 For more information about an error, try `rustc --explain E0445`.
index 5d1a9f25baffd954e3982f38dd2ec5810598461b..f1934f62fd88afcce777b09b67021168de6acc5b 100644 (file)
@@ -4,6 +4,7 @@
 extern crate issue_50493;
 
 #[derive(Derive)] //~ ERROR field `field` of struct `Restricted` is private
+                  //~| ERROR field `field` of struct `Restricted` is private
 struct Restricted {
     pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules
 }
index 6b8724457a6a3621bc2b3dd1fdb6795f713aa909..56c7800102176eef3ac768ed524552d3f48336f5 100644 (file)
@@ -1,5 +1,5 @@
 error[E0742]: visibilities can only be restricted to ancestor modules
-  --> $DIR/issue-50493.rs:8:12
+  --> $DIR/issue-50493.rs:9:12
    |
 LL |     pub(in restricted) field: usize,
    |            ^^^^^^^^^^
@@ -10,7 +10,13 @@ error[E0616]: field `field` of struct `Restricted` is private
 LL | #[derive(Derive)]
    |          ^^^^^^
 
-error: aborting due to 2 previous errors
+error[E0616]: field `field` of struct `Restricted` is private
+  --> $DIR/issue-50493.rs:6:10
+   |
+LL | #[derive(Derive)]
+   |          ^^^^^^
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0616, E0742.
 For more information about an error, try `rustc --explain E0616`.
index b17c0565932fd17d4f77c8fd882e32a777a30575..470b22b48749d8b5b090343ef663fa9ef3cfa530 100644 (file)
@@ -46,6 +46,7 @@ fn check_attr2() {}
 fn check_attr3() {}
 
 #[derive(my_macro)] //~ ERROR cannot find derive macro `my_macro` in this scope
+                    //~| ERROR cannot find derive macro `my_macro` in this scope
 #[derive(crate::my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines
                            //~| ERROR expected derive macro, found macro `crate::my_macro`
 struct CheckDerive1;
index c011a70cd0c8432e3184125b586c0bbea730c9e2..a617319faea80c906b28e9b0554b2732c4f271f8 100644 (file)
@@ -47,19 +47,19 @@ LL | #[MyTrait]
    |   ^^^^^^^ not an attribute
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:52:10
+  --> $DIR/macro-namespace-reserved-2.rs:53:10
    |
 LL | #[derive(my_macro_attr)]
    |          ^^^^^^^^^^^^^
 
 error: expected derive macro, found attribute macro `my_macro_attr`
-  --> $DIR/macro-namespace-reserved-2.rs:52:10
+  --> $DIR/macro-namespace-reserved-2.rs:53:10
    |
 LL | #[derive(my_macro_attr)]
    |          ^^^^^^^^^^^^^ not a derive macro
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:55:10
+  --> $DIR/macro-namespace-reserved-2.rs:56:10
    |
 LL | #[derive(MyTrait)]
    |          ^^^^^^^
@@ -77,13 +77,13 @@ LL | #[crate::my_macro]
    |   ^^^^^^^^^^^^^^^ not an attribute
 
 error: can't use a procedural macro from the same crate that defines it
-  --> $DIR/macro-namespace-reserved-2.rs:49:10
+  --> $DIR/macro-namespace-reserved-2.rs:50:10
    |
 LL | #[derive(crate::my_macro)]
    |          ^^^^^^^^^^^^^^^
 
 error: expected derive macro, found macro `crate::my_macro`
-  --> $DIR/macro-namespace-reserved-2.rs:49:10
+  --> $DIR/macro-namespace-reserved-2.rs:50:10
    |
 LL | #[derive(crate::my_macro)]
    |          ^^^^^^^^^^^^^^^ not a derive macro
@@ -112,5 +112,11 @@ error: cannot find derive macro `my_macro` in this scope
 LL | #[derive(my_macro)]
    |          ^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: cannot find derive macro `my_macro` in this scope
+  --> $DIR/macro-namespace-reserved-2.rs:48:10
+   |
+LL | #[derive(my_macro)]
+   |          ^^^^^^^^
+
+error: aborting due to 20 previous errors
 
index 7b2ffefb05b1937b2d5c3b149d56945267cc8aa3..95a3f9695127029d29b889fb9388ad131c64d49e 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 // aux-build:parent-source-spans.rs
 #![feature(decl_macro, proc_macro_hygiene)]
 
index 3e54a71f0e81005bd45e2f08c0660bb6f7398b53..9f0fefcfe6c03e68880ab9b759bc32f6dfb7d05a 100644 (file)
@@ -1,5 +1,5 @@
 error: first final: "hello"
-  --> $DIR/parent-source-spans.rs:15:12
+  --> $DIR/parent-source-spans.rs:19:12
    |
 LL |     three!($a, $b);
    |            ^^
@@ -8,7 +8,7 @@ LL |     one!("hello", "world");
    |     ----------------------- in this macro invocation
 
 error: second final: "world"
-  --> $DIR/parent-source-spans.rs:15:16
+  --> $DIR/parent-source-spans.rs:19:16
    |
 LL |     three!($a, $b);
    |                ^^
@@ -17,7 +17,7 @@ LL |     one!("hello", "world");
    |     ----------------------- in this macro invocation
 
 error: first parent: "hello"
-  --> $DIR/parent-source-spans.rs:9:5
+  --> $DIR/parent-source-spans.rs:13:5
    |
 LL |     two!($a, $b);
    |     ^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |     one!("hello", "world");
    |     ----------------------- in this macro invocation
 
 error: second parent: "world"
-  --> $DIR/parent-source-spans.rs:9:5
+  --> $DIR/parent-source-spans.rs:13:5
    |
 LL |     two!($a, $b);
    |     ^^^^^^^^^^^^^
@@ -35,31 +35,31 @@ LL |     one!("hello", "world");
    |     ----------------------- in this macro invocation
 
 error: first grandparent: "hello"
-  --> $DIR/parent-source-spans.rs:35:5
+  --> $DIR/parent-source-spans.rs:39:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: second grandparent: "world"
-  --> $DIR/parent-source-spans.rs:35:5
+  --> $DIR/parent-source-spans.rs:39:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: first source: "hello"
-  --> $DIR/parent-source-spans.rs:35:5
+  --> $DIR/parent-source-spans.rs:39:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: second source: "world"
-  --> $DIR/parent-source-spans.rs:35:5
+  --> $DIR/parent-source-spans.rs:39:5
    |
 LL |     one!("hello", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: first final: "yay"
-  --> $DIR/parent-source-spans.rs:15:12
+  --> $DIR/parent-source-spans.rs:19:12
    |
 LL |     three!($a, $b);
    |            ^^
@@ -68,7 +68,7 @@ LL |     two!("yay", "rust");
    |     -------------------- in this macro invocation
 
 error: second final: "rust"
-  --> $DIR/parent-source-spans.rs:15:16
+  --> $DIR/parent-source-spans.rs:19:16
    |
 LL |     three!($a, $b);
    |                ^^
@@ -77,79 +77,94 @@ LL |     two!("yay", "rust");
    |     -------------------- in this macro invocation
 
 error: first parent: "yay"
-  --> $DIR/parent-source-spans.rs:41:5
+  --> $DIR/parent-source-spans.rs:45:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: second parent: "rust"
-  --> $DIR/parent-source-spans.rs:41:5
+  --> $DIR/parent-source-spans.rs:45:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: first source: "yay"
-  --> $DIR/parent-source-spans.rs:41:5
+  --> $DIR/parent-source-spans.rs:45:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: second source: "rust"
-  --> $DIR/parent-source-spans.rs:41:5
+  --> $DIR/parent-source-spans.rs:45:5
    |
 LL |     two!("yay", "rust");
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: first final: "hip"
-  --> $DIR/parent-source-spans.rs:47:12
+  --> $DIR/parent-source-spans.rs:51:12
    |
 LL |     three!("hip", "hop");
    |            ^^^^^
 
 error: second final: "hop"
-  --> $DIR/parent-source-spans.rs:47:19
+  --> $DIR/parent-source-spans.rs:51:19
    |
 LL |     three!("hip", "hop");
    |                   ^^^^^
 
 error: first source: "hip"
-  --> $DIR/parent-source-spans.rs:47:12
+  --> $DIR/parent-source-spans.rs:51:12
    |
 LL |     three!("hip", "hop");
    |            ^^^^^
 
 error: second source: "hop"
-  --> $DIR/parent-source-spans.rs:47:19
+  --> $DIR/parent-source-spans.rs:51:19
    |
 LL |     three!("hip", "hop");
    |                   ^^^^^
 
 error[E0425]: cannot find value `ok` in this scope
-  --> $DIR/parent-source-spans.rs:28:5
+  --> $DIR/parent-source-spans.rs:32:5
    |
 LL |     parent_source_spans!($($tokens)*);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok`
 ...
 LL |     one!("hello", "world");
    |     ----------------------- in this macro invocation
+   | 
+  ::: $SRC_DIR/libcore/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     --------------------------------------------------- similarly named tuple variant `Ok` defined here
 
 error[E0425]: cannot find value `ok` in this scope
-  --> $DIR/parent-source-spans.rs:28:5
+  --> $DIR/parent-source-spans.rs:32:5
    |
 LL |     parent_source_spans!($($tokens)*);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok`
 ...
 LL |     two!("yay", "rust");
    |     -------------------- in this macro invocation
+   | 
+  ::: $SRC_DIR/libcore/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     --------------------------------------------------- similarly named tuple variant `Ok` defined here
 
 error[E0425]: cannot find value `ok` in this scope
-  --> $DIR/parent-source-spans.rs:28:5
+  --> $DIR/parent-source-spans.rs:32:5
    |
 LL |     parent_source_spans!($($tokens)*);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a tuple variant with a similar name exists: `Ok`
 ...
 LL |     three!("hip", "hop");
    |     --------------------- in this macro invocation
+   | 
+  ::: $SRC_DIR/libcore/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     --------------------------------------------------- similarly named tuple variant `Ok` defined here
 
 error: aborting due to 21 previous errors
 
index d2282af27f543441b455c067d092e15b96c4c9bf..8ff36ff0a26e21b5380cd02aabcd785a084a43e7 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 // aux-build:derive-foo.rs
 // aux-build:derive-clona.rs
 // aux-build:test-macros.rs
@@ -21,6 +25,7 @@ macro_rules! attr_proc_mac {
 
 #[derive(FooWithLongNan)]
 //~^ ERROR cannot find
+//~| ERROR cannot find
 struct Foo;
 
 // Interpreted as an unstable custom attribute
@@ -33,14 +38,17 @@ macro_rules! attr_proc_mac {
 
 #[derive(Dlone)]
 //~^ ERROR cannot find
+//~| ERROR cannot find
 struct A;
 
 #[derive(Dlona)]
 //~^ ERROR cannot find
+//~| ERROR cannot find
 struct B;
 
 #[derive(attr_proc_macra)]
 //~^ ERROR cannot find
+//~| ERROR cannot find
 struct C;
 
 fn main() {
index 02c82c01ed3e0fb80a06c98faab79b038b53ad82..73a6ab1cfb91055edaae2c166cc032270ed3786b 100644 (file)
@@ -1,17 +1,22 @@
 error: cannot find macro `bang_proc_macrp` in this scope
-  --> $DIR/resolve-error.rs:56:5
+  --> $DIR/resolve-error.rs:64:5
    |
 LL |     bang_proc_macrp!();
    |     ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro`
+   | 
+  ::: $DIR/auxiliary/test-macros.rs:15:1
+   |
+LL | pub fn empty(_: TokenStream) -> TokenStream {
+   | ------------------------------------------- similarly named macro `bang_proc_macro` defined here
 
 error: cannot find macro `Dlona` in this scope
-  --> $DIR/resolve-error.rs:53:5
+  --> $DIR/resolve-error.rs:61:5
    |
 LL |     Dlona!();
    |     ^^^^^
 
 error: cannot find macro `attr_proc_macra` in this scope
-  --> $DIR/resolve-error.rs:50:5
+  --> $DIR/resolve-error.rs:58:5
    |
 LL | / macro_rules! attr_proc_mac {
 LL | |     () => {}
@@ -22,7 +27,7 @@ LL |       attr_proc_macra!();
    |       ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac`
 
 error: cannot find macro `FooWithLongNama` in this scope
-  --> $DIR/resolve-error.rs:47:5
+  --> $DIR/resolve-error.rs:55:5
    |
 LL | / macro_rules! FooWithLongNam {
 LL | |     () => {}
@@ -33,40 +38,99 @@ LL |       FooWithLongNama!();
    |       ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `FooWithLongNam`
 
 error: cannot find derive macro `attr_proc_macra` in this scope
-  --> $DIR/resolve-error.rs:42:10
+  --> $DIR/resolve-error.rs:49:10
    |
 LL | #[derive(attr_proc_macra)]
    |          ^^^^^^^^^^^^^^^
 
+error: cannot find derive macro `attr_proc_macra` in this scope
+  --> $DIR/resolve-error.rs:49:10
+   |
+LL | #[derive(attr_proc_macra)]
+   |          ^^^^^^^^^^^^^^^
+
+error: cannot find derive macro `Dlona` in this scope
+  --> $DIR/resolve-error.rs:44:10
+   |
+LL | #[derive(Dlona)]
+   |          ^^^^^ help: a derive macro with a similar name exists: `Clona`
+   | 
+  ::: $DIR/auxiliary/derive-clona.rs:11:1
+   |
+LL | pub fn derive_clonea(input: TokenStream) -> TokenStream {
+   | ------------------------------------------------------- similarly named derive macro `Clona` defined here
+
 error: cannot find derive macro `Dlona` in this scope
-  --> $DIR/resolve-error.rs:38:10
+  --> $DIR/resolve-error.rs:44:10
    |
 LL | #[derive(Dlona)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clona`
+   | 
+  ::: $DIR/auxiliary/derive-clona.rs:11:1
+   |
+LL | pub fn derive_clonea(input: TokenStream) -> TokenStream {
+   | ------------------------------------------------------- similarly named derive macro `Clona` defined here
+
+error: cannot find derive macro `Dlone` in this scope
+  --> $DIR/resolve-error.rs:39:10
+   |
+LL | #[derive(Dlone)]
+   |          ^^^^^ help: a derive macro with a similar name exists: `Clone`
+   | 
+  ::: $SRC_DIR/libcore/clone.rs:LL:COL
+   |
+LL | pub macro Clone($item:item) {
+   | --------------------------- similarly named derive macro `Clone` defined here
 
 error: cannot find derive macro `Dlone` in this scope
-  --> $DIR/resolve-error.rs:34:10
+  --> $DIR/resolve-error.rs:39:10
    |
 LL | #[derive(Dlone)]
    |          ^^^^^ help: a derive macro with a similar name exists: `Clone`
+   | 
+  ::: $SRC_DIR/libcore/clone.rs:LL:COL
+   |
+LL | pub macro Clone($item:item) {
+   | --------------------------- similarly named derive macro `Clone` defined here
 
 error: cannot find attribute `FooWithLongNan` in this scope
-  --> $DIR/resolve-error.rs:31:3
+  --> $DIR/resolve-error.rs:36:3
    |
 LL | #[FooWithLongNan]
    |   ^^^^^^^^^^^^^^
 
 error: cannot find attribute `attr_proc_macra` in this scope
-  --> $DIR/resolve-error.rs:27:3
+  --> $DIR/resolve-error.rs:32:3
    |
 LL | #[attr_proc_macra]
    |   ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro`
+   | 
+  ::: $DIR/auxiliary/test-macros.rs:20:1
+   |
+LL | pub fn empty_attr(_: TokenStream, _: TokenStream) -> TokenStream {
+   | ---------------------------------------------------------------- similarly named attribute macro `attr_proc_macro` defined here
 
 error: cannot find derive macro `FooWithLongNan` in this scope
-  --> $DIR/resolve-error.rs:22:10
+  --> $DIR/resolve-error.rs:26:10
    |
 LL | #[derive(FooWithLongNan)]
    |          ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName`
+   | 
+  ::: $DIR/auxiliary/derive-foo.rs:11:1
+   |
+LL | pub fn derive_foo(input: TokenStream) -> TokenStream {
+   | ---------------------------------------------------- similarly named derive macro `FooWithLongName` defined here
+
+error: cannot find derive macro `FooWithLongNan` in this scope
+  --> $DIR/resolve-error.rs:26:10
+   |
+LL | #[derive(FooWithLongNan)]
+   |          ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName`
+   | 
+  ::: $DIR/auxiliary/derive-foo.rs:11:1
+   |
+LL | pub fn derive_foo(input: TokenStream) -> TokenStream {
+   | ---------------------------------------------------- similarly named derive macro `FooWithLongName` defined here
 
-error: aborting due to 10 previous errors
+error: aborting due to 14 previous errors
 
index e28e47435c2c2fa999be8b7eabec626e9f8cb160..4f57c32e913e1fa2f4e5b317c6613f2404ee170d 100644 (file)
@@ -4,21 +4,45 @@
 struct AllTheRanges {
     a: Range<usize>,
     //~^ ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
     //~| ERROR Ord
     b: RangeTo<usize>,
     //~^ ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
     //~| ERROR Ord
     c: RangeFrom<usize>,
     //~^ ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
     //~| ERROR Ord
     d: RangeFull,
     //~^ ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
     //~| ERROR Ord
     e: RangeInclusive<usize>,
     //~^ ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
     //~| ERROR Ord
     f: RangeToInclusive<usize>,
     //~^ ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
+    //~| ERROR can't compare
     //~| ERROR Ord
 }
 
index d085cab89a17c5e3287423723b48ae8f26144523..f60ec23bdb0daab0eadc95e84205c5e67e611056 100644 (file)
@@ -8,7 +8,7 @@ LL |     a: Range<usize>,
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
 error[E0277]: can't compare `std::ops::RangeTo<usize>` with `std::ops::RangeTo<usize>`
-  --> $DIR/range_traits-1.rs:8:5
+  --> $DIR/range_traits-1.rs:12:5
    |
 LL |     b: RangeTo<usize>,
    |     ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo<usize> < std::ops::RangeTo<usize>` and `std::ops::RangeTo<usize> > std::ops::RangeTo<usize>`
@@ -17,7 +17,7 @@ LL |     b: RangeTo<usize>,
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
 error[E0277]: can't compare `std::ops::RangeFrom<usize>` with `std::ops::RangeFrom<usize>`
-  --> $DIR/range_traits-1.rs:11:5
+  --> $DIR/range_traits-1.rs:19:5
    |
 LL |     c: RangeFrom<usize>,
    |     ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom<usize> < std::ops::RangeFrom<usize>` and `std::ops::RangeFrom<usize> > std::ops::RangeFrom<usize>`
@@ -26,7 +26,7 @@ LL |     c: RangeFrom<usize>,
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
 error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull`
-  --> $DIR/range_traits-1.rs:14:5
+  --> $DIR/range_traits-1.rs:26:5
    |
 LL |     d: RangeFull,
    |     ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull`
@@ -35,7 +35,7 @@ LL |     d: RangeFull,
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
 error[E0277]: can't compare `std::ops::RangeInclusive<usize>` with `std::ops::RangeInclusive<usize>`
-  --> $DIR/range_traits-1.rs:17:5
+  --> $DIR/range_traits-1.rs:33:5
    |
 LL |     e: RangeInclusive<usize>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive<usize> < std::ops::RangeInclusive<usize>` and `std::ops::RangeInclusive<usize> > std::ops::RangeInclusive<usize>`
@@ -44,7 +44,223 @@ LL |     e: RangeInclusive<usize>,
    = note: required by `std::cmp::PartialOrd::partial_cmp`
 
 error[E0277]: can't compare `std::ops::RangeToInclusive<usize>` with `std::ops::RangeToInclusive<usize>`
-  --> $DIR/range_traits-1.rs:20:5
+  --> $DIR/range_traits-1.rs:40:5
+   |
+LL |     f: RangeToInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive<usize> < std::ops::RangeToInclusive<usize>` and `std::ops::RangeToInclusive<usize> > std::ops::RangeToInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::Range<usize>` with `std::ops::Range<usize>`
+  --> $DIR/range_traits-1.rs:5:5
+   |
+LL |     a: Range<usize>,
+   |     ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range<usize> < std::ops::Range<usize>` and `std::ops::Range<usize> > std::ops::Range<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeTo<usize>` with `std::ops::RangeTo<usize>`
+  --> $DIR/range_traits-1.rs:12:5
+   |
+LL |     b: RangeTo<usize>,
+   |     ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo<usize> < std::ops::RangeTo<usize>` and `std::ops::RangeTo<usize> > std::ops::RangeTo<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFrom<usize>` with `std::ops::RangeFrom<usize>`
+  --> $DIR/range_traits-1.rs:19:5
+   |
+LL |     c: RangeFrom<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom<usize> < std::ops::RangeFrom<usize>` and `std::ops::RangeFrom<usize> > std::ops::RangeFrom<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull`
+  --> $DIR/range_traits-1.rs:26:5
+   |
+LL |     d: RangeFull,
+   |     ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeInclusive<usize>` with `std::ops::RangeInclusive<usize>`
+  --> $DIR/range_traits-1.rs:33:5
+   |
+LL |     e: RangeInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive<usize> < std::ops::RangeInclusive<usize>` and `std::ops::RangeInclusive<usize> > std::ops::RangeInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeToInclusive<usize>` with `std::ops::RangeToInclusive<usize>`
+  --> $DIR/range_traits-1.rs:40:5
+   |
+LL |     f: RangeToInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive<usize> < std::ops::RangeToInclusive<usize>` and `std::ops::RangeToInclusive<usize> > std::ops::RangeToInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::Range<usize>` with `std::ops::Range<usize>`
+  --> $DIR/range_traits-1.rs:5:5
+   |
+LL |     a: Range<usize>,
+   |     ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range<usize> < std::ops::Range<usize>` and `std::ops::Range<usize> > std::ops::Range<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeTo<usize>` with `std::ops::RangeTo<usize>`
+  --> $DIR/range_traits-1.rs:12:5
+   |
+LL |     b: RangeTo<usize>,
+   |     ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo<usize> < std::ops::RangeTo<usize>` and `std::ops::RangeTo<usize> > std::ops::RangeTo<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFrom<usize>` with `std::ops::RangeFrom<usize>`
+  --> $DIR/range_traits-1.rs:19:5
+   |
+LL |     c: RangeFrom<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom<usize> < std::ops::RangeFrom<usize>` and `std::ops::RangeFrom<usize> > std::ops::RangeFrom<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull`
+  --> $DIR/range_traits-1.rs:26:5
+   |
+LL |     d: RangeFull,
+   |     ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeInclusive<usize>` with `std::ops::RangeInclusive<usize>`
+  --> $DIR/range_traits-1.rs:33:5
+   |
+LL |     e: RangeInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive<usize> < std::ops::RangeInclusive<usize>` and `std::ops::RangeInclusive<usize> > std::ops::RangeInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeToInclusive<usize>` with `std::ops::RangeToInclusive<usize>`
+  --> $DIR/range_traits-1.rs:40:5
+   |
+LL |     f: RangeToInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive<usize> < std::ops::RangeToInclusive<usize>` and `std::ops::RangeToInclusive<usize> > std::ops::RangeToInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::Range<usize>` with `std::ops::Range<usize>`
+  --> $DIR/range_traits-1.rs:5:5
+   |
+LL |     a: Range<usize>,
+   |     ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range<usize> < std::ops::Range<usize>` and `std::ops::Range<usize> > std::ops::Range<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeTo<usize>` with `std::ops::RangeTo<usize>`
+  --> $DIR/range_traits-1.rs:12:5
+   |
+LL |     b: RangeTo<usize>,
+   |     ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo<usize> < std::ops::RangeTo<usize>` and `std::ops::RangeTo<usize> > std::ops::RangeTo<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFrom<usize>` with `std::ops::RangeFrom<usize>`
+  --> $DIR/range_traits-1.rs:19:5
+   |
+LL |     c: RangeFrom<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom<usize> < std::ops::RangeFrom<usize>` and `std::ops::RangeFrom<usize> > std::ops::RangeFrom<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull`
+  --> $DIR/range_traits-1.rs:26:5
+   |
+LL |     d: RangeFull,
+   |     ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeInclusive<usize>` with `std::ops::RangeInclusive<usize>`
+  --> $DIR/range_traits-1.rs:33:5
+   |
+LL |     e: RangeInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive<usize> < std::ops::RangeInclusive<usize>` and `std::ops::RangeInclusive<usize> > std::ops::RangeInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeToInclusive<usize>` with `std::ops::RangeToInclusive<usize>`
+  --> $DIR/range_traits-1.rs:40:5
+   |
+LL |     f: RangeToInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive<usize> < std::ops::RangeToInclusive<usize>` and `std::ops::RangeToInclusive<usize> > std::ops::RangeToInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::Range<usize>` with `std::ops::Range<usize>`
+  --> $DIR/range_traits-1.rs:5:5
+   |
+LL |     a: Range<usize>,
+   |     ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range<usize> < std::ops::Range<usize>` and `std::ops::Range<usize> > std::ops::Range<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeTo<usize>` with `std::ops::RangeTo<usize>`
+  --> $DIR/range_traits-1.rs:12:5
+   |
+LL |     b: RangeTo<usize>,
+   |     ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo<usize> < std::ops::RangeTo<usize>` and `std::ops::RangeTo<usize> > std::ops::RangeTo<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFrom<usize>` with `std::ops::RangeFrom<usize>`
+  --> $DIR/range_traits-1.rs:19:5
+   |
+LL |     c: RangeFrom<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom<usize> < std::ops::RangeFrom<usize>` and `std::ops::RangeFrom<usize> > std::ops::RangeFrom<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull`
+  --> $DIR/range_traits-1.rs:26:5
+   |
+LL |     d: RangeFull,
+   |     ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeInclusive<usize>` with `std::ops::RangeInclusive<usize>`
+  --> $DIR/range_traits-1.rs:33:5
+   |
+LL |     e: RangeInclusive<usize>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive<usize> < std::ops::RangeInclusive<usize>` and `std::ops::RangeInclusive<usize> > std::ops::RangeInclusive<usize>`
+   |
+   = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive<usize>`
+   = note: required by `std::cmp::PartialOrd::partial_cmp`
+
+error[E0277]: can't compare `std::ops::RangeToInclusive<usize>` with `std::ops::RangeToInclusive<usize>`
+  --> $DIR/range_traits-1.rs:40:5
    |
 LL |     f: RangeToInclusive<usize>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive<usize> < std::ops::RangeToInclusive<usize>` and `std::ops::RangeToInclusive<usize> > std::ops::RangeToInclusive<usize>`
@@ -61,7 +277,7 @@ LL |     a: Range<usize>,
    = note: required by `std::cmp::Ord::cmp`
 
 error[E0277]: the trait bound `std::ops::RangeTo<usize>: std::cmp::Ord` is not satisfied
-  --> $DIR/range_traits-1.rs:8:5
+  --> $DIR/range_traits-1.rs:12:5
    |
 LL |     b: RangeTo<usize>,
    |     ^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeTo<usize>`
@@ -69,7 +285,7 @@ LL |     b: RangeTo<usize>,
    = note: required by `std::cmp::Ord::cmp`
 
 error[E0277]: the trait bound `std::ops::RangeFrom<usize>: std::cmp::Ord` is not satisfied
-  --> $DIR/range_traits-1.rs:11:5
+  --> $DIR/range_traits-1.rs:19:5
    |
 LL |     c: RangeFrom<usize>,
    |     ^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeFrom<usize>`
@@ -77,7 +293,7 @@ LL |     c: RangeFrom<usize>,
    = note: required by `std::cmp::Ord::cmp`
 
 error[E0277]: the trait bound `std::ops::RangeFull: std::cmp::Ord` is not satisfied
-  --> $DIR/range_traits-1.rs:14:5
+  --> $DIR/range_traits-1.rs:26:5
    |
 LL |     d: RangeFull,
    |     ^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeFull`
@@ -85,7 +301,7 @@ LL |     d: RangeFull,
    = note: required by `std::cmp::Ord::cmp`
 
 error[E0277]: the trait bound `std::ops::RangeInclusive<usize>: std::cmp::Ord` is not satisfied
-  --> $DIR/range_traits-1.rs:17:5
+  --> $DIR/range_traits-1.rs:33:5
    |
 LL |     e: RangeInclusive<usize>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeInclusive<usize>`
@@ -93,13 +309,13 @@ LL |     e: RangeInclusive<usize>,
    = note: required by `std::cmp::Ord::cmp`
 
 error[E0277]: the trait bound `std::ops::RangeToInclusive<usize>: std::cmp::Ord` is not satisfied
-  --> $DIR/range_traits-1.rs:20:5
+  --> $DIR/range_traits-1.rs:40:5
    |
 LL |     f: RangeToInclusive<usize>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeToInclusive<usize>`
    |
    = note: required by `std::cmp::Ord::cmp`
 
-error: aborting due to 12 previous errors
+error: aborting due to 36 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 609c8ce2792c5bfa905e4ca808e7eda6157e0437..2921a2bb398c39ea189173b7b07e9ee0a4e944d3 100644 (file)
@@ -21,6 +21,7 @@ fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
         //~| ERROR the parameter type `T` may not live long enough
         //~| ERROR the parameter type `T` may not live long enough
         //~| ERROR the parameter type `T` may not live long enough
+        //~| ERROR the parameter type `T` may not live long enough
 }
 
 fn main() {}
index 01975d40fdf1f4b0c3b292deb99aa8209a87223f..7c530cec7c31af24f9c70d2b7e798eb69e431c69 100644 (file)
@@ -88,6 +88,21 @@ note: ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
 LL |     box B(&*v) as Box<X>
    |           ^^^
 
-error: aborting due to 6 previous errors
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:17:11
+   |
+LL | fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
+   |          - help: consider adding an explicit lifetime bound `T: 'static`...
+LL |     // oh dear!
+LL |     box B(&*v) as Box<X>
+   |           ^^^
+   |
+note: ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+  --> $DIR/regions-close-object-into-object-5.rs:17:11
+   |
+LL |     box B(&*v) as Box<X>
+   |           ^^^
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0310`.
index e94e8b25d65299616bbadf7c8ba5d6319182b604..e912805d855d2b57a370a6f6bfda5d6c0599c728 100644 (file)
@@ -20,6 +20,8 @@ fn foo<'a: 'b, 'b>()
 
 // Here we get an error: we need `'a: 'b`.
 fn bar<'a, 'b>() //~ ERROR cannot infer
+                 //~| ERROR cannot infer
+                 //~| ERROR cannot infer
     where <() as Project<'a, 'b>>::Item : Eq
 {
 }
index 8a600d2a1e6955166e78ccdf17a3f424abbf2790..cc2245f81ace5cef8c1d57e6533fa70a1c4cec17 100644 (file)
@@ -2,6 +2,8 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
    |
 LL | / fn bar<'a, 'b>()
+LL | |
+LL | |
 LL | |     where <() as Project<'a, 'b>>::Item : Eq
 LL | | {
 LL | | }
@@ -21,6 +23,8 @@ note: ...so that the types are compatible
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
    |
 LL | / fn bar<'a, 'b>()
+LL | |
+LL | |
 LL | |     where <() as Project<'a, 'b>>::Item : Eq
 LL | | {
 LL | | }
@@ -28,6 +32,74 @@ LL | | }
    = note: expected  `Project<'a, 'b>`
               found  `Project<'_, '_>`
 
-error: aborting due to previous error
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+   |
+LL | / fn bar<'a, 'b>()
+LL | |
+LL | |
+LL | |     where <() as Project<'a, 'b>>::Item : Eq
+LL | | {
+LL | | }
+   | |_^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:8
+   |
+LL | fn bar<'a, 'b>()
+   |        ^^
+note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:12
+   |
+LL | fn bar<'a, 'b>()
+   |            ^^
+note: ...so that the types are compatible
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+   |
+LL | / fn bar<'a, 'b>()
+LL | |
+LL | |
+LL | |     where <() as Project<'a, 'b>>::Item : Eq
+LL | | {
+LL | | }
+   | |_^
+   = note: expected  `Project<'a, 'b>`
+              found  `Project<'_, '_>`
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+   |
+LL | / fn bar<'a, 'b>()
+LL | |
+LL | |
+LL | |     where <() as Project<'a, 'b>>::Item : Eq
+LL | | {
+LL | | }
+   | |_^
+   |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:8
+   |
+LL | fn bar<'a, 'b>()
+   |        ^^
+note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:12
+   |
+LL | fn bar<'a, 'b>()
+   |            ^^
+note: ...so that the types are compatible
+  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+   |
+LL | / fn bar<'a, 'b>()
+LL | |
+LL | |
+LL | |     where <() as Project<'a, 'b>>::Item : Eq
+LL | | {
+LL | | }
+   | |_^
+   = note: expected  `Project<'a, 'b>`
+              found  `Project<'_, '_>`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0495`.
index 2e1d9a2d32691e33a339ec91fc5cc2aabc23d31b..59ca22e9728c6a857c6e676587b9b19bba1200ec 100644 (file)
@@ -3,9 +3,11 @@
 #![allow(dead_code)]
 
 #[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
+                 //~| ERROR incorrect `repr(align)` attribute format
 struct A(u64);
 
 #[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
+                   //~| ERROR incorrect `repr(align)` attribute format
 struct B(u64);
 
 fn main() {}
index b8f7c15ded695042ee86c7dfcfbb425c08dd1cab..6b7799297e89ec20bbb47ea78d2020afc8e029df 100644 (file)
@@ -3,9 +3,11 @@
 #![allow(dead_code)]
 
 #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format
+                 //~| ERROR incorrect `repr(align)` attribute format
 struct A(u64);
 
 #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format
+                   //~| ERROR incorrect `repr(align)` attribute format
 struct B(u64);
 
 fn main() {}
index 177bd81e8f265aa8f6bd3e277fcad79ab5a3fcfd..192312d165bc856477668e2f1c286c9d25793fdb 100644 (file)
@@ -5,10 +5,22 @@ LL | #[repr(align=8)]
    |        ^^^^^^^ help: use parentheses instead: `align(8)`
 
 error[E0693]: incorrect `repr(align)` attribute format
-  --> $DIR/repr-align-assign.rs:8:8
+  --> $DIR/repr-align-assign.rs:9:8
    |
 LL | #[repr(align="8")]
    |        ^^^^^^^^^ help: use parentheses instead: `align(8)`
 
-error: aborting due to 2 previous errors
+error[E0693]: incorrect `repr(align)` attribute format
+  --> $DIR/repr-align-assign.rs:5:8
+   |
+LL | #[repr(align=8)]
+   |        ^^^^^^^ help: use parentheses instead: `align(8)`
+
+error[E0693]: incorrect `repr(align)` attribute format
+  --> $DIR/repr-align-assign.rs:9:8
+   |
+LL | #[repr(align="8")]
+   |        ^^^^^^^^^ help: use parentheses instead: `align(8)`
+
+error: aborting due to 4 previous errors
 
index bc6a9fe562a6790289f279a36c01d2f628bef3c7..58ecf9a518327a0d056e2682a1d80b885a2b9b02 100644 (file)
@@ -1,24 +1,30 @@
 #![allow(dead_code)]
 
 #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
+                     //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
 struct S0(i32);
 
 #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
+                   //~| ERROR: invalid `repr(align)` attribute: not a power of two
 struct S1(i32);
 
 #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29
+                           //~| ERROR: invalid `repr(align)` attribute: larger than 2^29
 struct S2(i32);
 
 #[repr(align(536870912))] // ok: this is the largest accepted alignment
 struct S3(i32);
 
 #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
+                     //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
 enum E0 { A, B }
 
 #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
+                   //~| ERROR: invalid `repr(align)` attribute: not a power of two
 enum E1 { A, B }
 
 #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29
+                           //~| ERROR: invalid `repr(align)` attribute: larger than 2^29
 enum E2 { A, B }
 
 #[repr(align(536870912))] // ok: this is the largest accepted alignment
index 280cab2b4a144fed2ff097ec02ac54bbb4a09d50..900a811bb8ad7a8a725a78c6eae101e68b181274 100644 (file)
@@ -5,35 +5,71 @@ LL | #[repr(align(16.0))]
    |        ^^^^^^^^^^^
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:6:8
+  --> $DIR/repr-align.rs:7:8
    |
 LL | #[repr(align(15))]
    |        ^^^^^^^^^
 
 error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:9:8
+  --> $DIR/repr-align.rs:11:8
    |
 LL | #[repr(align(4294967296))]
    |        ^^^^^^^^^^^^^^^^^
 
 error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
-  --> $DIR/repr-align.rs:15:8
+  --> $DIR/repr-align.rs:18:8
+   |
+LL | #[repr(align(16.0))]
+   |        ^^^^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: not a power of two
+  --> $DIR/repr-align.rs:22:8
+   |
+LL | #[repr(align(15))]
+   |        ^^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: larger than 2^29
+  --> $DIR/repr-align.rs:26:8
+   |
+LL | #[repr(align(4294967296))]
+   |        ^^^^^^^^^^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
+  --> $DIR/repr-align.rs:3:8
    |
 LL | #[repr(align(16.0))]
    |        ^^^^^^^^^^^
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
+  --> $DIR/repr-align.rs:7:8
+   |
+LL | #[repr(align(15))]
+   |        ^^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: larger than 2^29
+  --> $DIR/repr-align.rs:11:8
+   |
+LL | #[repr(align(4294967296))]
+   |        ^^^^^^^^^^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
   --> $DIR/repr-align.rs:18:8
    |
+LL | #[repr(align(16.0))]
+   |        ^^^^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: not a power of two
+  --> $DIR/repr-align.rs:22:8
+   |
 LL | #[repr(align(15))]
    |        ^^^^^^^^^
 
 error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:21:8
+  --> $DIR/repr-align.rs:26:8
    |
 LL | #[repr(align(4294967296))]
    |        ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0589`.
index a6f47162568816ac1e035c9b03e7df3528764d22..6a98782a9badf07a7490b1113c168a894a7c5b15 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 const MAX_ITEM: usize = 10;
 
 fn foo_bar() {}
index 8d8f3f35211e29f6919e7ce3352ca9a92a32bef6..a622d6cb34948c62ec14cc50c90d7581fb1abf7b 100644 (file)
@@ -1,11 +1,11 @@
 error[E0412]: cannot find type `esize` in this scope
-  --> $DIR/levenshtein.rs:5:11
+  --> $DIR/levenshtein.rs:9:11
    |
 LL | fn foo(c: esize) {} // Misspelled primitive type name.
    |           ^^^^^ help: a builtin type with a similar name exists: `isize`
 
 error[E0412]: cannot find type `Baz` in this scope
-  --> $DIR/levenshtein.rs:10:10
+  --> $DIR/levenshtein.rs:14:10
    |
 LL | enum Bar { }
    | ------------ similarly named enum `Bar` defined here
@@ -14,19 +14,24 @@ LL | type A = Baz; // Misspelled type name.
    |          ^^^ help: an enum with a similar name exists: `Bar`
 
 error[E0412]: cannot find type `Opiton` in this scope
-  --> $DIR/levenshtein.rs:12:10
+  --> $DIR/levenshtein.rs:16:10
    |
 LL | type B = Opiton<u8>; // Misspelled type name from the prelude.
    |          ^^^^^^ help: an enum with a similar name exists: `Option`
+   | 
+  ::: $SRC_DIR/libcore/option.rs:LL:COL
+   |
+LL | pub enum Option<T> {
+   | ------------------ similarly named enum `Option` defined here
 
 error[E0412]: cannot find type `Baz` in this scope
-  --> $DIR/levenshtein.rs:16:14
+  --> $DIR/levenshtein.rs:20:14
    |
 LL |     type A = Baz; // No suggestion here, Bar is not visible
    |              ^^^ not found in this scope
 
 error[E0425]: cannot find value `MAXITEM` in this scope
-  --> $DIR/levenshtein.rs:24:20
+  --> $DIR/levenshtein.rs:28:20
    |
 LL | const MAX_ITEM: usize = 10;
    | --------------------------- similarly named constant `MAX_ITEM` defined here
@@ -35,7 +40,7 @@ LL |     let v = [0u32; MAXITEM]; // Misspelled constant name.
    |                    ^^^^^^^ help: a constant with a similar name exists: `MAX_ITEM`
 
 error[E0425]: cannot find function `foobar` in this scope
-  --> $DIR/levenshtein.rs:26:5
+  --> $DIR/levenshtein.rs:30:5
    |
 LL | fn foo_bar() {}
    | --------------- similarly named function `foo_bar` defined here
@@ -44,7 +49,7 @@ LL |     foobar(); // Misspelled function name.
    |     ^^^^^^ help: a function with a similar name exists: `foo_bar`
 
 error[E0412]: cannot find type `first` in module `m`
-  --> $DIR/levenshtein.rs:28:15
+  --> $DIR/levenshtein.rs:32:15
    |
 LL |     pub struct First;
    |     ----------------- similarly named struct `First` defined here
@@ -53,7 +58,7 @@ LL |     let b: m::first = m::second; // Misspelled item in module.
    |               ^^^^^ help: a struct with a similar name exists (notice the capitalization): `First`
 
 error[E0425]: cannot find value `second` in module `m`
-  --> $DIR/levenshtein.rs:28:26
+  --> $DIR/levenshtein.rs:32:26
    |
 LL |     pub struct Second;
    |     ------------------ similarly named unit struct `Second` defined here
diff --git a/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
new file mode 100644 (file)
index 0000000..be13076
--- /dev/null
@@ -0,0 +1,38 @@
+// run-pass
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(option_expect_none, option_unwrap_none)]
+
+//! Test that panic locations for `#[track_caller]` functions in std have the correct
+//! location reported.
+
+fn main() {
+    // inspect the `PanicInfo` we receive to ensure the right file is the source
+    std::panic::set_hook(Box::new(|info| {
+        let actual = info.location().unwrap();
+        if actual.file() != file!() {
+            eprintln!("expected a location in the test file, found {:?}", actual);
+            panic!();
+        }
+    }));
+
+    fn assert_panicked(f: impl FnOnce() + std::panic::UnwindSafe) {
+        std::panic::catch_unwind(f).unwrap_err();
+    }
+
+    let nope: Option<()> = None;
+    assert_panicked(|| nope.unwrap());
+    assert_panicked(|| nope.expect(""));
+
+    let yep: Option<()> = Some(());
+    assert_panicked(|| yep.unwrap_none());
+    assert_panicked(|| yep.expect_none(""));
+
+    let oops: Result<(), ()> = Err(());
+    assert_panicked(|| oops.unwrap());
+    assert_panicked(|| oops.expect(""));
+
+    let fine: Result<(), ()> = Ok(());
+    assert_panicked(|| fine.unwrap_err());
+    assert_panicked(|| fine.expect_err(""));
+}
index 64987663adb90bb3a7d520e82267520d59d18a6f..f5cb1860d4786b6167caae66b3d68bd7ee94015c 100644 (file)
@@ -123,9 +123,11 @@ macro_rules! use_expr {
     use_expr!((let 0 = 1 && 0 == 0));
     //~^ ERROR `let` expressions in this position are experimental [E0658]
     //~| ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
     use_expr!((let 0 = 1));
     //~^ ERROR `let` expressions in this position are experimental [E0658]
     //~| ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
     #[cfg(FALSE)] (let 0 = 1);
     //~^ ERROR `let` expressions in this position are experimental [E0658]
     use_expr!(let 0 = 1);
index abe200944b9696e6cd6d00a7a3fd0cee5b973ae7..c14a45af40bb17192c2a67f7e8b3e6ab7535df8c 100644 (file)
@@ -1,5 +1,5 @@
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:131:15
+  --> $DIR/feature-gate.rs:133:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -260,7 +260,7 @@ LL |     while let Range { start: _, end: _ } = (true..true) && false {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are experimental
-  --> $DIR/feature-gate.rs:129:20
+  --> $DIR/feature-gate.rs:131:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
    |                    ^^^^^^^^^
@@ -287,7 +287,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are experimental
-  --> $DIR/feature-gate.rs:126:16
+  --> $DIR/feature-gate.rs:127:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
@@ -557,7 +557,25 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/feature-gate.rs:126:16
+  --> $DIR/feature-gate.rs:123:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+  --> $DIR/feature-gate.rs:127:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: as well as when nested within `&&` and parenthesis in those conditions
+
+error: `let` expressions are not supported here
+  --> $DIR/feature-gate.rs:127:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
@@ -565,6 +583,6 @@ LL |     use_expr!((let 0 = 1));
    = note: only supported directly in conditions of `if`- and `while`-expressions
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
-error: aborting due to 63 previous errors
+error: aborting due to 65 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
new file mode 100644 (file)
index 0000000..0bf337a
--- /dev/null
@@ -0,0 +1,8 @@
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/feature-gate.rs:11:29
+   |
+LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
+   |                             ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
new file mode 100644 (file)
index 0000000..cf1ed30
--- /dev/null
@@ -0,0 +1,15 @@
+// revisions: stock gated
+// gate-test-const_trait_bound_opt_out
+
+#![cfg_attr(gated, feature(const_trait_bound_opt_out))]
+#![allow(incomplete_features)]
+
+trait T {
+    const CONST: i32;
+}
+
+const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
+//[stock]~^ ERROR `?const` on trait bounds is experimental
+//[stock,gated]~^^ ERROR `?const` on trait bounds is not yet implemented
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
new file mode 100644 (file)
index 0000000..6438800
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0658]: `?const` on trait bounds is experimental
+  --> $DIR/feature-gate.rs:11:29
+   |
+LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
+   |                             ^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67794
+   = help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/feature-gate.rs:11:29
+   |
+LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
+   |                             ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs
new file mode 100644 (file)
index 0000000..e4e6bed
--- /dev/null
@@ -0,0 +1,25 @@
+#![feature(const_trait_bound_opt_out)]
+#![feature(associated_type_bounds)]
+#![allow(incomplete_features)]
+
+trait T {}
+struct S;
+impl T for S {}
+
+fn rpit() -> impl ?const T { S }
+//~^ ERROR `?const` is not permitted in `impl Trait`
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn apit(_: impl ?const T) {}
+//~^ ERROR `?const` is not permitted in `impl Trait`
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
+//~^ ERROR `?const` is not permitted in `impl Trait`
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
+//~^ ERROR `?const` is not permitted in `impl Trait`
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr
new file mode 100644 (file)
index 0000000..f4abd4b
--- /dev/null
@@ -0,0 +1,50 @@
+error: `?const` is not permitted in `impl Trait`
+  --> $DIR/in-impl-trait.rs:9:19
+   |
+LL | fn rpit() -> impl ?const T { S }
+   |                   ^^^^^^^^
+
+error: `?const` is not permitted in `impl Trait`
+  --> $DIR/in-impl-trait.rs:13:17
+   |
+LL | fn apit(_: impl ?const T) {}
+   |                 ^^^^^^^^
+
+error: `?const` is not permitted in `impl Trait`
+  --> $DIR/in-impl-trait.rs:17:50
+   |
+LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
+   |                                                  ^^^^^^^^
+
+error: `?const` is not permitted in `impl Trait`
+  --> $DIR/in-impl-trait.rs:21:48
+   |
+LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
+   |                                                ^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-impl-trait.rs:9:19
+   |
+LL | fn rpit() -> impl ?const T { S }
+   |                   ^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-impl-trait.rs:13:17
+   |
+LL | fn apit(_: impl ?const T) {}
+   |                 ^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-impl-trait.rs:17:50
+   |
+LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
+   |                                                  ^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-impl-trait.rs:21:48
+   |
+LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
+   |                                                ^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs
new file mode 100644 (file)
index 0000000..4523b46
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+trait Super {}
+trait T: ?const Super {}
+//~^ ERROR `?const` is not permitted in supertraits
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr
new file mode 100644 (file)
index 0000000..8003361
--- /dev/null
@@ -0,0 +1,14 @@
+error: `?const` is not permitted in supertraits
+  --> $DIR/in-trait-bounds.rs:5:10
+   |
+LL | trait T: ?const Super {}
+   |          ^^^^^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-trait-bounds.rs:5:10
+   |
+LL | trait T: ?const Super {}
+   |          ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs
new file mode 100644 (file)
index 0000000..6cfca71
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(const_trait_bound_opt_out)]
+#![allow(bare_trait_objects)]
+#![allow(incomplete_features)]
+
+struct S;
+trait T {}
+impl T for S {}
+
+// An inherent impl for the trait object `?const T`.
+impl ?const T {}
+//~^ ERROR `?const` is not permitted in trait objects
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn trait_object() -> &'static dyn ?const T { &S }
+//~^ ERROR `?const` is not permitted in trait objects
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
+//~^ ERROR `?const` is not permitted in trait objects
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr
new file mode 100644 (file)
index 0000000..c059f16
--- /dev/null
@@ -0,0 +1,38 @@
+error: `?const` is not permitted in trait objects
+  --> $DIR/in-trait-object.rs:10:6
+   |
+LL | impl ?const T {}
+   |      ^^^^^^^^
+
+error: `?const` is not permitted in trait objects
+  --> $DIR/in-trait-object.rs:14:35
+   |
+LL | fn trait_object() -> &'static dyn ?const T { &S }
+   |                                   ^^^^^^^^
+
+error: `?const` is not permitted in trait objects
+  --> $DIR/in-trait-object.rs:18:61
+   |
+LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
+   |                                                             ^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-trait-object.rs:10:6
+   |
+LL | impl ?const T {}
+   |      ^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-trait-object.rs:14:35
+   |
+LL | fn trait_object() -> &'static dyn ?const T { &S }
+   |                                   ^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/in-trait-object.rs:18:61
+   |
+LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
+   |                                                             ^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs
new file mode 100644 (file)
index 0000000..01e941a
--- /dev/null
@@ -0,0 +1,8 @@
+// compile-flags: -Z parse-only
+
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+struct S<T: ?const ?const Tr>;
+//~^ ERROR expected identifier, found keyword `const`
+//~| ERROR expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr
new file mode 100644 (file)
index 0000000..f7924b3
--- /dev/null
@@ -0,0 +1,14 @@
+error: expected identifier, found keyword `const`
+  --> $DIR/opt-out-twice.rs:6:21
+   |
+LL | struct S<T: ?const ?const Tr>;
+   |                     ^^^^^ expected identifier, found keyword
+
+error: expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`, found `Tr`
+  --> $DIR/opt-out-twice.rs:6:27
+   |
+LL | struct S<T: ?const ?const Tr>;
+   |                           ^^ expected one of 7 possible tokens
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs
new file mode 100644 (file)
index 0000000..a0d9610
--- /dev/null
@@ -0,0 +1,10 @@
+// compile-flags: -Z parse-only
+// check-pass
+
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+struct S<
+    T: ?const ?for<'a> Tr<'a> + 'static + ?const std::ops::Add,
+    T: ?const ?for<'a: 'b> m::Trait<'a>,
+>;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs
new file mode 100644 (file)
index 0000000..425784f
--- /dev/null
@@ -0,0 +1,8 @@
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
+//~^ ERROR `?const` and `?` are mutually exclusive
+//~| ERROR `?const` on trait bounds is not yet implemented
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr
new file mode 100644 (file)
index 0000000..44f6d46
--- /dev/null
@@ -0,0 +1,14 @@
+error: `?const` and `?` are mutually exclusive
+  --> $DIR/with-maybe-sized.rs:4:13
+   |
+LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
+   |             ^^^^^^^^^^^^^
+
+error: `?const` on trait bounds is not yet implemented
+  --> $DIR/with-maybe-sized.rs:4:13
+   |
+LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
+   |             ^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs
new file mode 100644 (file)
index 0000000..b904a2e
--- /dev/null
@@ -0,0 +1,7 @@
+// compile-flags: -Z parse-only
+
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+
+struct S<T: const Tr>;
+//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr
new file mode 100644 (file)
index 0000000..0dbca95
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path, found keyword `const`
+  --> $DIR/without-question-mark.rs:6:13
+   |
+LL | struct S<T: const Tr>;
+   |             ^^^^^ expected one of 9 possible tokens
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr
new file mode 100644 (file)
index 0000000..b196f9e
--- /dev/null
@@ -0,0 +1,8 @@
+error: const trait impls are not yet implemented
+  --> $DIR/feature-gate.rs:9:1
+   |
+LL | impl const T for S {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs
new file mode 100644 (file)
index 0000000..49b6c09
--- /dev/null
@@ -0,0 +1,13 @@
+// revisions: stock gated
+// gate-test-const_trait_impl
+
+#![cfg_attr(gated, feature(const_trait_impl))]
+#![allow(incomplete_features)]
+
+struct S;
+trait T {}
+impl const T for S {}
+//[stock]~^ ERROR const trait impls are experimental
+//[stock,gated]~^^ ERROR const trait impls are not yet implemented
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr
new file mode 100644 (file)
index 0000000..093946f
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0658]: const trait impls are experimental
+  --> $DIR/feature-gate.rs:9:6
+   |
+LL | impl const T for S {}
+   |      ^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/67792
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
+error: const trait impls are not yet implemented
+  --> $DIR/feature-gate.rs:9:1
+   |
+LL | impl const T for S {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs
new file mode 100644 (file)
index 0000000..98d3a22
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(const_trait_bound_opt_out)]
+#![feature(const_trait_impl)]
+#![allow(incomplete_features)]
+
+struct S;
+trait T {}
+
+impl ?const T for S {}
+//~^ ERROR expected a trait, found type
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr
new file mode 100644 (file)
index 0000000..8f923ef
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected a trait, found type
+  --> $DIR/impl-opt-out-trait.rs:8:6
+   |
+LL | impl ?const T for S {}
+   |      ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs
new file mode 100644 (file)
index 0000000..9cffe75
--- /dev/null
@@ -0,0 +1,14 @@
+// compile-flags: -Z parse-only
+
+#![feature(const_trait_impl)]
+#![feature(const_trait_bound_opt_out)]
+#![allow(incomplete_features)]
+#![allow(bare_trait_objects)]
+
+struct S;
+trait T {}
+
+impl const T {}
+//~^ ERROR `const` cannot modify an inherent impl
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
new file mode 100644 (file)
index 0000000..1d24557
--- /dev/null
@@ -0,0 +1,10 @@
+error: `const` cannot modify an inherent impl
+  --> $DIR/inherent-impl.rs:11:6
+   |
+LL | impl const T {}
+   |      ^^^^^
+   |
+   = help: only a trait impl can be `const`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/syntax.rs
new file mode 100644 (file)
index 0000000..354d48d
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: -Z parse-only
+// check-pass
+
+#![feature(const_trait_bound_opt_out)]
+#![feature(const_trait_impl)]
+#![allow(incomplete_features)]
+
+// For now, this parses since an error does not occur until AST lowering.
+impl ?const T {}
index b8949ae8b500f3c25e42fada39b78ad2ee50a542..e9dcb4f85f60bfa43797e09e2c49a40501f468bd 100644 (file)
@@ -21,6 +21,7 @@ fn main() {
     match WRAP_DIRECT_INLINE {
         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => { println!("WRAP_DIRECT_INLINE did not match itself"); }
     }
 }
index c73a6cf1326b3e3a7401deec42407cebeeb144f8..9c7d1f3a18fecdd5b7f10747c0993cd91d0d5b91 100644 (file)
@@ -4,5 +4,11 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann
 LL |         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
    |         ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9
+   |
+LL |         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
index 584e7a00f0993339f42c09b510c531685443b63e..ab1cb3babaa25bd41f86c923879d22ddb35e29ea 100644 (file)
@@ -21,6 +21,7 @@ fn main() {
     match WRAP_DIRECT_PARAM {
         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => { println!("WRAP_DIRECT_PARAM did not match itself"); }
     }
 }
index 6fdf9db89b8dc4a74c007e6089bbe434394a39eb..6f49a8a0c9d212b036e7dbaa3eaefd657e8d6c73 100644 (file)
@@ -4,5 +4,11 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann
 LL |         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
    |         ^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9
+   |
+LL |         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
index 1cca27520618d531e7ce2f964320e1c3f9ad1162..59141eac3e896037a62afb2bfb0b37e142bd9a41 100644 (file)
@@ -12,6 +12,7 @@ fn main() {
     match y {
         FOO => { }
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => { }
     }
 
index c05bb8f19f362bafbaad9ef7574572d796b81193..b9476e399f3e7beb7c6e6e622fb17ee180b123bf 100644 (file)
@@ -5,7 +5,7 @@ LL |         FOO => { }
    |         ^^^
 
 warning: floating-point types cannot be used in patterns
-  --> $DIR/match-forbidden-without-eq.rs:20:9
+  --> $DIR/match-forbidden-without-eq.rs:21:9
    |
 LL |         f32::INFINITY => { }
    |         ^^^^^^^^^^^^^
@@ -14,8 +14,14 @@ LL |         f32::INFINITY => { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/match-forbidden-without-eq.rs:13:9
+   |
+LL |         FOO => { }
+   |         ^^^
+
 warning: floating-point types cannot be used in patterns
-  --> $DIR/match-forbidden-without-eq.rs:20:9
+  --> $DIR/match-forbidden-without-eq.rs:21:9
    |
 LL |         f32::INFINITY => { }
    |         ^^^^^^^^^^^^^
@@ -23,5 +29,5 @@ LL |         f32::INFINITY => { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
index 3d56fb05dc460ab3214b82424617ffc20fe4c94d..9ef8a68da80b9223c3ed90619e9155e51627e026 100644 (file)
@@ -15,5 +15,6 @@ fn main() {
     match [B(1)] {
         FOO => { }
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]`
     }
 }
index 371f8a0aa1d7745e6e47ed08873335bbe4a1d9ed..7e354bf9ade5aaed886f73c6249a9da3a69a7d83 100644 (file)
@@ -4,5 +4,11 @@ error: to use a constant of type `B` in a pattern, `B` must be annotated with `#
 LL |         FOO => { }
    |         ^^^
 
-error: aborting due to previous error
+error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9
+   |
+LL |         FOO => { }
+   |         ^^^
+
+error: aborting due to 2 previous errors
 
index 6b7d94603b567d889aff97f257d49b29d09c257c..9530a1ffec453ff3e5bc550896e40fb460b0dbb2 100644 (file)
@@ -16,6 +16,7 @@ fn main() {
     match y {
         FOO => { }
         //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => { }
     }
 }
index 4157cf65283e3d24ae23c88e23d5c9b9692f0716..7ef082852ba8d159e7bee051a54a7b7fa3c4f5b1 100644 (file)
@@ -4,5 +4,11 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit
 LL |         FOO => { }
    |         ^^^
 
-error: aborting due to previous error
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9
+   |
+LL |         FOO => { }
+   |         ^^^
+
+error: aborting due to 2 previous errors
 
index 27d6dbf4683e31530fd6799be160f00735238bc8..0ca7fa37a3096b547b45315107ea3de653b3c8d6 100644 (file)
@@ -6,6 +6,7 @@
 
 #[built_in_attr] //~ ERROR cannot use a built-in attribute through an import
 #[tool_mod::skip] //~ ERROR cannot use a tool module through an import
+                  //~| ERROR cannot use a tool module through an import
 fn main() {
     let _: built_in_type; // OK
 }
index fdde75faf5f0421fda0dc874f80174547b849093..45f77a0c9fe6a1972a84fa656a51eb15e9cbde8b 100644 (file)
@@ -22,5 +22,17 @@ note: the tool module imported here
 LL | use cross_crate::*;
    |     ^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: cannot use a tool module through an import
+  --> $DIR/cross-crate.rs:8:3
+   |
+LL | #[tool_mod::skip]
+   |   ^^^^^^^^
+   |
+note: the tool module imported here
+  --> $DIR/cross-crate.rs:5:5
+   |
+LL | use cross_crate::*;
+   |     ^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
index 541fc1be4e82f7920973868c25f9adeffaa35ba0..44da71de085be0d480dcab4591df10ab58230da6 100644 (file)
@@ -15,5 +15,7 @@ mod tool_mod {
 #[imported_inline] //~ ERROR cannot use a built-in attribute through an import
 #[builtin::imported_inline] //~ ERROR cannot use a built-in attribute through an import
 #[imported_rustfmt::skip] //~ ERROR cannot use a tool module through an import
+                          //~| ERROR cannot use a tool module through an import
 #[tool_mod::imported_rustfmt::skip] //~ ERROR cannot use a tool module through an import
+                                    //~| ERROR cannot use a tool module through an import
 fn main() {}
index fc6453193bc98ab3cd6bd09fa469390999d3a335..908bb498586131373fedff79731e1a4ddc2bf843 100644 (file)
@@ -29,7 +29,7 @@ LL | use rustfmt as imported_rustfmt;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot use a tool module through an import
-  --> $DIR/prelude-fail-2.rs:18:13
+  --> $DIR/prelude-fail-2.rs:19:13
    |
 LL | #[tool_mod::imported_rustfmt::skip]
    |             ^^^^^^^^^^^^^^^^
@@ -40,5 +40,29 @@ note: the tool module imported here
 LL |     pub use rustfmt as imported_rustfmt;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: cannot use a tool module through an import
+  --> $DIR/prelude-fail-2.rs:17:3
+   |
+LL | #[imported_rustfmt::skip]
+   |   ^^^^^^^^^^^^^^^^
+   |
+note: the tool module imported here
+  --> $DIR/prelude-fail-2.rs:10:5
+   |
+LL | use rustfmt as imported_rustfmt;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot use a tool module through an import
+  --> $DIR/prelude-fail-2.rs:19:13
+   |
+LL | #[tool_mod::imported_rustfmt::skip]
+   |             ^^^^^^^^^^^^^^^^
+   |
+note: the tool module imported here
+  --> $DIR/prelude-fail-2.rs:12:13
+   |
+LL |     pub use rustfmt as imported_rustfmt;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
index dec5809f1539bd8be297cdb7f2bbc38bf3f7a891..96401cb71d961efd64be50a3ad5db3d5059650f1 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `A` in the current scope
+error[E0599]: no method named `foo` found for struct `A` in the current scope
   --> $DIR/point-at-arbitrary-self-type-method.rs:8:7
    |
 LL | struct A;
index e93c4da9dfc85145735429a4aa9c5da0ecab9efd..28a7b68a6821f9c4a5f390bf2db1037b09305a3f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `A` in the current scope
+error[E0599]: no method named `foo` found for struct `A` in the current scope
   --> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7
    |
 LL | trait B { fn foo(self: Box<Self>); }
index d6bf543352701befc89fd10daca01e6bf4eb9281..1e001827e475feda512e1bdc6607132519610389 100644 (file)
@@ -18,7 +18,7 @@ fn foo(&self) {
         //~^ ERROR cannot find function `bar` in this scope
 
         self.bar();
-        //~^ ERROR no method named `bar` found for type
+        //~^ ERROR no method named `bar` found for reference
     }
 }
 
index 452c31275153a88a4fe6a62bc0a0c4f005fb0ea7..4bd025ea0763091d5cdb91d7a60512c6f7c48731 100644 (file)
@@ -28,7 +28,7 @@ error[E0425]: cannot find function `bar` in this scope
 LL |         bar();
    |         ^^^ not found in this scope
 
-error[E0599]: no method named `bar` found for type `&Foo` in the current scope
+error[E0599]: no method named `bar` found for reference `&Foo` in the current scope
   --> $DIR/suggest-self-2.rs:20:14
    |
 LL |         self.bar();
index 3597cc53420aa82e5bf63d18fb44e5a79876a7c4..362907ecbd7efeed96f65fef82aace80c04b7c0f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `f` found for type `()` in the current scope
+error[E0599]: no method named `f` found for unit type `()` in the current scope
   --> $DIR/shadowed-trait-methods.rs:13:8
    |
 LL |     ().f()
index 8f1599a5abcb0fbf98e965e8cf84dcff70d9f108..89b8eba1e95e77b8b5cb841ba53b38abb90ff6bb 100644 (file)
@@ -5,6 +5,9 @@
 //~| ERROR cannot determine resolution for the derive macro `Debug`
 //~| ERROR cannot determine resolution for the derive macro `PartialEq`
 //~| ERROR cannot determine resolution for the derive macro `Eq`
+//~| ERROR cannot determine resolution for the derive macro `Debug`
+//~| ERROR cannot determine resolution for the derive macro `PartialEq`
+//~| ERROR cannot determine resolution for the derive macro `Eq`
 struct DerivedOn;
 
 fn main() {}
index 47ce718600cec90510b39f79ced49b3464557edf..b68681c52973a9159e7dc304abb4a22d2879767a 100644 (file)
@@ -28,5 +28,29 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
    |
    = note: import resolution is stuck, try simplifying macro imports
 
-error: aborting due to 4 previous errors
+error: cannot determine resolution for the derive macro `Eq`
+  --> $DIR/issue-43927-non-ADT-derive.rs:3:29
+   |
+LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+   |                             ^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the derive macro `PartialEq`
+  --> $DIR/issue-43927-non-ADT-derive.rs:3:18
+   |
+LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+   |                  ^^^^^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the derive macro `Debug`
+  --> $DIR/issue-43927-non-ADT-derive.rs:3:11
+   |
+LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+   |           ^^^^^
+   |
+   = note: import resolution is stuck, try simplifying macro imports
+
+error: aborting due to 7 previous errors
 
index ea0a66540b93125888be4906a7f0d4c5b12fa7a4..eddd158aef0817d800679f6443fd4e11d14f7544 100644 (file)
@@ -60,15 +60,15 @@ impl ManyImplTrait for Myisize {}
 
 fn no_param_bound(u: usize, m: Myisize) -> usize {
     u.f8(42) + u.f9(342) + m.fff(42)
-            //~^ ERROR no method named `f9` found for type `usize` in the current scope
-            //~| ERROR no method named `fff` found for type `Myisize` in the current scope
+            //~^ ERROR no method named `f9` found
+            //~| ERROR no method named `fff` found
 
 
 }
 
 fn param_bound<T: ManyImplTrait>(t: T) -> bool {
     t.is_str()
-    //~^ ERROR no method named `is_str` found for type `T` in the current scope
+    //~^ ERROR no method named `is_str` found
 }
 
 fn main() {
index 53a6238422b571217f1b1a854f438540d0e6b031..eb85be039ba04a44b4d7ad005c0c1ddfff17efda 100644 (file)
@@ -38,7 +38,7 @@ help: disambiguate the method call for candidate #3
 LL |     u.f8(42) + UnusedTrait::f9(u, 342) + m.fff(42)
    |                ^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0599]: no method named `fff` found for type `Myisize` in the current scope
+error[E0599]: no method named `fff` found for struct `Myisize` in the current scope
   --> $DIR/issue-7575.rs:62:30
    |
 LL | struct Myisize(isize);
@@ -57,7 +57,7 @@ note: the candidate is defined in an impl for the type `Myisize`
 LL |     fn fff(i: isize) -> isize {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0599]: no method named `is_str` found for type `T` in the current scope
+error[E0599]: no method named `is_str` found for type parameter `T` in the current scope
   --> $DIR/issue-7575.rs:70:7
    |
 LL |     t.is_str()
index 34a141685739cfffa6607165c8e0405d66b2e407..5c104449fe9c0b4ce69b3a4c7515010f54c3bff9 100644 (file)
@@ -20,5 +20,5 @@ fn foo_one(&self) -> &'static str {
 
 fn main() {
     println!("{}", MyStruct.foo_one());
-    //~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope
+    //~^ ERROR no method named `foo_one` found
 }
index bbfe4c3d59dcf15e4e5cb4f372e1e8dfc9c257b4..19809778a5e360dac1f8cabe0b8c8bb51d5f6387 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo_one` found for type `MyStruct` in the current scope
+error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope
   --> $DIR/specialization-trait-not-implemented.rs:22:29
    |
 LL | struct MyStruct;
index a6531490c015914091f13b6423d65a64611090a5..c3a4eabad705021fa1f29554788035ae08b9cfbb 100644 (file)
@@ -1,15 +1,27 @@
 #![feature(rustc_attrs)]
 
 #[rustc_dummy = 1usize] //~ ERROR: suffixed literals are not allowed in attributes
+                        //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u8] //~ ERROR: suffixed literals are not allowed in attributes
+                     //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u16] //~ ERROR: suffixed literals are not allowed in attributes
+                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u32] //~ ERROR: suffixed literals are not allowed in attributes
+                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u64] //~ ERROR: suffixed literals are not allowed in attributes
+                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1isize] //~ ERROR: suffixed literals are not allowed in attributes
+                        //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i8] //~ ERROR: suffixed literals are not allowed in attributes
+                     //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i16] //~ ERROR: suffixed literals are not allowed in attributes
+                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i32] //~ ERROR: suffixed literals are not allowed in attributes
+                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i64] //~ ERROR: suffixed literals are not allowed in attributes
+                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes
+                        //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes
+                        //~| ERROR: suffixed literals are not allowed in attributes
 fn main() {}
index 83de173b1a703a4e553c0b160022108436947e73..ee35b53abe1113da8ee68a4cb1533080735d3f58 100644 (file)
@@ -7,7 +7,7 @@ LL | #[rustc_dummy = 1usize]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:4:17
+  --> $DIR/suffixed-literal-meta.rs:5:17
    |
 LL | #[rustc_dummy = 1u8]
    |                 ^^^
@@ -15,7 +15,7 @@ LL | #[rustc_dummy = 1u8]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:5:17
+  --> $DIR/suffixed-literal-meta.rs:7:17
    |
 LL | #[rustc_dummy = 1u16]
    |                 ^^^^
@@ -23,7 +23,7 @@ LL | #[rustc_dummy = 1u16]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:6:17
+  --> $DIR/suffixed-literal-meta.rs:9:17
    |
 LL | #[rustc_dummy = 1u32]
    |                 ^^^^
@@ -31,7 +31,7 @@ LL | #[rustc_dummy = 1u32]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:7:17
+  --> $DIR/suffixed-literal-meta.rs:11:17
    |
 LL | #[rustc_dummy = 1u64]
    |                 ^^^^
@@ -39,7 +39,7 @@ LL | #[rustc_dummy = 1u64]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:8:17
+  --> $DIR/suffixed-literal-meta.rs:13:17
    |
 LL | #[rustc_dummy = 1isize]
    |                 ^^^^^^
@@ -47,7 +47,7 @@ LL | #[rustc_dummy = 1isize]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:9:17
+  --> $DIR/suffixed-literal-meta.rs:15:17
    |
 LL | #[rustc_dummy = 1i8]
    |                 ^^^
@@ -55,7 +55,7 @@ LL | #[rustc_dummy = 1i8]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:10:17
+  --> $DIR/suffixed-literal-meta.rs:17:17
    |
 LL | #[rustc_dummy = 1i16]
    |                 ^^^^
@@ -63,7 +63,7 @@ LL | #[rustc_dummy = 1i16]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:11:17
+  --> $DIR/suffixed-literal-meta.rs:19:17
    |
 LL | #[rustc_dummy = 1i32]
    |                 ^^^^
@@ -71,28 +71,124 @@ LL | #[rustc_dummy = 1i32]
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:12:17
+  --> $DIR/suffixed-literal-meta.rs:21:17
    |
 LL | #[rustc_dummy = 1i64]
    |                 ^^^^
    |
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:23:17
+   |
+LL | #[rustc_dummy = 1.0f32]
+   |                 ^^^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:25:17
+   |
+LL | #[rustc_dummy = 1.0f64]
+   |                 ^^^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:3:17
+   |
+LL | #[rustc_dummy = 1usize]
+   |                 ^^^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:5:17
+   |
+LL | #[rustc_dummy = 1u8]
+   |                 ^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:7:17
+   |
+LL | #[rustc_dummy = 1u16]
+   |                 ^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:9:17
+   |
+LL | #[rustc_dummy = 1u32]
+   |                 ^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:11:17
+   |
+LL | #[rustc_dummy = 1u64]
+   |                 ^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
 error: suffixed literals are not allowed in attributes
   --> $DIR/suffixed-literal-meta.rs:13:17
    |
+LL | #[rustc_dummy = 1isize]
+   |                 ^^^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:15:17
+   |
+LL | #[rustc_dummy = 1i8]
+   |                 ^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:17:17
+   |
+LL | #[rustc_dummy = 1i16]
+   |                 ^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:19:17
+   |
+LL | #[rustc_dummy = 1i32]
+   |                 ^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:21:17
+   |
+LL | #[rustc_dummy = 1i64]
+   |                 ^^^^
+   |
+   = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
+
+error: suffixed literals are not allowed in attributes
+  --> $DIR/suffixed-literal-meta.rs:23:17
+   |
 LL | #[rustc_dummy = 1.0f32]
    |                 ^^^^^^
    |
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:14:17
+  --> $DIR/suffixed-literal-meta.rs:25:17
    |
 LL | #[rustc_dummy = 1.0f64]
    |                 ^^^^^^
    |
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
-error: aborting due to 12 previous errors
+error: aborting due to 24 previous errors
 
index 7c8231bbb24f80e8359fe11364e2ade19c44be91..e1e3317093a3191f9de7a12e898edb31693f7618 100644 (file)
@@ -1,3 +1,7 @@
+// FIXME: missing sysroot spans (#53081)
+// ignore-i586-unknown-linux-gnu
+// ignore-i586-unknown-linux-musl
+// ignore-i686-unknown-linux-musl
 #[deprcated] //~ ERROR cannot find attribute `deprcated` in this scope
 fn foo() {}
 
index e40329382fd409c7c73fd9e402fa126391a121cf..a0943592539af90689edc6574ebeadcdbaa148c2 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: attributes starting with `rustc` are reserved for use by the `rustc` compiler
-  --> $DIR/attribute-typos.rs:7:3
+  --> $DIR/attribute-typos.rs:11:3
    |
 LL | #[rustc_err]
    |   ^^^^^^^^^
@@ -8,19 +8,24 @@ LL | #[rustc_err]
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
 error: cannot find attribute `rustc_err` in this scope
-  --> $DIR/attribute-typos.rs:7:3
+  --> $DIR/attribute-typos.rs:11:3
    |
 LL | #[rustc_err]
    |   ^^^^^^^^^ help: a built-in attribute with a similar name exists: `rustc_error`
 
 error: cannot find attribute `tests` in this scope
-  --> $DIR/attribute-typos.rs:4:3
+  --> $DIR/attribute-typos.rs:8:3
    |
 LL | #[tests]
    |   ^^^^^ help: an attribute macro with a similar name exists: `test`
+   | 
+  ::: $SRC_DIR/libcore/macros/mod.rs:LL:COL
+   |
+LL |     pub macro test($item:item) {
+   |     -------------------------- similarly named attribute macro `test` defined here
 
 error: cannot find attribute `deprcated` in this scope
-  --> $DIR/attribute-typos.rs:1:3
+  --> $DIR/attribute-typos.rs:5:3
    |
 LL | #[deprcated]
    |   ^^^^^^^^^ help: a built-in attribute with a similar name exists: `deprecated`
index dda9e931353b21be902616f225b67f3c112c7bfa..f292f27f0f342b312a73681fb5ec6049c5009d43 100644 (file)
@@ -12,13 +12,13 @@ trait GetString {
 
 trait UseString: std::fmt::Debug + GetString {
     fn use_string(&self) {
-        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found
     }
 }
 
 trait UseString2: GetString {
     fn use_string(&self) {
-        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found
     }
 }
 
index 4ef0eff5bd7699b1417319c8b4c72ce203759043..99ccf7a7f3bdf712cf43b19f7c3576ed493318ad 100644 (file)
@@ -12,13 +12,13 @@ trait GetString {
 
 trait UseString: std::fmt::Debug {
     fn use_string(&self) {
-        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found
     }
 }
 
 trait UseString2 {
     fn use_string(&self) {
-        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found
     }
 }
 
index 3cc351ac80aed245af906e9420278697274feeb1..f1c50e59a845eaacd7e633765c0d2c320cacec4f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `get_a` found for type `&Self` in the current scope
+error[E0599]: no method named `get_a` found for reference `&Self` in the current scope
   --> $DIR/constrain-trait.rs:15:31
    |
 LL |         println!("{:?}", self.get_a());
@@ -10,7 +10,7 @@ help: the following trait defines an item `get_a`, perhaps you need to add anoth
 LL | trait UseString: std::fmt::Debug + GetString {
    |                                  ^^^^^^^^^^^
 
-error[E0599]: no method named `get_a` found for type `&Self` in the current scope
+error[E0599]: no method named `get_a` found for reference `&Self` in the current scope
   --> $DIR/constrain-trait.rs:21:31
    |
 LL |         println!("{:?}", self.get_a());
index 2f0a457a795946d49ba39dc72ec8a8eb0b295ac2..232e54b5d37b24e2b2bb90e73dfd46ca6e14c4bf 100644 (file)
@@ -236,7 +236,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:46:20
    |
 LL |     let closure = || 42;
-   |                   -- closure defined here
+   |                   ----- the found closure
 LL |     let _: usize = closure;
    |            -----   ^^^^^^^
    |            |       |
index 4aec72006eef03c36312150841e369bb60ff1350..db54d044d9e9264721834ad6f6a7dfd467b5ec55 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `hello` found for type `impl Foo` in the current scope
+error[E0599]: no method named `hello` found for type parameter `impl Foo` in the current scope
   --> $DIR/impl-trait-with-missing-trait-bounds-in-arg.rs:15:9
    |
 LL |     foo.hello();
index f2496f696d698294614be3a36aafc4620e714eb7..14c7b18ea51d36569afceba86ddff3ffb33d27d7 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `method` found for type `&T` in the current scope
+error[E0599]: no method named `method` found for reference `&T` in the current scope
   --> $DIR/issue-21673.rs:6:7
    |
 LL |     x.method()
@@ -10,7 +10,7 @@ help: the following trait defines an item `method`, perhaps you need to restrict
 LL | fn call_method<T: Foo + std::fmt::Debug>(x: &T) {
    |                ^^^^^^^^
 
-error[E0599]: no method named `method` found for type `T` in the current scope
+error[E0599]: no method named `method` found for type parameter `T` in the current scope
   --> $DIR/issue-21673.rs:10:7
    |
 LL |     x.method()
diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs
new file mode 100644 (file)
index 0000000..440bb65
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let a_longer_variable_name = 1;
+    println!("{}", a_variable_longer_name); //~ ERROR E0425
+}
diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr
new file mode 100644 (file)
index 0000000..d7b33ea
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `a_variable_longer_name` in this scope
+  --> $DIR/issue-66968-suggest-sorted-words.rs:3:20
+   |
+LL |     println!("{}", a_variable_longer_name);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `a_longer_variable_name`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
index dcef2ada63beac30a15d76f58ef2f085acf908b2..f8b86377187c589077d3ac33468f0cdae6ce5ce8 100644 (file)
@@ -19,5 +19,5 @@ fn main() {
     //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
     //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
 
-    writeln!(fp, "hello world").unwrap(); //~ ERROR no method named `write_fmt` found for type
+    writeln!(fp, "hello world").unwrap(); //~ ERROR no method named `write_fmt` found for struct
 }
index daa8e1162d197a54187ab4c548351cff66f93928..2c3c07c19e7bd87d5ceeab9d79d5d2943b7692dc 100644 (file)
@@ -25,7 +25,7 @@ LL |     let fp = BufWriter::new(fp);
    = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
    = note: required by `std::io::BufWriter`
 
-error[E0599]: no method named `write_fmt` found for type `std::io::BufWriter<&dyn std::io::Write>` in the current scope
+error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<&dyn std::io::Write>` in the current scope
   --> $DIR/mut-borrow-needed-by-trait.rs:22:5
    |
 LL |     writeln!(fp, "hello world").unwrap();
index 1465b9e49ef1aba38880a2fc2c77dbe2cc2fb9f1..167d61bdf7c704f176d8097b567b78dff3d61272 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/opaque-type-error.rs:20:9
    |
+LL |   fn thing_two() -> impl Future<Output = Result<(), ()>> {
+   |                     ------------------------------------ the found opaque type
+...
 LL | /     if true {
 LL | |         thing_one()
    | |         ----------- expected because of this
index d10300b48ba1e8c81810ef01dfffe2cdf9f8c4ac..289a784ba6af35129a3a2450838a087bb68ee23e 100644 (file)
@@ -1,21 +1,21 @@
 fn foo1(s: &str) {
     s.as_str();
-    //~^ ERROR no method named `as_str` found for type `&str` in the current scope
+    //~^ ERROR no method named `as_str` found
 }
 
 fn foo2<'a>(s: &'a str) {
     s.as_str();
-    //~^ ERROR no method named `as_str` found for type `&'a str` in the current scope
+    //~^ ERROR no method named `as_str` found
 }
 
 fn foo3(s: &mut str) {
     s.as_str();
-    //~^ ERROR no method named `as_str` found for type `&mut str` in the current scope
+    //~^ ERROR no method named `as_str` found
 }
 
 fn foo4(s: &&str) {
     s.as_str();
-    //~^ ERROR no method named `as_str` found for type `&&str` in the current scope
+    //~^ ERROR no method named `as_str` found
 }
 
 fn main() {}
index eae9cc075084a683c6b87d208b181bf2a9d3dab8..534c497780a95e959982113289f50a128fcc8629 100644 (file)
@@ -1,22 +1,22 @@
-error[E0599]: no method named `as_str` found for type `&str` in the current scope
+error[E0599]: no method named `as_str` found for reference `&str` in the current scope
   --> $DIR/remove-as_str.rs:2:7
    |
 LL |     s.as_str();
    |      -^^^^^^-- help: remove this method call
 
-error[E0599]: no method named `as_str` found for type `&'a str` in the current scope
+error[E0599]: no method named `as_str` found for reference `&'a str` in the current scope
   --> $DIR/remove-as_str.rs:7:7
    |
 LL |     s.as_str();
    |      -^^^^^^-- help: remove this method call
 
-error[E0599]: no method named `as_str` found for type `&mut str` in the current scope
+error[E0599]: no method named `as_str` found for mutable reference `&mut str` in the current scope
   --> $DIR/remove-as_str.rs:12:7
    |
 LL |     s.as_str();
    |      -^^^^^^-- help: remove this method call
 
-error[E0599]: no method named `as_str` found for type `&&str` in the current scope
+error[E0599]: no method named `as_str` found for reference `&&str` in the current scope
   --> $DIR/remove-as_str.rs:17:7
    |
 LL |     s.as_str();
index 5480adb31015a360e0b26cd35b8434a1105360f5..f738a1f2119811885144198c617f9e2defd8145a 100644 (file)
@@ -9,5 +9,5 @@ fn main() {
     let shared_state = RefCell::new(HasAssocMethod);
     let state = shared_state.borrow_mut();
     state.hello();
-    //~^ ERROR no method named `hello` found for type `std::cell::RefMut<'_, HasAssocMethod>`
+    //~^ ERROR no method named `hello` found
 }
index a1c0126146e73278a2f3942db88d02ef1a1cde84..507f822e7b8048a11227bad4ec664f0e1d8c3ef2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `hello` found for type `std::cell::RefMut<'_, HasAssocMethod>` in the current scope
+error[E0599]: no method named `hello` found for struct `std::cell::RefMut<'_, HasAssocMethod>` in the current scope
   --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11
    |
 LL |     state.hello();
index ef4b38de9473272d78c489e6349319622673832e..2a829db538390e6178c170477bf08b498018b022 100644 (file)
@@ -7,5 +7,5 @@ fn default_hello() {}
 fn main() {
     let x = GenericAssocMethod(33i32);
     x.default_hello();
-    //~^ ERROR no method named `default_hello` found for type `GenericAssocMethod<i32>`
+    //~^ ERROR no method named `default_hello` found
 }
index 8cfa7de08bb38f163ecc4c47a1e86280b2aa6fa4..dfc1887d3af90d4796c4168507684f4d6d171bde 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `default_hello` found for type `GenericAssocMethod<i32>` in the current scope
+error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod<i32>` in the current scope
   --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:9:7
    |
 LL | struct GenericAssocMethod<T>(T);
index 4678410eb48599b33ea3c4e8b266de11e4db9569..a715c565946e041ca5ff7926b0180415f498f51e 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `bat` found for type `Foo` in the current scope
+error[E0599]: no method named `bat` found for struct `Foo` in the current scope
   --> $DIR/suggest-methods.rs:18:7
    |
 LL | struct Foo;
@@ -7,7 +7,7 @@ LL | struct Foo;
 LL |     f.bat(1.0);
    |       ^^^ help: there is a method with a similar name: `bar`
 
-error[E0599]: no method named `is_emtpy` found for type `std::string::String` in the current scope
+error[E0599]: no method named `is_emtpy` found for struct `std::string::String` in the current scope
   --> $DIR/suggest-methods.rs:21:15
    |
 LL |     let _ = s.is_emtpy();
index d418834432e0844e15183c03703d97b8877b0538..dd05d0f04abe3c0ffe2e1e6e2848592574c62c05 100644 (file)
@@ -9,9 +9,9 @@ struct S {
 }
 
 fn main() {
-    println!("My shape is {:?}", Shape::Squareee { size: 5});  //~ ERROR no variant `Squareee`
-    println!("My shape is {:?}", Shape::Circl { size: 5}); //~ ERROR no variant `Circl`
-    println!("My shape is {:?}", Shape::Rombus{ size: 5}); //~ ERROR no variant `Rombus`
+    println!("My shape is {:?}", Shape::Squareee { size: 5});  //~ ERROR no variant named `Squareee`
+    println!("My shape is {:?}", Shape::Circl { size: 5}); //~ ERROR no variant named `Circl`
+    println!("My shape is {:?}", Shape::Rombus{ size: 5}); //~ ERROR no variant named `Rombus`
     Shape::Squareee; //~ ERROR no variant
     Shape::Circl; //~ ERROR no variant
     Shape::Rombus; //~ ERROR no variant
index b4338e2055431f74c9a3370704e9b067c9b9196b..9227baa3e1a5c2d689f991dcb804485c05a69519 100644 (file)
@@ -1,4 +1,4 @@
-error: no variant `Squareee` in enum `Shape`
+error[E0599]: no variant named `Squareee` found for enum `Shape`
   --> $DIR/suggest-variants.rs:12:41
    |
 LL | enum Shape {
@@ -7,7 +7,7 @@ LL | enum Shape {
 LL |     println!("My shape is {:?}", Shape::Squareee { size: 5});
    |                                         ^^^^^^^^ help: there is a variant with a similar name: `Square`
 
-error: no variant `Circl` in enum `Shape`
+error[E0599]: no variant named `Circl` found for enum `Shape`
   --> $DIR/suggest-variants.rs:13:41
    |
 LL | enum Shape {
@@ -16,7 +16,7 @@ LL | enum Shape {
 LL |     println!("My shape is {:?}", Shape::Circl { size: 5});
    |                                         ^^^^^ help: there is a variant with a similar name: `Circle`
 
-error: no variant `Rombus` in enum `Shape`
+error[E0599]: no variant named `Rombus` found for enum `Shape`
   --> $DIR/suggest-variants.rs:14:41
    |
 LL | enum Shape {
@@ -25,7 +25,7 @@ LL | enum Shape {
 LL |     println!("My shape is {:?}", Shape::Rombus{ size: 5});
    |                                         ^^^^^^ variant not found in `Shape`
 
-error[E0599]: no variant or associated item named `Squareee` found for type `Shape` in the current scope
+error[E0599]: no variant or associated item named `Squareee` found for enum `Shape` in the current scope
   --> $DIR/suggest-variants.rs:15:12
    |
 LL | enum Shape {
@@ -37,7 +37,7 @@ LL |     Shape::Squareee;
    |            variant or associated item not found in `Shape`
    |            help: there is a variant with a similar name: `Square`
 
-error[E0599]: no variant or associated item named `Circl` found for type `Shape` in the current scope
+error[E0599]: no variant or associated item named `Circl` found for enum `Shape` in the current scope
   --> $DIR/suggest-variants.rs:16:12
    |
 LL | enum Shape {
@@ -49,7 +49,7 @@ LL |     Shape::Circl;
    |            variant or associated item not found in `Shape`
    |            help: there is a variant with a similar name: `Circle`
 
-error[E0599]: no variant or associated item named `Rombus` found for type `Shape` in the current scope
+error[E0599]: no variant or associated item named `Rombus` found for enum `Shape` in the current scope
   --> $DIR/suggest-variants.rs:17:12
    |
 LL | enum Shape {
index 53ab2f9878f3041cd51c0ee08584e29f5ee80495..affb5537b18564a307344eade4dc84d3fbbaa367 100644 (file)
@@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h92c563325b7ff21aE)
+error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17hf07584432cd4d8beE)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h92c563325b7ff21a)
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::hf07584432cd4d8be)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
index d5698be8d4c573de06f6deb123d4648daa39d640..bf45ba2ed82279fd1dd3d8d1cdc0437b2bf96ac2 100644 (file)
@@ -2,6 +2,7 @@
 type B = rustfmt::skip; //~ ERROR expected type, found tool attribute `rustfmt::skip`
 
 #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
+                   //~| ERROR cannot find derive macro `rustfmt` in this scope
 struct S;
 
 // Interpreted as an unstable custom attribute
index b831e624cb6ff4403bf69fc047169f75edace6fe..71fd5f1d44a8d35586c86a8fa83121b6a36d2549 100644 (file)
@@ -4,14 +4,20 @@ error: cannot find derive macro `rustfmt` in this scope
 LL | #[derive(rustfmt)]
    |          ^^^^^^^
 
+error: cannot find derive macro `rustfmt` in this scope
+  --> $DIR/tool-attributes-misplaced-1.rs:4:10
+   |
+LL | #[derive(rustfmt)]
+   |          ^^^^^^^
+
 error: cannot find attribute `rustfmt` in this scope
-  --> $DIR/tool-attributes-misplaced-1.rs:8:3
+  --> $DIR/tool-attributes-misplaced-1.rs:9:3
    |
 LL | #[rustfmt]
    |   ^^^^^^^
 
 error: cannot find macro `rustfmt` in this scope
-  --> $DIR/tool-attributes-misplaced-1.rs:14:5
+  --> $DIR/tool-attributes-misplaced-1.rs:15:5
    |
 LL |     rustfmt!();
    |     ^^^^^^^
@@ -29,18 +35,18 @@ LL | type B = rustfmt::skip;
    |          ^^^^^^^^^^^^^ not a type
 
 error[E0423]: expected value, found tool module `rustfmt`
-  --> $DIR/tool-attributes-misplaced-1.rs:13:5
+  --> $DIR/tool-attributes-misplaced-1.rs:14:5
    |
 LL |     rustfmt;
    |     ^^^^^^^ not a value
 
 error[E0423]: expected value, found tool attribute `rustfmt::skip`
-  --> $DIR/tool-attributes-misplaced-1.rs:16:5
+  --> $DIR/tool-attributes-misplaced-1.rs:17:5
    |
 LL |     rustfmt::skip;
    |     ^^^^^^^^^^^^^ not a value
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0423, E0573.
 For more information about an error, try `rustc --explain E0423`.
index fa8f041c646c27547ca726ecbfd085a2fe8fddd8..9c8540eede7922b353d94145298126d29279d697 100644 (file)
@@ -1,3 +1,5 @@
 #[warn(foo::bar)]
 //~^ ERROR an unknown tool name found in scoped lint: `foo::bar`
+//~| ERROR an unknown tool name found in scoped lint: `foo::bar`
+//~| ERROR an unknown tool name found in scoped lint: `foo::bar`
 fn main() {}
index de941604a94913c6af8da8f52a9f94ab143a29a2..86f87784eaf866133a151a45e40c64910c17d07e 100644 (file)
@@ -4,5 +4,17 @@ error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
 LL | #[warn(foo::bar)]
    |        ^^^
 
-error: aborting due to previous error
+error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
+  --> $DIR/tool_lints.rs:1:8
+   |
+LL | #[warn(foo::bar)]
+   |        ^^^
+
+error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
+  --> $DIR/tool_lints.rs:1:8
+   |
+LL | #[warn(foo::bar)]
+   |        ^^^
+
+error: aborting due to 3 previous errors
 
index 43b822218354fafa4def2fff1cf7d350c18ecb1a..d22ac72d1cc4d48ad6f165cb045394b58f4e7323 100644 (file)
@@ -12,5 +12,5 @@ impl T for i32 {}
 
 fn main() {
     let x = &42i32;
-    x.foo(); //~ERROR: no method named `foo` found for type `&i32` in the current scope
+    x.foo(); //~ERROR: no method named `foo` found
 }
index 0d61c3ed00d909e3ddd1788b91d741c83133ea48..da0936e8eebdc55268630907bdf05c97f8a75c43 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for type `&i32` in the current scope
+error[E0599]: no method named `foo` found for reference `&i32` in the current scope
   --> $DIR/trait-impl-1.rs:15:7
    |
 LL |     x.foo();
index d58bbef38c492ba238c8b94c751ca919d5a1a44c..8507d8ef17e3649c9204b442b9d7a253b0440c07 100644 (file)
@@ -64,8 +64,8 @@ fn check_method() {
 
     // Methods, method call
     // a, b, c are resolved as trait items, their traits need to be in scope
-    S.a(); //~ ERROR no method named `a` found for type `S` in the current scope
-    S.b(); //~ ERROR no method named `b` found for type `S` in the current scope
+    S.a(); //~ ERROR no method named `a` found
+    S.b(); //~ ERROR no method named `b` found
     S.c(); // OK
     // a, b, c are resolved as inherent items, their traits don't need to be in scope
     let c = &S as &dyn C;
@@ -76,9 +76,9 @@ fn check_method() {
     // Methods, UFCS
     // a, b, c are resolved as trait items, their traits need to be in scope
     S::a(&S);
-    //~^ ERROR no function or associated item named `a` found for type `S`
+    //~^ ERROR no function or associated item named `a` found
     S::b(&S);
-    //~^ ERROR no function or associated item named `b` found for type `S`
+    //~^ ERROR no function or associated item named `b` found
     S::c(&S); // OK
     // a, b, c are resolved as inherent items, their traits don't need to be in scope
     C::a(&S); //~ ERROR method `a` is private
@@ -94,8 +94,8 @@ fn check_assoc_const() {
 
     // Associated constants
     // A, B, C are resolved as trait items, their traits need to be in scope
-    S::A; //~ ERROR no associated item named `A` found for type `S` in the current scope
-    S::B; //~ ERROR no associated item named `B` found for type `S` in the current scope
+    S::A; //~ ERROR no associated item named `A` found
+    S::B; //~ ERROR no associated item named `B` found
     S::C; // OK
     // A, B, C are resolved as inherent items, their traits don't need to be in scope
     C::A; //~ ERROR associated constant `A` is private
index 64a92c6b0b47860536d6d30ad45ad0a761d59a69..4df8845de279ae2042639aeede55455783ab14fa 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `a` found for type `S` in the current scope
+error[E0599]: no method named `a` found for struct `S` in the current scope
   --> $DIR/trait-item-privacy.rs:67:7
    |
 LL | struct S;
@@ -11,7 +11,7 @@ LL |     S.a();
    = note: the following trait defines an item `a`, perhaps you need to implement it:
            candidate #1: `method::A`
 
-error[E0599]: no method named `b` found for type `S` in the current scope
+error[E0599]: no method named `b` found for struct `S` in the current scope
   --> $DIR/trait-item-privacy.rs:68:7
    |
 LL | struct S;
@@ -39,7 +39,7 @@ error[E0624]: method `a` is private
 LL |     c.a();
    |       ^
 
-error[E0599]: no function or associated item named `a` found for type `S` in the current scope
+error[E0599]: no function or associated item named `a` found for struct `S` in the current scope
   --> $DIR/trait-item-privacy.rs:78:8
    |
 LL | struct S;
@@ -52,7 +52,7 @@ LL |     S::a(&S);
    = note: the following trait defines an item `a`, perhaps you need to implement it:
            candidate #1: `method::A`
 
-error[E0599]: no function or associated item named `b` found for type `S` in the current scope
+error[E0599]: no function or associated item named `b` found for struct `S` in the current scope
   --> $DIR/trait-item-privacy.rs:80:8
    |
 LL | struct S;
@@ -73,7 +73,7 @@ error[E0624]: method `a` is private
 LL |     C::a(&S);
    |     ^^^^
 
-error[E0599]: no associated item named `A` found for type `S` in the current scope
+error[E0599]: no associated item named `A` found for struct `S` in the current scope
   --> $DIR/trait-item-privacy.rs:97:8
    |
 LL | struct S;
@@ -86,7 +86,7 @@ LL |     S::A;
    = note: the following trait defines an item `A`, perhaps you need to implement it:
            candidate #1: `assoc_const::A`
 
-error[E0599]: no associated item named `B` found for type `S` in the current scope
+error[E0599]: no associated item named `B` found for struct `S` in the current scope
   --> $DIR/trait-item-privacy.rs:98:8
    |
 LL | struct S;
index fc0f78b12c9f7fe6f668518d0eaa9577f600cf14..2b2a2c127e9859e6ef1712b7bbb9a6b88d672acb 100644 (file)
@@ -9,6 +9,7 @@ macro_rules! define_struct {
 
 mod foo {
     define_struct! { (foo) } //~ ERROR cannot find type `foo` in this scope
+                             //~| ERROR cannot find type `foo` in this scope
 }
 
 fn main() {}
index d924c351439bd91749108bc8634598674eee7789..2f1ca2fe0c1e74c0db3e798c356e2b85db0970ef 100644 (file)
@@ -15,6 +15,12 @@ error[E0412]: cannot find type `foo` in this scope
 LL |     define_struct! { (foo) }
    |                       ^^^ not found in this scope
 
-error: aborting due to 2 previous errors
+error[E0412]: cannot find type `foo` in this scope
+  --> $DIR/test2.rs:11:23
+   |
+LL |     define_struct! { (foo) }
+   |                       ^^^ not found in this scope
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0412`.
index 6b8534b452411eb5bdd42f900f8e17b9fb4a4867..98d19426e7733b6c7e1d6f999f299468fd69d46f 100644 (file)
@@ -9,6 +9,7 @@ macro_rules! define_struct {
 
 mod foo {
     define_struct! { foo } //~ ERROR cannot find type `foo` in this scope
+                           //~| ERROR cannot find type `foo` in this scope
 }
 
 fn main() {}
index 50cac6c179e31a29fa9f8fd22cbcac3e5f7262a3..5d42fe6ef50b3884e1ec6229d30d7f73de7dda48 100644 (file)
@@ -15,6 +15,12 @@ error[E0412]: cannot find type `foo` in this scope
 LL |     define_struct! { foo }
    |                      ^^^ not found in this scope
 
-error: aborting due to 2 previous errors
+error[E0412]: cannot find type `foo` in this scope
+  --> $DIR/test3.rs:11:22
+   |
+LL |     define_struct! { foo }
+   |                      ^^^ not found in this scope
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0412`.
index dc41cbc5fe3f8d5634f1a134e5eb3c4bbb3eba3b..9549074d4bf78d73650b511c95330ed9624b43cb 100644 (file)
@@ -11,6 +11,9 @@ LL |     let z: i32 = x;
    |            ---   ^ expected `i32`, found opaque type
    |            |
    |            expected due to this
+...
+LL | type WrongGeneric<T> = impl 'static;
+   | ------------------------------------ the found opaque type
    |
    = note:     expected type `i32`
            found opaque type `WrongGeneric::<&{integer}>`
index 24d23de797690362f04e644e93886271972936a0..5a7f9d74eba5b31ef38fb701c781deec6088c83b 100644 (file)
@@ -11,6 +11,9 @@ LL |     let z: i32 = x;
    |            ---   ^ expected `i32`, found opaque type
    |            |
    |            expected due to this
+...
+LL | type WrongGeneric<T> = impl 'static;
+   | ------------------------------------ the found opaque type
    |
    = note:     expected type `i32`
            found opaque type `WrongGeneric::<&{integer}>`
diff --git a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs
new file mode 100644 (file)
index 0000000..c46c471
--- /dev/null
@@ -0,0 +1,16 @@
+// Regression test for issue 67856
+
+#![feature(unboxed_closures)]
+#![feature(type_alias_impl_trait)]
+#![feature(fn_traits)]
+
+trait MyTrait {}
+impl MyTrait for () {}
+
+impl<F> FnOnce<()> for &F {
+    //~^ ERROR conflicting implementations
+    //~| ERROR type parameter `F` must be used
+    type Output = impl MyTrait;
+    extern "rust-call" fn call_once(self, _: ()) -> Self::Output {}
+}
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr
new file mode 100644 (file)
index 0000000..f8e1e55
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0119]: conflicting implementations of trait `std::ops::FnOnce<()>` for type `&_`:
+  --> $DIR/incoherent-assoc-imp-trait.rs:10:1
+   |
+LL | impl<F> FnOnce<()> for &F {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `core`:
+           - impl<A, F> std::ops::FnOnce<A> for &F
+             where F: std::ops::Fn<A>, F: ?Sized;
+
+error[E0210]: type parameter `F` must be used as the type parameter for some local type (e.g., `MyStruct<F>`)
+  --> $DIR/incoherent-assoc-imp-trait.rs:10:6
+   |
+LL | impl<F> FnOnce<()> for &F {
+   |      ^ type parameter `F` must be used as the type parameter for some local type
+   |
+   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0210.
+For more information about an error, try `rustc --explain E0119`.
index 07962e36da1e66905187e1574575389e0e197e85..70c99c944d654d8f142f6c6992274b9f31b7cc45 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/never_reveal_concrete_type.rs:13:27
    |
+LL | type NoReveal = impl std::fmt::Debug;
+   | ------------------------------------- the found opaque type
+...
 LL |     let _: &'static str = x;
    |            ------------   ^ expected `&str`, found opaque type
    |            |
index a2081424ab497d241fa09b07ae46fcad62a62974..375c0bc7fe2ed078985862c3d54fc04778d6887d 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/no_revealing_outside_defining_module.rs:15:19
    |
+LL |     pub type Boo = impl ::std::fmt::Debug;
+   |     -------------------------------------- the found opaque type
+...
 LL |     let _: &str = bomp();
    |            ----   ^^^^^^ expected `&str`, found opaque type
    |            |
@@ -12,6 +15,9 @@ LL |     let _: &str = bomp();
 error[E0308]: mismatched types
   --> $DIR/no_revealing_outside_defining_module.rs:19:5
    |
+LL |     pub type Boo = impl ::std::fmt::Debug;
+   |     -------------------------------------- the expected opaque type
+...
 LL | fn bomp() -> boo::Boo {
    |              -------- expected `Boo` because of return type
 LL |     ""
index 5b0ca2f347ea821af5e3dee5ba0e3bb5ba9da736..adecbd7e5b40ea24cfa447dad7edd77e43ddaaf4 100644 (file)
@@ -1,3 +1,4 @@
+#![feature(type_alias_impl_trait)] // Needed for single test `type Y = impl Trait<_>`
 // This test checks that it is not possible to enable global type
 // inference by using the `_` type placeholder.
 
@@ -42,6 +43,16 @@ fn test10(&self, _x : _) { }
     //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
 }
 
+fn test11(x: &usize) -> &_ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+    &x
+}
+
+unsafe fn test12(x: *const usize) -> *const *const _ {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+    &x
+}
+
 impl Clone for Test9 {
     fn clone(&self) -> _ { Test9 }
     //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
@@ -131,3 +142,37 @@ trait T {
     fn assoc_fn_test3() -> _;
     //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
 }
+
+struct BadStruct<_>(_);
+//~^ ERROR expected identifier, found reserved identifier `_`
+//~| ERROR the type placeholder `_` is not allowed within types on item signatures
+trait BadTrait<_> {}
+//~^ ERROR expected identifier, found reserved identifier `_`
+impl BadTrait<_> for BadStruct<_> {}
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+
+fn impl_trait() -> impl BadTrait<_> {
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+    unimplemented!()
+}
+
+struct BadStruct1<_, _>(_);
+//~^ ERROR expected identifier, found reserved identifier `_`
+//~| ERROR expected identifier, found reserved identifier `_`
+//~| ERROR the name `_` is already used
+//~| ERROR the type placeholder `_` is not allowed within types on item signatures
+struct BadStruct2<_, T>(_, T);
+//~^ ERROR expected identifier, found reserved identifier `_`
+//~| ERROR the type placeholder `_` is not allowed within types on item signatures
+
+type X = Box<_>;
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+
+struct Struct;
+trait Trait<T> {}
+impl Trait<usize> for Struct {}
+type Y = impl Trait<_>;
+//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
+fn foo() -> Y {
+    Struct
+}
index 9fe7af4c822c17eacecb04ccb46c472d56d9fc30..05326a3e07a9324c302cb3563c644dc5a86005ab 100644 (file)
@@ -1,5 +1,43 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/typeck_type_placeholder_item.rs:146:18
+   |
+LL | struct BadStruct<_>(_);
+   |                  ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/typeck_type_placeholder_item.rs:149:16
+   |
+LL | trait BadTrait<_> {}
+   |                ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/typeck_type_placeholder_item.rs:159:19
+   |
+LL | struct BadStruct1<_, _>(_);
+   |                   ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/typeck_type_placeholder_item.rs:159:22
+   |
+LL | struct BadStruct1<_, _>(_);
+   |                      ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/typeck_type_placeholder_item.rs:164:19
+   |
+LL | struct BadStruct2<_, T>(_, T);
+   |                   ^ expected identifier, found reserved identifier
+
+error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters
+  --> $DIR/typeck_type_placeholder_item.rs:159:22
+   |
+LL | struct BadStruct1<_, _>(_);
+   |                   -  ^ already used
+   |                   |
+   |                   first use of `_`
+
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:4:14
+  --> $DIR/typeck_type_placeholder_item.rs:5:14
    |
 LL | fn test() -> _ { 5 }
    |              ^
@@ -8,7 +46,7 @@ LL | 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:7:16
+  --> $DIR/typeck_type_placeholder_item.rs:8:16
    |
 LL | fn test2() -> (_, _) { (5, 5) }
    |               -^--^-
@@ -18,7 +56,7 @@ LL | 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:10:15
+  --> $DIR/typeck_type_placeholder_item.rs:11:15
    |
 LL | static TEST3: _ = "test";
    |               ^
@@ -27,7 +65,7 @@ LL | static TEST3: _ = "test";
    |               help: replace `_` with the correct type: `&'static str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:13:15
+  --> $DIR/typeck_type_placeholder_item.rs:14:15
    |
 LL | static TEST4: _ = 145;
    |               ^
@@ -36,13 +74,13 @@ LL | static 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:16:15
+  --> $DIR/typeck_type_placeholder_item.rs:17:15
    |
 LL | static 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:19:13
+  --> $DIR/typeck_type_placeholder_item.rs:20:13
    |
 LL | fn test6(_: _) { }
    |             ^ not allowed in type signatures
@@ -53,7 +91,7 @@ LL | fn test6<T>(_: T) { }
    |         ^^^    ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:22:18
+  --> $DIR/typeck_type_placeholder_item.rs:23:18
    |
 LL | fn test6_b<T>(_: _, _: T) { }
    |                  ^ not allowed in type signatures
@@ -64,7 +102,7 @@ LL | fn test6_b<T, K>(_: K, _: T) { }
    |             ^^^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:25:30
+  --> $DIR/typeck_type_placeholder_item.rs:26:30
    |
 LL | fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
    |                              ^ not allowed in type signatures
@@ -75,7 +113,7 @@ LL | fn test6_c<T, K, L, A, B, C>(_: C, _: (T, K, L, A, B)) { }
    |                         ^^^     ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:28:13
+  --> $DIR/typeck_type_placeholder_item.rs:29:13
    |
 LL | fn test7(x: _) { let _x: usize = x; }
    |             ^ not allowed in type signatures
@@ -86,13 +124,13 @@ 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:31:22
+  --> $DIR/typeck_type_placeholder_item.rs:32:22
    |
 LL | fn test8(_f: fn() -> _) { }
    |                      ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:31:22
+  --> $DIR/typeck_type_placeholder_item.rs:32:22
    |
 LL | fn test8(_f: fn() -> _) { }
    |                      ^ not allowed in type signatures
@@ -103,7 +141,25 @@ 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:54:8
+  --> $DIR/typeck_type_placeholder_item.rs:46:26
+   |
+LL | fn test11(x: &usize) -> &_ {
+   |                         -^
+   |                         ||
+   |                         |not allowed in type signatures
+   |                         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
+   |
+LL | unsafe fn test12(x: *const usize) -> *const *const _ {
+   |                                      --------------^
+   |                                      |             |
+   |                                      |             not allowed in type signatures
+   |                                      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
    |
 LL |     a: _,
    |        ^ not allowed in type signatures
@@ -122,7 +178,7 @@ LL |     b: (T, T),
    |
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:60:21
+  --> $DIR/typeck_type_placeholder_item.rs:71:21
    |
 LL |     fn fn_test() -> _ { 5 }
    |                     ^
@@ -131,7 +187,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:63:23
+  --> $DIR/typeck_type_placeholder_item.rs:74:23
    |
 LL |     fn fn_test2() -> (_, _) { (5, 5) }
    |                      -^--^-
@@ -141,7 +197,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:66:22
+  --> $DIR/typeck_type_placeholder_item.rs:77:22
    |
 LL |     static FN_TEST3: _ = "test";
    |                      ^
@@ -150,7 +206,7 @@ LL |     static FN_TEST3: _ = "test";
    |                      help: replace `_` with the correct type: `&'static str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:69:22
+  --> $DIR/typeck_type_placeholder_item.rs:80:22
    |
 LL |     static FN_TEST4: _ = 145;
    |                      ^
@@ -159,13 +215,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:72:22
+  --> $DIR/typeck_type_placeholder_item.rs:83: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:75:20
+  --> $DIR/typeck_type_placeholder_item.rs:86:20
    |
 LL |     fn fn_test6(_: _) { }
    |                    ^ not allowed in type signatures
@@ -176,7 +232,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:78:20
+  --> $DIR/typeck_type_placeholder_item.rs:89:20
    |
 LL |     fn fn_test7(x: _) { let _x: usize = x; }
    |                    ^ not allowed in type signatures
@@ -187,13 +243,13 @@ 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:81:29
+  --> $DIR/typeck_type_placeholder_item.rs:92:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
    |                             ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:81:29
+  --> $DIR/typeck_type_placeholder_item.rs:92:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
    |                             ^ not allowed in type signatures
@@ -204,7 +260,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:104:12
+  --> $DIR/typeck_type_placeholder_item.rs:115:12
    |
 LL |         a: _,
    |            ^ not allowed in type signatures
@@ -223,13 +279,13 @@ LL |         b: (T, T),
    |
 
 error[E0282]: type annotations needed
-  --> $DIR/typeck_type_placeholder_item.rs:109:27
+  --> $DIR/typeck_type_placeholder_item.rs:120:27
    |
 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:109:28
+  --> $DIR/typeck_type_placeholder_item.rs:120:28
    |
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                            ^  ^ not allowed in type signatures
@@ -237,7 +293,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:113:30
+  --> $DIR/typeck_type_placeholder_item.rs:124:30
    |
 LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
    |                             -^--^-
@@ -247,7 +303,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:116:33
+  --> $DIR/typeck_type_placeholder_item.rs:127:33
    |
 LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           ------^-
@@ -256,7 +312,76 @@ 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:121:31
+  --> $DIR/typeck_type_placeholder_item.rs:146:21
+   |
+LL | struct BadStruct<_>(_);
+   |                     ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | struct BadStruct<T>(T);
+   |                  ^  ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:151:15
+   |
+LL | impl BadTrait<_> for BadStruct<_> {}
+   |               ^                ^ not allowed in type signatures
+   |               |
+   |               not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+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:154: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:159:25
+   |
+LL | struct BadStruct1<_, _>(_);
+   |                         ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | struct BadStruct1<T, _>(T);
+   |                   ^     ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:164:25
+   |
+LL | struct BadStruct2<_, T>(_, T);
+   |                         ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL | struct BadStruct2<K, T>(K, T);
+   |                   ^     ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:168: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
+   |
+LL |     fn test10(&self, _x : _) { }
+   |                           ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+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:132:31
    |
 LL |     fn method_test1(&self, x: _);
    |                               ^ not allowed in type signatures
@@ -267,7 +392,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:123:31
+  --> $DIR/typeck_type_placeholder_item.rs:134:31
    |
 LL |     fn method_test2(&self, x: _) -> _;
    |                               ^     ^ not allowed in type signatures
@@ -280,7 +405,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:125:31
+  --> $DIR/typeck_type_placeholder_item.rs:136:31
    |
 LL |     fn method_test3(&self) -> _;
    |                               ^ not allowed in type signatures
@@ -291,7 +416,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:127:26
+  --> $DIR/typeck_type_placeholder_item.rs:138:26
    |
 LL |     fn assoc_fn_test1(x: _);
    |                          ^ not allowed in type signatures
@@ -302,7 +427,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:129:26
+  --> $DIR/typeck_type_placeholder_item.rs:140:26
    |
 LL |     fn assoc_fn_test2(x: _) -> _;
    |                          ^     ^ not allowed in type signatures
@@ -315,7 +440,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:131:28
+  --> $DIR/typeck_type_placeholder_item.rs:142:28
    |
 LL |     fn assoc_fn_test3() -> _;
    |                            ^ not allowed in type signatures
@@ -326,47 +451,64 @@ 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:38:24
+  --> $DIR/typeck_type_placeholder_item.rs:60:37
    |
-LL |     fn test9(&self) -> _ { () }
-   |                        ^
-   |                        |
-   |                        not allowed in type signatures
-   |                        help: replace with the correct return type: `()`
+LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
+   |                                     ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+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:41:27
+  --> $DIR/typeck_type_placeholder_item.rs:102:34
    |
-LL |     fn test10(&self, _x : _) { }
-   |                           ^ not allowed in type signatures
+LL |         fn fn_test10(&self, _x : _) { }
+   |                                  ^ not allowed in type signatures
    |
 help: use type parameters instead
    |
-LL |     fn test10<T>(&self, _x : T) { }
-   |              ^^^             ^
+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:46:24
+  --> $DIR/typeck_type_placeholder_item.rs:110:41
    |
-LL |     fn clone(&self) -> _ { Test9 }
+LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
+   |                                         ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+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:174: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:39:24
+   |
+LL |     fn test9(&self) -> _ { () }
    |                        ^
    |                        |
    |                        not allowed in type signatures
-   |                        help: replace with the correct return type: `Test9`
+   |                        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:49:37
+  --> $DIR/typeck_type_placeholder_item.rs:57:24
    |
-LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
-   |                                     ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
-   |                  ^^^                   ^
+LL |     fn clone(&self) -> _ { Test9 }
+   |                        ^
+   |                        |
+   |                        not allowed in type signatures
+   |                        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:88:31
+  --> $DIR/typeck_type_placeholder_item.rs:99:31
    |
 LL |         fn fn_test9(&self) -> _ { () }
    |                               ^
@@ -375,18 +517,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:91:34
-   |
-LL |         fn fn_test10(&self, _x : _) { }
-   |                                  ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-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:96:28
+  --> $DIR/typeck_type_placeholder_item.rs:107:28
    |
 LL |         fn clone(&self) -> _ { FnTest9 }
    |                            ^
@@ -394,18 +525,7 @@ LL |         fn clone(&self) -> _ { FnTest9 }
    |                            not allowed in type signatures
    |                            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:99:41
-   |
-LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
-   |                                         ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
-   |                      ^^^                   ^
-
-error: aborting due to 40 previous errors
+error: aborting due to 55 previous errors
 
-Some errors have detailed explanations: E0121, E0282.
+Some errors have detailed explanations: E0121, E0282, E0403.
 For more information about an error, try `rustc --explain E0121`.
index 82a593ff16cfa165f87018dcf7dc2174b72a8eb4..66d4db3ebaf0a6df2feb64d0c437f7ad9b019553 100644 (file)
@@ -35,7 +35,7 @@ fn main() {
     <u8 as A>::N::NN; //~ ERROR cannot find associated type `N` in `A`
     let _: <u8 as Tr>::Y::NN; //~ ERROR ambiguous associated type
     let _: <u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
-    <u8 as Tr>::Y::NN; //~ ERROR no associated item named `NN` found for type `<u8 as Tr>::Y`
+    <u8 as Tr>::Y::NN; //~ ERROR no associated item named `NN` found
     <u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
 
     let _: <u8 as Tr::N>::NN; //~ ERROR cannot find associated type `NN` in `Tr::N`
@@ -52,5 +52,5 @@ fn main() {
     let _: <u8 as Dr>::Z; //~ ERROR expected associated type, found method `Dr::Z`
     <u8 as Dr>::X; //~ ERROR expected method or associated constant, found associated type `Dr::X`
     let _: <u8 as Dr>::Z::N; //~ ERROR expected associated type, found method `Dr::Z`
-    <u8 as Dr>::X::N; //~ ERROR no associated item named `N` found for type `<u8 as Dr>::X`
+    <u8 as Dr>::X::N; //~ ERROR no associated item named `N` found
 }
index dbd41da6daf0b9a59f49bc0bd3180b961324dd05..60ebe8ee053a6a3af905c060d307959a20ec8a29 100644 (file)
@@ -207,13 +207,13 @@ error[E0223]: ambiguous associated type
 LL |     let _: <u8 as Tr>::Y::NN;
    |            ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<u8 as Tr>::Y as Trait>::NN`
 
-error[E0599]: no associated item named `NN` found for type `<u8 as Tr>::Y` in the current scope
+error[E0599]: no associated item named `NN` found for associated type `<u8 as Tr>::Y` in the current scope
   --> $DIR/ufcs-partially-resolved.rs:38:20
    |
 LL |     <u8 as Tr>::Y::NN;
    |                    ^^ associated item not found in `<u8 as Tr>::Y`
 
-error[E0599]: no associated item named `N` found for type `<u8 as Dr>::X` in the current scope
+error[E0599]: no associated item named `N` found for associated type `<u8 as Dr>::X` in the current scope
   --> $DIR/ufcs-partially-resolved.rs:55:20
    |
 LL |     <u8 as Dr>::X::N;
index 18276d5710cf8950f2230dd756ded993b156f366..2d058521e4ef609f84b01d701907043116ac0f49 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `call` found for type `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]` in the current scope
+error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]` in the current scope
   --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
    |
 LL |     mut_.call((0, ));
index 44cfc5cc5d22e21cbb17df7860b34e732f38c667..2983613786038ec12c506d3085c3e29d4392ac3b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `deref` found for type `&()` in the current scope
+error[E0599]: no method named `deref` found for reference `&()` in the current scope
   --> $DIR/hygiene.rs:38:11
    |
 LL |     (&()).deref();
@@ -10,7 +10,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
 LL | use std::ops::Deref;
    |
 
-error[E0599]: no method named `deref_mut` found for type `&mut ()` in the current scope
+error[E0599]: no method named `deref_mut` found for mutable reference `&mut ()` in the current scope
   --> $DIR/hygiene.rs:39:15
    |
 LL |     (&mut ()).deref_mut();
index 102c17f6f5618017da5299e4d963617c54fdd3c3..eb16fa9d5660b49fa5c90344a539ef42afa061e2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `deref` found for type `&()` in the current scope
+error[E0599]: no method named `deref` found for reference `&()` in the current scope
   --> $DIR/shadow.rs:19:11
    |
 LL |         x.deref();
index e7cb248a201acb8d0dffa58ca3a1cee2803d7613..cb2248cc6d18924f30e0b426022095f23af4933d 100644 (file)
@@ -8,6 +8,7 @@ union U {
 fn main() {
     match C {
         C => {} //~ ERROR cannot use unions in constant patterns
+                //~| ERROR cannot use unions in constant patterns
         _ => {}
     }
 }
index dc87f4de5219f445a8f25fabd598bcaab18fb592..bec720401b9e1aa7260ca88f200f397270f5312d 100644 (file)
@@ -4,5 +4,11 @@ error: cannot use unions in constant patterns
 LL |         C => {}
    |         ^
 
-error: aborting due to previous error
+error: cannot use unions in constant patterns
+  --> $DIR/union-const-pat.rs:10:9
+   |
+LL |         C => {}
+   |         ^
+
+error: aborting due to 2 previous errors
 
index 60e280f53f52c8dc0caabf6f4aad068a4c312c73..4a106cc940a18a35a8f668bca0ced845eb2b3a17 100644 (file)
@@ -34,5 +34,5 @@ union U5<T> {
 
 fn main() {
     let u = U5 { a: ManuallyDrop::new(CloneNoCopy) };
-    let w = u.clone(); //~ ERROR no method named `clone` found for type `U5<CloneNoCopy>`
+    let w = u.clone(); //~ ERROR no method named `clone` found for union `U5<CloneNoCopy>`
 }
index 6893f9176f2db7778bd846d090c0707a2f9dcacc..0ef5753b5907d847e1e8e5afc7e87c5d8a4d0ab9 100644 (file)
@@ -6,7 +6,7 @@ LL | #[derive(Clone)]
    |
    = note: required by `std::clone::AssertParamIsCopy`
 
-error[E0599]: no method named `clone` found for type `U5<CloneNoCopy>` in the current scope
+error[E0599]: no method named `clone` found for union `U5<CloneNoCopy>` in the current scope
   --> $DIR/union-derive-clone.rs:37:15
    |
 LL | union U5<T> {
index cd46878c19be4972473a49ed57466a77fbc0c036..92cda6482c0d90c896bdfd7d2756f65948f5cbfd 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `clone` found for type `std::boxed::Box<dyn Foo>` in the current scope
+error[E0599]: no method named `clone` found for struct `std::boxed::Box<dyn Foo>` in the current scope
   --> $DIR/unique-object-noncopyable.rs:24:16
    |
 LL |     let _z = y.clone();
index 19ef2b21c26854b1b853ca54782ac829b26b5199..e5c3eaccbd3ecf73ea90e9edfe48e97b1b3f8eb2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `clone` found for type `std::boxed::Box<R>` in the current scope
+error[E0599]: no method named `clone` found for struct `std::boxed::Box<R>` in the current scope
   --> $DIR/unique-pinned-nocopy.rs:12:16
    |
 LL |     let _j = i.clone();
index c92a71e93971105a0c09140408e74f7451242db1..182aec34b4781c5f9c06ab52c1572411f21d2839 100644 (file)
@@ -1,4 +1,8 @@
 #![deny(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`
+                   //~| ERROR an unknown tool name found in scoped lint: `foo::bar`
+                   //~| ERROR an unknown tool name found in scoped lint: `foo::bar`
 
 #[allow(foo::bar)] //~ ERROR an unknown tool name found in scoped lint: `foo::bar`
+                   //~| ERROR an unknown tool name found in scoped lint: `foo::bar`
+                   //~| ERROR an unknown tool name found in scoped lint: `foo::bar`
 fn main() {}
index dd3070bbcb3d2e2eaeace762cd32b9bf94de5b84..1940f61a47b68d71848474139c8de03769c59458 100644 (file)
@@ -5,10 +5,34 @@ LL | #![deny(foo::bar)]
    |         ^^^
 
 error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
-  --> $DIR/unknown-lint-tool-name.rs:3:9
+  --> $DIR/unknown-lint-tool-name.rs:5:9
    |
 LL | #[allow(foo::bar)]
    |         ^^^
 
-error: aborting due to 2 previous errors
+error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:1:9
+   |
+LL | #![deny(foo::bar)]
+   |         ^^^
+
+error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:5:9
+   |
+LL | #[allow(foo::bar)]
+   |         ^^^
+
+error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:1:9
+   |
+LL | #![deny(foo::bar)]
+   |         ^^^
+
+error[E0710]: an unknown tool name found in scoped lint: `foo::bar`
+  --> $DIR/unknown-lint-tool-name.rs:5:9
+   |
+LL | #[allow(foo::bar)]
+   |         ^^^
+
+error: aborting due to 6 previous errors
 
index b72d45ebdbfbc0e47d5643153de8a106716cf37a..e057a7842b2aaa386f1561ef94282a53a4279fad 100644 (file)
@@ -1,22 +1,22 @@
-error[E0599]: no function or associated item named `lol` found for type `dyn Foo<_>` in the current scope
+error[E0599]: no function or associated item named `lol` found for trait object `dyn Foo<_>` in the current scope
   --> $DIR/unspecified-self-in-trait-ref.rs:10:18
    |
 LL |     let a = Foo::lol();
    |                  ^^^ function or associated item not found in `dyn Foo<_>`
 
-error[E0599]: no function or associated item named `lol` found for type `dyn Foo<_>` in the current scope
+error[E0599]: no function or associated item named `lol` found for trait object `dyn Foo<_>` in the current scope
   --> $DIR/unspecified-self-in-trait-ref.rs:12:23
    |
 LL |     let b = Foo::<_>::lol();
    |                       ^^^ function or associated item not found in `dyn Foo<_>`
 
-error[E0599]: no function or associated item named `lol` found for type `dyn Bar<_, _>` in the current scope
+error[E0599]: no function or associated item named `lol` found for trait object `dyn Bar<_, _>` in the current scope
   --> $DIR/unspecified-self-in-trait-ref.rs:14:18
    |
 LL |     let c = Bar::lol();
    |                  ^^^ function or associated item not found in `dyn Bar<_, _>`
 
-error[E0599]: no function or associated item named `lol` found for type `dyn Bar<usize, _>` in the current scope
+error[E0599]: no function or associated item named `lol` found for trait object `dyn Bar<usize, _>` in the current scope
   --> $DIR/unspecified-self-in-trait-ref.rs:16:30
    |
 LL |     let d = Bar::<usize, _>::lol();
index 3e0ebccc0a0d647346a173175e55bf84139d4e35..27a4a653b49039a5ae0b1e9169644a0145ddeadc 100644 (file)
@@ -5,6 +5,7 @@
 
 mod foo {
     use ::super::{S, Z}; //~ ERROR global paths cannot start with `super`
+                         //~| ERROR global paths cannot start with `super`
 
     pub fn g() {
         use ::super::main; //~ ERROR global paths cannot start with `super`
index 3ca30ebebbab7794d31b24c8a65d46afc62b7edf..7f98ac7cd0fefc117616cd6f1a65c26955b84a11 100644 (file)
@@ -5,13 +5,19 @@ LL |     use ::super::{S, Z};
    |           ^^^^^ global paths cannot start with `super`
 
 error[E0433]: failed to resolve: global paths cannot start with `super`
-  --> $DIR/use-super-global-path.rs:10:15
+  --> $DIR/use-super-global-path.rs:7:11
+   |
+LL |     use ::super::{S, Z};
+   |           ^^^^^ global paths cannot start with `super`
+
+error[E0433]: failed to resolve: global paths cannot start with `super`
+  --> $DIR/use-super-global-path.rs:11:15
    |
 LL |         use ::super::main;
    |               ^^^^^ global paths cannot start with `super`
 
 error[E0425]: cannot find function `main` in this scope
-  --> $DIR/use-super-global-path.rs:11:9
+  --> $DIR/use-super-global-path.rs:12:9
    |
 LL |         main();
    |         ^^^^ not found in this scope
@@ -21,7 +27,7 @@ help: possible candidate is found in another module, you can import it into scop
 LL |     use main;
    |
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0425, E0433.
 For more information about an error, try `rustc --explain E0425`.
index e8642c7a2900bed28003a98d4db8b62290ac802f..920cdb59e1edf2c4cb2f266fa521f12c1b97a499 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e8642c7a2900bed28003a98d4db8b62290ac802f
+Subproject commit 920cdb59e1edf2c4cb2f266fa521f12c1b97a499
index da1e3760e010dd7a2b00bf56274c18b5a09825a9..efa9d05f16c38136e10db0a5841f611a60a9739b 100644 (file)
@@ -1,6 +1,9 @@
 #![crate_name = "compiletest"]
-#![feature(test)]
+#![feature(vec_remove_item)]
 #![deny(warnings)]
+// The `test` crate is the only unstable feature
+// allowed here, just to share similar code.
+#![feature(test)]
 
 extern crate test;
 
index 226a12c6734b70b404118b0f7a55f238726bd3c2..1912c9ef5baeb4265497c8de0dfea8022cea7174 100644 (file)
@@ -1864,12 +1864,14 @@ fn make_compile_args(
                     rustc.args(&["--error-format", "json"]);
                 }
                 rustc.arg("-Zui-testing");
+                rustc.arg("-Zdeduplicate-diagnostics=no");
             }
             Ui => {
                 if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) {
                     rustc.args(&["--error-format", "json"]);
                 }
                 rustc.arg("-Zui-testing");
+                rustc.arg("-Zdeduplicate-diagnostics=no");
             }
             MirOpt => {
                 rustc.args(&[
index 003f51a0f43bbbdbe7e446f38dca36442c3595c1..2663b3d160a7a4ad1359d7ac83a9da71bdab5912 100644 (file)
@@ -67,6 +67,7 @@
     ("powerpc", "powerpc"),
     ("powerpc64", "powerpc64"),
     ("powerpc64le", "powerpc64"),
+    ("riscv64gc", "riscv64"),
     ("s390x", "s390x"),
     ("sparc", "sparc"),
     ("sparc64", "sparc64"),