]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #73456 - tmiasko:musl-libdir, r=Mark-Simulacrum
authorbors <bors@rust-lang.org>
Tue, 30 Jun 2020 15:41:50 +0000 (15:41 +0000)
committerbors <bors@rust-lang.org>
Tue, 30 Jun 2020 15:41:50 +0000 (15:41 +0000)
bootstrap: Configurable musl libdir

Make it possible to customize the location of musl libdir using
musl-libdir in config.toml, e.g., to use lib64 instead of lib.

1783 files changed:
.github/workflows/ci.yml
Cargo.lock
Cargo.toml
config.toml.example
src/bootstrap/bin/rustc.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/compile.rs
src/bootstrap/configure.py
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/flags.rs
src/bootstrap/install.rs
src/bootstrap/lib.rs
src/bootstrap/metadata.rs
src/bootstrap/native.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/azure-pipelines/try.yml
src/ci/docker/disabled/riscv64gc-linux/0001-Remove-stime-function-calls.patch [new file with mode: 0644]
src/ci/docker/disabled/riscv64gc-linux/Dockerfile [new file with mode: 0644]
src/ci/docker/disabled/riscv64gc-linux/linux.config [new file with mode: 0644]
src/ci/docker/dist-aarch64-linux/Dockerfile
src/ci/docker/dist-various-2/Dockerfile
src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh
src/ci/docker/x86_64-gnu-tools/Dockerfile
src/ci/github-actions/ci.yml
src/doc/book
src/doc/embedded-book
src/doc/reference
src/doc/rust-by-example
src/doc/rustc/src/command-line-arguments.md
src/doc/unstable-book/src/compiler-flags/control-flow-guard.md
src/doc/unstable-book/src/compiler-flags/sanitizer.md
src/doc/unstable-book/src/compiler-flags/self-profile.md
src/doc/unstable-book/src/language-features/const-if-match.md [deleted file]
src/doc/unstable-book/src/library-features/asm.md
src/liballoc/Cargo.toml
src/liballoc/alloc.rs
src/liballoc/benches/lib.rs
src/liballoc/boxed.rs
src/liballoc/collections/binary_heap.rs
src/liballoc/collections/btree/map.rs
src/liballoc/collections/btree/mod.rs
src/liballoc/collections/btree/navigate.rs
src/liballoc/collections/btree/node.rs
src/liballoc/collections/btree/set.rs
src/liballoc/collections/linked_list.rs
src/liballoc/collections/vec_deque.rs
src/liballoc/collections/vec_deque/tests.rs
src/liballoc/lib.rs
src/liballoc/raw_vec.rs
src/liballoc/raw_vec/tests.rs
src/liballoc/rc.rs
src/liballoc/slice.rs
src/liballoc/str.rs
src/liballoc/string.rs
src/liballoc/sync.rs
src/liballoc/task.rs
src/liballoc/tests/btree/map.rs
src/liballoc/tests/btree/set.rs
src/liballoc/tests/lib.rs
src/liballoc/tests/vec.rs
src/liballoc/vec.rs
src/libcore/Cargo.toml
src/libcore/benches/lib.rs
src/libcore/convert/mod.rs
src/libcore/convert/num.rs
src/libcore/future/future.rs
src/libcore/hash/mod.rs
src/libcore/intrinsics.rs
src/libcore/iter/traits/iterator.rs
src/libcore/lib.rs
src/libcore/mem/mod.rs
src/libcore/num/mod.rs
src/libcore/ops/function.rs
src/libcore/option.rs
src/libcore/ptr/const_ptr.rs
src/libcore/ptr/mod.rs
src/libcore/ptr/mut_ptr.rs
src/libcore/result.rs
src/libcore/slice/mod.rs
src/libcore/slice/sort.rs
src/libcore/tests/array.rs
src/libcore/tests/lib.rs
src/libcore/tests/nonzero.rs
src/libcore/tests/slice.rs
src/libcore/time.rs
src/libpanic_abort/lib.rs
src/libpanic_unwind/lib.rs
src/libprofiler_builtins/build.rs
src/librustc_arena/lib.rs
src/librustc_ast/ast.rs
src/librustc_ast/attr/mod.rs
src/librustc_ast/lib.rs
src/librustc_ast/mut_visit.rs
src/librustc_ast/token.rs
src/librustc_ast/util/literal.rs
src/librustc_ast/util/parser.rs
src/librustc_ast_lowering/expr.rs
src/librustc_ast_lowering/item.rs
src/librustc_ast_lowering/lib.rs
src/librustc_ast_passes/ast_validation.rs
src/librustc_ast_pretty/pprust.rs
src/librustc_ast_pretty/pprust/tests.rs
src/librustc_builtin_macros/asm.rs
src/librustc_builtin_macros/deriving/mod.rs
src/librustc_builtin_macros/env.rs
src/librustc_builtin_macros/lib.rs
src/librustc_builtin_macros/proc_macro_harness.rs
src/librustc_builtin_macros/standard_library_imports.rs
src/librustc_builtin_macros/test_harness.rs
src/librustc_codegen_llvm/asm.rs
src/librustc_codegen_llvm/attributes.rs
src/librustc_codegen_llvm/back/lto.rs
src/librustc_codegen_llvm/back/write.rs
src/librustc_codegen_llvm/base.rs
src/librustc_codegen_llvm/builder.rs
src/librustc_codegen_llvm/common.rs
src/librustc_codegen_llvm/context.rs
src/librustc_codegen_llvm/debuginfo/metadata.rs
src/librustc_codegen_llvm/debuginfo/mod.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_llvm/llvm/ffi.rs
src/librustc_codegen_llvm/llvm_util.rs
src/librustc_codegen_llvm/type_of.rs
src/librustc_codegen_ssa/back/link.rs
src/librustc_codegen_ssa/back/linker.rs
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/back/write.rs
src/librustc_codegen_ssa/common.rs
src/librustc_codegen_ssa/debuginfo/type_names.rs
src/librustc_codegen_ssa/mir/analyze.rs
src/librustc_codegen_ssa/mir/block.rs
src/librustc_codegen_ssa/mir/place.rs
src/librustc_codegen_ssa/traits/builder.rs
src/librustc_codegen_ssa/traits/intrinsic.rs
src/librustc_codegen_ssa/traits/type_.rs
src/librustc_data_structures/Cargo.toml
src/librustc_data_structures/sync.rs
src/librustc_driver/lib.rs
src/librustc_error_codes/error_codes.rs
src/librustc_error_codes/error_codes/E0081.md
src/librustc_error_codes/error_codes/E0668.md
src/librustc_error_codes/error_codes/E0670.md
src/librustc_error_codes/error_codes/E0689.md
src/librustc_error_codes/error_codes/E0695.md
src/librustc_error_codes/error_codes/E0699.md
src/librustc_error_codes/error_codes/E0701.md
src/librustc_error_codes/error_codes/E0759.md [new file with mode: 0644]
src/librustc_error_codes/error_codes/E0763.md [new file with mode: 0644]
src/librustc_error_codes/error_codes/E0764.md [new file with mode: 0644]
src/librustc_error_codes/error_codes/E0765.md [new file with mode: 0644]
src/librustc_error_codes/error_codes/E0766.md [new file with mode: 0644]
src/librustc_errors/emitter.rs
src/librustc_errors/json.rs
src/librustc_errors/lib.rs
src/librustc_expand/base.rs
src/librustc_expand/mbe/macro_parser.rs
src/librustc_expand/mbe/transcribe.rs
src/librustc_expand/proc_macro.rs
src/librustc_expand/proc_macro_server.rs
src/librustc_feature/accepted.rs
src/librustc_feature/active.rs
src/librustc_feature/removed.rs
src/librustc_hir/definitions.rs
src/librustc_hir/hir.rs
src/librustc_hir/lang_items.rs
src/librustc_hir/lib.rs
src/librustc_index/bit_set.rs
src/librustc_index/lib.rs
src/librustc_infer/infer/canonical/canonicalizer.rs
src/librustc_infer/infer/canonical/mod.rs
src/librustc_infer/infer/error_reporting/mod.rs
src/librustc_infer/infer/error_reporting/need_type_info.rs
src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs
src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs
src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs
src/librustc_infer/infer/error_reporting/nice_region_error/util.rs
src/librustc_infer/infer/freshen.rs
src/librustc_infer/infer/higher_ranked/mod.rs
src/librustc_infer/infer/mod.rs
src/librustc_infer/infer/nll_relate/mod.rs
src/librustc_infer/infer/outlives/verify.rs
src/librustc_infer/infer/region_constraints/leak_check.rs
src/librustc_infer/infer/region_constraints/mod.rs
src/librustc_infer/infer/resolve.rs
src/librustc_infer/infer/sub.rs
src/librustc_infer/infer/undo_log.rs
src/librustc_infer/lib.rs
src/librustc_infer/traits/mod.rs
src/librustc_infer/traits/util.rs
src/librustc_interface/interface.rs
src/librustc_interface/passes.rs
src/librustc_interface/queries.rs
src/librustc_interface/tests.rs
src/librustc_lexer/src/lib.rs
src/librustc_lint/Cargo.toml
src/librustc_lint/array_into_iter.rs
src/librustc_lint/builtin.rs
src/librustc_lint/context.rs
src/librustc_lint/early.rs
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/types.rs
src/librustc_lint/unused.rs
src/librustc_llvm/build.rs
src/librustc_llvm/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/locator.rs
src/librustc_metadata/rmeta/decoder.rs
src/librustc_metadata/rmeta/encoder.rs
src/librustc_metadata/rmeta/mod.rs
src/librustc_middle/Cargo.toml
src/librustc_middle/arena.rs
src/librustc_middle/hir/map/collector.rs
src/librustc_middle/hir/map/mod.rs
src/librustc_middle/ich/hcx.rs
src/librustc_middle/ich/impls_hir.rs
src/librustc_middle/lib.rs
src/librustc_middle/lint.rs
src/librustc_middle/middle/codegen_fn_attrs.rs
src/librustc_middle/mir/interpret/error.rs
src/librustc_middle/mir/mod.rs
src/librustc_middle/mir/mono.rs
src/librustc_middle/mir/query.rs
src/librustc_middle/mir/type_foldable.rs
src/librustc_middle/mir/visit.rs
src/librustc_middle/query/mod.rs
src/librustc_middle/traits/chalk.rs
src/librustc_middle/traits/mod.rs
src/librustc_middle/traits/query.rs
src/librustc_middle/ty/_match.rs
src/librustc_middle/ty/codec.rs
src/librustc_middle/ty/consts.rs [new file with mode: 0644]
src/librustc_middle/ty/context.rs
src/librustc_middle/ty/diagnostics.rs
src/librustc_middle/ty/error.rs
src/librustc_middle/ty/fast_reject.rs
src/librustc_middle/ty/flags.rs
src/librustc_middle/ty/fold.rs
src/librustc_middle/ty/instance.rs
src/librustc_middle/ty/layout.rs
src/librustc_middle/ty/list.rs
src/librustc_middle/ty/mod.rs
src/librustc_middle/ty/outlives.rs
src/librustc_middle/ty/print/mod.rs
src/librustc_middle/ty/print/obsolete.rs
src/librustc_middle/ty/print/pretty.rs
src/librustc_middle/ty/query/on_disk_cache.rs
src/librustc_middle/ty/query/values.rs
src/librustc_middle/ty/relate.rs
src/librustc_middle/ty/structural_impls.rs
src/librustc_middle/ty/sty.rs
src/librustc_middle/ty/subst.rs
src/librustc_middle/ty/util.rs
src/librustc_middle/ty/walk.rs
src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
src/librustc_mir/borrow_check/diagnostics/mod.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/type_check/free_region_relations.rs
src/librustc_mir/borrow_check/type_check/mod.rs
src/librustc_mir/borrow_check/type_check/relate_tys.rs
src/librustc_mir/borrow_check/universal_regions.rs
src/librustc_mir/borrow_check/used_muts.rs
src/librustc_mir/const_eval/error.rs
src/librustc_mir/const_eval/machine.rs
src/librustc_mir/const_eval/mod.rs
src/librustc_mir/dataflow/framework/direction.rs
src/librustc_mir/dataflow/impls/borrowed_locals.rs
src/librustc_mir/dataflow/impls/liveness.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/interpret/cast.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/intern.rs
src/librustc_mir/interpret/intrinsics.rs
src/librustc_mir/interpret/intrinsics/type_name.rs
src/librustc_mir/interpret/machine.rs
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/operator.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/interpret/step.rs
src/librustc_mir/interpret/terminator.rs
src/librustc_mir/interpret/validity.rs
src/librustc_mir/lib.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_mir/monomorphize/partitioning.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/add_moves_for_packed_drops.rs
src/librustc_mir/transform/check_consts/ops.rs
src/librustc_mir/transform/check_consts/post_drop_elaboration.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/instrument_coverage.rs [new file with mode: 0644]
src/librustc_mir/transform/mod.rs
src/librustc_mir/transform/no_landing_pads.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_min_const_fn.rs
src/librustc_mir/transform/validate.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_mir/util/pretty.rs
src/librustc_mir_build/build/expr/as_operand.rs
src/librustc_mir_build/build/expr/as_rvalue.rs
src/librustc_mir_build/build/mod.rs
src/librustc_mir_build/build/scope.rs
src/librustc_mir_build/hair/cx/expr.rs
src/librustc_mir_build/hair/cx/mod.rs
src/librustc_mir_build/hair/pattern/_match.rs
src/librustc_mir_build/hair/pattern/check_match.rs
src/librustc_mir_build/hair/pattern/const_to_pat.rs
src/librustc_mir_build/hair/pattern/mod.rs
src/librustc_mir_build/lib.rs
src/librustc_parse/lexer/mod.rs
src/librustc_parse/parser/attr.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/pat.rs
src/librustc_parse/parser/stmt.rs
src/librustc_parse_format/lib.rs
src/librustc_passes/check_attr.rs
src/librustc_passes/check_const.rs
src/librustc_passes/hir_id_validator.rs
src/librustc_passes/intrinsicck.rs
src/librustc_passes/lang_items.rs
src/librustc_passes/liveness.rs
src/librustc_passes/loops.rs
src/librustc_passes/stability.rs
src/librustc_passes/weak_lang_items.rs
src/librustc_privacy/lib.rs
src/librustc_query_system/lib.rs
src/librustc_query_system/query/job.rs
src/librustc_resolve/Cargo.toml
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/check_unused.rs
src/librustc_resolve/def_collector.rs
src/librustc_resolve/diagnostics.rs
src/librustc_resolve/imports.rs
src/librustc_resolve/late.rs
src/librustc_resolve/late/diagnostics.rs
src/librustc_resolve/late/lifetimes.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_save_analysis/lib.rs
src/librustc_session/Cargo.toml
src/librustc_session/config.rs
src/librustc_session/filesearch.rs
src/librustc_session/lib.rs
src/librustc_session/lint.rs
src/librustc_session/lint/builtin.rs
src/librustc_session/options.rs
src/librustc_session/parse.rs
src/librustc_session/session.rs
src/librustc_span/hygiene.rs
src/librustc_span/lib.rs
src/librustc_span/symbol.rs
src/librustc_symbol_mangling/v0.rs
src/librustc_target/abi/mod.rs
src/librustc_target/asm/arm.rs
src/librustc_target/asm/hexagon.rs [new file with mode: 0644]
src/librustc_target/asm/mod.rs
src/librustc_target/asm/riscv.rs
src/librustc_target/asm/x86.rs
src/librustc_target/lib.rs
src/librustc_target/spec/apple_sdk_base.rs
src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
src/librustc_target/spec/x86_64_unknown_linux_musl.rs
src/librustc_trait_selection/autoderef.rs [new file with mode: 0644]
src/librustc_trait_selection/infer.rs
src/librustc_trait_selection/lib.rs
src/librustc_trait_selection/opaque_types.rs
src/librustc_trait_selection/traits/chalk_fulfill.rs
src/librustc_trait_selection/traits/coherence.rs
src/librustc_trait_selection/traits/error_reporting/mod.rs
src/librustc_trait_selection/traits/error_reporting/suggestions.rs
src/librustc_trait_selection/traits/fulfill.rs
src/librustc_trait_selection/traits/project.rs
src/librustc_trait_selection/traits/query/dropck_outlives.rs
src/librustc_trait_selection/traits/query/normalize.rs
src/librustc_trait_selection/traits/select/candidate_assembly.rs
src/librustc_trait_selection/traits/select/confirmation.rs
src/librustc_trait_selection/traits/select/mod.rs
src/librustc_trait_selection/traits/specialize/mod.rs
src/librustc_trait_selection/traits/structural_match.rs
src/librustc_trait_selection/traits/util.rs
src/librustc_trait_selection/traits/wf.rs
src/librustc_traits/Cargo.toml
src/librustc_traits/chalk/db.rs
src/librustc_traits/chalk/lowering.rs
src/librustc_traits/chalk/mod.rs
src/librustc_traits/dropck_outlives.rs
src/librustc_ty/needs_drop.rs
src/librustc_ty/ty.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/compare_method.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/expr.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/librustc_typeck/check/pat.rs
src/librustc_typeck/check/place_op.rs [new file with mode: 0644]
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/collect.rs
src/librustc_typeck/collect/type_of.rs
src/librustc_typeck/expr_use_visitor.rs
src/librustc_typeck/impl_wf_check.rs
src/librustc_typeck/mem_categorization.rs
src/librustc_typeck/variance/constraints.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/doctree.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/html/render/cache.rs
src/librustdoc/html/static/main.js
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/passes/collect_intra_doc_links.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/libstd/Cargo.toml
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/fs.rs
src/libstd/io/buffered.rs
src/libstd/io/error.rs
src/libstd/io/stdio.rs
src/libstd/keyword_docs.rs
src/libstd/lib.rs
src/libstd/net/addr.rs
src/libstd/os/illumos/fs.rs
src/libstd/panicking.rs
src/libstd/path.rs
src/libstd/prelude/mod.rs
src/libstd/rt.rs
src/libstd/sys/hermit/stdio.rs
src/libstd/sys/sgx/abi/entry.S
src/libstd/sys/sgx/abi/mod.rs
src/libstd/sys/unix/args.rs
src/libstd/sys/unix/ext/fs.rs
src/libstd/sys/unix/ext/net.rs
src/libstd/sys/unix/process/process_common.rs
src/libstd/sys/vxworks/args.rs
src/libstd/sys/vxworks/ext/fs.rs
src/libstd/sys/vxworks/rand.rs
src/libstd/sys/vxworks/rwlock.rs
src/libstd/sys/vxworks/time.rs
src/libstd/sys/wasi/alloc.rs
src/libstd/sys/wasi/stdio.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/mod.rs
src/libstd/time.rs
src/libunwind/build.rs
src/llvm-project
src/rustllvm/PassWrapper.cpp
src/rustllvm/RustWrapper.cpp
src/stage0.txt
src/test/assembly/asm/hexagon-types.rs [new file with mode: 0644]
src/test/codegen-units/partitioning/compiler-builtins.rs [deleted file]
src/test/codegen/asm-multiple-options.rs [new file with mode: 0644]
src/test/codegen/async-fn-debug-msvc.rs [new file with mode: 0644]
src/test/codegen/async-fn-debug.rs [new file with mode: 0644]
src/test/codegen/cdylib-external-inline-fns.rs [new file with mode: 0644]
src/test/codegen/cfguard_checks.rs
src/test/codegen/cfguard_disabled.rs
src/test/codegen/cfguard_nochecks.rs
src/test/codegen/debug-linkage-name.rs [new file with mode: 0644]
src/test/codegen/export-no-mangle.rs
src/test/codegen/external-no-mangle-fns.rs
src/test/codegen/generator-debug-msvc.rs [new file with mode: 0644]
src/test/codegen/generator-debug.rs [new file with mode: 0644]
src/test/codegen/issue-69101-bounds-check.rs [new file with mode: 0644]
src/test/codegen/sanitizer-memory-track-orgins.rs
src/test/codegen/sanitizer-no-sanitize-inlining.rs
src/test/codegen/sanitizer-no-sanitize.rs
src/test/codegen/sanitizer-recover.rs
src/test/codegen/staticlib-external-inline-fns.rs [new file with mode: 0644]
src/test/codegen/vec-clear.rs
src/test/codegen/vec-optimizes-away.rs
src/test/compile-fail/issue-52443.rs
src/test/compile-fail/specialization/issue-50452.rs
src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/byte_slice/rustc.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/combine_array_len/32bit/rustc.norm2.InstCombine.diff
src/test/mir-opt/combine_array_len/64bit/rustc.norm2.InstCombine.diff
src/test/mir-opt/const_prop/aggregate/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/boxes/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/cast/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/checked_add/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/discriminant.rs
src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/indirect/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/issue-66971/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/issue-67019/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_no_prop/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.SimplifyLocals.after.mir
src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.SimplifyLocals.after.mir
src/test/mir-opt/const_prop/read_immutable_static/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref/rustc.main.PromoteTemps.diff
src/test/mir-opt/const_prop/ref_deref_project/rustc.main.PromoteTemps.diff
src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/return_place/rustc.add.ConstProp.diff
src/test/mir-opt/const_prop/return_place/rustc.add.PreCodegen.before.mir
src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/switch_int/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop/switch_int/rustc.main.SimplifyBranches-after-const-prop.diff
src/test/mir-opt/const_prop/tuple_literal_propagation/rustc.main.ConstProp.diff
src/test/mir-opt/const_prop_miscompile.rs [new file with mode: 0644]
src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff [new file with mode: 0644]
src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff [new file with mode: 0644]
src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff
src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff
src/test/mir-opt/exponential-or/rustc.match_tuple.SimplifyCfg-initial.after.mir
src/test/mir-opt/fn-ptr-shim.rs [new file with mode: 0644]
src/test/mir-opt/fn-ptr-shim/rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir [new file with mode: 0644]
src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir
src/test/mir-opt/generator-storage-dead-unwind/rustc.main-{{closure}}.StateTransform.before.mir
src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir
src/test/mir-opt/inline/inline-any-operand/rustc.bar.Inline.after.mir
src/test/mir-opt/inline/inline-into-box-place/32bit/rustc.main.Inline.diff
src/test/mir-opt/inline/inline-into-box-place/64bit/rustc.main.Inline.diff
src/test/mir-opt/inline/inline-specialization/rustc.main.Inline.diff
src/test/mir-opt/instrument_coverage.rs [new file with mode: 0644]
src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff [new file with mode: 0644]
src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff [new file with mode: 0644]
src/test/mir-opt/issue-41697/32bit/rustc.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir
src/test/mir-opt/issue-41697/64bit/rustc.{{impl}}-{{constant}}.SimplifyCfg-qualify-consts.after.mir
src/test/mir-opt/issue-41888/rustc.main.ElaborateDrops.after.mir
src/test/mir-opt/issue-49232/rustc.main.mir_map.0.mir
src/test/mir-opt/issue-62289/rustc.test.ElaborateDrops.before.mir
src/test/mir-opt/issue-72181-1.rs [new file with mode: 0644]
src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181.rs [new file with mode: 0644]
src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir [new file with mode: 0644]
src/test/mir-opt/loop_test/rustc.main.SimplifyCfg-qualify-consts.after.mir
src/test/mir-opt/match-arm-scopes/rustc.complicated_match.ElaborateDrops.after.mir
src/test/mir-opt/match-arm-scopes/rustc.complicated_match.SimplifyCfg-initial.after.mir
src/test/mir-opt/match_false_edges/rustc.full_tested_match.PromoteTemps.after.mir
src/test/mir-opt/match_false_edges/rustc.full_tested_match2.PromoteTemps.before.mir
src/test/mir-opt/match_false_edges/rustc.main.PromoteTemps.before.mir
src/test/mir-opt/match_test/rustc.main.SimplifyCfg-initial.after.mir
src/test/mir-opt/no-drop-for-inactive-variant/rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/nrvo-simple/rustc.nrvo.RenameReturnPlace.diff
src/test/mir-opt/packed-struct-drop-aligned/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/packed-struct-drop-aligned/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/remove_fake_borrows/rustc.match_guard.CleanupNonCodegenStatements.diff
src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/simple-match/32bit/rustc.match_bool.mir_map.0.mir
src/test/mir-opt/simple-match/64bit/rustc.match_bool.mir_map.0.mir
src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff
src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff
src/test/mir-opt/simplify-arm-identity/rustc.main.SimplifyArmIdentity.diff
src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff
src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff
src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff
src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff
src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff
src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff
src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff
src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff
src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/32bit/rustc.map.SimplifyLocals.diff [new file with mode: 0644]
src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/64bit/rustc.map.SimplifyLocals.diff [new file with mode: 0644]
src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/rustc.map.SimplifyLocals.diff [deleted file]
src/test/mir-opt/simplify_try/rustc.try_identity.SimplifyArmIdentity.diff
src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff
src/test/mir-opt/slice-drop-shim/32bit/rustc.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir
src/test/mir-opt/slice-drop-shim/64bit/rustc.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir
src/test/mir-opt/storage_live_dead_in_statics/rustc.XXX.mir_map.0.mir
src/test/mir-opt/storage_ranges/rustc.main.nll.0.mir
src/test/mir-opt/tls-access/rustc.main.SimplifyCfg-final.after.mir
src/test/mir-opt/uniform_array_move_out/rustc.move_out_by_subslice.mir_map.0.mir
src/test/mir-opt/uniform_array_move_out/rustc.move_out_from_end.mir_map.0.mir
src/test/mir-opt/uninhabited_enum_branching/rustc.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
src/test/mir-opt/uninhabited_enum_branching/rustc.main.UninhabitedEnumBranching.diff
src/test/mir-opt/unreachable/rustc.main.UnreachablePropagation.diff
src/test/mir-opt/unreachable_asm/rustc.main.UnreachablePropagation.diff
src/test/mir-opt/unreachable_asm_2/rustc.main.UnreachablePropagation.diff
src/test/mir-opt/unreachable_diverging/rustc.main.UnreachablePropagation.diff
src/test/mir-opt/unusual-item-types/32bit/rustc.E-V-{{constant}}.mir_map.0.mir
src/test/mir-opt/unusual-item-types/32bit/rustc.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir
src/test/mir-opt/unusual-item-types/64bit/rustc.E-V-{{constant}}.mir_map.0.mir
src/test/mir-opt/unusual-item-types/64bit/rustc.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir
src/test/pretty/asm.pp
src/test/pretty/asm.rs
src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile
src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile
src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
src/test/run-make/env-dep-info/Makefile [new file with mode: 0644]
src/test/run-make/env-dep-info/main.rs [new file with mode: 0644]
src/test/run-make/static-pie/Makefile [new file with mode: 0644]
src/test/run-make/static-pie/test-aslr.rs [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter-out.js [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter-out.rs [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter.js [new file with mode: 0644]
src/test/rustdoc-js/doc-alias-filter.rs [new file with mode: 0644]
src/test/rustdoc-ui/check-doc-alias-attr.rs [new file with mode: 0644]
src/test/rustdoc-ui/check-doc-alias-attr.stderr [new file with mode: 0644]
src/test/rustdoc-ui/intra-links-private.public.stderr [new file with mode: 0644]
src/test/rustdoc-ui/intra-links-private.rs [new file with mode: 0644]
src/test/rustdoc-ui/reference-link-has-one-warning.rs [new file with mode: 0644]
src/test/rustdoc-ui/reference-link-has-one-warning.stderr [new file with mode: 0644]
src/test/rustdoc-ui/test-compile-fail3.stderr
src/test/rustdoc-ui/unparseable-doc-test.stdout
src/test/rustdoc/codeblock-title.rs
src/test/rustdoc/const-generics/add-impl.rs
src/test/rustdoc/sanitizer-option.rs
src/test/rustdoc/synthetic_auto/overflow.rs [new file with mode: 0644]
src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs
src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
src/test/ui/abi/abi-sysv64-register-usage.rs
src/test/ui/align-with-extern-c-fn.rs
src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
src/test/ui/asm/duplicate-options.fixed [new file with mode: 0644]
src/test/ui/asm/duplicate-options.rs [new file with mode: 0644]
src/test/ui/asm/duplicate-options.stderr [new file with mode: 0644]
src/test/ui/asm/parse-error.rs
src/test/ui/asm/parse-error.stderr
src/test/ui/asm/srcloc.rs
src/test/ui/asm/srcloc.stderr
src/test/ui/assoc-lang-items.rs [new file with mode: 0644]
src/test/ui/assoc-lang-items.stderr [new file with mode: 0644]
src/test/ui/associated-const/defaults-not-assumed-fail.stderr
src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr
src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr
src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr
src/test/ui/associated-types/associated-types-eq-1.stderr
src/test/ui/associated-types/associated-types-eq-hr.nll.stderr [new file with mode: 0644]
src/test/ui/associated-types/associated-types-eq-hr.rs
src/test/ui/associated-types/associated-types-eq-hr.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
src/test/ui/associated-types/defaults-specialization.rs
src/test/ui/associated-types/defaults-specialization.stderr
src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr [new file with mode: 0644]
src/test/ui/associated-types/higher-ranked-projection.bad.stderr
src/test/ui/associated-types/higher-ranked-projection.rs
src/test/ui/associated-types/hr-associated-type-bound-1.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-1.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-2.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-2.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-object.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-object.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-1.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-2.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-3.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-4.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-5.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-6.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-projection-1.rs [new file with mode: 0644]
src/test/ui/associated-types/hr-associated-type-projection-1.stderr [new file with mode: 0644]
src/test/ui/async-await/async-error-span.rs
src/test/ui/async-await/async-error-span.stderr
src/test/ui/async-await/issue-70594.rs
src/test/ui/async-await/issue-70594.stderr
src/test/ui/async-await/issues/issue-62009-1.stderr
src/test/ui/async-await/issues/issue-62097.stderr
src/test/ui/auto-is-contextual.rs [deleted file]
src/test/ui/auto-trait-validation.rs [deleted file]
src/test/ui/auto-trait-validation.stderr [deleted file]
src/test/ui/auto-traits/auto-is-contextual.rs [new file with mode: 0644]
src/test/ui/auto-traits/auto-trait-projection-recursion.rs [new file with mode: 0644]
src/test/ui/auto-traits/auto-trait-validation.rs [new file with mode: 0644]
src/test/ui/auto-traits/auto-trait-validation.stderr [new file with mode: 0644]
src/test/ui/auto-traits/auto-traits.rs [new file with mode: 0644]
src/test/ui/auto-traits/issue-23080-2.rs [new file with mode: 0644]
src/test/ui/auto-traits/issue-23080-2.stderr [new file with mode: 0644]
src/test/ui/auto-traits/issue-23080.rs [new file with mode: 0644]
src/test/ui/auto-traits/issue-23080.stderr [new file with mode: 0644]
src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs [new file with mode: 0644]
src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr [new file with mode: 0644]
src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.rs [new file with mode: 0644]
src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.rs [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-negation.rs [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-precedence.rs [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr [new file with mode: 0644]
src/test/ui/binary-op-on-double-ref.fixed [new file with mode: 0644]
src/test/ui/binary-op-on-double-ref.rs
src/test/ui/binary-op-on-double-ref.stderr
src/test/ui/borrowck/issue-41962.stderr
src/test/ui/borrowck/issue-64453.rs
src/test/ui/borrowck/issue-64453.stderr
src/test/ui/borrowck/move-in-pattern-mut.rs [new file with mode: 0644]
src/test/ui/borrowck/move-in-pattern-mut.stderr [new file with mode: 0644]
src/test/ui/borrowck/move-in-pattern.fixed [new file with mode: 0644]
src/test/ui/borrowck/move-in-pattern.rs [new file with mode: 0644]
src/test/ui/borrowck/move-in-pattern.stderr [new file with mode: 0644]
src/test/ui/borrowck/mut-borrow-in-loop-2.fixed [new file with mode: 0644]
src/test/ui/borrowck/mut-borrow-in-loop-2.rs [new file with mode: 0644]
src/test/ui/borrowck/mut-borrow-in-loop-2.stderr [new file with mode: 0644]
src/test/ui/cast/cast-from-nil.stderr
src/test/ui/cast/cast-to-bare-fn.stderr
src/test/ui/cast/cast-to-nil.stderr
src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr
src/test/ui/cenum_impl_drop_cast.rs [new file with mode: 0644]
src/test/ui/cenum_impl_drop_cast.stderr [new file with mode: 0644]
src/test/ui/chalkify/closure.rs [new file with mode: 0644]
src/test/ui/chalkify/closure.stderr [new file with mode: 0644]
src/test/ui/chalkify/impl_wf.rs
src/test/ui/chalkify/impl_wf.stderr
src/test/ui/chalkify/inherent_impl.rs
src/test/ui/chalkify/recursive_where_clause_on_type.rs
src/test/ui/chalkify/recursive_where_clause_on_type.stderr
src/test/ui/chalkify/type_inference.rs
src/test/ui/chalkify/type_inference.stderr
src/test/ui/chalkify/type_wf.rs
src/test/ui/chalkify/type_wf.stderr [new file with mode: 0644]
src/test/ui/check-static-immutable-mut-slices.rs
src/test/ui/check-static-immutable-mut-slices.stderr
src/test/ui/check-static-values-constraints.stderr
src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
src/test/ui/closure-expected-type/expect-fn-supply-fn.rs
src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
src/test/ui/closures/closure-no-fn-3.stderr
src/test/ui/closures/issue-41366.rs
src/test/ui/closures/issue-41366.stderr
src/test/ui/closures/issue-52437.rs
src/test/ui/closures/issue-52437.stderr
src/test/ui/codemap_tests/tab_2.stderr
src/test/ui/coerce/coerce-expect-unsized.rs [deleted file]
src/test/ui/coerce/coerce-overloaded-autoderef.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-imm-ptr-arg.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-imm-ptr-rcvr.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-imm-vec-arg.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-imm-vec-rcvr.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-mut-ptr-arg.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-mut-ptr-rcvr.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-mut-vec-arg.rs [deleted file]
src/test/ui/coerce/coerce-reborrow-mut-vec-rcvr.rs [deleted file]
src/test/ui/coerce/coerce-unify-return.rs [deleted file]
src/test/ui/coerce/coerce-unify.rs [deleted file]
src/test/ui/coerce/coerce-unsize-subtype.rs [deleted file]
src/test/ui/coercion/coerce-expect-unsized.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr [new file with mode: 0644]
src/test/ui/coercion/coerce-overloaded-autoderef.rs
src/test/ui/coercion/coerce-overloaded-autoderef.stderr [deleted file]
src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-multi-arg.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-to-bang-cast.rs
src/test/ui/coercion/coerce-to-bang-cast.stderr
src/test/ui/coercion/coerce-unify-return.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-unify.rs [new file with mode: 0644]
src/test/ui/coercion/coerce-unsize-subtype.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-fn-implied-bounds.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-fn-implied-bounds.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-fn-inputs.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-fn-inputs.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-free-vs-bound-region.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-free-vs-bound-region.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs
src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr
src/test/ui/coherence/coherence-subtyping.old.stderr [deleted file]
src/test/ui/coherence/coherence-subtyping.re.stderr [deleted file]
src/test/ui/coherence/coherence-subtyping.rs
src/test/ui/coherence/coherence-subtyping.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-wasm-bindgen.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-wasm-bindgen.stderr [new file with mode: 0644]
src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr
src/test/ui/const-generics/auxiliary/impl-const.rs [new file with mode: 0644]
src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
src/test/ui/const-generics/different_byref.stderr
src/test/ui/const-generics/fn-const-param-call.rs
src/test/ui/const-generics/fn-const-param-call.stderr
src/test/ui/const-generics/fn-const-param-infer.rs
src/test/ui/const-generics/fn-const-param-infer.stderr
src/test/ui/const-generics/issue-68104-print-stack-overflow.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71381.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71381.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71382.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71382.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71611.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-71611.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-72352.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-72352.stderr [new file with mode: 0644]
src/test/ui/const-generics/raw-ptr-const-param-deref.rs
src/test/ui/const-generics/raw-ptr-const-param-deref.stderr
src/test/ui/const-generics/raw-ptr-const-param.rs
src/test/ui/const-generics/raw-ptr-const-param.stderr
src/test/ui/const-generics/types-mismatch-const-args.stderr
src/test/ui/consts/const-err-early.stderr
src/test/ui/consts/const-err-multi.stderr
src/test/ui/consts/const-err2.noopt.stderr
src/test/ui/consts/const-err2.opt.stderr
src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr
src/test/ui/consts/const-eval/conditional_array_execution.stderr
src/test/ui/consts/const-eval/const-eval-overflow-3.stderr
src/test/ui/consts/const-eval/const-eval-overflow-4.stderr
src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
src/test/ui/consts/const-eval/const-eval-overflow2.stderr
src/test/ui/consts/const-eval/const-eval-overflow2b.stderr
src/test/ui/consts/const-eval/const-eval-overflow2c.stderr
src/test/ui/consts/const-eval/const_let.stderr
src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/double_check2.stderr
src/test/ui/consts/const-eval/infinite_loop.rs
src/test/ui/consts/const-eval/infinite_loop.stderr
src/test/ui/consts/const-eval/issue-43197.stderr
src/test/ui/consts/const-eval/issue-50814.stderr
src/test/ui/consts/const-eval/issue-52442.rs
src/test/ui/consts/const-eval/issue-52442.stderr
src/test/ui/consts/const-eval/issue-52475.rs
src/test/ui/consts/const-eval/issue-52475.stderr
src/test/ui/consts/const-eval/issue-62272.rs [deleted file]
src/test/ui/consts/const-eval/issue-62272.stderr [deleted file]
src/test/ui/consts/const-eval/issue-65394.rs
src/test/ui/consts/const-eval/issue-65394.stderr
src/test/ui/consts/const-eval/issue-70723.rs
src/test/ui/consts/const-eval/issue-70723.stderr
src/test/ui/consts/const-eval/livedrop.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/livedrop.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/match-test-ptr-null.rs
src/test/ui/consts/const-eval/match-test-ptr-null.stderr
src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
src/test/ui/consts/const-eval/promoted_errors.opt.stderr
src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
src/test/ui/consts/const-eval/pub_const_err.stderr
src/test/ui/consts/const-eval/pub_const_err_bin.stderr
src/test/ui/consts/const-eval/shift_overflow.stderr
src/test/ui/consts/const-eval/ub-enum.stderr
src/test/ui/consts/const-labeled-break.rs
src/test/ui/consts/const-labeled-break.stderr [deleted file]
src/test/ui/consts/const-len-underflow-separate-spans.stderr
src/test/ui/consts/const-len-underflow-subspans.rs
src/test/ui/consts/const-len-underflow-subspans.stderr
src/test/ui/consts/const-match-check.eval1.stderr
src/test/ui/consts/const-match-check.eval2.stderr
src/test/ui/consts/const-match-check.matchck.stderr
src/test/ui/consts/const-match-pattern-arm.rs
src/test/ui/consts/const-match-pattern-arm.stderr [deleted file]
src/test/ui/consts/const-multi-ref.rs
src/test/ui/consts/const-multi-ref.stderr
src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr [new file with mode: 0644]
src/test/ui/consts/const-mut-refs/const_mut_refs.rs
src/test/ui/consts/const-mut-refs/const_mut_refs.stderr [new file with mode: 0644]
src/test/ui/consts/const-pattern-irrefutable.rs
src/test/ui/consts/const-pattern-irrefutable.stderr
src/test/ui/consts/const-variant-count.rs [new file with mode: 0644]
src/test/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
src/test/ui/consts/const_in_pattern/issue-73431.rs [new file with mode: 0644]
src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs
src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
src/test/ui/consts/const_let_assign3.rs
src/test/ui/consts/const_let_assign3.stderr
src/test/ui/consts/const_let_refutable.rs
src/test/ui/consts/const_let_refutable.stderr
src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs
src/test/ui/consts/const_limit/const_eval_limit_reached.rs
src/test/ui/consts/const_limit/const_eval_limit_reached.stderr
src/test/ui/consts/const_short_circuit.rs
src/test/ui/consts/const_short_circuit.stderr [deleted file]
src/test/ui/consts/control-flow/assert.both.stderr [deleted file]
src/test/ui/consts/control-flow/assert.if_match.stderr [deleted file]
src/test/ui/consts/control-flow/assert.panic.stderr
src/test/ui/consts/control-flow/assert.rs
src/test/ui/consts/control-flow/assert.stock.stderr
src/test/ui/consts/control-flow/basics.rs
src/test/ui/consts/control-flow/drop-fail.precise.stderr
src/test/ui/consts/control-flow/drop-fail.rs
src/test/ui/consts/control-flow/drop-fail.stock.stderr
src/test/ui/consts/control-flow/drop-pass.rs
src/test/ui/consts/control-flow/drop-precise.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 [deleted file]
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 [deleted file]
src/test/ui/consts/control-flow/interior-mutability.rs
src/test/ui/consts/control-flow/interior-mutability.stderr
src/test/ui/consts/control-flow/issue-46843.if_match.stderr [deleted file]
src/test/ui/consts/control-flow/issue-46843.rs
src/test/ui/consts/control-flow/issue-46843.stderr [new file with mode: 0644]
src/test/ui/consts/control-flow/issue-46843.stock.stderr [deleted file]
src/test/ui/consts/control-flow/issue-50577.if_match.stderr [deleted file]
src/test/ui/consts/control-flow/issue-50577.rs
src/test/ui/consts/control-flow/issue-50577.stderr [new file with mode: 0644]
src/test/ui/consts/control-flow/issue-50577.stock.stderr [deleted file]
src/test/ui/consts/control-flow/loop.both.stderr [deleted file]
src/test/ui/consts/control-flow/loop.if_match.stderr [deleted file]
src/test/ui/consts/control-flow/loop.loop_.stderr [deleted file]
src/test/ui/consts/control-flow/loop.rs
src/test/ui/consts/control-flow/loop.stderr [new file with mode: 0644]
src/test/ui/consts/control-flow/loop.stock.stderr [deleted file]
src/test/ui/consts/control-flow/short-circuit-let.rs
src/test/ui/consts/control-flow/short-circuit.if_match.stderr [deleted file]
src/test/ui/consts/control-flow/short-circuit.rs
src/test/ui/consts/control-flow/short-circuit.stock.stderr [deleted file]
src/test/ui/consts/control-flow/single_variant_match_ice.rs
src/test/ui/consts/control-flow/try.rs
src/test/ui/consts/control-flow/try.stderr
src/test/ui/consts/min_const_fn/loop_ice.rs [deleted file]
src/test/ui/consts/min_const_fn/loop_ice.stderr [deleted file]
src/test/ui/consts/min_const_fn/min_const_fn.rs
src/test/ui/consts/min_const_fn/min_const_fn.stderr
src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
src/test/ui/consts/miri_unleashed/feature-gate-unleash_the_miri_inside_of_you.stderr
src/test/ui/consts/miri_unleashed/ptr_arith.rs
src/test/ui/consts/miri_unleashed/ptr_arith.stderr
src/test/ui/consts/miri_unleashed/slice_eq.rs [new file with mode: 0644]
src/test/ui/consts/offset_from_ub.stderr
src/test/ui/consts/projection_qualif.mut_refs.stderr
src/test/ui/consts/projection_qualif.rs
src/test/ui/consts/projection_qualif.stock.stderr
src/test/ui/consts/read_from_static_mut_ref.rs
src/test/ui/consts/read_from_static_mut_ref.stderr [new file with mode: 0644]
src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
src/test/ui/consts/static_mut_containing_mut_ref2.rs
src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
src/test/ui/consts/trait_specialization.rs
src/test/ui/consts/trait_specialization.stderr [new file with mode: 0644]
src/test/ui/consts/unstable-const-fn-in-libcore.rs
src/test/ui/consts/unstable-const-fn-in-libcore.stderr
src/test/ui/dst/dst-sized-trait-param.stderr
src/test/ui/enum-discriminant/niche.rs
src/test/ui/error-codes/E0017.rs
src/test/ui/error-codes/E0017.stderr
src/test/ui/error-codes/E0080.rs
src/test/ui/error-codes/E0080.stderr
src/test/ui/error-codes/E0388.rs
src/test/ui/error-codes/E0388.stderr
src/test/ui/error-codes/E0395.rs
src/test/ui/error-codes/E0395.stderr
src/test/ui/error-codes/E0520.rs
src/test/ui/error-codes/E0520.stderr
src/test/ui/error-codes/E0604.stderr
src/test/ui/error-codes/E0605.stderr
src/test/ui/error-festival.stderr
src/test/ui/eval-enum.rs
src/test/ui/eval-enum.stderr
src/test/ui/extern/extern-types-unsized.stderr
src/test/ui/fat-ptr-cast.stderr
src/test/ui/feature-gates/feature-gate-const_generics-ptr.rs
src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr
src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
src/test/ui/fn/fn-item-type.rs
src/test/ui/fn/fn-item-type.stderr
src/test/ui/for/for-loop-refutable-pattern-error-message.stderr
src/test/ui/generator/resume-arg-late-bound.nll.stderr [new file with mode: 0644]
src/test/ui/generator/resume-arg-late-bound.rs
src/test/ui/generator/resume-arg-late-bound.stderr
src/test/ui/generic-associated-types/collections-project-default.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/collections-project-default.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/collections.rs
src/test/ui/generic-associated-types/collections.stderr [deleted file]
src/test/ui/generic-associated-types/construct_with_other_type.rs
src/test/ui/generic-associated-types/construct_with_other_type.stderr [deleted file]
src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs
src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr
src/test/ui/generic-associated-types/generic-associated-types-where.rs
src/test/ui/generic-associated-types/generic-associated-types-where.stderr
src/test/ui/generic-associated-types/issue-47206-where-clause.rs
src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs
src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr [deleted file]
src/test/ui/generic-associated-types/issue-67424.rs
src/test/ui/generic-associated-types/issue-67424.stderr
src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68643-broken-mir.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68656-unsized-values.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/iterable.rs
src/test/ui/generic-associated-types/iterable.stderr [deleted file]
src/test/ui/generic-associated-types/missing-bounds.fixed
src/test/ui/generic-associated-types/missing-bounds.rs
src/test/ui/generic-associated-types/missing-bounds.stderr
src/test/ui/generic-associated-types/parameter_number_and_kind.rs
src/test/ui/generic-associated-types/parameter_number_and_kind.stderr
src/test/ui/generic-associated-types/pointer_family.rs
src/test/ui/generic-associated-types/pointer_family.stderr [deleted file]
src/test/ui/generic-associated-types/shadowing.rs
src/test/ui/generic-associated-types/shadowing.stderr
src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr [new file with mode: 0644]
src/test/ui/glob-resolve1.rs
src/test/ui/glob-resolve1.stderr
src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr [new file with mode: 0644]
src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr [new file with mode: 0644]
src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr [new file with mode: 0644]
src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
src/test/ui/hr-subtype/hr-subtype.rs
src/test/ui/hr-subtype/return-static.rs [new file with mode: 0644]
src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr [new file with mode: 0644]
src/test/ui/hrtb/hrtb-conflate-regions.stderr
src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr [new file with mode: 0644]
src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr [new file with mode: 0644]
src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr [deleted file]
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr [new file with mode: 0644]
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
src/test/ui/hrtb/hrtb-just-for-static.nll.stderr [new file with mode: 0644]
src/test/ui/hrtb/hrtb-just-for-static.stderr
src/test/ui/hrtb/issue-30786.migrate.stderr
src/test/ui/hrtb/issue-30786.nll.stderr
src/test/ui/hrtb/issue-30786.rs
src/test/ui/hrtb/issue-46989.nll.stderr [new file with mode: 0644]
src/test/ui/hrtb/issue-46989.rs
src/test/ui/hrtb/issue-46989.stderr
src/test/ui/hygiene/globs.stderr
src/test/ui/hygiene/unpretty-debug.stdout
src/test/ui/impl-trait/binding-without-value.rs [new file with mode: 0644]
src/test/ui/impl-trait/binding-without-value.stderr [new file with mode: 0644]
src/test/ui/impl-trait/equality-rpass.rs
src/test/ui/impl-trait/equality-rpass.stderr [new file with mode: 0644]
src/test/ui/impl-trait/equality.rs
src/test/ui/impl-trait/equality.stderr
src/test/ui/impl-trait/equality2.rs
src/test/ui/impl-trait/equality2.stderr
src/test/ui/impl-trait/issue-69840.rs [new file with mode: 0644]
src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs
src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
src/test/ui/impl-trait/no-method-suggested-traits.stderr
src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr
src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs
src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr
src/test/ui/impl-trait/static-return-lifetime-infered.stderr
src/test/ui/impl-trait/where-allowed-2.rs
src/test/ui/impl-trait/where-allowed-2.stderr
src/test/ui/infinite/infinite-instantiation.rs
src/test/ui/infinite/infinite-instantiation.stderr
src/test/ui/internal/internal-unstable-const.rs
src/test/ui/internal/internal-unstable-const.stderr
src/test/ui/issues-71798.rs
src/test/ui/issues-71798.stderr
src/test/ui/issues/issue-10412.stderr
src/test/ui/issues/issue-10991.stderr
src/test/ui/issues/issue-16048.rs
src/test/ui/issues/issue-16048.stderr
src/test/ui/issues/issue-16441.rs
src/test/ui/issues/issue-16922.stderr
src/test/ui/issues/issue-17441.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-1866.rs
src/test/ui/issues/issue-1866.stderr [new file with mode: 0644]
src/test/ui/issues/issue-18919.stderr
src/test/ui/issues/issue-22289.stderr
src/test/ui/issues/issue-22312.rs
src/test/ui/issues/issue-22312.stderr
src/test/ui/issues/issue-23046.rs
src/test/ui/issues/issue-23046.stderr
src/test/ui/issues/issue-23080-2.rs [deleted file]
src/test/ui/issues/issue-23080-2.stderr [deleted file]
src/test/ui/issues/issue-23080.rs [deleted file]
src/test/ui/issues/issue-23080.stderr [deleted file]
src/test/ui/issues/issue-23281.stderr
src/test/ui/issues/issue-25826.rs
src/test/ui/issues/issue-25826.stderr
src/test/ui/issues/issue-26545.rs [new file with mode: 0644]
src/test/ui/issues/issue-26545.stderr [new file with mode: 0644]
src/test/ui/issues/issue-26997.rs
src/test/ui/issues/issue-28600.rs
src/test/ui/issues/issue-2995.stderr
src/test/ui/issues/issue-35376.rs
src/test/ui/issues/issue-35376.stderr [new file with mode: 0644]
src/test/ui/issues/issue-35668.stderr
src/test/ui/issues/issue-35675.rs
src/test/ui/issues/issue-38091.rs
src/test/ui/issues/issue-38091.stderr [new file with mode: 0644]
src/test/ui/issues/issue-38763.rs
src/test/ui/issues/issue-40000.nll.stderr [new file with mode: 0644]
src/test/ui/issues/issue-40000.stderr
src/test/ui/issues/issue-42944.rs
src/test/ui/issues/issue-42944.stderr
src/test/ui/issues/issue-43623.rs
src/test/ui/issues/issue-43623.stderr
src/test/ui/issues/issue-4366-2.stderr
src/test/ui/issues/issue-4366.stderr
src/test/ui/issues/issue-44078.stderr
src/test/ui/issues/issue-45730.stderr
src/test/ui/issues/issue-46604.rs
src/test/ui/issues/issue-46604.stderr
src/test/ui/issues/issue-48508.rs
src/test/ui/issues/issue-51714.rs
src/test/ui/issues/issue-51714.stderr
src/test/ui/issues/issue-51907.rs
src/test/ui/issues/issue-5239-1.stderr
src/test/ui/issues/issue-55380.rs
src/test/ui/issues/issue-55380.stderr [new file with mode: 0644]
src/test/ui/issues/issue-57362-2.stderr
src/test/ui/issues/issue-5791.rs
src/test/ui/issues/issue-5791.stderr [new file with mode: 0644]
src/test/ui/issues/issue-59326.rs [new file with mode: 0644]
src/test/ui/issues/issue-60283.rs
src/test/ui/issues/issue-60283.stderr
src/test/ui/issues/issue-66706.rs
src/test/ui/issues/issue-66706.stderr
src/test/ui/issues/issue-67552.rs
src/test/ui/issues/issue-67552.stderr
src/test/ui/issues/issue-72690.rs [new file with mode: 0644]
src/test/ui/issues/issue-72690.stderr [new file with mode: 0644]
src/test/ui/issues/issue-8460-const.noopt.stderr
src/test/ui/issues/issue-8460-const.opt.stderr
src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr
src/test/ui/issues/issue-8727.rs
src/test/ui/issues/issue-8727.stderr
src/test/ui/layout/debug.stderr
src/test/ui/lint/auxiliary/external_extern_fn.rs [new file with mode: 0644]
src/test/ui/lint/clashing-extern-fn.rs [new file with mode: 0644]
src/test/ui/lint/clashing-extern-fn.stderr [new file with mode: 0644]
src/test/ui/lint/crate_level_only_lint.rs [new file with mode: 0644]
src/test/ui/lint/crate_level_only_lint.stderr [new file with mode: 0644]
src/test/ui/lint/dead-code/lint-dead-code-3.rs
src/test/ui/lint/dead-code/lint-dead-code-3.stderr
src/test/ui/lint/lint-ctypes-73249-1.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249-2.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249-2.stderr [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249-3.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249-3.stderr [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249-4.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249-5.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249-5.stderr [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73249.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73251-1.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73251-1.stderr [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73251-2.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73251-2.stderr [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-73251.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-fn.rs [new file with mode: 0644]
src/test/ui/lint/lint-ctypes-fn.stderr [new file with mode: 0644]
src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
src/test/ui/lint/lint-exceeding-bitshifts.rs
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr [new file with mode: 0644]
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.rs
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-non-ascii-idents.stderr
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.rs
src/test/ui/lint/rfc-2457-non-ascii-idents/lint-uncommon-codepoints.stderr
src/test/ui/lub-glb/old-lub-glb-hr-eq.rs [new file with mode: 0644]
src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr [new file with mode: 0644]
src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs [new file with mode: 0644]
src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr [new file with mode: 0644]
src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs [new file with mode: 0644]
src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr [new file with mode: 0644]
src/test/ui/lub-glb/old-lub-glb-hr.rs [deleted file]
src/test/ui/lub-glb/old-lub-glb-hr.stderr [deleted file]
src/test/ui/lub-glb/old-lub-glb-object.nll.stderr [new file with mode: 0644]
src/test/ui/lub-glb/old-lub-glb-object.rs
src/test/ui/lub-glb/old-lub-glb-object.stderr
src/test/ui/mir-dataflow/liveness-projection.rs [new file with mode: 0644]
src/test/ui/mir-dataflow/liveness-projection.stderr [new file with mode: 0644]
src/test/ui/mir/mir_cast_fn_ret.rs
src/test/ui/mir/mir_codegen_calls.rs
src/test/ui/mir/mir_detects_invalid_ops.rs
src/test/ui/mir/mir_detects_invalid_ops.stderr
src/test/ui/mismatched_types/cast-rfc0401.stderr
src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
src/test/ui/mismatched_types/closure-mismatch.nll.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/closure-mismatch.rs
src/test/ui/mismatched_types/closure-mismatch.stderr
src/test/ui/mismatched_types/issue-26480.stderr
src/test/ui/moves/issue-46099-move-in-macro.rs [new file with mode: 0644]
src/test/ui/moves/issue-46099-move-in-macro.stderr [new file with mode: 0644]
src/test/ui/moves/move-in-guard-2.stderr
src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr
src/test/ui/namespace/namespace-mix.stderr
src/test/ui/never_type/issue-51506.rs [new file with mode: 0644]
src/test/ui/never_type/issue-51506.stderr [new file with mode: 0644]
src/test/ui/nll/issue-53807.stderr
src/test/ui/nonscalar-cast.fixed [new file with mode: 0644]
src/test/ui/nonscalar-cast.rs
src/test/ui/nonscalar-cast.stderr
src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr
src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr
src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr
src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr
src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr
src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr
src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr
src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr
src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr
src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr
src/test/ui/numeric/numeric-cast-no-fix.rs [new file with mode: 0644]
src/test/ui/numeric/numeric-cast-no-fix.stderr [new file with mode: 0644]
src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
src/test/ui/or-patterns/const-fn.rs [new file with mode: 0644]
src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs
src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr
src/test/ui/or-patterns/feature-gate-const-fn.rs [deleted file]
src/test/ui/or-patterns/feature-gate-const-fn.stderr [deleted file]
src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
src/test/ui/order-dependent-cast-inference.stderr
src/test/ui/overlap-doesnt-conflict-with-specialization.rs
src/test/ui/overlap-doesnt-conflict-with-specialization.stderr [new file with mode: 0644]
src/test/ui/parser/assoc-static-semantic-fail.rs
src/test/ui/parser/assoc-static-semantic-fail.stderr
src/test/ui/parser/byte-literals.rs
src/test/ui/parser/byte-literals.stderr
src/test/ui/parser/byte-string-literals.stderr
src/test/ui/parser/default.rs
src/test/ui/parser/default.stderr
src/test/ui/parser/extern-abi-from-mac-literal-frag.rs
src/test/ui/parser/issue-62524.rs
src/test/ui/parser/issue-62524.stderr
src/test/ui/parser/let-binop.rs [new file with mode: 0644]
src/test/ui/parser/let-binop.stderr [new file with mode: 0644]
src/test/ui/parser/shebang/shebang-empty.rs [new file with mode: 0644]
src/test/ui/parser/shebang/shebang-space.rs [new file with mode: 0644]
src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs
src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
src/test/ui/parser/unbalanced-doublequote.stderr
src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr
src/test/ui/pattern/usefulness/issue-43253.stderr
src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr
src/test/ui/pattern/usefulness/match-non-exhaustive.stderr
src/test/ui/pattern/usefulness/non-exhaustive-match.rs
src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
src/test/ui/pattern/usefulness/refutable-pattern-errors.rs
src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr
src/test/ui/precise_pointer_size_matching.stderr
src/test/ui/privacy/privacy-ns1.stderr
src/test/ui/privacy/privacy-ns2.stderr
src/test/ui/proc-macro/auxiliary/first-second.rs [new file with mode: 0644]
src/test/ui/proc-macro/auxiliary/recollect.rs [new file with mode: 0644]
src/test/ui/proc-macro/auxiliary/weird-hygiene.rs [new file with mode: 0644]
src/test/ui/proc-macro/capture-macro-rules-invoke.rs [new file with mode: 0644]
src/test/ui/proc-macro/macro-rules-derive.rs [new file with mode: 0644]
src/test/ui/proc-macro/macro-rules-derive.stderr [new file with mode: 0644]
src/test/ui/proc-macro/weird-hygiene.rs [new file with mode: 0644]
src/test/ui/range/issue-73553-misinterp-range-literal.rs [new file with mode: 0644]
src/test/ui/range/issue-73553-misinterp-range-literal.stderr [new file with mode: 0644]
src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
src/test/ui/recursion/recursion.rs
src/test/ui/recursion/recursion.stderr
src/test/ui/ref-suggestion.stderr
src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr [new file with mode: 0644]
src/test/ui/regions-fn-subtyping-return-static-fail.rs
src/test/ui/regions-fn-subtyping-return-static-fail.stderr
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
src/test/ui/regions/region-object-lifetime-in-coercion.rs
src/test/ui/regions/region-object-lifetime-in-coercion.stderr
src/test/ui/regions/regions-close-object-into-object-2.stderr
src/test/ui/regions/regions-close-object-into-object-4.stderr
src/test/ui/regions/regions-fn-subtyping-return-static.rs
src/test/ui/regions/regions-fn-subtyping-return-static.stderr [deleted file]
src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
src/test/ui/regions/regions-proc-bound-capture.nll.stderr [new file with mode: 0644]
src/test/ui/regions/regions-proc-bound-capture.rs
src/test/ui/regions/regions-proc-bound-capture.stderr
src/test/ui/repeat_count.stderr
src/test/ui/resolve/issue-21221-1.stderr
src/test/ui/resolve/issue-21221-2.stderr
src/test/ui/resolve/privacy-enum-ctor.stderr
src/test/ui/return/return-match-array-const.rs
src/test/ui/return/return-match-array-const.stderr
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs [new file with mode: 0644]
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr [new file with mode: 0644]
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs [new file with mode: 0644]
src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs
src/test/ui/rfc-2632-const-trait-impl/hir-const-check.stderr
src/test/ui/rfc1623.nll.stderr [new file with mode: 0644]
src/test/ui/rfc1623.rs
src/test/ui/rfc1623.stderr
src/test/ui/sanitize/address.rs
src/test/ui/sanitize/badfree.rs
src/test/ui/sanitize/cfg.rs
src/test/ui/sanitize/incompatible.rs [new file with mode: 0644]
src/test/ui/sanitize/incompatible.stderr [new file with mode: 0644]
src/test/ui/sanitize/issue-72154-lifetime-markers.rs
src/test/ui/sanitize/leak.rs
src/test/ui/sanitize/memory.rs
src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs
src/test/ui/sanitize/thread.rs
src/test/ui/sanitize/unsupported-target.rs
src/test/ui/sanitize/unsupported-target.stderr
src/test/ui/sanitize/use-after-scope.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
src/test/ui/shebang.rs [deleted file]
src/test/ui/span/E0493.stderr
src/test/ui/specialization/assoc-ty-graph-cycle.rs
src/test/ui/specialization/assoc-ty-graph-cycle.stderr [new file with mode: 0644]
src/test/ui/specialization/cross-crate-defaults.rs
src/test/ui/specialization/cross-crate-defaults.stderr [new file with mode: 0644]
src/test/ui/specialization/deafult-associated-type-bound-1.rs [new file with mode: 0644]
src/test/ui/specialization/deafult-associated-type-bound-1.stderr [new file with mode: 0644]
src/test/ui/specialization/deafult-associated-type-bound-2.rs [new file with mode: 0644]
src/test/ui/specialization/deafult-associated-type-bound-2.stderr [new file with mode: 0644]
src/test/ui/specialization/deafult-generic-associated-type-bound.rs [new file with mode: 0644]
src/test/ui/specialization/deafult-generic-associated-type-bound.stderr [new file with mode: 0644]
src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs
src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr [new file with mode: 0644]
src/test/ui/specialization/defaultimpl/out-of-order.rs
src/test/ui/specialization/defaultimpl/out-of-order.stderr [new file with mode: 0644]
src/test/ui/specialization/defaultimpl/overlap-projection.rs
src/test/ui/specialization/defaultimpl/overlap-projection.stderr [new file with mode: 0644]
src/test/ui/specialization/defaultimpl/projection.rs
src/test/ui/specialization/defaultimpl/projection.stderr [new file with mode: 0644]
src/test/ui/specialization/defaultimpl/specialization-no-default.rs
src/test/ui/specialization/defaultimpl/specialization-no-default.stderr
src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs
src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr [new file with mode: 0644]
src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs
src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr
src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs
src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs
src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr
src/test/ui/specialization/defaultimpl/validation.rs
src/test/ui/specialization/defaultimpl/validation.stderr
src/test/ui/specialization/issue-36804.rs
src/test/ui/specialization/issue-36804.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-39448.rs
src/test/ui/specialization/issue-39448.stderr
src/test/ui/specialization/issue-39618.rs
src/test/ui/specialization/issue-39618.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-44861.rs [new file with mode: 0644]
src/test/ui/specialization/issue-44861.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-50452.rs
src/test/ui/specialization/issue-50452.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-52050.rs
src/test/ui/specialization/issue-52050.stderr
src/test/ui/specialization/issue-59435.rs [new file with mode: 0644]
src/test/ui/specialization/issue-59435.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-63716-parse-async.rs
src/test/ui/specialization/issue-63716-parse-async.stderr [new file with mode: 0644]
src/test/ui/specialization/issue-70442.rs
src/test/ui/specialization/issue-70442.stderr [new file with mode: 0644]
src/test/ui/specialization/non-defaulted-item-fail.rs
src/test/ui/specialization/non-defaulted-item-fail.stderr
src/test/ui/specialization/specialization-allowed-cross-crate.rs
src/test/ui/specialization/specialization-allowed-cross-crate.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-assoc-fns.rs
src/test/ui/specialization/specialization-assoc-fns.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-basics.rs
src/test/ui/specialization/specialization-basics.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-cross-crate.rs
src/test/ui/specialization/specialization-cross-crate.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-default-methods.rs
src/test/ui/specialization/specialization-default-methods.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-default-projection.rs
src/test/ui/specialization/specialization-default-projection.stderr
src/test/ui/specialization/specialization-default-types.rs
src/test/ui/specialization/specialization-default-types.stderr
src/test/ui/specialization/specialization-no-default.rs
src/test/ui/specialization/specialization-no-default.stderr
src/test/ui/specialization/specialization-on-projection.rs
src/test/ui/specialization/specialization-on-projection.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-out-of-order.rs
src/test/ui/specialization/specialization-out-of-order.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-overlap-negative.rs
src/test/ui/specialization/specialization-overlap-negative.stderr
src/test/ui/specialization/specialization-overlap-projection.rs
src/test/ui/specialization/specialization-overlap-projection.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-overlap.rs
src/test/ui/specialization/specialization-overlap.stderr
src/test/ui/specialization/specialization-polarity.rs
src/test/ui/specialization/specialization-polarity.stderr
src/test/ui/specialization/specialization-projection-alias.rs
src/test/ui/specialization/specialization-projection-alias.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-projection.rs
src/test/ui/specialization/specialization-projection.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-super-traits.rs
src/test/ui/specialization/specialization-super-traits.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs
src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-translate-projections-with-params.rs
src/test/ui/specialization/specialization-translate-projections-with-params.stderr [new file with mode: 0644]
src/test/ui/specialization/specialization-translate-projections.rs
src/test/ui/specialization/specialization-translate-projections.stderr [new file with mode: 0644]
src/test/ui/static/static-drop-scope.stderr
src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs [new file with mode: 0644]
src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr [new file with mode: 0644]
src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
src/test/ui/suggestions/invalid-bin-op.rs [new file with mode: 0644]
src/test/ui/suggestions/invalid-bin-op.stderr [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr [new file with mode: 0644]
src/test/ui/suggestions/missing-trait-bound-for-op.fixed [new file with mode: 0644]
src/test/ui/suggestions/missing-trait-bound-for-op.rs [new file with mode: 0644]
src/test/ui/suggestions/missing-trait-bound-for-op.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-move-types.stderr
src/test/ui/suggestions/type-not-found-in-adt-field.rs [new file with mode: 0644]
src/test/ui/suggestions/type-not-found-in-adt-field.stderr [new file with mode: 0644]
src/test/ui/tag-variant-cast-non-nullary.fixed [new file with mode: 0644]
src/test/ui/tag-variant-cast-non-nullary.rs
src/test/ui/tag-variant-cast-non-nullary.stderr
src/test/ui/terminal-width/flag-human.rs [new file with mode: 0644]
src/test/ui/terminal-width/flag-human.stderr [new file with mode: 0644]
src/test/ui/terminal-width/flag-json.rs [new file with mode: 0644]
src/test/ui/terminal-width/flag-json.stderr [new file with mode: 0644]
src/test/ui/tls.rs [new file with mode: 0644]
src/test/ui/traits/auto-traits.rs [deleted file]
src/test/ui/traits/negative-impls/negative-default-impls.rs
src/test/ui/traits/negative-impls/negative-default-impls.stderr
src/test/ui/traits/negative-impls/negative-specializes-negative.rs
src/test/ui/traits/negative-impls/negative-specializes-negative.stderr [new file with mode: 0644]
src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs
src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr
src/test/ui/traits/negative-impls/negative-specializes-positive.rs
src/test/ui/traits/negative-impls/negative-specializes-positive.stderr
src/test/ui/traits/negative-impls/positive-specializes-negative.rs
src/test/ui/traits/negative-impls/positive-specializes-negative.stderr
src/test/ui/traits/trait-item-privacy.stderr
src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-issue-39029.rs [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-issue-62530.rs [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-multiple-0.rs [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-multiple-1.rs [new file with mode: 0644]
src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr [new file with mode: 0644]
src/test/ui/traits/traits-inductive-overflow-lifetime.rs [new file with mode: 0644]
src/test/ui/traits/traits-inductive-overflow-lifetime.stderr [new file with mode: 0644]
src/test/ui/transmute-specialization.rs
src/test/ui/transmute-specialization.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs [new file with mode: 0644]
src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs [new file with mode: 0644]
src/test/ui/typeck/issue-73592-borrow_mut-through-deref.rs [new file with mode: 0644]
src/test/ui/typeck/issue-73592-borrow_mut-through-deref.stderr [new file with mode: 0644]
src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.rs [deleted file]
src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr [deleted file]
src/test/ui/typeck/typeck-auto-trait-no-supertraits.rs [deleted file]
src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.rs [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-constituent-types.rs [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-negation.rs [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-negation.stderr [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-precedence.rs [deleted file]
src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr [deleted file]
src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs
src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs
src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
src/test/ui/uninhabited/uninhabited-enum-cast.stderr
src/test/ui/unop-move-semantics.stderr
src/test/ui/unsafe/unsafe-unstable-const-fn.rs
src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
src/test/ui/unsized/unsized-enum.stderr
src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
src/test/ui/unsized/unsized-struct.stderr
src/test/ui/unsized/unsized-trait-impl-self-type.stderr
src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
src/test/ui/unsized3.stderr
src/test/ui/unsized7.stderr
src/test/ui/utf8_idents.rs
src/test/ui/utf8_idents.stderr
src/test/ui/wf/wf-fn-where-clause.stderr
src/test/ui/where-clauses/where-for-self-2.nll.stderr [new file with mode: 0644]
src/test/ui/where-clauses/where-for-self-2.rs
src/test/ui/where-clauses/where-for-self-2.stderr
src/test/ui/where-clauses/where-lifetime-resolution.rs
src/test/ui/where-clauses/where-lifetime-resolution.stderr
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/cargotest/main.rs
src/tools/clippy/.github/ISSUE_TEMPLATE.md [deleted file]
src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/config.yml [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md [new file with mode: 0644]
src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md [new file with mode: 0644]
src/tools/clippy/.github/PULL_REQUEST_TEMPLATE.md
src/tools/clippy/.github/driver.sh
src/tools/clippy/clippy_lints/src/arithmetic.rs
src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
src/tools/clippy/clippy_lints/src/assign_ops.rs
src/tools/clippy/clippy_lints/src/atomic_ordering.rs
src/tools/clippy/clippy_lints/src/bit_mask.rs
src/tools/clippy/clippy_lints/src/booleans.rs
src/tools/clippy/clippy_lints/src/bytecount.rs
src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
src/tools/clippy/clippy_lints/src/comparison_chain.rs
src/tools/clippy/clippy_lints/src/consts.rs
src/tools/clippy/clippy_lints/src/copies.rs
src/tools/clippy/clippy_lints/src/default_trait_access.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
src/tools/clippy/clippy_lints/src/duration_subsec.rs
src/tools/clippy/clippy_lints/src/entry.rs
src/tools/clippy/clippy_lints/src/eq_op.rs
src/tools/clippy/clippy_lints/src/erasing_op.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
src/tools/clippy/clippy_lints/src/float_literal.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/format.rs
src/tools/clippy/clippy_lints/src/functions.rs
src/tools/clippy/clippy_lints/src/get_last_with_len.rs
src/tools/clippy/clippy_lints/src/identity_op.rs
src/tools/clippy/clippy_lints/src/if_let_mutex.rs
src/tools/clippy/clippy_lints/src/if_let_some_result.rs
src/tools/clippy/clippy_lints/src/implicit_return.rs
src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
src/tools/clippy/clippy_lints/src/indexing_slicing.rs
src/tools/clippy/clippy_lints/src/infinite_iter.rs
src/tools/clippy/clippy_lints/src/integer_division.rs
src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/let_and_return.rs
src/tools/clippy/clippy_lints/src/let_if_seq.rs
src/tools/clippy/clippy_lints/src/let_underscore.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/loops.rs
src/tools/clippy/clippy_lints/src/macro_use.rs
src/tools/clippy/clippy_lints/src/map_clone.rs
src/tools/clippy/clippy_lints/src/map_unit_fn.rs
src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/mem_discriminant.rs
src/tools/clippy/clippy_lints/src/mem_forget.rs
src/tools/clippy/clippy_lints/src/mem_replace.rs
src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
src/tools/clippy/clippy_lints/src/minmax.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
src/tools/clippy/clippy_lints/src/mut_key.rs
src/tools/clippy/clippy_lints/src/mut_mut.rs
src/tools/clippy/clippy_lints/src/mut_reference.rs
src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
src/tools/clippy/clippy_lints/src/mutex_atomic.rs
src/tools/clippy/clippy_lints/src/needless_bool.rs
src/tools/clippy/clippy_lints/src/needless_borrow.rs
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
src/tools/clippy/clippy_lints/src/needless_update.rs
src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
src/tools/clippy/clippy_lints/src/neg_multiply.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/no_effect.rs
src/tools/clippy/clippy_lints/src/non_copy_const.rs
src/tools/clippy/clippy_lints/src/open_options.rs
src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs
src/tools/clippy/clippy_lints/src/regex.rs
src/tools/clippy/clippy_lints/src/shadow.rs
src/tools/clippy/clippy_lints/src/strings.rs
src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
src/tools/clippy/clippy_lints/src/swap.rs
src/tools/clippy/clippy_lints/src/temporary_assignment.rs
src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_lints/src/transmute.rs
src/tools/clippy/clippy_lints/src/transmuting_null.rs
src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
src/tools/clippy/clippy_lints/src/try_err.rs
src/tools/clippy/clippy_lints/src/types.rs
src/tools/clippy/clippy_lints/src/unnamed_address.rs
src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
src/tools/clippy/clippy_lints/src/unwrap.rs
src/tools/clippy/clippy_lints/src/useless_conversion.rs
src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
src/tools/clippy/clippy_lints/src/utils/author.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/higher.rs
src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
src/tools/clippy/clippy_lints/src/utils/inspector.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/mod.rs
src/tools/clippy/clippy_lints/src/utils/sugg.rs
src/tools/clippy/clippy_lints/src/utils/usage.rs
src/tools/clippy/clippy_lints/src/vec.rs
src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
src/tools/clippy/clippy_lints/src/wildcard_imports.rs
src/tools/clippy/clippy_lints/src/zero_div_zero.rs
src/tools/clippy/doc/common_tools_writing_lints.md
src/tools/clippy/src/driver.rs
src/tools/clippy/src/lintlist/mod.rs
src/tools/clippy/src/main.rs
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/blacklisted_name.rs
src/tools/clippy/tests/ui/blacklisted_name.stderr
src/tools/clippy/tests/ui/crashes/ice-5389.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/if_same_then_else.rs
src/tools/clippy/tests/ui/macro_use_imports.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/macro_use_imports.rs
src/tools/clippy/tests/ui/macro_use_imports.stderr
src/tools/clippy/tests/ui/redundant_pattern_matching.fixed
src/tools/clippy/tests/ui/redundant_pattern_matching.rs
src/tools/clippy/tests/ui/redundant_pattern_matching.stderr
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/repl_uninit.rs
src/tools/clippy/tests/ui/repl_uninit.stderr
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/header/tests.rs
src/tools/compiletest/src/json.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/read2.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/error_index_generator/main.rs
src/tools/expand-yaml-anchors/src/main.rs
src/tools/linkchecker/main.rs
src/tools/miri
src/tools/remote-test-client/src/main.rs
src/tools/remote-test-server/src/main.rs
src/tools/rls
src/tools/rustbook/Cargo.toml
src/tools/rustbook/src/main.rs
src/tools/rustc-workspace-hack/Cargo.toml
src/tools/rustdoc-js/tester.js
src/tools/rustfmt
src/tools/tidy/src/deps.rs
src/tools/tidy/src/features.rs
src/tools/tidy/src/main.rs
src/tools/tidy/src/pal.rs
src/tools/unstable-book-gen/src/main.rs
triagebot.toml

index bf3c22744f1650c1a8aa2ef06dee11e2be7a8652..7b9f87c079e3a4070f3afe71a695d47417d8710f 100644 (file)
@@ -152,10 +152,6 @@ jobs:
           - name: dist-x86_64-linux
             os: ubuntu-latest-xl
             env: {}
-          - name: dist-x86_64-linux-alt
-            env:
-              IMAGE: dist-x86_64-linux
-            os: ubuntu-latest-xl
     timeout-minutes: 600
     runs-on: "${{ matrix.os }}"
     steps:
@@ -373,35 +369,6 @@ jobs:
             env:
               DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
             os: ubuntu-latest-xl
-          - name: dist-x86_64-apple
-            env:
-              SCRIPT: "./x.py dist"
-              RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc"
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-              DIST_REQUIRE_ALL_TOOLS: 1
-            os: macos-latest
-          - name: dist-x86_64-apple-alt
-            env:
-              SCRIPT: "./x.py dist"
-              RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc"
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            os: macos-latest
-          - name: x86_64-apple
-            env:
-              SCRIPT: "./x.py test"
-              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.8
-              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            os: macos-latest
           - name: x86_64-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -584,6 +551,135 @@ jobs:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
         if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
+  auto-fallible:
+    name: auto-fallible
+    env:
+      CI_JOB_NAME: "${{ matrix.name }}"
+      SCCACHE_BUCKET: rust-lang-gha-caches
+      DEPLOY_BUCKET: rust-lang-gha
+      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
+      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+      TOOLSTATE_PUBLISH: 1
+      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
+      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
+      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+    if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
+    strategy:
+      matrix:
+        include:
+          - name: dist-x86_64-apple
+            env:
+              SCRIPT: "./x.py dist"
+              RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+            os: macos-latest
+          - name: dist-x86_64-apple-alt
+            env:
+              SCRIPT: "./x.py dist"
+              RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            os: macos-latest
+          - name: x86_64-apple
+            env:
+              SCRIPT: "./x.py test"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.8
+              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            os: macos-latest
+    timeout-minutes: 600
+    runs-on: "${{ matrix.os }}"
+    steps:
+      - name: disable git crlf conversion
+        run: git config --global core.autocrlf false
+        shell: bash
+      - name: checkout the source code
+        uses: actions/checkout@v1
+        with:
+          fetch-depth: 2
+      - name: configure GitHub Actions to kill the build when outdated
+        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.github_token }}"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+      - name: add extra environment variables
+        run: src/ci/scripts/setup-environment.sh
+        env:
+          EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
+        if: success() && !env.SKIP_JOB
+      - name: decide whether to skip this job
+        run: src/ci/scripts/should-skip-this.sh
+        if: success() && !env.SKIP_JOB
+      - name: collect CPU statistics
+        run: src/ci/scripts/collect-cpu-stats.sh
+        if: success() && !env.SKIP_JOB
+      - name: show the current environment
+        run: src/ci/scripts/dump-environment.sh
+        if: success() && !env.SKIP_JOB
+      - name: install awscli
+        run: src/ci/scripts/install-awscli.sh
+        if: success() && !env.SKIP_JOB
+      - name: install sccache
+        run: src/ci/scripts/install-sccache.sh
+        if: success() && !env.SKIP_JOB
+      - name: install clang
+        run: src/ci/scripts/install-clang.sh
+        if: success() && !env.SKIP_JOB
+      - name: install WIX
+        run: src/ci/scripts/install-wix.sh
+        if: success() && !env.SKIP_JOB
+      - name: install InnoSetup
+        run: src/ci/scripts/install-innosetup.sh
+        if: success() && !env.SKIP_JOB
+      - name: ensure the build happens on a partition with enough space
+        run: src/ci/scripts/symlink-build-dir.sh
+        if: success() && !env.SKIP_JOB
+      - name: disable git crlf conversion
+        run: src/ci/scripts/disable-git-crlf-conversion.sh
+        if: success() && !env.SKIP_JOB
+      - name: install MSYS2
+        run: src/ci/scripts/install-msys2.sh
+        if: success() && !env.SKIP_JOB
+      - name: install MinGW
+        run: src/ci/scripts/install-mingw.sh
+        if: success() && !env.SKIP_JOB
+      - name: install ninja
+        run: src/ci/scripts/install-ninja.sh
+        if: success() && !env.SKIP_JOB
+      - name: enable ipv6 on Docker
+        run: src/ci/scripts/enable-docker-ipv6.sh
+        if: success() && !env.SKIP_JOB
+      - name: disable git crlf conversion
+        run: src/ci/scripts/disable-git-crlf-conversion.sh
+        if: success() && !env.SKIP_JOB
+      - name: checkout submodules
+        run: src/ci/scripts/checkout-submodules.sh
+        if: success() && !env.SKIP_JOB
+      - name: ensure line endings are correct
+        run: src/ci/scripts/verify-line-endings.sh
+        if: success() && !env.SKIP_JOB
+      - name: run the build
+        run: src/ci/scripts/run-build-from-ci.sh
+        env:
+          AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
+          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
+          TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
+        if: success() && !env.SKIP_JOB
+      - name: upload artifacts to S3
+        run: src/ci/scripts/upload-artifacts.sh
+        env:
+          AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
+          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
+        if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
   master:
     name: master
     runs-on: ubuntu-latest
index 009767934d447c0853ceacf5d089f0ac3e7ef6a9..e9fb097df92d2d6243fcc13be8dd2da794f974d0 100644 (file)
@@ -65,9 +65,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.26"
+version = "1.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
+checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
 
 [[package]]
 name = "arc-swap"
@@ -143,15 +143,6 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
-[[package]]
-name = "base64"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
-dependencies = [
- "byteorder",
-]
-
 [[package]]
 name = "bitflags"
 version = "1.2.1"
@@ -270,7 +261,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
 dependencies = [
  "byteorder",
- "either",
  "iovec",
 ]
 
@@ -291,7 +281,7 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "clap",
- "core-foundation 0.7.0",
+ "core-foundation",
  "crates-io",
  "crossbeam-utils 0.7.2",
  "crypto-hash",
@@ -434,9 +424,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-derive"
-version = "0.10.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d4620afad4d4d9e63f915cfa10c930b7a3c9c3ca5cd88dd771ff8e5bf04ea10"
+checksum = "d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d"
 dependencies = [
  "proc-macro2 1.0.3",
  "quote 1.0.2",
@@ -446,61 +436,40 @@ dependencies = [
 
 [[package]]
 name = "chalk-engine"
-version = "0.10.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ca6e5cef10197789da0b4ec310eda58da4c55530613b2323432642a97372735"
+checksum = "efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000"
 dependencies = [
- "chalk-macros",
+ "chalk-derive",
+ "chalk-ir",
  "rustc-hash",
+ "tracing",
 ]
 
 [[package]]
 name = "chalk-ir"
-version = "0.10.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d45df5fb6328527f976e8a32c9e1c9970084d937ebe93d0d34f5bbf4231cb956"
+checksum = "fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe"
 dependencies = [
  "chalk-derive",
- "chalk-engine",
- "chalk-macros",
-]
-
-[[package]]
-name = "chalk-macros"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e4782d108e420a1fcf94d8a919cf248db33c5071678e87d9c2d4f20ed1feb32"
-dependencies = [
  "lazy_static",
 ]
 
-[[package]]
-name = "chalk-rust-ir"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0ec96dbe0ab5fdbadfca4179ec2e1d35f0439c3b53a74988b1aec239c63eb08"
-dependencies = [
- "chalk-derive",
- "chalk-engine",
- "chalk-ir",
- "chalk-macros",
-]
-
 [[package]]
 name = "chalk-solve"
-version = "0.10.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfb99fa9530f0e101475fb60adc931f51bdea05b4642a48928b814d7f0141a6b"
+checksum = "5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29"
 dependencies = [
  "chalk-derive",
  "chalk-engine",
  "chalk-ir",
- "chalk-macros",
- "chalk-rust-ir",
- "ena 0.13.1",
+ "ena",
  "itertools 0.9.0",
  "petgraph",
  "rustc-hash",
+ "tracing",
 ]
 
 [[package]]
@@ -560,7 +529,7 @@ dependencies = [
  "if_chain",
  "itertools 0.9.0",
  "lazy_static",
- "pulldown-cmark 0.7.1",
+ "pulldown-cmark",
  "quine-mc_cluskey",
  "quote 1.0.2",
  "regex-syntax",
@@ -591,26 +560,6 @@ dependencies = [
  "cc",
 ]
 
-[[package]]
-name = "codespan"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de67bdcd653002a6dba3eb53850ce3a485547225d81cb6c2bbdbc5a0cba5d15d"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
-name = "codespan-reporting"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd1d915d9e2b2ad696b2cd73215a84823ef3f0e3084d90304204415921b62c6"
-dependencies = [
- "codespan",
- "termcolor",
- "unicode-width",
-]
-
 [[package]]
 name = "colored"
 version = "1.9.3"
@@ -697,34 +646,6 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
 
-[[package]]
-name = "cookie"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
-dependencies = [
- "time",
- "url 1.7.2",
-]
-
-[[package]]
-name = "cookie_store"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c"
-dependencies = [
- "cookie",
- "failure",
- "idna 0.1.5",
- "log",
- "publicsuffix",
- "serde",
- "serde_json",
- "time",
- "try_from",
- "url 1.7.2",
-]
-
 [[package]]
 name = "core"
 version = "0.0.0"
@@ -732,32 +653,16 @@ dependencies = [
  "rand 0.7.3",
 ]
 
-[[package]]
-name = "core-foundation"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
-dependencies = [
- "core-foundation-sys 0.6.2",
- "libc",
-]
-
 [[package]]
 name = "core-foundation"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
 dependencies = [
- "core-foundation-sys 0.7.0",
+ "core-foundation-sys",
  "libc",
 ]
 
-[[package]]
-name = "core-foundation-sys"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
-
 [[package]]
 name = "core-foundation-sys"
 version = "0.7.0"
@@ -902,40 +807,6 @@ dependencies = [
  "winapi 0.3.8",
 ]
 
-[[package]]
-name = "darling"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9158d690bc62a3a57c3e45b85e4d50de2008b39345592c64efd79345c7e24be0"
-dependencies = [
- "darling_core",
- "darling_macro",
-]
-
-[[package]]
-name = "darling_core"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2a368589465391e127e10c9e3a08efc8df66fd49b87dc8524c764bbe7f2ef82"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2 0.4.30",
- "quote 0.6.12",
- "syn 0.15.35",
-]
-
-[[package]]
-name = "darling_macro"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1"
-dependencies = [
- "darling_core",
- "quote 0.6.12",
- "syn 0.15.35",
-]
-
 [[package]]
 name = "datafrog"
 version = "2.0.1"
@@ -1028,18 +899,6 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
-[[package]]
-name = "dtoa"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
-
-[[package]]
-name = "dunce"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0ad6bf6a88548d1126045c413548df1453d9be094a8ab9fd59bf1fdd338da4f"
-
 [[package]]
 name = "either"
 version = "1.5.0"
@@ -1061,15 +920,6 @@ dependencies = [
  "strum_macros",
 ]
 
-[[package]]
-name = "ena"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36"
-dependencies = [
- "log",
-]
-
 [[package]]
 name = "ena"
 version = "0.14.0"
@@ -1079,15 +929,6 @@ dependencies = [
  "log",
 ]
 
-[[package]]
-name = "encoding_rs"
-version = "0.8.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
-dependencies = [
- "cfg-if",
-]
-
 [[package]]
 name = "env_logger"
 version = "0.6.2"
@@ -1114,15 +955,6 @@ dependencies = [
  "termcolor",
 ]
 
-[[package]]
-name = "error-chain"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
-dependencies = [
- "backtrace",
-]
-
 [[package]]
 name = "error_index_generator"
 version = "0.0.0"
@@ -1181,9 +1013,9 @@ dependencies = [
 
 [[package]]
 name = "fixedbitset"
-version = "0.1.9"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
 
 [[package]]
 name = "flate2"
@@ -1282,16 +1114,6 @@ version = "0.1.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869"
 
-[[package]]
-name = "futures-cpupool"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
-dependencies = [
- "futures",
- "num_cpus",
-]
-
 [[package]]
 name = "fwdansi"
 version = "1.0.1"
@@ -1379,24 +1201,6 @@ dependencies = [
  "regex",
 ]
 
-[[package]]
-name = "h2"
-version = "0.1.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a539b63339fbbb00e081e84b6e11bd1d9634a82d91da2984a18ac74a8823f392"
-dependencies = [
- "byteorder",
- "bytes",
- "fnv",
- "futures",
- "http",
- "indexmap",
- "log",
- "slab",
- "string",
- "tokio-io",
-]
-
 [[package]]
 name = "handlebars"
 version = "3.0.1"
@@ -1479,35 +1283,6 @@ dependencies = [
  "syn 1.0.11",
 ]
 
-[[package]]
-name = "http"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http-body"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d"
-dependencies = [
- "bytes",
- "futures",
- "http",
- "tokio-buf",
-]
-
-[[package]]
-name = "httparse"
-version = "1.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
-
 [[package]]
 name = "humantime"
 version = "1.3.0"
@@ -1523,55 +1298,6 @@ version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da"
 
-[[package]]
-name = "hyper"
-version = "0.12.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6481fff8269772d4463253ca83c788104a7305cb3fb9136bc651a6211e46e03f"
-dependencies = [
- "bytes",
- "futures",
- "futures-cpupool",
- "h2",
- "http",
- "http-body",
- "httparse",
- "iovec",
- "itoa",
- "log",
- "net2",
- "rustc_version",
- "time",
- "tokio",
- "tokio-buf",
- "tokio-executor",
- "tokio-io",
- "tokio-reactor",
- "tokio-tcp",
- "tokio-threadpool",
- "tokio-timer",
- "want",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f"
-dependencies = [
- "bytes",
- "futures",
- "hyper",
- "native-tls",
- "tokio-io",
-]
-
-[[package]]
-name = "ident_case"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
-
 [[package]]
 name = "idna"
 version = "0.1.5"
@@ -1664,12 +1390,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "is-match"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
-
 [[package]]
 name = "itertools"
 version = "0.8.0"
@@ -2022,23 +1742,22 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.3.7"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ec525f7ebccc2dd935c263717250cd37f9a4b264a77c5dbc950ea2734d8159"
+checksum = "2567ffadc0fd26fe15d6f6e0a80639f19f6a50082fdb460d0ae5d1f7298181be"
 dependencies = [
  "ammonia",
+ "anyhow",
  "chrono",
  "clap",
  "elasticlunr-rs",
- "env_logger 0.6.2",
- "error-chain",
+ "env_logger 0.7.1",
  "handlebars",
- "itertools 0.8.0",
  "lazy_static",
  "log",
  "memchr",
  "open",
- "pulldown-cmark 0.6.1",
+ "pulldown-cmark",
  "regex",
  "serde",
  "serde_derive",
@@ -2046,34 +1765,6 @@ dependencies = [
  "shlex",
  "tempfile",
  "toml",
- "toml-query",
-]
-
-[[package]]
-name = "mdbook-linkcheck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0a04db564ca37c47771f8455c825dc941ea851ff0deffcf55a04c512406b409"
-dependencies = [
- "codespan",
- "codespan-reporting",
- "dunce",
- "either",
- "env_logger 0.7.1",
- "failure",
- "http",
- "log",
- "mdbook",
- "percent-encoding 2.1.0",
- "pulldown-cmark 0.6.1",
- "rayon",
- "regex",
- "reqwest",
- "semver 0.9.0",
- "serde",
- "serde_derive",
- "serde_json",
- "structopt",
 ]
 
 [[package]]
@@ -2113,25 +1804,6 @@ dependencies = [
  "rustc_version",
 ]
 
-[[package]]
-name = "mime"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
-dependencies = [
- "unicase",
-]
-
-[[package]]
-name = "mime_guess"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599"
-dependencies = [
- "mime",
- "unicase",
-]
-
 [[package]]
 name = "minifier"
 version = "0.0.33"
@@ -2232,24 +1904,6 @@ dependencies = [
  "shell-escape",
 ]
 
-[[package]]
-name = "native-tls"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
-dependencies = [
- "lazy_static",
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
 [[package]]
 name = "net2"
 version = "0.2.33"
@@ -2370,12 +2024,6 @@ dependencies = [
  "vcpkg",
 ]
 
-[[package]]
-name = "ordermap"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
-
 [[package]]
 name = "ordslice"
 version = "0.3.0"
@@ -2546,12 +2194,12 @@ dependencies = [
 
 [[package]]
 name = "petgraph"
-version = "0.4.13"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
 dependencies = [
  "fixedbitset",
- "ordermap",
+ "indexmap",
 ]
 
 [[package]]
@@ -2706,31 +2354,6 @@ dependencies = [
  "cc",
 ]
 
-[[package]]
-name = "publicsuffix"
-version = "1.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510"
-dependencies = [
- "error-chain",
- "idna 0.2.0",
- "lazy_static",
- "regex",
- "url 2.1.0",
-]
-
-[[package]]
-name = "pulldown-cmark"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c205cc82214f3594e2d50686730314f817c67ffa80fe800cf0db78c3c2b9d9e"
-dependencies = [
- "bitflags",
- "getopts",
- "memchr",
- "unicase",
-]
-
 [[package]]
 name = "pulldown-cmark"
 version = "0.7.1"
@@ -2738,6 +2361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3e142c3b8f49d2200605ee6ba0b1d757310e9e7a72afe78c36ee2ef67300ee00"
 dependencies = [
  "bitflags",
+ "getopts",
  "memchr",
  "unicase",
 ]
@@ -2780,9 +2404,9 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.34"
+version = "2.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc9caecf1286a3ed28d3ae35207a178ba12e58de95540781e5c6cba05e0f0833"
+checksum = "421174f19211ba9e5fda34aa0cbc292188aae8e0cfbff4aebbae23f1a416bfb3"
 dependencies = [
  "bitflags",
  "clap",
@@ -3038,40 +2662,6 @@ dependencies = [
  "winapi 0.3.8",
 ]
 
-[[package]]
-name = "reqwest"
-version = "0.9.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c2064233e442ce85c77231ebd67d9eca395207dec2127fe0bbedde4bd29a650"
-dependencies = [
- "base64",
- "bytes",
- "cookie",
- "cookie_store",
- "encoding_rs",
- "flate2",
- "futures",
- "http",
- "hyper",
- "hyper-tls",
- "log",
- "mime",
- "mime_guess",
- "native-tls",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "time",
- "tokio",
- "tokio-executor",
- "tokio-io",
- "tokio-threadpool",
- "tokio-timer",
- "url 1.7.2",
- "uuid",
- "winreg",
-]
-
 [[package]]
 name = "rls"
 version = "1.41.0"
@@ -3198,52 +2788,42 @@ name = "rustbook"
 version = "0.1.0"
 dependencies = [
  "clap",
- "codespan",
- "codespan-reporting",
- "failure",
  "mdbook",
- "mdbook-linkcheck",
- "rustc-workspace-hack",
 ]
 
 [[package]]
-name = "rustc-ap-arena"
-version = "659.0.0"
+name = "rustc-ap-rustc_arena"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdaf0295fc40b10ec1091aad1a1760b4bb3b4e7c4f77d543d1a2e9d50a01e6b1"
+checksum = "0c6683b49209f8b132bec33dc6b6c8f9958c8c94eb3586d4cb495e092b61c1da"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "smallvec 1.4.0",
 ]
 
-[[package]]
-name = "rustc-ap-graphviz"
-version = "659.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8028e8cdb4eb71810d0c22a5a5e1e3106c81123be63ce7f044b6d4ac100d8941"
-
 [[package]]
 name = "rustc-ap-rustc_ast"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16e9e502bb3a5568433db1cf2fb1f1e1074934636069cf744ad7c77b58e1428e"
+checksum = "5b21784d92fb2d584800f528866f00fe814f73abda794f406bfd1fbb2f1ca7f7"
 dependencies = [
+ "bitflags",
  "log",
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_index",
  "rustc-ap-rustc_lexer",
  "rustc-ap-rustc_macros",
+ "rustc-ap-rustc_serialize",
  "rustc-ap-rustc_span",
- "rustc-ap-serialize",
  "scoped-tls",
  "smallvec 1.4.0",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_ast_passes"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faf35ffecab28f97f7ac01cf6a13afaca6408529d15eb95f317a43b2ffb88933"
+checksum = "820c46fde7ef1df0432073090d775f097b7279ca75ea34ba954081ce4b884d4c"
 dependencies = [
  "itertools 0.8.0",
  "log",
@@ -3260,20 +2840,21 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_ast_pretty"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3684ed43dc552f1e030e3f7a5a300a7a834bdda4e9e00ab80284be4220d8c603"
+checksum = "013db7dd198fe95962d2cefa5bd0b350cf2028af77c169b17b4baa9c3bbf77d1"
 dependencies = [
  "log",
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_span",
+ "rustc-ap-rustc_target",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_attr"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31b413927daa666983b3b49227f9ac218aa29254546abdb585f20cd71c391870"
+checksum = "35b5a85c90eb341eec543600ffdd9e262da5ea72a73a23ae4ca2f4ab8cd1a188"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_ast_pretty",
@@ -3281,32 +2862,33 @@ dependencies = [
  "rustc-ap-rustc_errors",
  "rustc-ap-rustc_feature",
  "rustc-ap-rustc_macros",
+ "rustc-ap-rustc_serialize",
  "rustc-ap-rustc_session",
  "rustc-ap-rustc_span",
- "rustc-ap-serialize",
  "version_check",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b1c6069e5c522657f1c6f5ab33074e097092f48e804cc896d337e319aacbd60"
+checksum = "b92e4c6cb6c43ee9031a71709dc12853b358253c2b41d12a26379994fab625e0"
 dependencies = [
  "bitflags",
  "cfg-if",
  "crossbeam-utils 0.7.2",
- "ena 0.14.0",
+ "ena",
  "indexmap",
  "jobserver",
  "lazy_static",
  "libc",
  "log",
  "measureme",
+ "once_cell",
  "parking_lot 0.10.2",
- "rustc-ap-graphviz",
+ "rustc-ap-rustc_graphviz",
  "rustc-ap-rustc_index",
- "rustc-ap-serialize",
+ "rustc-ap-rustc_serialize",
  "rustc-hash",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -3318,16 +2900,16 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c374e89b3c9714869ef86076942155383804ba6778c26be2169d324563c31f9"
+checksum = "6b0aa79423260c1b9e2f856e144e040f606b0f5d43644408375becf9d7bcdf86"
 dependencies = [
- "annotate-snippets 0.6.1",
+ "annotate-snippets 0.8.0",
  "atty",
  "log",
  "rustc-ap-rustc_data_structures",
+ "rustc-ap-rustc_serialize",
  "rustc-ap-rustc_span",
- "rustc-ap-serialize",
  "termcolor",
  "termize",
  "unicode-width",
@@ -3336,9 +2918,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_expand"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "259d2a7aa7a12f3c99a4ce4123643ec065f1a26f8e89be1f9bedd9757ea53fdc"
+checksum = "c07d76ba2a1b7d4325a2ed21d6345ccebd89ddc6666a1535a6edd489fb4cbc11"
 dependencies = [
  "log",
  "rustc-ap-rustc_ast",
@@ -3350,17 +2932,17 @@ dependencies = [
  "rustc-ap-rustc_feature",
  "rustc-ap-rustc_lexer",
  "rustc-ap-rustc_parse",
+ "rustc-ap-rustc_serialize",
  "rustc-ap-rustc_session",
  "rustc-ap-rustc_span",
- "rustc-ap-serialize",
  "smallvec 1.4.0",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_feature"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0296fbc29b629d5ae2ebee1bbf0407bb22de04d26d87216c20899b79579ccb3"
+checksum = "1bbd625705c1db42a0c7503736292813d7b76ada5da20578fb55c63228c80ab5"
 dependencies = [
  "lazy_static",
  "rustc-ap-rustc_data_structures",
@@ -3369,34 +2951,40 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_fs_util"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34734f6cc681399630acd836a14207c6b5b9671a290cc7cad0354b0a4d71b3c9"
+checksum = "34cca6e2942fa0b059c582437ead666d5bcf20fa7c242599e2bbea9b609f29ae"
+
+[[package]]
+name = "rustc-ap-rustc_graphviz"
+version = "664.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13d6a029b81f5e02da85763f82c135507f278a4a0c776432c728520563059529"
 
 [[package]]
 name = "rustc-ap-rustc_index"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1e4508753d71d3523209c2ca5086db15a1413e71ebf17ad5412bb7ced5e44c2"
+checksum = "bae50852d303e230b2781c994513788136dc6c2fe4ebe032959f0b990a425767"
 dependencies = [
- "rustc-ap-serialize",
+ "rustc-ap-rustc_serialize",
  "smallvec 1.4.0",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42b9fcd8407e322908a721262fbc0b35b5f3c35bb173a26dd1e0070bde336e33"
+checksum = "b7186e74aa2d31bf0e2454325fefcdf0a3da77d9344134592144b9e40d45b15d"
 dependencies = [
  "unicode-xid 0.2.0",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_macros"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d104115a689367d2e0bcd99f37e0ebd6b9c8c78bab0d9cbea5bae86323601b5"
+checksum = "4fc1add04e9d2301164118660ee0bc3266e9a7b1973fc2303fdbe002a12e5401"
 dependencies = [
  "proc-macro2 1.0.3",
  "quote 1.0.2",
@@ -3406,9 +2994,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_parse"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afaaab91853fc5a3916785ccae727a4433359d9787c260d42b96a2265fe5b287"
+checksum = "9cd7fc4968bd60084f2fa4f280fa450b0cf98660a7983d6b93a7ae41b6d1d322"
 dependencies = [
  "bitflags",
  "log",
@@ -3423,11 +3011,21 @@ dependencies = [
  "unicode-normalization",
 ]
 
+[[package]]
+name = "rustc-ap-rustc_serialize"
+version = "664.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00bf4c110271d9a2b7dfd2c6eb82e56fd80606a8bad6c102e158c54e44044046"
+dependencies = [
+ "indexmap",
+ "smallvec 1.4.0",
+]
+
 [[package]]
 name = "rustc-ap-rustc_session"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86e756a57ce6ce1b868e35e64a7e10ab28d49ece80d7c661b07aff5afc6e5d2d"
+checksum = "431cf962de71d4c03fb877d54f331ec36eca77350b0539017abc40a4410d6501"
 dependencies = [
  "getopts",
  "log",
@@ -3437,26 +3035,25 @@ dependencies = [
  "rustc-ap-rustc_errors",
  "rustc-ap-rustc_feature",
  "rustc-ap-rustc_fs_util",
- "rustc-ap-rustc_index",
+ "rustc-ap-rustc_serialize",
  "rustc-ap-rustc_span",
  "rustc-ap-rustc_target",
- "rustc-ap-serialize",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_span"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21031c3396ee452f4c6e994b67513a633055c57c86d00336afd9d63149518f34"
+checksum = "b912039640597624f4bcb75f1e1fcfa5710267d715a7f73a6336baef341b23d1"
 dependencies = [
  "cfg-if",
  "log",
  "md-5",
- "rustc-ap-arena",
+ "rustc-ap-rustc_arena",
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_index",
  "rustc-ap-rustc_macros",
- "rustc-ap-serialize",
+ "rustc-ap-rustc_serialize",
  "scoped-tls",
  "sha-1",
  "unicode-width",
@@ -3464,27 +3061,17 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_target"
-version = "659.0.0"
+version = "664.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff21badfbead5b0050391eaad8840f2e4fcb03b6b0fc6006f447443529e9ae6e"
+checksum = "51347a9dadc5ad0b5916cc12d42624b31955285ad13745dbe72f0140038b84e9"
 dependencies = [
  "bitflags",
  "log",
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_index",
  "rustc-ap-rustc_macros",
+ "rustc-ap-rustc_serialize",
  "rustc-ap-rustc_span",
- "rustc-ap-serialize",
-]
-
-[[package]]
-name = "rustc-ap-serialize"
-version = "659.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "768b5a305669d934522712bc13502962edfde5128ea63b9e7db4000410be1dc6"
-dependencies = [
- "indexmap",
- "smallvec 1.4.0",
 ]
 
 [[package]]
@@ -3499,12 +3086,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-hash"
-version = "1.0.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
-dependencies = [
- "byteorder",
-]
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
 [[package]]
 name = "rustc-main"
@@ -3571,7 +3155,6 @@ dependencies = [
  "serde_json",
  "smallvec 0.6.10",
  "smallvec 1.4.0",
- "syn 0.15.35",
  "syn 1.0.11",
  "url 2.1.0",
  "winapi 0.3.8",
@@ -3755,7 +3338,7 @@ dependencies = [
  "bitflags",
  "cfg-if",
  "crossbeam-utils 0.7.2",
- "ena 0.14.0",
+ "ena",
  "indexmap",
  "jobserver",
  "lazy_static",
@@ -4240,6 +3823,7 @@ dependencies = [
  "rustc_expand",
  "rustc_feature",
  "rustc_hir",
+ "rustc_index",
  "rustc_metadata",
  "rustc_middle",
  "rustc_session",
@@ -4278,6 +3862,7 @@ dependencies = [
 name = "rustc_session"
 version = "0.0.0"
 dependencies = [
+ "bitflags",
  "getopts",
  "log",
  "num_cpus",
@@ -4373,7 +3958,6 @@ name = "rustc_traits"
 version = "0.0.0"
 dependencies = [
  "chalk-ir",
- "chalk-rust-ir",
  "chalk-solve",
  "log",
  "rustc_ast",
@@ -4439,7 +4023,7 @@ version = "0.0.0"
 dependencies = [
  "itertools 0.8.0",
  "minifier",
- "pulldown-cmark 0.7.1",
+ "pulldown-cmark",
  "rustc-rayon",
  "serde",
  "serde_json",
@@ -4481,16 +4065,16 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.15"
+version = "1.4.18"
 dependencies = [
  "annotate-snippets 0.6.1",
+ "anyhow",
  "bytecount",
  "cargo_metadata 0.8.0",
  "derive-new",
  "diff",
  "dirs",
  "env_logger 0.6.2",
- "failure",
  "getopts",
  "ignore",
  "itertools 0.8.0",
@@ -4512,6 +4096,7 @@ dependencies = [
  "serde_json",
  "structopt",
  "term 0.6.0",
+ "thiserror",
  "toml",
  "unicode-segmentation",
  "unicode-width",
@@ -4561,27 +4146,6 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
 
-[[package]]
-name = "security-framework"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
-dependencies = [
- "core-foundation 0.6.3",
- "core-foundation-sys 0.6.2",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
-dependencies = [
- "core-foundation-sys 0.6.2",
-]
-
 [[package]]
 name = "semver"
 version = "0.9.0"
@@ -4659,18 +4223,6 @@ dependencies = [
  "syn 1.0.11",
 ]
 
-[[package]]
-name = "serde_urlencoded"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
-dependencies = [
- "dtoa",
- "itoa",
- "serde",
- "url 1.7.2",
-]
-
 [[package]]
 name = "sha-1"
 version = "0.8.2"
@@ -4792,15 +4344,6 @@ dependencies = [
  "wasi",
 ]
 
-[[package]]
-name = "string"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
-dependencies = [
- "bytes",
-]
-
 [[package]]
 name = "string_cache"
 version = "0.7.3"
@@ -5108,17 +4651,6 @@ dependencies = [
  "tokio-uds",
 ]
 
-[[package]]
-name = "tokio-buf"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
-dependencies = [
- "bytes",
- "either",
- "futures",
-]
-
 [[package]]
 name = "tokio-codec"
 version = "0.1.1"
@@ -5345,44 +4877,34 @@ dependencies = [
 ]
 
 [[package]]
-name = "toml-query"
-version = "0.9.0"
+name = "tracing"
+version = "0.1.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a24369a1894ac8224efcfd567c3d141aea360292f49888e7ec7dcc316527aebb"
+checksum = "a41f40ed0e162c911ac6fcb53ecdc8134c46905fdbbae8c50add462a538b495f"
 dependencies = [
- "failure",
- "failure_derive",
- "is-match",
- "lazy_static",
- "regex",
- "toml",
- "toml-query_derive",
+ "cfg-if",
+ "tracing-attributes",
+ "tracing-core",
 ]
 
 [[package]]
-name = "toml-query_derive"
-version = "0.9.0"
+name = "tracing-attributes"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c99ca245ec273c7e75c8ee58f47b882d0146f3c2c8495158082c6671e8b5335"
+checksum = "99bbad0de3fd923c9c3232ead88510b783e5a4d16a6154adffa3d53308de984c"
 dependencies = [
- "darling",
- "quote 0.6.12",
- "syn 0.15.35",
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.11",
 ]
 
 [[package]]
-name = "try-lock"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
-
-[[package]]
-name = "try_from"
-version = "0.3.2"
+name = "tracing-core"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
+checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715"
 dependencies = [
- "cfg-if",
+ "lazy_static",
 ]
 
 [[package]]
@@ -5443,15 +4965,15 @@ dependencies = [
 
 [[package]]
 name = "unicode-script"
-version = "0.4.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b2c5c29e805da6817f5af6a627d65adb045cebf05cccd5a3493d6109454391c"
+checksum = "58b33414ea8db4b7ea0343548dbdc31d27aef06beacf7044a87e564d9b0feb7d"
 
 [[package]]
 name = "unicode-security"
-version = "0.0.3"
+version = "0.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5f9011bbed9c13372bc8df618b55a38138445199caf3b61d432c6859c36dee0"
+checksum = "5d87c28edc5b263377e448d6cdcb935c06b95413d8013ba6fae470558ccab18f"
 dependencies = [
  "unicode-normalization",
  "unicode-script",
@@ -5546,15 +5068,6 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
 
-[[package]]
-name = "uuid"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
-dependencies = [
- "rand 0.6.1",
-]
-
 [[package]]
 name = "vcpkg"
 version = "0.2.8"
@@ -5603,17 +5116,6 @@ dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "want"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230"
-dependencies = [
- "futures",
- "log",
- "try-lock",
-]
-
 [[package]]
 name = "wasi"
 version = "0.9.0+wasi-snapshot-preview1"
@@ -5678,15 +5180,6 @@ dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "winreg"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
-dependencies = [
- "winapi 0.3.8",
-]
-
 [[package]]
 name = "ws2_32-sys"
 version = "0.2.1"
index f2177a99a9b88b09672694ee4a2ac60ab2293d65..be15e50e2bcca07d92d6615542914b4c0ba112f7 100644 (file)
@@ -33,14 +33,27 @@ exclude = [
   "obj",
 ]
 
-# These options are controlled from our rustc wrapper script, so turn them off
-# here and have them controlled elsewhere.
-[profile.dev]
-debug = false
-debug-assertions = false
-[profile.test]
-debug = false
+[profile.release.package.compiler_builtins]
+# The compiler-builtins crate cannot reference libcore, and it's own CI will
+# verify that this is the case. This requires, however, that the crate is built
+# without overflow checks and debug assertions. Forcefully disable debug
+# assertions and overflow checks here which should ensure that even if these
+# assertions are enabled for libstd we won't enable then for compiler_builtins
+# which should ensure we still link everything correctly.
 debug-assertions = false
+overflow-checks = false
+
+# For compiler-builtins we always use a high number of codegen units.
+# The goal here is to place every single intrinsic into its own object
+# file to avoid symbol clashes with the system libgcc if possible. Note
+# that this number doesn't actually produce this many object files, we
+# just don't create more than this number of object files.
+#
+# It's a bit of a bummer that we have to pass this here, unfortunately.
+# Ideally this would be specified through an env var to Cargo so Cargo
+# knows how many CGUs are for this specific crate, but for now
+# per-crate configuration isn't specifiable in the environment.
+codegen-units = 10000
 
 # We want the RLS to use the version of Cargo that we've got vendored in this
 # repository to ensure that the same exact version of Cargo is used by both the
index 6214f2a68c596a3b18795854c4e1e14889775b2d..2fa613755d64c45e46a3e795ea5e8a01931681ca 100644 (file)
 # nightlies are already produced for. The current platform must be able to run
 # binaries of this build triple and the nightly will be used to bootstrap the
 # first compiler.
-#build = "x86_64-unknown-linux-gnu"    # defaults to your host platform
+#
+# Defaults to host platform
+#build = "x86_64-unknown-linux-gnu"
 
 # In addition to the build triple, other triples to produce full compiler
 # toolchains for. Each of these triples will be bootstrapped from the build
 # triple and then will continue to bootstrap themselves. This platform must
 # currently be able to run all of the triples provided here.
-#host = ["x86_64-unknown-linux-gnu"]   # defaults to just the build triple
+#
+# Defaults to just the build triple
+#host = ["x86_64-unknown-linux-gnu"]
 
 # In addition to all host triples, other triples to produce the standard library
 # for. Each host triple will be used to produce a copy of the standard library
 # for each target triple.
-#target = ["x86_64-unknown-linux-gnu"] # defaults to just the build triple
+#
+# Defaults to just the build triple
+#target = ["x86_64-unknown-linux-gnu"]
 
 # Use this directory to store build artifacts.
 # You can use "$ROOT" to indicate the root of the git repository.
 # Python interpreter to use for various tasks throughout the build, notably
 # rustdoc tests, the lldb python interpreter, and some dist bits and pieces.
 #
-# Defaults to the Python interpreter used to execute x.py.
+# Defaults to the Python interpreter used to execute x.py
 #python = "python"
 
 # Force Cargo to check that Cargo.lock describes the precise dependency
 # Build the sanitizer runtimes
 #sanitizers = false
 
-# Build the profiler runtime
+# Build the profiler runtime (required when compiling with options that depend
+# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
 #profiler = false
 
 # Indicates whether the native libraries linked into Cargo will be statically
 
 # Whether or not debug assertions are enabled for the compiler and standard
 # library.
-#debug-assertions = debug
+#
+# Defaults to rust.debug value
+#debug-assertions = false
 
 # Whether or not debug assertions are enabled for the standard library.
 # Overrides the `debug-assertions` option, if defined.
-#debug-assertions-std = debug-assertions
+#
+# Defaults to rust.debug-assertions value
+#debug-assertions-std = false
 
 # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
 # `0` - no debug info
 # Can be overridden for specific subsets of Rust code (rustc, std or tools).
 # Debuginfo for tests run with compiletest is not controlled by this option
 # and needs to be enabled separately with `debuginfo-level-tests`.
-#debuginfo-level = if debug { 2 } else { 0 }
+#
+# Defaults to 2 if debug is true
+#debuginfo-level = 0
 
 # Debuginfo level for the compiler.
-#debuginfo-level-rustc = debuginfo-level
+#
+# Defaults to rust.debuginfo-level value
+#debuginfo-level-rustc = 0
 
 # Debuginfo level for the standard library.
-#debuginfo-level-std = debuginfo-level
+#
+# Defaults to rust.debuginfo-level value
+#debuginfo-level-std = 0
 
 # Debuginfo level for the tools.
-#debuginfo-level-tools = debuginfo-level
+#
+# Defaults to rust.debuginfo-level value
+#debuginfo-level-tools = 0
 
 # Debuginfo level for the test suites run with compiletest.
 # FIXME(#61117): Some tests fail when this option is enabled.
index a8c00c8c3ca88368764e4d5cb22068f9057671fc..3072a4a1ae7c035c987c06332b63dc32e91bbe51 100644 (file)
@@ -101,30 +101,6 @@ fn main() {
         {
             cmd.arg("-C").arg("panic=abort");
         }
-
-        // Set various options from config.toml to configure how we're building
-        // code.
-        let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") {
-            Ok(s) => {
-                if s == "true" {
-                    "y"
-                } else {
-                    "n"
-                }
-            }
-            Err(..) => "n",
-        };
-
-        // The compiler builtins are pretty sensitive to symbols referenced in
-        // libcore and such, so we never compile them with debug assertions.
-        //
-        // FIXME(rust-lang/cargo#7253) we should be doing this in `builder.rs`
-        // with env vars instead of doing it here in this script.
-        if crate_name == Some("compiler_builtins") {
-            cmd.arg("-C").arg("debug-assertions=no");
-        } else {
-            cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));
-        }
     } else {
         // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
         // here, but rather Cargo should know what flags to pass rustc itself.
index b7d0fac5be31fdca554d690289ce8756c0df6fac..1949d70e5deea1b370f1f583651b02a39a99a56a 100644 (file)
@@ -184,6 +184,7 @@ def default_build_triple():
     ostype = require(["uname", "-s"], exit=required)
     cputype = require(['uname', '-m'], exit=required)
 
+    # If we do not have `uname`, assume Windows.
     if ostype is None or cputype is None:
         return 'x86_64-pc-windows-msvc'
 
@@ -236,6 +237,11 @@ def default_build_triple():
         if ostype.endswith('WOW64'):
             cputype = 'x86_64'
         ostype = 'pc-windows-gnu'
+    elif sys.platform == 'win32':
+        # Some Windows platforms might have a `uname` command that returns a
+        # non-standard string (e.g. gnuwin32 tools returns `windows32`). In
+        # these cases, fall back to using sys.platform.
+        return 'x86_64-pc-windows-msvc'
     else:
         err = "unknown OS type: {}".format(ostype)
         sys.exit(err)
@@ -893,15 +899,18 @@ def bootstrap(help_triggered):
     build.verbose = args.verbose
     build.clean = args.clean
 
-    try:
-        toml_path = args.config or 'config.toml'
+    # Read from `RUST_BOOTSTRAP_CONFIG`, then `--config`, then fallback to `config.toml` (if it
+    # exists).
+    toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config
+    if not toml_path and os.path.exists('config.toml'):
+        toml_path = 'config.toml'
+
+    if toml_path:
         if not os.path.exists(toml_path):
             toml_path = os.path.join(build.rust_root, toml_path)
 
         with open(toml_path) as config:
             build.config_toml = config.read()
-    except (OSError, IOError):
-        pass
 
     config_verbose = build.get_toml('verbose', 'build')
     if config_verbose is not None:
@@ -951,6 +960,8 @@ def bootstrap(help_triggered):
     env["RUSTC_BOOTSTRAP"] = '1'
     env["CARGO"] = build.cargo()
     env["RUSTC"] = build.rustc()
+    if toml_path:
+        env["BOOTSTRAP_CONFIG"] = toml_path
     if build.rustfmt():
         env["RUSTFMT"] = build.rustfmt()
     run(args, env=env, verbose=build.verbose)
index ea5300bdfc04cbf26add156fe37a0793aef19198..c5e2a4a38cff5487a092bb59476ac6e6c3960e2e 100644 (file)
@@ -23,7 +23,7 @@
 use crate::native;
 use crate::run;
 use crate::test;
-use crate::tool;
+use crate::tool::{self, SourceType};
 use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir};
 use crate::{Build, DocTests, GitRepo, Mode};
 
@@ -99,9 +99,21 @@ struct StepDescription {
     name: &'static str,
 }
 
+/// Collection of paths used to match a task rule.
 #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
 pub enum PathSet {
+    /// A collection of individual paths.
+    ///
+    /// These are generally matched as a path suffix. For example, a
+    /// command-line value of `libstd` will match if `src/libstd` is in the
+    /// set.
     Set(BTreeSet<PathBuf>),
+    /// A "suite" of paths.
+    ///
+    /// These can match as a path suffix (like `Set`), or as a prefix. For
+    /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs`
+    /// will match `src/test/ui`. A command-line value of `ui` would also
+    /// match `src/test/ui`.
     Suite(PathBuf),
 }
 
@@ -251,21 +263,33 @@ pub fn default_condition(mut self, cond: bool) -> Self {
         self
     }
 
-    // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually
-    // ever be used, but as we transition to having all rules properly handle passing krate(...) by
-    // actually doing something different for every crate passed.
+    /// Indicates it should run if the command-line selects the given crate or
+    /// any of its (local) dependencies.
+    ///
+    /// Compared to `krate`, this treats the dependencies as aliases for the
+    /// same job. Generally it is preferred to use `krate`, and treat each
+    /// individual path separately. For example `./x.py test src/liballoc`
+    /// (which uses `krate`) will test just `liballoc`. However, `./x.py check
+    /// src/liballoc` (which uses `all_krates`) will check all of `libtest`.
+    /// `all_krates` should probably be removed at some point.
     pub fn all_krates(mut self, name: &str) -> Self {
         let mut set = BTreeSet::new();
         for krate in self.builder.in_tree_crates(name) {
-            set.insert(PathBuf::from(&krate.path));
+            let path = krate.local_path(self.builder);
+            set.insert(path);
         }
         self.paths.insert(PathSet::Set(set));
         self
     }
 
+    /// Indicates it should run if the command-line selects the given crate or
+    /// any of its (local) dependencies.
+    ///
+    /// `make_run` will be called separately for each matching command-line path.
     pub fn krate(mut self, name: &str) -> Self {
         for krate in self.builder.in_tree_crates(name) {
-            self.paths.insert(PathSet::one(&krate.path));
+            let path = krate.local_path(self.builder);
+            self.paths.insert(PathSet::one(path));
         }
         self
     }
@@ -488,13 +512,19 @@ pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
             should_run = (desc.should_run)(should_run);
         }
         let mut help = String::from("Available paths:\n");
+        let mut add_path = |path: &Path| {
+            help.push_str(&format!("    ./x.py {} {}\n", subcommand, path.display()));
+        };
         for pathset in should_run.paths {
-            if let PathSet::Set(set) = pathset {
-                set.iter().for_each(|path| {
-                    help.push_str(
-                        format!("    ./x.py {} {}\n", subcommand, path.display()).as_str(),
-                    )
-                })
+            match pathset {
+                PathSet::Set(set) => {
+                    for path in set {
+                        add_path(&path);
+                    }
+                }
+                PathSet::Suite(path) => {
+                    add_path(&path.join("..."));
+                }
             }
         }
         Some(help)
@@ -729,6 +759,7 @@ pub fn cargo(
         &self,
         compiler: Compiler,
         mode: Mode,
+        source_type: SourceType,
         target: Interned<String>,
         cmd: &str,
     ) -> Cargo {
@@ -919,14 +950,6 @@ pub fn cargo(
             .env("RUSTC", self.out.join("bootstrap/debug/rustc"))
             .env("RUSTC_REAL", self.rustc(compiler))
             .env("RUSTC_STAGE", stage.to_string())
-            .env(
-                "RUSTC_DEBUG_ASSERTIONS",
-                if mode == Mode::Std {
-                    self.config.rust_debug_assertions_std.to_string()
-                } else {
-                    self.config.rust_debug_assertions.to_string()
-                },
-            )
             .env("RUSTC_SYSROOT", &sysroot)
             .env("RUSTC_LIBDIR", &libdir)
             .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
@@ -1010,6 +1033,14 @@ pub fn cargo(
             }
         };
         cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
+        cargo.env(
+            profile_var("DEBUG_ASSERTIONS"),
+            if mode == Mode::Std {
+                self.config.rust_debug_assertions_std.to_string()
+            } else {
+                self.config.rust_debug_assertions.to_string()
+            },
+        );
 
         if !mode.is_tool() {
             cargo.env("RUSTC_FORCE_UNSTABLE", "1");
@@ -1095,7 +1126,7 @@ pub fn cargo(
 
         cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
 
-        if !mode.is_tool() {
+        if source_type == SourceType::InTree {
             // When extending this list, add the new lints to the RUSTFLAGS of the
             // build_bootstrap function of src/bootstrap/bootstrap.py as well as
             // some code doesn't go through this `rustc` wrapper.
@@ -1176,7 +1207,7 @@ pub fn cargo(
             );
         }
 
-        // If Control Flow Guard is enabled, pass the `control_flow_guard=checks` flag to rustc
+        // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
         // when compiling the standard library, since this might be linked into the final outputs
         // produced by rustc. Since this mitigation is only available on Windows, only enable it
         // for the standard library in case the compiler is run on a non-Windows platform.
@@ -1187,7 +1218,7 @@ pub fn cargo(
             && self.config.control_flow_guard
             && compiler.stage >= 1
         {
-            rustflags.arg("-Zcontrol_flow_guard=checks");
+            rustflags.arg("-Zcontrol-flow-guard");
         }
 
         // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
index 7a8bfb2d5d877190661a8a83973a679e3e94709c..0d38d2eebe79390fefb2eae22ca674574f0f136f 100644 (file)
@@ -44,7 +44,13 @@ fn run(self, builder: &Builder<'_>) {
         let target = self.target;
         let compiler = builder.compiler(0, builder.config.build);
 
-        let mut cargo = builder.cargo(compiler, Mode::Std, target, cargo_subcommand(builder.kind));
+        let mut cargo = builder.cargo(
+            compiler,
+            Mode::Std,
+            SourceType::InTree,
+            target,
+            cargo_subcommand(builder.kind),
+        );
         std_cargo(builder, target, compiler.stage, &mut cargo);
 
         builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
@@ -92,8 +98,13 @@ fn run(self, builder: &Builder<'_>) {
 
         builder.ensure(Std { target });
 
-        let mut cargo =
-            builder.cargo(compiler, Mode::Rustc, target, cargo_subcommand(builder.kind));
+        let mut cargo = builder.cargo(
+            compiler,
+            Mode::Rustc,
+            SourceType::InTree,
+            target,
+            cargo_subcommand(builder.kind),
+        );
         rustc_cargo(builder, &mut cargo, target);
 
         builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
@@ -113,7 +124,7 @@ fn run(self, builder: &Builder<'_>) {
 }
 
 macro_rules! tool_check_step {
-    ($name:ident, $path:expr) => {
+    ($name:ident, $path:expr, $source_type:expr) => {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub target: Interned<String>,
@@ -145,7 +156,7 @@ fn run(self, builder: &Builder<'_>) {
                     target,
                     cargo_subcommand(builder.kind),
                     $path,
-                    SourceType::InTree,
+                    $source_type,
                     &[],
                 );
 
@@ -184,8 +195,12 @@ fn stamp(
     };
 }
 
-tool_check_step!(Rustdoc, "src/tools/rustdoc");
-tool_check_step!(Clippy, "src/tools/clippy");
+tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree);
+// Clippy is a hybrid. It is an external tool, but uses a git subtree instead
+// of a submodule. Since the SourceType only drives the deny-warnings
+// behavior, treat it as in-tree so that any new warnings in clippy will be
+// rejected.
+tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
index 62bca0015c063056688bae2d38f503932ed78ff2..84545dcedb6d972480c1026dd6494bfcefc88178 100644 (file)
 use serde::Deserialize;
 
 use crate::builder::Cargo;
+use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
+use crate::cache::{Interned, INTERNER};
 use crate::dist;
 use crate::native;
+use crate::tool::SourceType;
 use crate::util::{exe, is_dylib, symlink_dir};
-use crate::{Compiler, GitRepo, Mode};
-
-use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
-use crate::cache::{Interned, INTERNER};
+use crate::{Compiler, DependencyType, GitRepo, Mode};
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
@@ -74,6 +74,7 @@ fn run(self, builder: &Builder<'_>) {
             // Even if we're not building std this stage, the new sysroot must
             // still contain the third party objects needed by various targets.
             copy_third_party_objects(builder, &compiler, target);
+            copy_self_contained_objects(builder, &compiler, target);
 
             builder.ensure(StdLink {
                 compiler: compiler_to_use,
@@ -83,9 +84,10 @@ fn run(self, builder: &Builder<'_>) {
             return;
         }
 
-        target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter());
+        target_deps.extend(copy_third_party_objects(builder, &compiler, target));
+        target_deps.extend(copy_self_contained_objects(builder, &compiler, target));
 
-        let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
+        let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build");
         std_cargo(builder, target, compiler.stage, &mut cargo);
 
         builder.info(&format!(
@@ -109,21 +111,63 @@ fn run(self, builder: &Builder<'_>) {
     }
 }
 
+fn copy_and_stamp(
+    builder: &Builder<'_>,
+    libdir: &Path,
+    sourcedir: &Path,
+    name: &str,
+    target_deps: &mut Vec<(PathBuf, DependencyType)>,
+    dependency_type: DependencyType,
+) {
+    let target = libdir.join(name);
+    builder.copy(&sourcedir.join(name), &target);
+
+    target_deps.push((target, dependency_type));
+}
+
 /// Copies third party objects needed by various targets.
 fn copy_third_party_objects(
     builder: &Builder<'_>,
     compiler: &Compiler,
     target: Interned<String>,
-) -> Vec<PathBuf> {
-    let libdir = builder.sysroot_libdir(*compiler, target);
-
+) -> Vec<(PathBuf, DependencyType)> {
     let mut target_deps = vec![];
 
-    let mut copy_and_stamp = |sourcedir: &Path, name: &str| {
-        let target = libdir.join(name);
-        builder.copy(&sourcedir.join(name), &target);
-        target_deps.push(target);
+    // FIXME: remove this in 2021
+    if target == "x86_64-fortanix-unknown-sgx" {
+        if env::var_os("X86_FORTANIX_SGX_LIBS").is_some() {
+            builder.info("Warning: X86_FORTANIX_SGX_LIBS environment variable is ignored, libunwind is now compiled as part of rustbuild");
+        }
+    }
+
+    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)
+                .into_iter()
+                .map(|d| (d, DependencyType::Target)),
+        );
+    }
+
+    target_deps
+}
+
+/// Copies third party objects needed by various targets for self-contained linkage.
+fn copy_self_contained_objects(
+    builder: &Builder<'_>,
+    compiler: &Compiler,
+    target: Interned<String>,
+) -> Vec<(PathBuf, DependencyType)> {
+    // cfg(bootstrap)
+    // Remove when upgrading bootstrap compiler.
+    let libdir_self_contained = if compiler.stage == 0 {
+        builder.sysroot_libdir(*compiler, target).to_path_buf()
+    } else {
+        builder.sysroot_libdir(*compiler, target).join("self-contained")
     };
+    t!(fs::create_dir_all(&libdir_self_contained));
+    let mut target_deps = vec![];
 
     // Copies the CRT objects.
     //
@@ -135,29 +179,32 @@ fn copy_third_party_objects(
     if target.contains("musl") {
         let srcdir = builder.musl_libdir(target).unwrap();
         for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
-            copy_and_stamp(&srcdir, obj);
+            copy_and_stamp(
+                builder,
+                &libdir_self_contained,
+                &srcdir,
+                obj,
+                &mut target_deps,
+                DependencyType::TargetSelfContained,
+            );
         }
     } else if target.ends_with("-wasi") {
         let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi");
-        copy_and_stamp(&srcdir, "crt1.o");
-    }
-
-    // Copies libunwind.a compiled to be linked with x86_64-fortanix-unknown-sgx.
-    //
-    // This target needs to be linked to Fortanix's port of llvm's libunwind.
-    // libunwind requires support for rwlock and printing to stderr,
-    // which is provided by std for this target.
-    if target == "x86_64-fortanix-unknown-sgx" {
-        let src_path_env = "X86_FORTANIX_SGX_LIBS";
-        let src =
-            env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env));
-        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));
+        copy_and_stamp(
+            builder,
+            &libdir_self_contained,
+            &srcdir,
+            "crt1.o",
+            &mut target_deps,
+            DependencyType::TargetSelfContained,
+        );
+    } else if target.contains("windows-gnu") {
+        for obj in ["crt2.o", "dllcrt2.o"].iter() {
+            let src = compiler_file(builder, builder.cc(target), target, obj);
+            let target = libdir_self_contained.join(obj);
+            builder.copy(&src, &target);
+            target_deps.push((target, DependencyType::TargetSelfContained));
+        }
     }
 
     target_deps
@@ -335,7 +382,7 @@ pub struct StartupObjects {
 }
 
 impl Step for StartupObjects {
-    type Output = Vec<PathBuf>;
+    type Output = Vec<(PathBuf, DependencyType)>;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         run.path("src/rtstartup")
@@ -354,7 +401,7 @@ fn make_run(run: RunConfig<'_>) {
     /// They don't require any library support as they're just plain old object
     /// files, so we just use the nightly snapshot compiler to always build them (as
     /// no other compilers are guaranteed to be available).
-    fn run(self, builder: &Builder<'_>) -> Vec<PathBuf> {
+    fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
         let for_compiler = self.compiler;
         let target = self.target;
         if !target.contains("windows-gnu") {
@@ -388,14 +435,7 @@ fn run(self, builder: &Builder<'_>) -> Vec<PathBuf> {
 
             let target = sysroot_dir.join((*file).to_string() + ".o");
             builder.copy(dst_file, &target);
-            target_deps.push(target);
-        }
-
-        for obj in ["crt2.o", "dllcrt2.o"].iter() {
-            let src = compiler_file(builder, builder.cc(target), target, obj);
-            let target = sysroot_dir.join(obj);
-            builder.copy(&src, &target);
-            target_deps.push(target);
+            target_deps.push((target, DependencyType::Target));
         }
 
         target_deps
@@ -460,7 +500,7 @@ fn run(self, builder: &Builder<'_>) {
             target: builder.config.build,
         });
 
-        let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build");
+        let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
         rustc_cargo(builder, &mut cargo, target);
 
         builder.info(&format!(
@@ -808,14 +848,17 @@ pub fn add_to_sysroot(
     sysroot_host_dst: &Path,
     stamp: &Path,
 ) {
+    let self_contained_dst = &sysroot_dst.join("self-contained");
     t!(fs::create_dir_all(&sysroot_dst));
     t!(fs::create_dir_all(&sysroot_host_dst));
-    for (path, host) in builder.read_stamp_file(stamp) {
-        if host {
-            builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap()));
-        } else {
-            builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
-        }
+    t!(fs::create_dir_all(&self_contained_dst));
+    for (path, dependency_type) in builder.read_stamp_file(stamp) {
+        let dst = match dependency_type {
+            DependencyType::Host => sysroot_host_dst,
+            DependencyType::Target => sysroot_dst,
+            DependencyType::TargetSelfContained => self_contained_dst,
+        };
+        builder.copy(&path, &dst.join(path.file_name().unwrap()));
     }
 }
 
@@ -824,7 +867,7 @@ pub fn run_cargo(
     cargo: Cargo,
     tail_args: Vec<String>,
     stamp: &Path,
-    additional_target_deps: Vec<PathBuf>,
+    additional_target_deps: Vec<(PathBuf, DependencyType)>,
     is_check: bool,
 ) -> Vec<PathBuf> {
     if builder.config.dry_run {
@@ -875,7 +918,7 @@ pub fn run_cargo(
             if filename.starts_with(&host_root_dir) {
                 // Unless it's a proc macro used in the compiler
                 if crate_types.iter().any(|t| t == "proc-macro") {
-                    deps.push((filename.to_path_buf(), true));
+                    deps.push((filename.to_path_buf(), DependencyType::Host));
                 }
                 continue;
             }
@@ -883,7 +926,7 @@ pub fn run_cargo(
             // If this was output in the `deps` dir then this is a precise file
             // name (hash included) so we start tracking it.
             if filename.starts_with(&target_deps_dir) {
-                deps.push((filename.to_path_buf(), false));
+                deps.push((filename.to_path_buf(), DependencyType::Target));
                 continue;
             }
 
@@ -935,17 +978,21 @@ pub fn run_cargo(
             let candidate = format!("{}.lib", path_to_add);
             let candidate = PathBuf::from(candidate);
             if candidate.exists() {
-                deps.push((candidate, false));
+                deps.push((candidate, DependencyType::Target));
             }
         }
-        deps.push((path_to_add.into(), false));
+        deps.push((path_to_add.into(), DependencyType::Target));
     }
 
-    deps.extend(additional_target_deps.into_iter().map(|d| (d, false)));
+    deps.extend(additional_target_deps);
     deps.sort();
     let mut new_contents = Vec::new();
-    for (dep, proc_macro) in deps.iter() {
-        new_contents.extend(if *proc_macro { b"h" } else { b"t" });
+    for (dep, dependency_type) in deps.iter() {
+        new_contents.extend(match *dependency_type {
+            DependencyType::Host => b"h",
+            DependencyType::Target => b"t",
+            DependencyType::TargetSelfContained => b"s",
+        });
         new_contents.extend(dep.to_str().unwrap().as_bytes());
         new_contents.extend(b"\0");
     }
index d1e53db573e4cbd8366902f8e49a7a861ff61b73..47673ce1e870304894f260e5d33925db20cf2f45 100755 (executable)
@@ -141,6 +141,8 @@ v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
   "rootfs in qemu testing, you probably don't want to use this")
 v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
   "rootfs in qemu testing, you probably don't want to use this")
+v("qemu-riscv64-rootfs", "target.riscv64gc-unknown-linux-gnu.qemu-rootfs",
+  "rootfs in qemu testing, you probably don't want to use this")
 v("experimental-targets", "llvm.experimental-targets",
   "experimental LLVM targets to build")
 v("release-channel", "rust.channel", "the name of the release channel to build")
index a752d8045f7b4c8f0472030363a2d633afb008f7..8a2463d378fdb8642cea130e3bd1c10fb5bbd3ba 100644 (file)
@@ -22,7 +22,7 @@
 use crate::compile;
 use crate::tool::{self, Tool};
 use crate::util::{exe, is_dylib, timeit};
-use crate::{Compiler, Mode, LLVM_TOOLS};
+use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
 use time::{self, Timespec};
 
 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
@@ -306,7 +306,12 @@ fn make_win_dist(
     }
 
     //Copy platform tools to platform-specific bin directory
-    let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
+    let target_bin_dir = plat_root
+        .join("lib")
+        .join("rustlib")
+        .join(target_triple)
+        .join("bin")
+        .join("self-contained");
     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
     for src in target_tools {
         builder.copy_to_folder(&src, &target_bin_dir);
@@ -321,7 +326,12 @@ fn make_win_dist(
     );
 
     //Copy platform libs to platform-specific lib directory
-    let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
+    let target_lib_dir = plat_root
+        .join("lib")
+        .join("rustlib")
+        .join(target_triple)
+        .join("lib")
+        .join("self-contained");
     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
     for src in target_libs {
         builder.copy_to_folder(&src, &target_lib_dir);
@@ -652,9 +662,13 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
 /// Copy stamped files into an image's `target/lib` directory.
 fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) {
     let dst = image.join("lib/rustlib").join(target).join("lib");
+    let self_contained_dst = dst.join("self-contained");
     t!(fs::create_dir_all(&dst));
-    for (path, host) in builder.read_stamp_file(stamp) {
-        if !host || builder.config.build == target {
+    t!(fs::create_dir_all(&self_contained_dst));
+    for (path, dependency_type) in builder.read_stamp_file(stamp) {
+        if dependency_type == DependencyType::TargetSelfContained {
+            builder.copy(&path, &self_contained_dst.join(path.file_name().unwrap()));
+        } else if dependency_type == DependencyType::Target || builder.config.build == target {
             builder.copy(&path, &dst.join(path.file_name().unwrap()));
         }
     }
index 5c01c5e852c48caf781a96be2d71a6f0c10e767a..8b76158f9e5645d7e4dba8a31425c70927411dc4 100644 (file)
@@ -435,7 +435,8 @@ fn run(self, builder: &Builder<'_>) {
         t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
 
         let run_cargo_rustdoc_for = |package: &str| {
-            let mut cargo = builder.cargo(compiler, Mode::Std, target, "rustdoc");
+            let mut cargo =
+                builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc");
             compile::std_cargo(builder, target, compiler.stage, &mut cargo);
 
             // Keep a whitelist so we do not build internal stdlib crates, these will be
@@ -534,7 +535,7 @@ fn run(self, builder: &Builder<'_>) {
         t!(symlink_dir_force(&builder.config, &out, &out_dir));
 
         // Build cargo command.
-        let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
+        let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
         cargo.env(
             "RUSTDOCFLAGS",
             "--document-private-items \
@@ -548,8 +549,8 @@ fn run(self, builder: &Builder<'_>) {
         // Find dependencies for top level crates.
         let mut compiler_crates = HashSet::new();
         for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
-            let interned_root_crate = INTERNER.intern_str(root_crate);
-            find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates);
+            compiler_crates
+                .extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name));
         }
 
         for krate in &compiler_crates {
@@ -564,22 +565,6 @@ fn run(self, builder: &Builder<'_>) {
     }
 }
 
-fn find_compiler_crates(
-    builder: &Builder<'_>,
-    name: &Interned<String>,
-    crates: &mut HashSet<Interned<String>>,
-) {
-    // Add current crate.
-    crates.insert(*name);
-
-    // Look for dependencies.
-    for dep in builder.crates.get(name).unwrap().deps.iter() {
-        if builder.crates.get(dep).unwrap().is_local(builder) {
-            find_compiler_crates(builder, dep, crates);
-        }
-    }
-}
-
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Rustdoc {
     stage: u32,
index 3726115357436166b5fa9e6cf05c616d9cc6d62e..f477c752933856e0ffd07747f963dcf20fff026c 100644 (file)
@@ -3,19 +3,17 @@
 //! This module implements the command-line parsing of the build system which
 //! has various flags to configure how it's run.
 
-use std::fs;
+use std::env;
 use std::path::PathBuf;
 use std::process;
 
 use getopts::Options;
 
 use crate::builder::Builder;
+use crate::cache::{Interned, INTERNER};
 use crate::config::Config;
-use crate::metadata;
 use crate::{Build, DocTests};
 
-use crate::cache::{Interned, INTERNER};
-
 /// Deserialized version of all flags for this compile.
 pub struct Flags {
     pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo
@@ -438,19 +436,12 @@ pub fn parse(args: &[String]) -> Flags {
         // Get any optional paths which occur after the subcommand
         let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
 
-        let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
-            if fs::metadata("config.toml").is_ok() {
-                Some(PathBuf::from("config.toml"))
-            } else {
-                None
-            }
-        });
+        let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
 
         // All subcommands except `clean` can have an optional "Available paths" section
         if matches.opt_present("verbose") {
             let config = Config::parse(&["build".to_string()]);
-            let mut build = Build::new(config);
-            metadata::build(&mut build);
+            let build = Build::new(config);
 
             let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
             extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
index fafd3cdf927c08224ad0676e581da510b770d4e3..fbdef9d8272f7686f61187dbed6330896eedbf6b 100644 (file)
@@ -70,7 +70,10 @@ fn install_sh(
     let libdir_default = PathBuf::from("lib");
     let mandir_default = datadir_default.join("man");
     let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
-        fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display()))
+        fs::create_dir_all(p)
+            .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err));
+        fs::canonicalize(p)
+            .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err))
     });
     let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
     let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
index 32f6e9605e765865008b5c9753c61e0cbb0a4f5c..b611af54565ac537e0312ee2742a14089be3aece 100644 (file)
@@ -270,16 +270,22 @@ struct Crate {
 }
 
 impl Crate {
-    fn is_local(&self, build: &Build) -> bool {
-        self.path.starts_with(&build.config.src) && !self.path.to_string_lossy().ends_with("_shim")
-    }
-
     fn local_path(&self, build: &Build) -> PathBuf {
-        assert!(self.is_local(build));
         self.path.strip_prefix(&build.config.src).unwrap().into()
     }
 }
 
+/// When building Rust various objects are handled differently.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum DependencyType {
+    /// Libraries originating from proc-macros.
+    Host,
+    /// Typical Rust libraries.
+    Target,
+    /// Non Rust libraries and objects shipped to ease usage of certain targets.
+    TargetSelfContained,
+}
+
 /// The various "modes" of invoking Cargo.
 ///
 /// These entries currently correspond to the various output directories of the
@@ -295,16 +301,21 @@ pub enum Mode {
     /// Build codegen libraries, placing output in the "stageN-codegen" directory
     Codegen,
 
-    /// Build some tools, placing output in the "stageN-tools" directory. The
-    /// "other" here is for miscellaneous sets of tools that are built using the
-    /// bootstrap compiler in its entirety (target libraries and all).
-    /// Typically these tools compile with stable Rust.
+    /// Build a tool, placing output in the "stage0-bootstrap-tools"
+    /// directory. This is for miscellaneous sets of tools that are built
+    /// using the bootstrap stage0 compiler in its entirety (target libraries
+    /// and all). Typically these tools compile with stable Rust.
     ToolBootstrap,
 
-    /// Compile a tool which uses all libraries we compile (up to rustc).
-    /// Doesn't use the stage0 compiler libraries like "other", and includes
-    /// tools like rustdoc, cargo, rls, etc.
+    /// Build a tool which uses the locally built std, placing output in the
+    /// "stageN-tools" directory. Its usage is quite rare, mainly used by
+    /// compiletest which needs libtest.
     ToolStd,
+
+    /// Build a tool which uses the locally built rustc and the target std,
+    /// placing the output in the "stageN-tools" directory. This is used for
+    /// anything that needs a fully functional rustc, such as rustdoc, clippy,
+    /// cargo, rls, rustfmt, miri, etc.
     ToolRustc,
 }
 
@@ -1088,17 +1099,29 @@ fn unstable_features(&self) -> bool {
         }
     }
 
+    /// Returns a Vec of all the dependencies of the given root crate,
+    /// including transitive dependencies and the root itself. Only includes
+    /// "local" crates (those in the local source tree, not from a registry).
     fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
         let mut ret = Vec::new();
         let mut list = vec![INTERNER.intern_str(root)];
         let mut visited = HashSet::new();
         while let Some(krate) = list.pop() {
             let krate = &self.crates[&krate];
-            if krate.is_local(self) {
-                ret.push(krate);
-            }
+            ret.push(krate);
             for dep in &krate.deps {
-                if visited.insert(dep) && dep != "build_helper" {
+                // Don't include optional deps if their features are not
+                // enabled. Ideally this would be computed from `cargo
+                // metadata --features …`, but that is somewhat slow. Just
+                // skip `build_helper` since there aren't any operations we
+                // want to perform on it. In the future, we may want to
+                // consider just filtering all build and dev dependencies in
+                // metadata::build.
+                if visited.insert(dep)
+                    && dep != "build_helper"
+                    && (dep != "profiler_builtins" || self.config.profiler)
+                    && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled())
+                {
                     list.push(*dep);
                 }
             }
@@ -1106,7 +1129,7 @@ fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
         ret
     }
 
-    fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> {
+    fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> {
         if self.config.dry_run {
             return Vec::new();
         }
@@ -1119,9 +1142,14 @@ fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> {
             if part.is_empty() {
                 continue;
             }
-            let host = part[0] as char == 'h';
+            let dependency_type = match part[0] as char {
+                'h' => DependencyType::Host,
+                's' => DependencyType::TargetSelfContained,
+                't' => DependencyType::Target,
+                _ => unreachable!(),
+            };
             let path = PathBuf::from(t!(str::from_utf8(&part[1..])));
-            paths.push((path, host));
+            paths.push((path, dependency_type));
         }
         paths
     }
index 292aa3b1e24a73e7eddcfba383cf154280e62378..a38391c7b88f28f31125681682e41bc4441e1d76 100644 (file)
@@ -1,5 +1,3 @@
-use std::collections::HashMap;
-use std::collections::HashSet;
 use std::path::PathBuf;
 use std::process::Command;
 
@@ -12,7 +10,6 @@
 #[derive(Deserialize)]
 struct Output {
     packages: Vec<Package>,
-    resolve: Resolve,
 }
 
 #[derive(Deserialize)]
@@ -21,63 +18,25 @@ struct Package {
     name: String,
     source: Option<String>,
     manifest_path: String,
+    dependencies: Vec<Dependency>,
 }
 
 #[derive(Deserialize)]
-struct Resolve {
-    nodes: Vec<ResolveNode>,
-}
-
-#[derive(Deserialize)]
-struct ResolveNode {
-    id: String,
-    dependencies: Vec<String>,
+struct Dependency {
+    name: String,
+    source: Option<String>,
 }
 
 pub fn build(build: &mut Build) {
-    let mut resolves = Vec::new();
-    build_krate(&build.std_features(), build, &mut resolves, "src/libstd");
-    build_krate("", build, &mut resolves, "src/libtest");
-    build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc");
-
-    let mut id2name = HashMap::with_capacity(build.crates.len());
-    for (name, krate) in build.crates.iter() {
-        id2name.insert(krate.id.clone(), name.clone());
-    }
-
-    for node in resolves {
-        let name = match id2name.get(&node.id) {
-            Some(name) => name,
-            None => continue,
-        };
-
-        let krate = build.crates.get_mut(name).unwrap();
-        for dep in node.dependencies.iter() {
-            let dep = match id2name.get(dep) {
-                Some(dep) => dep,
-                None => continue,
-            };
-            krate.deps.insert(*dep);
-        }
-    }
-}
-
-fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode>, krate: &str) {
     // Run `cargo metadata` to figure out what crates we're testing.
-    //
-    // Down below we're going to call `cargo test`, but to test the right set
-    // of packages we're going to have to know what `-p` arguments to pass it
-    // to know what crates to test. Here we run `cargo metadata` to learn about
-    // the dependency graph and what `-p` arguments there are.
     let mut cargo = Command::new(&build.initial_cargo);
     cargo
         .arg("metadata")
         .arg("--format-version")
         .arg("1")
-        .arg("--features")
-        .arg(features)
+        .arg("--no-deps")
         .arg("--manifest-path")
-        .arg(build.src.join(krate).join("Cargo.toml"));
+        .arg(build.src.join("Cargo.toml"));
     let output = output(&mut cargo);
     let output: Output = serde_json::from_str(&output).unwrap();
     for package in output.packages {
@@ -85,8 +44,13 @@ fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode
             let name = INTERNER.intern_string(package.name);
             let mut path = PathBuf::from(package.manifest_path);
             path.pop();
-            build.crates.insert(name, Crate { name, id: package.id, deps: HashSet::new(), path });
+            let deps = package
+                .dependencies
+                .into_iter()
+                .filter(|dep| dep.source.is_none())
+                .map(|dep| INTERNER.intern_string(dep.name))
+                .collect();
+            build.crates.insert(name, Crate { name, id: package.id, deps, path });
         }
     }
-    resolves.extend(output.resolve.nodes);
 }
index 252a6316e574b99cdf440b6b90d7ee2b155daa58..106db90b2d0f0c95fccb0922be22bf0563f287cf 100644 (file)
@@ -158,7 +158,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .define("LLVM_INCLUDE_TESTS", "OFF")
             .define("LLVM_INCLUDE_DOCS", "OFF")
             .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
-            .define("LLVM_ENABLE_ZLIB", "OFF")
             .define("WITH_POLLY", "OFF")
             .define("LLVM_ENABLE_TERMINFO", "OFF")
             .define("LLVM_ENABLE_LIBEDIT", "OFF")
@@ -168,6 +167,14 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
             .define("LLVM_DEFAULT_TARGET_TRIPLE", target);
 
+        if !target.contains("netbsd") {
+            cfg.define("LLVM_ENABLE_ZLIB", "ON");
+        } else {
+            // FIXME: Enable zlib on NetBSD too
+            // https://github.com/rust-lang/rust/pull/72696#issuecomment-641517185
+            cfg.define("LLVM_ENABLE_ZLIB", "OFF");
+        }
+
         if builder.config.llvm_thin_lto {
             cfg.define("LLVM_ENABLE_LTO", "Thin");
             if !target.contains("apple") {
@@ -689,48 +696,41 @@ fn supported_sanitizers(
     target: Interned<String>,
     channel: &str,
 ) -> Vec<SanitizerRuntime> {
-    let mut result = Vec::new();
+    let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
+        components
+            .into_iter()
+            .map(move |c| SanitizerRuntime {
+                cmake_target: format!("clang_rt.{}_{}_dynamic", c, os),
+                path: out_dir
+                    .join(&format!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c, os)),
+                name: format!("librustc-{}_rt.{}.dylib", channel, c),
+            })
+            .collect()
+    };
+
+    let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
+        components
+            .into_iter()
+            .map(move |c| SanitizerRuntime {
+                cmake_target: format!("clang_rt.{}-{}", c, arch),
+                path: out_dir.join(&format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)),
+                name: format!("librustc-{}_rt.{}.a", channel, c),
+            })
+            .collect()
+    };
+
     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", channel, s),
-                });
-            }
+        "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
+        "aarch64-unknown-linux-gnu" => {
+            common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
         }
+        "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
+        "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
         "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", channel, s),
-                });
-            }
-        }
-        "x86_64-fuchsia" => {
-            for s in &["asan"] {
-                result.push(SanitizerRuntime {
-                    cmake_target: format!("clang_rt.{}-x86_64", s),
-                    path: out_dir.join(&format!("build/lib/fuchsia/libclang_rt.{}-x86_64.a", s)),
-                    name: format!("librustc-{}_rt.{}.a", channel, s),
-                });
-            }
-        }
-        "aarch64-fuchsia" => {
-            for s in &["asan"] {
-                result.push(SanitizerRuntime {
-                    cmake_target: format!("clang_rt.{}-aarch64", s),
-                    path: out_dir.join(&format!("build/lib/fuchsia/libclang_rt.{}-aarch64.a", s)),
-                    name: format!("librustc-{}_rt.{}.a", channel, s),
-                });
-            }
+            common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
         }
-        _ => {}
+        _ => Vec::new(),
     }
-    result
 }
 
 struct HashStamp {
index 161f5d5ffd8f5cfb34c768329a0007e4aa10c6d0..12ab6b1636cc17aa23e9be5e4c0a4c8d032ef5b1 100644 (file)
@@ -367,7 +367,8 @@ fn run(self, builder: &Builder<'_>) {
             extra_features: Vec::new(),
         });
         if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) {
-            let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "install");
+            let mut cargo =
+                builder.cargo(compiler, Mode::ToolRustc, SourceType::Submodule, host, "install");
             cargo.arg("xargo");
             // Configure `cargo install` path. cargo adds a `bin/`.
             cargo.env("CARGO_INSTALL_ROOT", &builder.out);
@@ -554,10 +555,7 @@ fn run(self, builder: &Builder<'_>) {
 
         builder.add_rustc_lib_path(compiler, &mut cargo);
 
-        // FIXME: Disable clippy tests for now, they're failing on master
-        // (generally this would mean a toolstate failure but we don't have
-        // toolstate for clippy anymore).
-        // builder.run(&mut cargo.into());
+        builder.run(&mut cargo.into());
     }
 }
 
@@ -1648,14 +1646,8 @@ impl Step for Crate {
     type Output = ();
     const DEFAULT: bool = true;
 
-    fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
-        let builder = run.builder;
-        for krate in run.builder.in_tree_crates("test") {
-            if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) {
-                run = run.path(krate.local_path(&builder).to_str().unwrap());
-            }
-        }
-        run
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.krate("test")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1705,7 +1697,8 @@ fn run(self, builder: &Builder<'_>) {
         // we're working with automatically.
         let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
 
-        let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand());
+        let mut cargo =
+            builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
         match mode {
             Mode::Std => {
                 compile::std_cargo(builder, target, compiler.stage, &mut cargo);
index 9c95de0a81eae7ff53db0368a960e0eb9f9a6041..063fb8fbb9526b0f4dec0726217d0586af9b6e5e 100644 (file)
 use crate::channel::GitInfo;
 use crate::compile;
 use crate::toolstate::ToolState;
-use crate::util::{add_dylib_path, exe, CiEnv};
+use crate::util::{add_dylib_path, exe};
 use crate::Compiler;
 use crate::Mode;
 
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub enum SourceType {
     InTree,
     Submodule,
@@ -226,21 +226,16 @@ pub fn prepare_tool_cargo(
     source_type: SourceType,
     extra_features: &[String],
 ) -> CargoCommand {
-    let mut cargo = builder.cargo(compiler, mode, target, command);
+    let mut cargo = builder.cargo(compiler, mode, source_type, target, command);
     let dir = builder.src.join(path);
     cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
 
-    if source_type == SourceType::Submodule {
-        cargo.env("RUSTC_EXTERNAL_TOOL", "1");
-    }
-
     let mut features = extra_features.to_vec();
     if builder.build.config.cargo_native_static {
         if path.ends_with("cargo")
             || path.ends_with("rls")
             || path.ends_with("clippy")
             || path.ends_with("miri")
-            || path.ends_with("rustbook")
             || path.ends_with("rustfmt")
         {
             cargo.env("LIBZ_SYS_STATIC", "1");
@@ -276,20 +271,6 @@ pub fn prepare_tool_cargo(
     cargo
 }
 
-fn rustbook_features() -> Vec<String> {
-    let mut features = Vec::new();
-
-    // Due to CI budged and risk of spurious failures we want to limit jobs running this check.
-    // At same time local builds should run it regardless of the platform.
-    // `CiEnv::None` means it's local build and `CHECK_LINKS` is defined in x86_64-gnu-tools to
-    // explicitly enable it on single job
-    if CiEnv::current() == CiEnv::None || env::var("CHECK_LINKS").is_ok() {
-        features.push("linkcheck".to_string());
-    }
-
-    features
-}
-
 macro_rules! bootstrap_tool {
     ($(
         $name:ident, $path:expr, $tool_name:expr
@@ -372,7 +353,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 }
 
 bootstrap_tool!(
-    Rustbook, "src/tools/rustbook", "rustbook", features = rustbook_features();
+    Rustbook, "src/tools/rustbook", "rustbook";
     UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen";
     Tidy, "src/tools/tidy", "tidy";
     Linkchecker, "src/tools/linkchecker", "linkchecker";
@@ -481,7 +462,7 @@ impl Step for Rustdoc {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/rustdoc")
+        run.path("src/tools/rustdoc").path("src/librustdoc")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -596,6 +577,7 @@ macro_rules! tool_extended {
        $path:expr,
        $tool_name:expr,
        stable = $stable:expr,
+       $(in_tree = $in_tree:expr,)*
        $extra_deps:block;)+) => {
         $(
             #[derive(Debug, Clone, Hash, PartialEq, Eq)]
@@ -647,7 +629,11 @@ fn run(mut $sel, $builder: &Builder<'_>) -> Option<PathBuf> {
                     path: $path,
                     extra_features: $sel.extra_features,
                     is_optional_tool: true,
-                    source_type: SourceType::Submodule,
+                    source_type: if false $(|| $in_tree)* {
+                        SourceType::InTree
+                    } else {
+                        SourceType::Submodule
+                    },
                 })
             }
         }
@@ -659,8 +645,8 @@ fn run(mut $sel, $builder: &Builder<'_>) -> Option<PathBuf> {
 // to make `./x.py build <tool>` work.
 tool_extended!((self, builder),
     Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", stable=true, {};
-    CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", stable=true, {};
-    Clippy, clippy, "src/tools/clippy", "clippy-driver", stable=true, {};
+    CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", stable=true, in_tree=true, {};
+    Clippy, clippy, "src/tools/clippy", "clippy-driver", stable=true, in_tree=true, {};
     Miri, miri, "src/tools/miri", "miri", stable=false, {};
     CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", stable=false, {};
     Rls, rls, "src/tools/rls", "rls", stable=true, {
index 38a0685e0f75a04cf2746584bbc49c658847ffae..818306a00922986ab4fe3c3f8ceb079b574a3acd 100644 (file)
@@ -26,8 +26,6 @@ jobs:
   strategy:
     matrix:
       dist-x86_64-linux: {}
-      dist-x86_64-linux-alt:
-        IMAGE: dist-x86_64-linux
 
 # The macOS and Windows builds here are currently disabled due to them not being
 # overly necessary on `try` builds. We also don't actually have anything that
diff --git a/src/ci/docker/disabled/riscv64gc-linux/0001-Remove-stime-function-calls.patch b/src/ci/docker/disabled/riscv64gc-linux/0001-Remove-stime-function-calls.patch
new file mode 100644 (file)
index 0000000..08d0c5b
--- /dev/null
@@ -0,0 +1,96 @@
+From c820da85c65c7f3aa9e9cb3ed71ada69bf9b783e Mon Sep 17 00:00:00 2001
+From: Alistair Francis <alistair.francis@wdc.com>
+Date: Tue, 19 Nov 2019 13:06:40 +0100
+Subject: [PATCH] Remove stime() function calls
+
+stime() has been deprecated in glibc 2.31 and replaced with
+clock_settime(). Let's replace the stime() function calls with
+clock_settime() in preperation.
+
+function                                             old     new   delta
+rdate_main                                           197     224     +27
+clock_settime                                          -      27     +27
+date_main                                            926     941     +15
+stime                                                 37       -     -37
+------------------------------------------------------------------------------
+(add/remove: 2/2 grow/shrink: 2/0 up/down: 69/-37)             Total: 32 bytes
+
+Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
+Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
+
+[Tom Eccles: adjust patch context to apply on top of 1.31.1-stable]
+Signed-off-by: Tom Eccles <tom.eccles@codethink.co.uk>
+---
+ coreutils/date.c         | 6 +++++-
+ libbb/missing_syscalls.c | 8 --------
+ util-linux/rdate.c       | 8 ++++++--
+ 3 files changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/coreutils/date.c b/coreutils/date.c
+index 3414d38ae..4ade6abb4 100644
+--- a/coreutils/date.c
++++ b/coreutils/date.c
+@@ -279,6 +279,9 @@ int date_main(int argc UNUSED_PARAM, char **argv)
+               time(&ts.tv_sec);
+ #endif
+       }
++#if !ENABLE_FEATURE_DATE_NANO
++      ts.tv_nsec = 0;
++#endif
+       localtime_r(&ts.tv_sec, &tm_time);
+       /* If date string is given, update tm_time, and maybe set date */
+@@ -301,9 +304,10 @@ int date_main(int argc UNUSED_PARAM, char **argv)
+               if (date_str[0] != '@')
+                       tm_time.tm_isdst = -1;
+               ts.tv_sec = validate_tm_time(date_str, &tm_time);
++              ts.tv_nsec = 0;
+               /* if setting time, set it */
+-              if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) {
++              if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) {
+                       bb_perror_msg("can't set date");
+               }
+       }
+diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c
+index 87cf59b3d..dc40d9155 100644
+--- a/libbb/missing_syscalls.c
++++ b/libbb/missing_syscalls.c
+@@ -15,14 +15,6 @@ pid_t getsid(pid_t pid)
+       return syscall(__NR_getsid, pid);
+ }
+-int stime(const time_t *t)
+-{
+-      struct timeval tv;
+-      tv.tv_sec = *t;
+-      tv.tv_usec = 0;
+-      return settimeofday(&tv, NULL);
+-}
+-
+ int sethostname(const char *name, size_t len)
+ {
+       return syscall(__NR_sethostname, name, len);
+diff --git a/util-linux/rdate.c b/util-linux/rdate.c
+index 70f829e7f..878375d78 100644
+--- a/util-linux/rdate.c
++++ b/util-linux/rdate.c
+@@ -95,9 +95,13 @@ int rdate_main(int argc UNUSED_PARAM, char **argv)
+       if (!(flags & 2)) { /* no -p (-s may be present) */
+               if (time(NULL) == remote_time)
+                       bb_error_msg("current time matches remote time");
+-              else
+-                      if (stime(&remote_time) < 0)
++              else {
++                      struct timespec ts;
++                      ts.tv_sec = remote_time;
++                      ts.tv_nsec = 0;
++                      if (clock_settime(CLOCK_REALTIME, &ts) < 0)
+                               bb_perror_msg_and_die("can't set time of day");
++              }
+       }
+       if (flags != 1) /* not lone -s */
+-- 
+2.25.1
+
diff --git a/src/ci/docker/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/disabled/riscv64gc-linux/Dockerfile
new file mode 100644 (file)
index 0000000..f21dc2b
--- /dev/null
@@ -0,0 +1,102 @@
+# based on armhf-gnu/Dockerfile
+FROM ubuntu:20.04
+
+RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
+RUN apt-get update -y && apt-get install -y --no-install-recommends \
+    bc \
+    bison \
+    ca-certificates \
+    cmake \
+    cpio \
+    curl \
+    debian-ports-archive-keyring \
+    debootstrap \
+    flex \
+    gcc \
+    gcc-riscv64-linux-gnu \
+    git \
+    g++-riscv64-linux-gnu \
+    g++ \
+    libc6-dev \
+    libc6-dev-riscv64-cross \
+    make \
+    patch \
+    python3 \
+    qemu-system-misc \
+    xz-utils
+
+ENV ARCH=riscv
+ENV CROSS_COMPILE=riscv64-linux-gnu-
+
+WORKDIR /build
+
+# From https://github.com/michaeljclark/busybear-linux/blob/master/conf/linux.config
+COPY riscv64gc-linux/linux.config /build
+
+# Compile the kernel that we're going to be emulating with. This is
+# basically just done to be compatible with the QEMU target that we're going
+# to be using when running tests.
+RUN curl https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.6.16.tar.xz | tar xJf - && \
+    cp linux.config linux-5.6.16/.config && \
+    cd /build/linux-5.6.16 && \
+    make olddefconfig && \
+    make -j$(nproc) vmlinux
+RUN cp linux-5.6.16/vmlinux /tmp
+RUN rm -rf linux-5.6.16
+
+# Compile an instance of busybox as this provides a lightweight system and init
+# binary which we will boot into. Only trick here is configuring busybox to
+# build static binaries.
+RUN curl https://busybox.net/downloads/busybox-1.31.1.tar.bz2 | tar xjf -
+COPY riscv64gc-linux/0001-Remove-stime-function-calls.patch /build/busybox-1.31.1/
+RUN cd /build/busybox-1.31.1 && \
+    patch -p1 -i 0001-Remove-stime-function-calls.patch && \
+    make defconfig && \
+    sed -i 's/.*CONFIG_STATIC.*/CONFIG_STATIC=y/' .config && \
+    make -j$(nproc) && \
+    make install && \
+    mv _install /tmp/rootfs && \
+    cd /build && \
+    rm -rf busybox-1.31.1
+
+# Download the ubuntu rootfs, which we'll use as a chroot for all our tests
+# This is only needed to provide /lib/* and /usr/lib/*
+WORKDIR /tmp
+RUN debootstrap --variant=minbase --arch=riscv64 --foreign focal /tmp/rootfs/ubuntu
+RUN cd rootfs && mkdir proc sys dev etc etc/init.d
+# rootfs/ubuntu/proc is in a weird state (access fails with ELOOP) until
+# rootfs/ubuntu/debootstrap/debootstrap --second-stage is run (under emulation),
+# but this takes ages. Instead hack it into a good enough state.
+# /proc is used by std::env::current_exe() (which is roughly
+# `readlink /proc/self/exe`)
+RUN cd rootfs/ubuntu && rm -rf proc && mkdir proc
+
+# Copy over our init script, which starts up our test server and also a few other
+# misc tasks
+COPY scripts/qemu-bare-bones-rcS rootfs/etc/init.d/rcS
+RUN chmod +x rootfs/etc/init.d/rcS
+
+# Helper to quickly fill the entropy pool in the kernel
+COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c
+RUN riscv64-linux-gnu-gcc addentropy.c -o rootfs/addentropy -static
+
+# download and build the riscv bootloader
+RUN git clone https://github.com/riscv/riscv-pk
+WORKDIR /tmp/riscv-pk
+# nothing special about this revision: it is just master at the time of writing
+# v1.0.0 doesn't build
+RUN git checkout 5d9ed238e1cabfbca3c47f50d32894ce94bfc304
+RUN mkdir build && cd build && \
+    ../configure --with-payload=/tmp/vmlinux --host=riscv64-linux-gnu && \
+    make -j$(nproc) && \
+    cp bbl /tmp
+WORKDIR /tmp
+RUN rm -rf /tmp/riscv-pk
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV RUST_CONFIGURE_ARGS --qemu-riscv64-rootfs=/tmp/rootfs
+ENV SCRIPT python3 ../x.py test --target riscv64gc-unknown-linux-gnu
+
+ENV NO_CHANGE_USER=1
diff --git a/src/ci/docker/disabled/riscv64gc-linux/linux.config b/src/ci/docker/disabled/riscv64gc-linux/linux.config
new file mode 100644 (file)
index 0000000..5142664
--- /dev/null
@@ -0,0 +1,51 @@
+CONFIG_DEFAULT_HOSTNAME="busybear"
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_CHECKPOINT_RESTORE=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_SMP=y
+CONFIG_MODULES=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_PACKET_DIAG=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_NETLINK_DIAG=y
+# CONFIG_WIRELESS is not set
+CONFIG_PCI=y
+CONFIG_DEVTMPFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
+# CONFIG_ETHERNET is not set
+# CONFIG_WLAN is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_HVC_RISCV_SBI=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_VIRTIO_MMIO=y
+CONFIG_SIFIVE_PLIC=y
+CONFIG_RAS=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_CRYPTO_ECHAINIV is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_PRINTK_TIME=y
index 74766dc970d9f8fbcfb173ce21c6101824c499a0..fd764965ef21b1d85e50c9d3008b75219e5ad866 100644 (file)
@@ -35,5 +35,6 @@ ENV HOSTS=aarch64-unknown-linux-gnu
 ENV RUST_CONFIGURE_ARGS \
       --enable-full-tools \
       --enable-profiler \
+      --enable-sanitizers \
       --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
index 43f5581f996ea437b6fd32bcb5651407d858dadc..1f1c2460023525049c10769abe694b8f1d03f3a6 100644 (file)
@@ -71,9 +71,7 @@ RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
 COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
 COPY dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh /usr/bin/x86_64-fortanix-unknown-sgx-clang-11
 RUN ln -s /usr/bin/x86_64-fortanix-unknown-sgx-clang-11 /usr/bin/x86_64-fortanix-unknown-sgx-clang++-11
-# We pass the commit id of the port of LLVM's libunwind to the build script.
-# Any update to the commit id here, should cause the container image to be re-built from this point on.
-RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "800f95131fe6acd20b96b6f4723ca3c820f3d379"
+RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
 
 COPY dist-various-2/build-wasi-toolchain.sh /tmp/
 RUN /tmp/build-wasi-toolchain.sh
@@ -105,8 +103,6 @@ ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda
 ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabi
 ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabi
 
-ENV X86_FORTANIX_SGX_LIBS="/x86_64-fortanix-unknown-sgx/lib/"
-
 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
 # we need asm in the search path for gcc-7 (for gnux32) but not in the search path of the
 # cross compilers.
index 4294b1ef93dd825226241d9dbe2236a46c752944..78bf4527feff19e953c4d06d4f4bd4e0ecc6fd8d 100755 (executable)
@@ -3,14 +3,7 @@
 set -eu
 source shared.sh
 
-if [ -z "$1" ]; then
-    echo "Usage: ${0} <commit_id>"
-    exit -1
-fi
-
 target="x86_64-fortanix-unknown-sgx"
-url="https://github.com/fortanix/llvm-project/archive/${1}.tar.gz"
-repo_name="llvm-project"
 
 install_prereq() {
     curl https://apt.llvm.org/llvm-snapshot.gpg.key|apt-key add -
@@ -24,39 +17,4 @@ install_prereq() {
             clang-11
 }
 
-build_unwind() {
-    set -x
-    dir_name="${target}_temp"
-    rm -rf ${dir_name}
-    mkdir -p ${dir_name}
-    pushd ${dir_name}
-
-    # Clone Fortanix's fork of llvm-project which has a port of libunwind
-    fetch_github_commit_archive "$repo_name" "$url"
-    cd "${repo_name}/libunwind"
-
-    # Build libunwind
-    mkdir -p build
-    cd build
-    target_CC="CC_${target//-/_}"
-    target_CXX="CXX_${target//-/_}"
-    target_CFLAGS="CFLAGS_${target//-/_}"
-    target_CXXFLAGS="CXXFLAGS_${target//-/_}"
-    cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" \
-        -DCMAKE_C_COMPILER="${!target_CC}" -DCMAKE_CXX_COMPILER="${!target_CXX}" \
-        -DCMAKE_C_FLAGS="${!target_CFLAGS}" -DCMAKE_CXX_FLAGS="${!target_CXXFLAGS}" \
-        -DCMAKE_C_COMPILER_TARGET=$target -DCMAKE_CXX_COMPILER_TARGET=$target \
-        -DLLVM_ENABLE_WARNINGS=1 -DLIBUNWIND_ENABLE_WERROR=1 -DLIBUNWIND_ENABLE_PEDANTIC=0 \
-        -DLLVM_PATH=../../llvm/ ../
-    make unwind_static
-    install -D "lib/libunwind.a" "/${target}/lib/libunwind.a"
-
-    popd
-    rm -rf ${dir_name}
-
-    { set +x; } 2>/dev/null
-}
-
-set -x
 hide_output install_prereq
-build_unwind
index 148e09f6ad104c17177b126fcbb9339db907ffc1..3b6e4c2cb98df44778eca619185bb7e9c2734a70 100644 (file)
@@ -19,9 +19,6 @@ RUN sh /scripts/sccache.sh
 
 COPY x86_64-gnu-tools/checktools.sh /tmp/
 
-# Run rustbook with `linkcheck` feature enabled
-ENV CHECK_LINKS 1
-
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json
index a052d0879a3dbfe1c6aecf1f9077e2dcbfe1ea1a..5e67567c76b4ff0e9ac797112a4739e3d7cfcf56 100644 (file)
@@ -281,11 +281,6 @@ jobs:
           - name: dist-x86_64-linux
             <<: *job-linux-xl
 
-          - name: dist-x86_64-linux-alt
-            env:
-              IMAGE: dist-x86_64-linux
-            <<: *job-linux-xl
-
   auto:
     <<: *base-ci-job
     name: auto
@@ -419,42 +414,6 @@ jobs:
               DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
             <<: *job-linux-xl
 
-          ####################
-          #  macOS Builders  #
-          ####################
-
-          - name: dist-x86_64-apple
-            env:
-              SCRIPT: ./x.py dist
-              RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-              DIST_REQUIRE_ALL_TOOLS: 1
-            <<: *job-macos-xl
-
-          - name: dist-x86_64-apple-alt
-            env:
-              SCRIPT: ./x.py dist
-              RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            <<: *job-macos-xl
-
-          - name: x86_64-apple
-            env:
-              SCRIPT: ./x.py test
-              RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.8
-              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            <<: *job-macos-xl
-
           ######################
           #  Windows Builders  #
           ######################
@@ -600,6 +559,51 @@ jobs:
               SCRIPT: python x.py dist
             <<: *job-windows-xl
 
+  auto-fallible:
+    <<: *base-ci-job
+    name: auto-fallible
+    env:
+      <<: [*shared-ci-variables, *prod-variables]
+    if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
+    strategy:
+      matrix:
+        include:
+          ####################
+          #  macOS Builders  #
+          ####################
+
+          - name: dist-x86_64-apple
+            env:
+              SCRIPT: ./x.py dist
+              RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+            <<: *job-macos-xl
+
+          - name: dist-x86_64-apple-alt
+            env:
+              SCRIPT: ./x.py dist
+              RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            <<: *job-macos-xl
+
+          - name: x86_64-apple
+            env:
+              SCRIPT: ./x.py test
+              RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.8
+              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            <<: *job-macos-xl
+
   master:
     name: master
     runs-on: ubuntu-latest
index 30cd9dfe71c446de63826bb4472627af45acc9db..4e7c00bece1544d409312ec93467beb62b5bd0cb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 30cd9dfe71c446de63826bb4472627af45acc9db
+Subproject commit 4e7c00bece1544d409312ec93467beb62b5bd0cb
index 5555a97f04ad7974ac6fb8fb47c267c4274adf4a..616962ad0dd80f34d8b802da038d0aed9dd691bb 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5555a97f04ad7974ac6fb8fb47c267c4274adf4a
+Subproject commit 616962ad0dd80f34d8b802da038d0aed9dd691bb
index 5d40ba5c2515caffa7790cda621239dc21ef5a72..04d5d5d7ba624b6f5016298451f3a63d557f3260 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5d40ba5c2515caffa7790cda621239dc21ef5a72
+Subproject commit 04d5d5d7ba624b6f5016298451f3a63d557f3260
index 7aa82129aa23e7e181efbeb8da03a2a897ef6afc..6f94ccb48da6fa4ed0031290f21411cf789f7d5e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 7aa82129aa23e7e181efbeb8da03a2a897ef6afc
+Subproject commit 6f94ccb48da6fa4ed0031290f21411cf789f7d5e
index 7a7838d965bc77f5255c184fcbf03698a9991510..30b18eb56a1256c0d011ce58c7f0a200e8985014 100644 (file)
@@ -273,10 +273,18 @@ This flag, when combined with other flags, makes them produce extra output.
 This flag allows you to pass the name and location for an external crate of a
 direct dependency. Indirect dependencies (dependencies of dependencies) are
 located using the [`-L` flag](#option-l-search-path). The given crate name is
-added to the [extern prelude], which is the same as specifying `extern crate`
-within the root module. The given crate name does not need to match the name
+added to the [extern prelude], similar to specifying `extern crate` within the
+root module. The given crate name does not need to match the name
 the library was built with.
 
+Specifying `--extern` has one behavior difference from `extern crate`:
+`--extern` merely makes the crate a _candidate_ for being linked; it does not
+actually link it unless it's actively used. In rare occasions you may wish
+to ensure a crate is linked even if you don't actively use it from your
+code: for example, if it changes the global allocator or if it contains
+`#[no_mangle]` symbols for use by other programming languages. In such
+cases you'll need to use `extern crate`.
+
 This flag may be specified multiple times. This flag takes an argument with
 either of the following formats:
 
index 48dea213e8cee040f5d8427ac08273dfe9b5862f..4115825e920838947ab4dee93124a1811980daaf 100644 (file)
@@ -1,10 +1,10 @@
-# `control_flow_guard`
+# `control-flow-guard`
 
 The tracking issue for this feature is: [#68793](https://github.com/rust-lang/rust/issues/68793).
 
 ------------------------
 
-The rustc flag `-Z control_flow_guard=checks` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature.
+The rustc flag `-Z control-flow-guard` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature.
 
 CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported Windows platforms (Windows 8.1 onwards). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete. 
 
@@ -29,7 +29,7 @@ The CFG checks and metadata can potentially increase binary size and runtime ove
 
 ## Testing Control Flow Guard
 
-The rustc flag `-Z control_flow_guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement.
+The rustc flag `-Z control-flow-guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement.
 
 
 ## Control Flow Guard in libraries
@@ -44,14 +44,14 @@ For example:
 ```cmd
 rustup toolchain install --force nightly
 rustup component add rust-src
-SET RUSTFLAGS=-Z control_flow_guard=checks
+SET RUSTFLAGS=-Z control-flow-guard
 cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
 ```
 
 ```PowerShell
 rustup toolchain install --force nightly
 rustup component add rust-src
-$Env:RUSTFLAGS = "-Z control_flow_guard=checks"
+$Env:RUSTFLAGS = "-Z control-flow-guard"
 cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
 ```
 
index 7ebd8054ba0b0d19361365675332ba55b1d32eb2..5e2e04c063bc483abff4700462958c6791e9573a 100644 (file)
@@ -12,8 +12,7 @@ This feature allows for use of one of following sanitizers:
 * [ThreadSanitizer][clang-tsan] a fast data race detector.
 
 To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`,
-`-Zsanitizer=memory` or `-Zsanitizer=thread`. Only a single sanitizer can be
-enabled at a time.
+`-Zsanitizer=memory` or `-Zsanitizer=thread`.
 
 # AddressSanitizer
 
index 6de1c774f7cd7d19255cfa60042d838663efca4e..7305141a427146ada0c2361245e863ac60fda507 100644 (file)
@@ -13,7 +13,7 @@ For example:
 First, run a compilation session and provide the `-Zself-profile` flag:
 
 ```console
-$ rustc --crate-name foo -Zself-profile`
+$ rustc --crate-name foo -Zself-profile
 ```
 
 This will generate three files in the working directory such as:
diff --git a/src/doc/unstable-book/src/language-features/const-if-match.md b/src/doc/unstable-book/src/language-features/const-if-match.md
deleted file mode 100644 (file)
index ee9cfcb..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# `const_if_match`
-
-The tracking issue for this feature is: [#49146]
-
-[#49146]: https://github.com/rust-lang/rust/issues/49146
-
-------------------------
-
-Allows for the use of conditionals (`if` and `match`) in a const context.
-Const contexts include `static`, `static mut`, `const`, `const fn`, const
-generics, and array initializers. Enabling this feature flag will also make
-`&&` and `||` function normally in a const-context by removing the hack that
-replaces them with their non-short-circuiting equivalents, `&` and `|`, in a
-`const` or `static`.
index fbb40f1d2f3d4b07e8ea1e476f33cfa71af87c54..c4c985dd134ba375dc23c4fc7438fc48373f6293 100644 (file)
@@ -68,10 +68,13 @@ Let us see another example that also uses an input:
 let i: u64 = 3;
 let o: u64;
 unsafe {
-    asm!("
-        mov {0}, {1}
-        add {0}, {number}
-    ", out(reg) o, in(reg) i, number = const 5);
+    asm!(
+        "mov {0}, {1}",
+        "add {0}, {number}",
+        out(reg) o,
+        in(reg) i,
+        number = const 5,
+    );
 }
 assert_eq!(o, 8);
 ```
@@ -82,13 +85,18 @@ and then adding `5` to it.
 
 The example shows a few things:
 
-First we can see that inputs are declared by writing `in` instead of `out`.
+First, we can see that `asm!` allows multiple template string arguments; each
+one is treated as a separate line of assembly code, as if they were all joined
+together with newlines between them. This makes it easy to format assembly
+code.
+
+Second, we can see that inputs are declared by writing `in` instead of `out`.
 
-Second one of our operands has a type we haven't seen yet, `const`.
+Third, one of our operands has a type we haven't seen yet, `const`.
 This tells the compiler to expand this argument to value directly inside the assembly template.
 This is only possible for constants and literals.
 
-Third we can see that we can specify an argument number, or name as in any format string.
+Fourth, we can see that we can specify an argument number, or name as in any format string.
 For inline assembly templates this is particularly useful as arguments are often used more than once.
 For more complex inline assembly using this facility is generally recommended, as it improves
 readability, and allows reordering instructions without changing the argument order.
@@ -137,10 +145,13 @@ let mut a: u64 = 4;
 let b: u64 = 4;
 let c: u64 = 4;
 unsafe {
-    asm!("
-        add {0}, {1}
-        add {0}, {2}
-    ", inout(reg) a, in(reg) b, in(reg) c);
+    asm!(
+        "add {0}, {1}",
+        "add {0}, {2}",
+        inout(reg) a,
+        in(reg) b,
+        in(reg) c,
+    );
 }
 assert_eq!(a, 12);
 ```
@@ -233,7 +244,7 @@ unsafe {
         // ECX 0 selects the L0 cache information.
         inout("ecx") 0 => ecx,
         lateout("ebx") ebx,
-        lateout("edx") _
+        lateout("edx") _,
     );
 }
 
@@ -255,12 +266,14 @@ This can also be used with a general register class (e.g. `reg`) to obtain a scr
 // Multiply x by 6 using shifts and adds
 let mut x: u64 = 4;
 unsafe {
-    asm!("
-        mov {tmp}, {x}
-        shl {tmp}, 1
-        shl {x}, 2
-        add {x}, {tmp}
-    ", x = inout(reg) x, tmp = out(reg) _);
+    asm!(
+        "mov {tmp}, {x}",
+        "shl {tmp}, 1",
+        "shl {x}, 2",
+        "add {x}, {tmp}",
+        x = inout(reg) x,
+        tmp = out(reg) _,
+    );
 }
 assert_eq!(x, 4 * 6);
 ```
@@ -338,7 +351,7 @@ unsafe {
     asm!(
         "add {0}, {1}",
         inlateout(reg) a, in(reg) b,
-        options(pure, nomem, nostack)
+        options(pure, nomem, nostack),
     );
 }
 assert_eq!(a, 8);
@@ -371,24 +384,26 @@ reg_operand := dir_spec "(" reg_spec ")" operand_expr
 operand := reg_operand / "const" const_expr / "sym" path
 option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax"
 options := "options(" option *["," option] [","] ")"
-asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")"
+asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
 ```
 
-The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
+The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
 
 [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
 
-## Template string
+## Template string arguments
 
 The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.
 
+An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.
+
 As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any.
 
 Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.
 
 The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
 
-The 4 targets specified in this RFC (x86, ARM, AArch64, RISC-V) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
+The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
 
 [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795
 
@@ -459,7 +474,7 @@ Here is the list of currently supported register classes:
 | AArch64 | `reg` | `x[0-28]`, `x30` | `r` |
 | AArch64 | `vreg` | `v[0-31]` | `w` |
 | AArch64 | `vreg_low16` | `v[0-15]` | `x` |
-| ARM | `reg` | `r[0-r10]`, `r12`, `r14` | `r` |
+| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` |
 | ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
 | ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |
 | ARM | `sreg` | `s[0-31]` | `t` |
@@ -475,12 +490,15 @@ Here is the list of currently supported register classes:
 | NVPTX | `reg64` | None\* | `l` |
 | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
 | RISC-V | `freg` | `f[0-31]` | `f` |
+| Hexagon | `reg` | `r[0-28]` | `r` |
 
 > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
 >
 > Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
 >
 > Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
+>
+> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
 
 Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
 
@@ -509,6 +527,7 @@ Each register class has constraints on which value types they can be used with.
 | RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
 | RISC-V | `freg` | `f` | `f32` |
 | RISC-V | `freg` | `d` | `f64` |
+| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
 
 > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
 
@@ -565,13 +584,18 @@ Some registers have multiple names. These are all treated by the compiler as ide
 | RISC-V | `f[10-17]` | `fa[0-7]` |
 | RISC-V | `f[18-27]` | `fs[2-11]` |
 | RISC-V | `f[28-31]` | `ft[8-11]` |
+| Hexagon | `r29` | `sp` |
+| Hexagon | `r30` | `fr` |
+| Hexagon | `r31` | `lr` |
 
 Some registers cannot be used for input or output operands:
 
 | Architecture | Unsupported register | Reason |
 | ------------ | -------------------- | ------ |
 | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
-| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. |
+| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |
+| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
+| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |
 | x86 | `k0` | This is a constant zero register which can't be modified. |
 | x86 | `ip` | This is the program counter, not a real register. |
 | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
@@ -580,6 +604,7 @@ Some registers cannot be used for input or output operands:
 | ARM | `pc` | This is the program counter, not a real register. |
 | RISC-V | `x0` | This is a constant zero register which can't be modified. |
 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
+| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
 
 ## Template modifiers
 
@@ -625,6 +650,7 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
 | NVPTX | `reg64` | None | `rd0` | None |
 | RISC-V | `reg` | None | `x1` | None |
 | RISC-V | `freg` | None | `f0` | None |
+| Hexagon | `reg` | None | `r0` | None |
 
 > Notes:
 > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
index d1119f7b7c0a7f6a83cccaa0aa7c8d0897d5abde..914195f015b5a83daf9325285aa6074c61c79dec 100644 (file)
@@ -25,6 +25,7 @@ path = "../liballoc/tests/lib.rs"
 [[bench]]
 name = "collectionsbenches"
 path = "../liballoc/benches/lib.rs"
+test = true
 
 [[bench]]
 name = "vec_deque_append_bench"
index d31c73cc1bd8d576e3e2492d46bce1e0c3e34f36..98c7ac3f2ef17cde30f163dfd658c70a0bfeae45 100644 (file)
@@ -77,7 +77,7 @@
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn alloc(layout: Layout) -> *mut u8 {
-    __rust_alloc(layout.size(), layout.align())
+    unsafe { __rust_alloc(layout.size(), layout.align()) }
 }
 
 /// Deallocate memory with the global allocator.
@@ -99,7 +99,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
-    __rust_dealloc(ptr, layout.size(), layout.align())
+    unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
 }
 
 /// Reallocate memory with the global allocator.
@@ -121,7 +121,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-    __rust_realloc(ptr, layout.size(), layout.align(), new_size)
+    unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
 }
 
 /// Allocate zero-initialized memory with the global allocator.
@@ -158,7 +158,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
-    __rust_alloc_zeroed(layout.size(), layout.align())
+    unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
 }
 
 #[unstable(feature = "allocator_api", issue = "32838")]
@@ -183,7 +183,7 @@ fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, Allo
     #[inline]
     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
         if layout.size() != 0 {
-            dealloc(ptr.as_ptr(), layout)
+            unsafe { dealloc(ptr.as_ptr(), layout) }
         }
     }
 
@@ -209,16 +209,21 @@ unsafe fn grow(
         match placement {
             ReallocPlacement::InPlace => Err(AllocErr),
             ReallocPlacement::MayMove if layout.size() == 0 => {
-                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
+                let new_layout =
+                    unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
                 self.alloc(new_layout, init)
             }
             ReallocPlacement::MayMove => {
                 // `realloc` probably checks for `new_size > size` or something similar.
-                intrinsics::assume(new_size > size);
-                let ptr = realloc(ptr.as_ptr(), layout, new_size);
+                let ptr = unsafe {
+                    intrinsics::assume(new_size > size);
+                    realloc(ptr.as_ptr(), layout, new_size)
+                };
                 let memory =
                     MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
-                init.init_offset(memory, size);
+                unsafe {
+                    init.init_offset(memory, size);
+                }
                 Ok(memory)
             }
         }
@@ -245,13 +250,17 @@ unsafe fn shrink(
         match placement {
             ReallocPlacement::InPlace => Err(AllocErr),
             ReallocPlacement::MayMove if new_size == 0 => {
-                self.dealloc(ptr, layout);
+                unsafe {
+                    self.dealloc(ptr, layout);
+                }
                 Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
             }
             ReallocPlacement::MayMove => {
                 // `realloc` probably checks for `new_size < size` or something similar.
-                intrinsics::assume(new_size < size);
-                let ptr = realloc(ptr.as_ptr(), layout, new_size);
+                let ptr = unsafe {
+                    intrinsics::assume(new_size < size);
+                    realloc(ptr.as_ptr(), layout, new_size)
+                };
                 Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
             }
         }
@@ -264,7 +273,7 @@ unsafe fn shrink(
 #[lang = "exchange_malloc"]
 #[inline]
 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
-    let layout = Layout::from_size_align_unchecked(size, align);
+    let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
     match Global.alloc(layout, AllocInit::Uninitialized) {
         Ok(memory) => memory.ptr.as_ptr(),
         Err(_) => handle_alloc_error(layout),
@@ -279,10 +288,12 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
 // For example if `Box` is changed to  `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
 // this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
 pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
-    let size = size_of_val(ptr.as_ref());
-    let align = min_align_of_val(ptr.as_ref());
-    let layout = Layout::from_size_align_unchecked(size, align);
-    Global.dealloc(ptr.cast().into(), layout)
+    unsafe {
+        let size = size_of_val(ptr.as_ref());
+        let align = min_align_of_val(ptr.as_ref());
+        let layout = Layout::from_size_align_unchecked(size, align);
+        Global.dealloc(ptr.cast().into(), layout)
+    }
 }
 
 /// Abort on memory allocation error or failure.
index f31717d9fd517e76b860364f430e7170d2194822..608eafc88d2a6d8b181ad4d504691630180f8c76 100644 (file)
@@ -1,3 +1,6 @@
+// Disabling on android for the time being
+// See https://github.com/rust-lang/rust/issues/73535#event-3477699747
+#![cfg(not(target_os = "android"))]
 #![feature(btree_drain_filter)]
 #![feature(map_first_last)]
 #![feature(repr_simd)]
index 22c344323a2edd6354b99a61e77fcb1ec3f14953..f1b560b9b968550dea1950fd4bba412e18190f5c 100644 (file)
 //! pub struct Foo;
 //!
 //! #[no_mangle]
+//! #[allow(improper_ctypes_definitions)]
 //! pub extern "C" fn foo_new() -> Box<Foo> {
 //!     Box::new(Foo)
 //! }
 //!
 //! #[no_mangle]
+//! #[allow(improper_ctypes_definitions)]
 //! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
 //! ```
 //!
@@ -248,7 +250,7 @@ pub fn pin(x: T) -> Pin<Box<T>> {
     #[unstable(feature = "box_into_boxed_slice", issue = "71582")]
     pub fn into_boxed_slice(boxed: Box<T>) -> Box<[T]> {
         // *mut T and *mut [T; 1] have the same size and alignment
-        unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1] as *mut [T]) }
+        unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1]) }
     }
 }
 
@@ -311,7 +313,7 @@ impl<T> Box<mem::MaybeUninit<T>> {
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
     pub unsafe fn assume_init(self) -> Box<T> {
-        Box::from_raw(Box::into_raw(self) as *mut T)
+        unsafe { Box::from_raw(Box::into_raw(self) as *mut T) }
     }
 }
 
@@ -349,7 +351,7 @@ impl<T> Box<[mem::MaybeUninit<T>]> {
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
     pub unsafe fn assume_init(self) -> Box<[T]> {
-        Box::from_raw(Box::into_raw(self) as *mut [T])
+        unsafe { Box::from_raw(Box::into_raw(self) as *mut [T]) }
     }
 }
 
@@ -393,7 +395,7 @@ impl<T: ?Sized> Box<T> {
     #[stable(feature = "box_raw", since = "1.4.0")]
     #[inline]
     pub unsafe fn from_raw(raw: *mut T) -> Self {
-        Box(Unique::new_unchecked(raw))
+        Box(unsafe { Unique::new_unchecked(raw) })
     }
 
     /// Consumes the `Box`, returning a wrapped raw pointer.
index c2fe4691b34c098f689b7d27a42e81ae1829fd0e..15313e333ce732a876646d5fe533b77a58f4d0bf 100644 (file)
@@ -1003,7 +1003,7 @@ impl<'a, T> Hole<'a, T> {
     unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
         debug_assert!(pos < data.len());
         // SAFE: pos should be inside the slice
-        let elt = ptr::read(data.get_unchecked(pos));
+        let elt = unsafe { ptr::read(data.get_unchecked(pos)) };
         Hole { data, elt: ManuallyDrop::new(elt), pos }
     }
 
@@ -1025,7 +1025,7 @@ fn element(&self) -> &T {
     unsafe fn get(&self, index: usize) -> &T {
         debug_assert!(index != self.pos);
         debug_assert!(index < self.data.len());
-        self.data.get_unchecked(index)
+        unsafe { self.data.get_unchecked(index) }
     }
 
     /// Move hole to new location
@@ -1035,9 +1035,11 @@ unsafe fn get(&self, index: usize) -> &T {
     unsafe fn move_to(&mut self, index: usize) {
         debug_assert!(index != self.pos);
         debug_assert!(index < self.data.len());
-        let index_ptr: *const _ = self.data.get_unchecked(index);
-        let hole_ptr = self.data.get_unchecked_mut(self.pos);
-        ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
+        unsafe {
+            let index_ptr: *const _ = self.data.get_unchecked(index);
+            let hole_ptr = self.data.get_unchecked_mut(self.pos);
+            ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
+        }
         self.pos = index;
     }
 }
index fa1c09d9ece87141bd839841e27cade56d3570c8..bb9091a66594bda1665309811e38deab38fe4bd4 100644 (file)
@@ -488,7 +488,9 @@ struct MergeIter<K, V, I: Iterator<Item = (K, V)>> {
 }
 
 impl<K: Ord, V> BTreeMap<K, V> {
-    /// Makes a new empty BTreeMap with a reasonable choice for B.
+    /// Makes a new empty BTreeMap.
+    ///
+    /// Does not allocate anything on its own.
     ///
     /// # Examples
     ///
@@ -1394,6 +1396,14 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     fn last(mut self) -> Option<(&'a K, &'a V)> {
         self.next_back()
     }
+
+    fn min(mut self) -> Option<(&'a K, &'a V)> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<(&'a K, &'a V)> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -1456,6 +1466,14 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     fn last(mut self) -> Option<(&'a K, &'a mut V)> {
         self.next_back()
     }
+
+    fn min(mut self) -> Option<(&'a K, &'a mut V)> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<(&'a K, &'a mut V)> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1593,6 +1611,14 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     fn last(mut self) -> Option<&'a K> {
         self.next_back()
     }
+
+    fn min(mut self) -> Option<&'a K> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<&'a K> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1725,7 +1751,7 @@ unsafe fn next_kv(
         &mut self,
     ) -> Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>> {
         let edge = self.cur_leaf_edge.as_ref()?;
-        ptr::read(edge).next_kv().ok()
+        unsafe { ptr::read(edge).next_kv().ok() }
     }
 
     /// Implementation of a typical `DrainFilter::next` method, given the predicate.
@@ -1766,6 +1792,14 @@ fn next(&mut self) -> Option<(&'a K, &'a V)> {
     fn last(mut self) -> Option<(&'a K, &'a V)> {
         self.next_back()
     }
+
+    fn min(mut self) -> Option<(&'a K, &'a V)> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<(&'a K, &'a V)> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1808,7 +1842,7 @@ fn is_empty(&self) -> bool {
     }
 
     unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
-        unwrap_unchecked(self.front.as_mut()).next_unchecked()
+        unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
     }
 }
 
@@ -1821,7 +1855,7 @@ fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
 
 impl<'a, K, V> Range<'a, K, V> {
     unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
-        unwrap_unchecked(self.back.as_mut()).next_back_unchecked()
+        unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() }
     }
 }
 
@@ -1851,6 +1885,14 @@ fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
     fn last(mut self) -> Option<(&'a K, &'a mut V)> {
         self.next_back()
     }
+
+    fn min(mut self) -> Option<(&'a K, &'a mut V)> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<(&'a K, &'a mut V)> {
+        self.next_back()
+    }
 }
 
 impl<'a, K, V> RangeMut<'a, K, V> {
@@ -1859,7 +1901,7 @@ fn is_empty(&self) -> bool {
     }
 
     unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
-        unwrap_unchecked(self.front.as_mut()).next_unchecked()
+        unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
     }
 }
 
@@ -1880,7 +1922,7 @@ impl<K, V> FusedIterator for RangeMut<'_, K, V> {}
 
 impl<'a, K, V> RangeMut<'a, K, V> {
     unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
-        unwrap_unchecked(self.back.as_mut()).next_back_unchecked()
+        unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() }
     }
 }
 
index fb5825ee21a9e4459551e269026ae2208a59168c..543ff41a4d48d55fc2b4616f39a8a17cc69c2a87 100644 (file)
@@ -19,7 +19,9 @@ pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
         if cfg!(debug_assertions) {
             panic!("'unchecked' unwrap on None in BTreeMap");
         } else {
-            core::intrinsics::unreachable();
+            unsafe {
+                core::intrinsics::unreachable();
+            }
         }
     })
 }
index 5e8dcf247ae5996af8fde8a55ceea5d5bcb464e1..5478d822438b1ca3afd2f169f7d50422147dbd52 100644 (file)
@@ -64,8 +64,10 @@ unsafe fn $name <K, V>(
                 edge = match edge.$adjacent_kv() {
                     Ok(internal_kv) => return internal_kv,
                     Err(last_edge) => {
-                        let parent_edge = last_edge.into_node().deallocate_and_ascend();
-                        unwrap_unchecked(parent_edge).forget_node_type()
+                        unsafe {
+                            let parent_edge = last_edge.into_node().deallocate_and_ascend();
+                            unwrap_unchecked(parent_edge).forget_node_type()
+                        }
                     }
                 }
             }
@@ -82,9 +84,11 @@ unsafe fn $name <K, V>(
 /// Safety: The change closure must not panic.
 #[inline]
 unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
-    let value = ptr::read(v);
+    let value = unsafe { ptr::read(v) };
     let (new_value, ret) = change(value);
-    ptr::write(v, new_value);
+    unsafe {
+        ptr::write(v, new_value);
+    }
     ret
 }
 
@@ -93,22 +97,26 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed
     /// key and value in between.
     /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
     pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
-        replace(self, |leaf_edge| {
-            let kv = leaf_edge.next_kv();
-            let kv = unwrap_unchecked(kv.ok());
-            (kv.next_leaf_edge(), kv.into_kv())
-        })
+        unsafe {
+            replace(self, |leaf_edge| {
+                let kv = leaf_edge.next_kv();
+                let kv = unwrap_unchecked(kv.ok());
+                (kv.next_leaf_edge(), kv.into_kv())
+            })
+        }
     }
 
     /// Moves the leaf edge handle to the previous leaf edge and returns references to the
     /// key and value in between.
     /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
     pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
-        replace(self, |leaf_edge| {
-            let kv = leaf_edge.next_back_kv();
-            let kv = unwrap_unchecked(kv.ok());
-            (kv.next_back_leaf_edge(), kv.into_kv())
-        })
+        unsafe {
+            replace(self, |leaf_edge| {
+                let kv = leaf_edge.next_back_kv();
+                let kv = unwrap_unchecked(kv.ok());
+                (kv.next_back_leaf_edge(), kv.into_kv())
+            })
+        }
     }
 }
 
@@ -119,14 +127,16 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
     /// - The caller must ensure that the leaf edge is not the last one in the tree.
     /// - Using the updated handle may well invalidate the returned references.
     pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
-        let kv = replace(self, |leaf_edge| {
-            let kv = leaf_edge.next_kv();
-            let kv = unwrap_unchecked(kv.ok());
-            (ptr::read(&kv).next_leaf_edge(), kv)
-        });
-        // Doing the descend (and perhaps another move) invalidates the references
-        // returned by `into_kv_mut`, so we have to do this last.
-        kv.into_kv_mut()
+        unsafe {
+            let kv = replace(self, |leaf_edge| {
+                let kv = leaf_edge.next_kv();
+                let kv = unwrap_unchecked(kv.ok());
+                (ptr::read(&kv).next_leaf_edge(), kv)
+            });
+            // Doing the descend (and perhaps another move) invalidates the references
+            // returned by `into_kv_mut`, so we have to do this last.
+            kv.into_kv_mut()
+        }
     }
 
     /// Moves the leaf edge handle to the previous leaf and returns references to the
@@ -135,14 +145,16 @@ pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
     /// - The caller must ensure that the leaf edge is not the first one in the tree.
     /// - Using the updated handle may well invalidate the returned references.
     pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
-        let kv = replace(self, |leaf_edge| {
-            let kv = leaf_edge.next_back_kv();
-            let kv = unwrap_unchecked(kv.ok());
-            (ptr::read(&kv).next_back_leaf_edge(), kv)
-        });
-        // Doing the descend (and perhaps another move) invalidates the references
-        // returned by `into_kv_mut`, so we have to do this last.
-        kv.into_kv_mut()
+        unsafe {
+            let kv = replace(self, |leaf_edge| {
+                let kv = leaf_edge.next_back_kv();
+                let kv = unwrap_unchecked(kv.ok());
+                (ptr::read(&kv).next_back_leaf_edge(), kv)
+            });
+            // Doing the descend (and perhaps another move) invalidates the references
+            // returned by `into_kv_mut`, so we have to do this last.
+            kv.into_kv_mut()
+        }
     }
 }
 
@@ -159,12 +171,14 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
     ///   if the two preconditions above hold.
     /// - Using the updated handle may well invalidate the returned references.
     pub unsafe fn next_unchecked(&mut self) -> (K, V) {
-        replace(self, |leaf_edge| {
-            let kv = next_kv_unchecked_dealloc(leaf_edge);
-            let k = ptr::read(kv.reborrow().into_kv().0);
-            let v = ptr::read(kv.reborrow().into_kv().1);
-            (kv.next_leaf_edge(), (k, v))
-        })
+        unsafe {
+            replace(self, |leaf_edge| {
+                let kv = next_kv_unchecked_dealloc(leaf_edge);
+                let k = ptr::read(kv.reborrow().into_kv().0);
+                let v = ptr::read(kv.reborrow().into_kv().1);
+                (kv.next_leaf_edge(), (k, v))
+            })
+        }
     }
 
     /// Moves the leaf edge handle to the previous leaf edge and returns the key
@@ -179,12 +193,14 @@ pub unsafe fn next_unchecked(&mut self) -> (K, V) {
     ///   if the two preconditions above hold.
     /// - Using the updated handle may well invalidate the returned references.
     pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
-        replace(self, |leaf_edge| {
-            let kv = next_back_kv_unchecked_dealloc(leaf_edge);
-            let k = ptr::read(kv.reborrow().into_kv().0);
-            let v = ptr::read(kv.reborrow().into_kv().1);
-            (kv.next_back_leaf_edge(), (k, v))
-        })
+        unsafe {
+            replace(self, |leaf_edge| {
+                let kv = next_back_kv_unchecked_dealloc(leaf_edge);
+                let k = ptr::read(kv.reborrow().into_kv().0);
+                let v = ptr::read(kv.reborrow().into_kv().1);
+                (kv.next_back_leaf_edge(), (k, v))
+            })
+        }
     }
 }
 
index 5569c293e2f6605e50ba1e0f7250188b19d4337a..a4b6cf12a23bd92671d30db8cdc4eaa8b293aeed 100644 (file)
@@ -107,7 +107,7 @@ impl<K, V> InternalNode<K, V> {
     /// `len` of 0), there must be one initialized and valid edge. This function does not set up
     /// such an edge.
     unsafe fn new() -> Self {
-        InternalNode { data: LeafNode::new(), edges: [MaybeUninit::UNINIT; 2 * B] }
+        InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] }
     }
 }
 
@@ -131,7 +131,7 @@ fn from_internal(node: Box<InternalNode<K, V>>) -> Self {
     }
 
     unsafe fn from_ptr(ptr: NonNull<LeafNode<K, V>>) -> Self {
-        BoxedNode { ptr: Unique::new_unchecked(ptr.as_ptr()) }
+        BoxedNode { ptr: unsafe { Unique::new_unchecked(ptr.as_ptr()) } }
     }
 
     fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
@@ -392,14 +392,16 @@ pub unsafe fn deallocate_and_ascend(
         let height = self.height;
         let node = self.node;
         let ret = self.ascend().ok();
-        Global.dealloc(
-            node.cast(),
-            if height > 0 {
-                Layout::new::<InternalNode<K, V>>()
-            } else {
-                Layout::new::<LeafNode<K, V>>()
-            },
-        );
+        unsafe {
+            Global.dealloc(
+                node.cast(),
+                if height > 0 {
+                    Layout::new::<InternalNode<K, V>>()
+                } else {
+                    Layout::new::<LeafNode<K, V>>()
+                },
+            );
+        }
         ret
     }
 }
@@ -565,7 +567,7 @@ unsafe fn correct_childrens_parent_links(&mut self, first: usize, after_last: us
         debug_assert!(first <= self.len());
         debug_assert!(after_last <= self.len() + 1);
         for i in first..after_last {
-            Handle::new_edge(self.reborrow_mut(), i).correct_parent_link();
+            unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link();
         }
     }
 
@@ -789,7 +791,7 @@ pub unsafe fn reborrow_mut(
         &mut self,
     ) -> Handle<NodeRef<marker::Mut<'_>, K, V, NodeType>, HandleType> {
         // We can't use Handle::new_kv or Handle::new_edge because we don't know our type
-        Handle { node: self.node.reborrow_mut(), idx: self.idx, _marker: PhantomData }
+        Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData }
     }
 }
 
@@ -885,7 +887,7 @@ fn correct_parent_link(mut self) {
     unsafe fn cast_unchecked<NewType>(
         &mut self,
     ) -> Handle<NodeRef<marker::Mut<'_>, K, V, NewType>, marker::Edge> {
-        Handle::new_edge(self.node.cast_unchecked(), self.idx)
+        unsafe { Handle::new_edge(self.node.cast_unchecked(), self.idx) }
     }
 
     /// Inserts a new key/value pair and an edge that will go to the right of that new pair
@@ -1330,8 +1332,10 @@ unsafe fn move_kv<K, V>(
     dest_offset: usize,
     count: usize,
 ) {
-    ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count);
-    ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count);
+    unsafe {
+        ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count);
+        ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count);
+    }
 }
 
 // Source and destination must have the same height.
@@ -1344,8 +1348,10 @@ unsafe fn move_edges<K, V>(
 ) {
     let source_ptr = source.as_internal_mut().edges.as_mut_ptr();
     let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr();
-    ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
-    dest.correct_childrens_parent_links(dest_offset, dest_offset + count);
+    unsafe {
+        ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
+        dest.correct_childrens_parent_links(dest_offset, dest_offset + count);
+    }
 }
 
 impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
@@ -1459,12 +1465,16 @@ pub enum Edge {}
 }
 
 unsafe fn slice_insert<T>(slice: &mut [T], idx: usize, val: T) {
-    ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
-    ptr::write(slice.get_unchecked_mut(idx), val);
+    unsafe {
+        ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
+        ptr::write(slice.get_unchecked_mut(idx), val);
+    }
 }
 
 unsafe fn slice_remove<T>(slice: &mut [T], idx: usize) -> T {
-    let ret = ptr::read(slice.get_unchecked(idx));
-    ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
-    ret
+    unsafe {
+        let ret = ptr::read(slice.get_unchecked(idx));
+        ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
+        ret
+    }
 }
index 525ef38c32fa269f2e31fefbbb3074a85bc9548a..d8959966fe5ad38a8f846780af27892a77fba621 100644 (file)
@@ -1291,12 +1291,22 @@ impl<'a, T> Iterator for Iter<'a, T> {
     fn next(&mut self) -> Option<&'a T> {
         self.iter.next()
     }
+
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+
     fn last(mut self) -> Option<&'a T> {
         self.next_back()
     }
+
+    fn min(mut self) -> Option<&'a T> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<&'a T> {
+        self.next_back()
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
@@ -1321,6 +1331,7 @@ impl<T> Iterator for IntoIter<T> {
     fn next(&mut self) -> Option<T> {
         self.iter.next().map(|(k, _)| k)
     }
+
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
@@ -1359,6 +1370,14 @@ fn next(&mut self) -> Option<&'a T> {
     fn last(mut self) -> Option<&'a T> {
         self.next_back()
     }
+
+    fn min(mut self) -> Option<&'a T> {
+        self.next()
+    }
+
+    fn max(mut self) -> Option<&'a T> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "btree_range", since = "1.17.0")]
@@ -1429,6 +1448,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         };
         (self_len.saturating_sub(other_len), Some(self_len))
     }
+
+    fn min(mut self) -> Option<&'a T> {
+        self.next()
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -1460,6 +1483,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         // the number of elements to less than half the range of usize.
         (0, Some(a_len + b_len))
     }
+
+    fn min(mut self) -> Option<&'a T> {
+        self.next()
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -1516,6 +1543,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
             IntersectionInner::Answer(Some(_)) => (1, Some(1)),
         }
     }
+
+    fn min(mut self) -> Option<&'a T> {
+        self.next()
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -1541,6 +1572,10 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         // No checked_add - see SymmetricDifference::size_hint.
         (max(a_len, b_len), Some(a_len + b_len))
     }
+
+    fn min(mut self) -> Option<&'a T> {
+        self.next()
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
index 85f2505f756aa256ea6d3077e1bbe9299ed443fe..36b5785fdf6c5ed930340eb4b38d772d7dd21f4a 100644 (file)
@@ -225,17 +225,17 @@ fn pop_back_node(&mut self) -> Option<Box<Node<T>>> {
     /// maintain validity of aliasing pointers.
     #[inline]
     unsafe fn unlink_node(&mut self, mut node: NonNull<Node<T>>) {
-        let node = node.as_mut(); // this one is ours now, we can create an &mut.
+        let node = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut.
 
         // Not creating new mutable (unique!) references overlapping `element`.
         match node.prev {
-            Some(prev) => (*prev.as_ptr()).next = node.next,
+            Some(prev) => unsafe { (*prev.as_ptr()).next = node.next },
             // this node is the head node
             None => self.head = node.next,
         };
 
         match node.next {
-            Some(next) => (*next.as_ptr()).prev = node.prev,
+            Some(next) => unsafe { (*next.as_ptr()).prev = node.prev },
             // this node is the tail node
             None => self.tail = node.prev,
         };
@@ -258,17 +258,23 @@ unsafe fn splice_nodes(
         // This method takes care not to create multiple mutable references to whole nodes at the same time,
         // to maintain validity of aliasing pointers into `element`.
         if let Some(mut existing_prev) = existing_prev {
-            existing_prev.as_mut().next = Some(splice_start);
+            unsafe {
+                existing_prev.as_mut().next = Some(splice_start);
+            }
         } else {
             self.head = Some(splice_start);
         }
         if let Some(mut existing_next) = existing_next {
-            existing_next.as_mut().prev = Some(splice_end);
+            unsafe {
+                existing_next.as_mut().prev = Some(splice_end);
+            }
         } else {
             self.tail = Some(splice_end);
         }
-        splice_start.as_mut().prev = existing_prev;
-        splice_end.as_mut().next = existing_next;
+        unsafe {
+            splice_start.as_mut().prev = existing_prev;
+            splice_end.as_mut().next = existing_next;
+        }
 
         self.len += splice_length;
     }
@@ -297,9 +303,13 @@ unsafe fn split_off_before_node(
         if let Some(mut split_node) = split_node {
             let first_part_head;
             let first_part_tail;
-            first_part_tail = split_node.as_mut().prev.take();
+            unsafe {
+                first_part_tail = split_node.as_mut().prev.take();
+            }
             if let Some(mut tail) = first_part_tail {
-                tail.as_mut().next = None;
+                unsafe {
+                    tail.as_mut().next = None;
+                }
                 first_part_head = self.head;
             } else {
                 first_part_head = None;
@@ -333,9 +343,13 @@ unsafe fn split_off_after_node(
         if let Some(mut split_node) = split_node {
             let second_part_head;
             let second_part_tail;
-            second_part_head = split_node.as_mut().next.take();
+            unsafe {
+                second_part_head = split_node.as_mut().next.take();
+            }
             if let Some(mut head) = second_part_head {
-                head.as_mut().prev = None;
+                unsafe {
+                    head.as_mut().prev = None;
+                }
                 second_part_tail = self.tail;
             } else {
                 second_part_tail = None;
index ae54d3971baac42ee57703b401ced2808ce1fabd..15f3a94ca2d6a84d1dc270114de33daddaa15efc 100644 (file)
@@ -7,6 +7,8 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+// ignore-tidy-filelength
+
 use core::array::LengthAtMost32;
 use core::cmp::{self, Ordering};
 use core::fmt;
@@ -201,25 +203,27 @@ fn cap(&self) -> usize {
     /// Turn ptr into a slice
     #[inline]
     unsafe fn buffer_as_slice(&self) -> &[T] {
-        slice::from_raw_parts(self.ptr(), self.cap())
+        unsafe { slice::from_raw_parts(self.ptr(), self.cap()) }
     }
 
     /// Turn ptr into a mut slice
     #[inline]
     unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] {
-        slice::from_raw_parts_mut(self.ptr(), self.cap())
+        unsafe { slice::from_raw_parts_mut(self.ptr(), self.cap()) }
     }
 
     /// Moves an element out of the buffer
     #[inline]
     unsafe fn buffer_read(&mut self, off: usize) -> T {
-        ptr::read(self.ptr().add(off))
+        unsafe { ptr::read(self.ptr().add(off)) }
     }
 
     /// Writes an element into the buffer, moving it.
     #[inline]
     unsafe fn buffer_write(&mut self, off: usize, value: T) {
-        ptr::write(self.ptr().add(off), value);
+        unsafe {
+            ptr::write(self.ptr().add(off), value);
+        }
     }
 
     /// Returns `true` if the buffer is at full capacity.
@@ -268,7 +272,9 @@ unsafe fn copy(&self, dst: usize, src: usize, len: usize) {
             len,
             self.cap()
         );
-        ptr::copy(self.ptr().add(src), self.ptr().add(dst), len);
+        unsafe {
+            ptr::copy(self.ptr().add(src), self.ptr().add(dst), len);
+        }
     }
 
     /// Copies a contiguous block of memory len long from src to dst
@@ -290,7 +296,9 @@ unsafe fn copy_nonoverlapping(&self, dst: usize, src: usize, len: usize) {
             len,
             self.cap()
         );
-        ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len);
+        unsafe {
+            ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len);
+        }
     }
 
     /// Copies a potentially wrapping block of memory len long from src to dest.
@@ -330,7 +338,9 @@ fn diff(a: usize, b: usize) -> usize {
                 // 2 [_ _ A A A A B B _]
                 //            D . . .
                 //
-                self.copy(dst, src, len);
+                unsafe {
+                    self.copy(dst, src, len);
+                }
             }
             (false, false, true) => {
                 // dst before src, src doesn't wrap, dst wraps
@@ -341,8 +351,10 @@ fn diff(a: usize, b: usize) -> usize {
                 // 3 [B B B B _ _ _ A A]
                 //    . .           D .
                 //
-                self.copy(dst, src, dst_pre_wrap_len);
-                self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+                unsafe {
+                    self.copy(dst, src, dst_pre_wrap_len);
+                    self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+                }
             }
             (true, false, true) => {
                 // src before dst, src doesn't wrap, dst wraps
@@ -353,8 +365,10 @@ fn diff(a: usize, b: usize) -> usize {
                 // 3 [B B _ _ _ A A A A]
                 //    . .           D .
                 //
-                self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
-                self.copy(dst, src, dst_pre_wrap_len);
+                unsafe {
+                    self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+                    self.copy(dst, src, dst_pre_wrap_len);
+                }
             }
             (false, true, false) => {
                 // dst before src, src wraps, dst doesn't wrap
@@ -365,8 +379,10 @@ fn diff(a: usize, b: usize) -> usize {
                 // 3 [C C _ _ _ B B C C]
                 //              D . . .
                 //
-                self.copy(dst, src, src_pre_wrap_len);
-                self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+                unsafe {
+                    self.copy(dst, src, src_pre_wrap_len);
+                    self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+                }
             }
             (true, true, false) => {
                 // src before dst, src wraps, dst doesn't wrap
@@ -377,8 +393,10 @@ fn diff(a: usize, b: usize) -> usize {
                 // 3 [C C A A _ _ _ C C]
                 //    D . . .
                 //
-                self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
-                self.copy(dst, src, src_pre_wrap_len);
+                unsafe {
+                    self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+                    self.copy(dst, src, src_pre_wrap_len);
+                }
             }
             (false, true, true) => {
                 // dst before src, src wraps, dst wraps
@@ -392,9 +410,11 @@ fn diff(a: usize, b: usize) -> usize {
                 //
                 debug_assert!(dst_pre_wrap_len > src_pre_wrap_len);
                 let delta = dst_pre_wrap_len - src_pre_wrap_len;
-                self.copy(dst, src, src_pre_wrap_len);
-                self.copy(dst + src_pre_wrap_len, 0, delta);
-                self.copy(0, delta, len - dst_pre_wrap_len);
+                unsafe {
+                    self.copy(dst, src, src_pre_wrap_len);
+                    self.copy(dst + src_pre_wrap_len, 0, delta);
+                    self.copy(0, delta, len - dst_pre_wrap_len);
+                }
             }
             (true, true, true) => {
                 // src before dst, src wraps, dst wraps
@@ -408,9 +428,11 @@ fn diff(a: usize, b: usize) -> usize {
                 //
                 debug_assert!(src_pre_wrap_len > dst_pre_wrap_len);
                 let delta = src_pre_wrap_len - dst_pre_wrap_len;
-                self.copy(delta, 0, len - src_pre_wrap_len);
-                self.copy(0, self.cap() - delta, delta);
-                self.copy(dst, src, dst_pre_wrap_len);
+                unsafe {
+                    self.copy(delta, 0, len - src_pre_wrap_len);
+                    self.copy(0, self.cap() - delta, delta);
+                    self.copy(dst, src, dst_pre_wrap_len);
+                }
             }
         }
     }
@@ -440,13 +462,17 @@ unsafe fn handle_capacity_increase(&mut self, old_capacity: usize) {
             // Nop
         } else if self.head < old_capacity - self.tail {
             // B
-            self.copy_nonoverlapping(old_capacity, 0, self.head);
+            unsafe {
+                self.copy_nonoverlapping(old_capacity, 0, self.head);
+            }
             self.head += old_capacity;
             debug_assert!(self.head > self.tail);
         } else {
             // C
             let new_tail = new_capacity - (old_capacity - self.tail);
-            self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail);
+            unsafe {
+                self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail);
+            }
             self.tail = new_tail;
             debug_assert!(self.head < self.tail);
         }
@@ -2297,7 +2323,9 @@ pub fn rotate_right(&mut self, k: usize) {
 
     unsafe fn rotate_left_inner(&mut self, mid: usize) {
         debug_assert!(mid * 2 <= self.len());
-        self.wrap_copy(self.head, self.tail, mid);
+        unsafe {
+            self.wrap_copy(self.head, self.tail, mid);
+        }
         self.head = self.wrap_add(self.head, mid);
         self.tail = self.wrap_add(self.tail, mid);
     }
@@ -2306,7 +2334,9 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
         debug_assert!(k * 2 <= self.len());
         self.head = self.wrap_sub(self.head, k);
         self.tail = self.wrap_sub(self.tail, k);
-        self.wrap_copy(self.tail, self.head, k);
+        unsafe {
+            self.wrap_copy(self.tail, self.head, k);
+        }
     }
 }
 
index fc2ec7908e82368e5c667a847a1abc2ab8a6765b..960af4bfda0533ee12d400bb1f359d51cd989b15 100644 (file)
@@ -1,7 +1,5 @@
 use super::*;
 
-use test;
-
 #[bench]
 #[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
 fn bench_push_back_100(b: &mut test::Bencher) {
index 9bcfc9457f50eeeddb839efdfeb8e94a02dcf5a1..5f18fe8bfab845dd30da591aefa9b80ab918a99d 100644 (file)
@@ -72,6 +72,7 @@
 #![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
 #![allow(explicit_outlives_requirements)]
 #![allow(incomplete_features)]
+#![deny(unsafe_op_in_unsafe_fn)]
 #![cfg_attr(not(test), feature(generator_trait))]
 #![cfg_attr(test, feature(test))]
 #![feature(allocator_api)]
@@ -86,7 +87,7 @@
 #![feature(const_generic_impls_guard)]
 #![feature(const_generics)]
 #![feature(const_in_array_repeat_expressions)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(cow_is_borrowed)]
 #![feature(dispatch_from_dyn)]
 #![feature(core_intrinsics)]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
 #![feature(unicode_internals)]
+#![feature(unsafe_block_in_unsafe_fn)]
 #![feature(unsize)]
 #![feature(unsized_locals)]
 #![feature(allocator_internals)]
index 805dbfe277584f58c2c699931dc5bff56174af08..b2cf98a5de6794fdbd0a34905ebb9559b9e1c859 100644 (file)
@@ -60,7 +60,7 @@ impl<T> RawVec<T, Global> {
     /// `#[rustc_force_min_const_fn]` attribute which requires conformance
     /// with `min_const_fn` but does not necessarily allow calling it in
     /// `stable(...) const fn` / user code not enabling `foo` when
-    /// `#[rustc_const_unstable(feature = "foo", ..)]` is present.
+    /// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present.
     pub const NEW: Self = Self::new();
 
     /// Creates the biggest possible `RawVec` (on the system heap)
@@ -80,9 +80,7 @@ pub const fn new() -> Self {
     ///
     /// # Panics
     ///
-    /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
-    /// * Panics on 32-bit platforms if the requested capacity exceeds
-    ///   `isize::MAX` bytes.
+    /// Panics if the requested capacity exceeds `isize::MAX` bytes.
     ///
     /// # Aborts
     ///
@@ -108,7 +106,7 @@ pub fn with_capacity_zeroed(capacity: usize) -> Self {
     /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed.
     #[inline]
     pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self {
-        Self::from_raw_parts_in(ptr, capacity, Global)
+        unsafe { Self::from_raw_parts_in(ptr, capacity, Global) }
     }
 
     /// Converts a `Box<[T]>` into a `RawVec<T>`.
@@ -139,8 +137,10 @@ pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>]> {
         );
 
         let me = ManuallyDrop::new(self);
-        let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
-        Box::from_raw(slice)
+        unsafe {
+            let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
+            Box::from_raw(slice)
+        }
     }
 }
 
@@ -192,7 +192,7 @@ fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self {
     /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
     #[inline]
     pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
-        Self { ptr: Unique::new_unchecked(ptr), cap: capacity, alloc: a }
+        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc: a }
     }
 
     /// Gets a raw pointer to the start of the allocation. Note that this is
@@ -249,9 +249,7 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
     ///
     /// # Panics
     ///
-    /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
-    /// * Panics on 32-bit platforms if the requested capacity exceeds
-    ///   `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` bytes.
     ///
     /// # Aborts
     ///
@@ -316,9 +314,7 @@ pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryRe
     ///
     /// # Panics
     ///
-    /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
-    /// * Panics on 32-bit platforms if the requested capacity exceeds
-    ///   `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` bytes.
     ///
     /// # Aborts
     ///
index 17622d72a059c2e99266c23f7e489023bdea8f7c..5408faa079c1532ee3462acb023416ffd9ef145e 100644 (file)
@@ -12,7 +12,6 @@ fn allocator_param() {
     //
     // Instead, this just checks that the `RawVec` methods do at
     // least go through the Allocator API when it reserves
-
     // storage.
 
     // A dumb allocator that consumes a fixed amount of fuel
@@ -35,7 +34,7 @@ fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, Allo
             }
         }
         unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
-            Global.dealloc(ptr, layout)
+            unsafe { Global.dealloc(ptr, layout) }
         }
     }
 
index 0327a9f9a96e54d89c9dae49955706560faee84e..4d50ae9efca9532eb717f17db20985e2541e233e 100644 (file)
@@ -304,7 +304,7 @@ fn from_inner(ptr: NonNull<RcBox<T>>) -> Self {
     }
 
     unsafe fn from_ptr(ptr: *mut RcBox<T>) -> Self {
-        Self::from_inner(NonNull::new_unchecked(ptr))
+        Self::from_inner(unsafe { NonNull::new_unchecked(ptr) })
     }
 }
 
@@ -544,7 +544,7 @@ impl<T> Rc<[mem::MaybeUninit<T>]> {
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
     pub unsafe fn assume_init(self) -> Rc<[T]> {
-        Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
+        unsafe { Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) }
     }
 }
 
@@ -643,13 +643,13 @@ pub fn as_ptr(this: &Self) -> *const T {
     /// ```
     #[stable(feature = "rc_raw", since = "1.17.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
-        let offset = data_offset(ptr);
+        let offset = unsafe { data_offset(ptr) };
 
         // Reverse the offset to find the original RcBox.
         let fake_ptr = ptr as *mut RcBox<T>;
-        let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+        let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) };
 
-        Self::from_ptr(rc_ptr)
+        unsafe { Self::from_ptr(rc_ptr) }
     }
 
     /// Consumes the `Rc`, returning the wrapped pointer as `NonNull<T>`.
@@ -805,7 +805,7 @@ pub fn get_mut(this: &mut Self) -> Option<&mut T> {
     #[inline]
     #[unstable(feature = "get_mut_unchecked", issue = "63292")]
     pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
-        &mut this.ptr.as_mut().value
+        unsafe { &mut this.ptr.as_mut().value }
     }
 
     #[inline]
@@ -964,10 +964,12 @@ unsafe fn allocate_for_layout(
 
         // Initialize the RcBox
         let inner = mem_to_rcbox(mem.ptr.as_ptr());
-        debug_assert_eq!(Layout::for_value(&*inner), layout);
+        unsafe {
+            debug_assert_eq!(Layout::for_value(&*inner), layout);
 
-        ptr::write(&mut (*inner).strong, Cell::new(1));
-        ptr::write(&mut (*inner).weak, Cell::new(1));
+            ptr::write(&mut (*inner).strong, Cell::new(1));
+            ptr::write(&mut (*inner).weak, Cell::new(1));
+        }
 
         inner
     }
@@ -975,9 +977,11 @@ unsafe fn allocate_for_layout(
     /// Allocates an `RcBox<T>` with sufficient space for an unsized inner value
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
         // Allocate for the `RcBox<T>` using the given value.
-        Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
-            set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>
-        })
+        unsafe {
+            Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
+                set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>
+            })
+        }
     }
 
     fn from_box(v: Box<T>) -> Rc<T> {
@@ -1006,9 +1010,11 @@ fn from_box(v: Box<T>) -> Rc<T> {
 impl<T> Rc<[T]> {
     /// Allocates an `RcBox<[T]>` with the given length.
     unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
-        Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
-            ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>
-        })
+        unsafe {
+            Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
+                ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>
+            })
+        }
     }
 }
 
@@ -1017,7 +1023,9 @@ unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
 /// For a slice/trait object, this sets the `data` field and leaves the rest
 /// unchanged. For a sized raw pointer, this simply sets the pointer.
 unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
-    ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+    unsafe {
+        ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+    }
     ptr
 }
 
@@ -1026,11 +1034,11 @@ impl<T> Rc<[T]> {
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`
     unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
-        let ptr = Self::allocate_for_slice(v.len());
-
-        ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len());
-
-        Self::from_ptr(ptr)
+        unsafe {
+            let ptr = Self::allocate_for_slice(v.len());
+            ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len());
+            Self::from_ptr(ptr)
+        }
     }
 
     /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size.
@@ -1058,25 +1066,27 @@ fn drop(&mut self) {
             }
         }
 
-        let ptr = Self::allocate_for_slice(len);
+        unsafe {
+            let ptr = Self::allocate_for_slice(len);
 
-        let mem = ptr as *mut _ as *mut u8;
-        let layout = Layout::for_value(&*ptr);
+            let mem = ptr as *mut _ as *mut u8;
+            let layout = Layout::for_value(&*ptr);
 
-        // Pointer to first element
-        let elems = &mut (*ptr).value as *mut [T] as *mut T;
+            // Pointer to first element
+            let elems = &mut (*ptr).value as *mut [T] as *mut T;
 
-        let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
+            let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
 
-        for (i, item) in iter.enumerate() {
-            ptr::write(elems.add(i), item);
-            guard.n_elems += 1;
-        }
+            for (i, item) in iter.enumerate() {
+                ptr::write(elems.add(i), item);
+                guard.n_elems += 1;
+            }
 
-        // All clear. Forget the guard so it doesn't free the new RcBox.
-        forget(guard);
+            // All clear. Forget the guard so it doesn't free the new RcBox.
+            forget(guard);
 
-        Self::from_ptr(ptr)
+            Self::from_ptr(ptr)
+        }
     }
 }
 
@@ -1786,10 +1796,12 @@ pub unsafe fn from_raw(ptr: *const T) -> Self {
             Self::new()
         } else {
             // See Rc::from_raw for details
-            let offset = data_offset(ptr);
-            let fake_ptr = ptr as *mut RcBox<T>;
-            let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
-            Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+            unsafe {
+                let offset = data_offset(ptr);
+                let fake_ptr = ptr as *mut RcBox<T>;
+                let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+                Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+            }
         }
     }
 }
@@ -2106,7 +2118,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
     // Because it is ?Sized, it will always be the last field in memory.
     // Note: This is a detail of the current implementation of the compiler,
     // and is not a guaranteed language detail. Do not rely on it outside of std.
-    data_offset_align(align_of_val(&*ptr))
+    unsafe { data_offset_align(align_of_val(&*ptr)) }
 }
 
 /// Computes the offset of the data field within `RcBox`.
index 53477288b59ee8a89d39bb2bbbd5eceb0730ea8e..d7dc2174d665f3bce0a3ebb5da7da0b328b1576e 100644 (file)
@@ -831,8 +831,7 @@ unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
 {
     let len = v.len();
     let v = v.as_mut_ptr();
-    let v_mid = v.add(mid);
-    let v_end = v.add(len);
+    let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) };
 
     // The merge process first copies the shorter run into `buf`. Then it traces the newly copied
     // run and the longer run forwards (or backwards), comparing their next unconsumed elements and
@@ -855,8 +854,10 @@ unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
 
     if mid <= len - mid {
         // The left run is shorter.
-        ptr::copy_nonoverlapping(v, buf, mid);
-        hole = MergeHole { start: buf, end: buf.add(mid), dest: v };
+        unsafe {
+            ptr::copy_nonoverlapping(v, buf, mid);
+            hole = MergeHole { start: buf, end: buf.add(mid), dest: v };
+        }
 
         // Initially, these pointers point to the beginnings of their arrays.
         let left = &mut hole.start;
@@ -866,17 +867,21 @@ unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
         while *left < hole.end && right < v_end {
             // Consume the lesser side.
             // If equal, prefer the left run to maintain stability.
-            let to_copy = if is_less(&*right, &**left) {
-                get_and_increment(&mut right)
-            } else {
-                get_and_increment(left)
-            };
-            ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
+            unsafe {
+                let to_copy = if is_less(&*right, &**left) {
+                    get_and_increment(&mut right)
+                } else {
+                    get_and_increment(left)
+                };
+                ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
+            }
         }
     } else {
         // The right run is shorter.
-        ptr::copy_nonoverlapping(v_mid, buf, len - mid);
-        hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid };
+        unsafe {
+            ptr::copy_nonoverlapping(v_mid, buf, len - mid);
+            hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid };
+        }
 
         // Initially, these pointers point past the ends of their arrays.
         let left = &mut hole.dest;
@@ -886,12 +891,14 @@ unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
         while v < *left && buf < *right {
             // Consume the greater side.
             // If equal, prefer the right run to maintain stability.
-            let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) {
-                decrement_and_get(left)
-            } else {
-                decrement_and_get(right)
-            };
-            ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
+            unsafe {
+                let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) {
+                    decrement_and_get(left)
+                } else {
+                    decrement_and_get(right)
+                };
+                ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
+            }
         }
     }
     // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of
@@ -899,12 +906,12 @@ unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
 
     unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T {
         let old = *ptr;
-        *ptr = ptr.offset(1);
+        *ptr = unsafe { ptr.offset(1) };
         old
     }
 
     unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T {
-        *ptr = ptr.offset(-1);
+        *ptr = unsafe { ptr.offset(-1) };
         *ptr
     }
 
index 70860c09a2c31d0b031b753253265b667e391311..57927c688479b5f72746d6220b271f58dd2c7e41 100644 (file)
@@ -583,5 +583,5 @@ pub fn to_ascii_lowercase(&self) -> String {
 #[stable(feature = "str_box_extras", since = "1.20.0")]
 #[inline]
 pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
-    Box::from_raw(Box::into_raw(v) as *mut str)
+    unsafe { Box::from_raw(Box::into_raw(v) as *mut str) }
 }
index 0378ff5362a8b9b0af6e2036e6d0ae1d128030f7..64d9692244dde2ce0ebaefca78196c2dc029fdd6 100644 (file)
@@ -724,7 +724,7 @@ pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String {
-        String { vec: Vec::from_raw_parts(buf, length, capacity) }
+        unsafe { String { vec: Vec::from_raw_parts(buf, length, capacity) } }
     }
 
     /// Converts a vector of bytes to a `String` without checking that the
@@ -1329,9 +1329,11 @@ unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
         let amt = bytes.len();
         self.vec.reserve(amt);
 
-        ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx);
-        ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
-        self.vec.set_len(len + amt);
+        unsafe {
+            ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx);
+            ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
+            self.vec.set_len(len + amt);
+        }
     }
 
     /// Inserts a string slice into this `String` at a byte position.
@@ -2228,6 +2230,14 @@ impl<T: fmt::Display + ?Sized> ToString for T {
     }
 }
 
+#[stable(feature = "char_to_string_specialization", since = "1.46.0")]
+impl ToString for char {
+    #[inline]
+    fn to_string(&self) -> String {
+        String::from(self.encode_utf8(&mut [0; 4]))
+    }
+}
+
 #[stable(feature = "str_to_string_specialization", since = "1.9.0")]
 impl ToString for str {
     #[inline]
index cd4172d6a2d249eed56a0c461f266d5c4f9cd76b..826f0c8fa833fbf001e0aacb434ccddeab100e66 100644 (file)
@@ -232,7 +232,7 @@ fn from_inner(ptr: NonNull<ArcInner<T>>) -> Self {
     }
 
     unsafe fn from_ptr(ptr: *mut ArcInner<T>) -> Self {
-        Self::from_inner(NonNull::new_unchecked(ptr))
+        unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
     }
 }
 
@@ -543,7 +543,7 @@ impl<T> Arc<[mem::MaybeUninit<T>]> {
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
     pub unsafe fn assume_init(self) -> Arc<[T]> {
-        Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
+        unsafe { Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) }
     }
 }
 
@@ -642,13 +642,15 @@ pub fn as_ptr(this: &Self) -> *const T {
     /// ```
     #[stable(feature = "rc_raw", since = "1.17.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
-        let offset = data_offset(ptr);
+        unsafe {
+            let offset = data_offset(ptr);
 
-        // Reverse the offset to find the original ArcInner.
-        let fake_ptr = ptr as *mut ArcInner<T>;
-        let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+            // Reverse the offset to find the original ArcInner.
+            let fake_ptr = ptr as *mut ArcInner<T>;
+            let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
 
-        Self::from_ptr(arc_ptr)
+            Self::from_ptr(arc_ptr)
+        }
     }
 
     /// Consumes the `Arc`, returning the wrapped pointer as `NonNull<T>`.
@@ -807,7 +809,7 @@ pub fn strong_count(this: &Self) -> usize {
     #[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
     pub unsafe fn incr_strong_count(ptr: *const T) {
         // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
-        let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr));
+        let arc = unsafe { mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr)) };
         // Now increase refcount, but don't drop new refcount either
         let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
     }
@@ -847,7 +849,7 @@ pub unsafe fn incr_strong_count(ptr: *const T) {
     #[inline]
     #[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
     pub unsafe fn decr_strong_count(ptr: *const T) {
-        mem::drop(Arc::from_raw(ptr));
+        unsafe { mem::drop(Arc::from_raw(ptr)) };
     }
 
     #[inline]
@@ -865,7 +867,7 @@ fn inner(&self) -> &ArcInner<T> {
     unsafe fn drop_slow(&mut self) {
         // Destroy the data at this time, even though we may not free the box
         // allocation itself (there may still be weak pointers lying around).
-        ptr::drop_in_place(Self::get_mut_unchecked(self));
+        unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
 
         // Drop the weak ref collectively held by all strong references
         drop(Weak { ptr: self.ptr });
@@ -917,10 +919,12 @@ unsafe fn allocate_for_layout(
 
         // Initialize the ArcInner
         let inner = mem_to_arcinner(mem.ptr.as_ptr());
-        debug_assert_eq!(Layout::for_value(&*inner), layout);
+        debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout);
 
-        ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1));
-        ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1));
+        unsafe {
+            ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1));
+            ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1));
+        }
 
         inner
     }
@@ -928,9 +932,11 @@ unsafe fn allocate_for_layout(
     /// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value.
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
         // Allocate for the `ArcInner<T>` using the given value.
-        Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
-            set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>
-        })
+        unsafe {
+            Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| {
+                set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>
+            })
+        }
     }
 
     fn from_box(v: Box<T>) -> Arc<T> {
@@ -959,9 +965,11 @@ fn from_box(v: Box<T>) -> Arc<T> {
 impl<T> Arc<[T]> {
     /// Allocates an `ArcInner<[T]>` with the given length.
     unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
-        Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
-            ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>
-        })
+        unsafe {
+            Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
+                ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>
+            })
+        }
     }
 }
 
@@ -970,7 +978,9 @@ unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
 /// For a slice/trait object, this sets the `data` field and leaves the rest
 /// unchanged. For a sized raw pointer, this simply sets the pointer.
 unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
-    ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+    unsafe {
+        ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8);
+    }
     ptr
 }
 
@@ -979,11 +989,13 @@ impl<T> Arc<[T]> {
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`.
     unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {
-        let ptr = Self::allocate_for_slice(v.len());
+        unsafe {
+            let ptr = Self::allocate_for_slice(v.len());
 
-        ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len());
+            ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len());
 
-        Self::from_ptr(ptr)
+            Self::from_ptr(ptr)
+        }
     }
 
     /// Constructs an `Arc<[T]>` from an iterator known to be of a certain size.
@@ -1011,25 +1023,27 @@ fn drop(&mut self) {
             }
         }
 
-        let ptr = Self::allocate_for_slice(len);
+        unsafe {
+            let ptr = Self::allocate_for_slice(len);
 
-        let mem = ptr as *mut _ as *mut u8;
-        let layout = Layout::for_value(&*ptr);
+            let mem = ptr as *mut _ as *mut u8;
+            let layout = Layout::for_value(&*ptr);
 
-        // Pointer to first element
-        let elems = &mut (*ptr).data as *mut [T] as *mut T;
+            // Pointer to first element
+            let elems = &mut (*ptr).data as *mut [T] as *mut T;
 
-        let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
+            let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 };
 
-        for (i, item) in iter.enumerate() {
-            ptr::write(elems.add(i), item);
-            guard.n_elems += 1;
-        }
+            for (i, item) in iter.enumerate() {
+                ptr::write(elems.add(i), item);
+                guard.n_elems += 1;
+            }
 
-        // All clear. Forget the guard so it doesn't free the new ArcInner.
-        mem::forget(guard);
+            // All clear. Forget the guard so it doesn't free the new ArcInner.
+            mem::forget(guard);
 
-        Self::from_ptr(ptr)
+            Self::from_ptr(ptr)
+        }
     }
 }
 
@@ -1274,7 +1288,7 @@ pub fn get_mut(this: &mut Self) -> Option<&mut T> {
     pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
         // We are careful to *not* create a reference covering the "count" fields, as
         // this would alias with concurrent access to the reference counts (e.g. by `Weak`).
-        &mut (*this.ptr.as_ptr()).data
+        unsafe { &mut (*this.ptr.as_ptr()).data }
     }
 
     /// Determine whether this is the unique reference (including weak refs) to
@@ -1551,10 +1565,12 @@ pub unsafe fn from_raw(ptr: *const T) -> Self {
             Self::new()
         } else {
             // See Arc::from_raw for details
-            let offset = data_offset(ptr);
-            let fake_ptr = ptr as *mut ArcInner<T>;
-            let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
-            Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+            unsafe {
+                let offset = data_offset(ptr);
+                let fake_ptr = ptr as *mut ArcInner<T>;
+                let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+                Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
+            }
         }
     }
 }
@@ -2260,7 +2276,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
     // Because it is `?Sized`, it will always be the last field in memory.
     // Note: This is a detail of the current implementation of the compiler,
     // and is not a guaranteed language detail. Do not rely on it outside of std.
-    data_offset_align(align_of_val(&*ptr))
+    unsafe { data_offset_align(align_of_val(&*ptr)) }
 }
 
 /// Computes the offset of the data field within `ArcInner`.
index 745444a152e1b737ba4b399ee3970e424430f9fe..0d1cc99df47c552e24bccd7b7e22bd63b7ddd352 100644 (file)
@@ -60,7 +60,7 @@ fn from(waker: Arc<W>) -> RawWaker {
 fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
     // Increment the reference count of the arc to clone it.
     unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
-        Arc::incr_strong_count(waker as *const W);
+        unsafe { Arc::incr_strong_count(waker as *const W) };
         RawWaker::new(
             waker as *const (),
             &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
@@ -69,19 +69,20 @@ unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawW
 
     // Wake by value, moving the Arc into the Wake::wake function
     unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
-        let waker: Arc<W> = Arc::from_raw(waker as *const W);
+        let waker: Arc<W> = unsafe { Arc::from_raw(waker as *const W) };
         <W as Wake>::wake(waker);
     }
 
     // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
     unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
-        let waker: ManuallyDrop<Arc<W>> = ManuallyDrop::new(Arc::from_raw(waker as *const W));
+        let waker: ManuallyDrop<Arc<W>> =
+            unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
         <W as Wake>::wake_by_ref(&waker);
     }
 
     // Decrement the reference count of the Arc on drop
     unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
-        Arc::decr_strong_count(waker as *const W);
+        unsafe { Arc::decr_strong_count(waker as *const W) };
     }
 
     RawWaker::new(
index 731a1b5f875b7c32bcf1f046684287df1b5c599d..682d829d219f31ee918ed1fb42ef9c65a00b5189 100644 (file)
@@ -309,6 +309,41 @@ fn test<T>(size: usize, mut iter: T)
     test(size, map.into_iter());
 }
 
+#[test]
+fn test_iter_min_max() {
+    let mut a = BTreeMap::new();
+    assert_eq!(a.iter().min(), None);
+    assert_eq!(a.iter().max(), None);
+    assert_eq!(a.iter_mut().min(), None);
+    assert_eq!(a.iter_mut().max(), None);
+    assert_eq!(a.range(..).min(), None);
+    assert_eq!(a.range(..).max(), None);
+    assert_eq!(a.range_mut(..).min(), None);
+    assert_eq!(a.range_mut(..).max(), None);
+    assert_eq!(a.keys().min(), None);
+    assert_eq!(a.keys().max(), None);
+    assert_eq!(a.values().min(), None);
+    assert_eq!(a.values().max(), None);
+    assert_eq!(a.values_mut().min(), None);
+    assert_eq!(a.values_mut().max(), None);
+    a.insert(1, 42);
+    a.insert(2, 24);
+    assert_eq!(a.iter().min(), Some((&1, &42)));
+    assert_eq!(a.iter().max(), Some((&2, &24)));
+    assert_eq!(a.iter_mut().min(), Some((&1, &mut 42)));
+    assert_eq!(a.iter_mut().max(), Some((&2, &mut 24)));
+    assert_eq!(a.range(..).min(), Some((&1, &42)));
+    assert_eq!(a.range(..).max(), Some((&2, &24)));
+    assert_eq!(a.range_mut(..).min(), Some((&1, &mut 42)));
+    assert_eq!(a.range_mut(..).max(), Some((&2, &mut 24)));
+    assert_eq!(a.keys().min(), Some(&1));
+    assert_eq!(a.keys().max(), Some(&2));
+    assert_eq!(a.values().min(), Some(&24));
+    assert_eq!(a.values().max(), Some(&42));
+    assert_eq!(a.values_mut().min(), Some(&mut 24));
+    assert_eq!(a.values_mut().max(), Some(&mut 42));
+}
+
 fn range_keys(map: &BTreeMap<i32, i32>, range: impl RangeBounds<i32>) -> Vec<i32> {
     map.range(range)
         .map(|(&k, &v)| {
index 75251ca0d51e9b8b4c49f4f057d03da80f886e54..b6c34b7c6c346dae023617482ffba7cbff6917d7 100644 (file)
@@ -33,6 +33,37 @@ fn test_hash() {
     assert_eq!(hash(&x), hash(&y));
 }
 
+#[test]
+fn test_iter_min_max() {
+    let mut a = BTreeSet::new();
+    assert_eq!(a.iter().min(), None);
+    assert_eq!(a.iter().max(), None);
+    assert_eq!(a.range(..).min(), None);
+    assert_eq!(a.range(..).max(), None);
+    assert_eq!(a.difference(&BTreeSet::new()).min(), None);
+    assert_eq!(a.difference(&BTreeSet::new()).max(), None);
+    assert_eq!(a.intersection(&a).min(), None);
+    assert_eq!(a.intersection(&a).max(), None);
+    assert_eq!(a.symmetric_difference(&BTreeSet::new()).min(), None);
+    assert_eq!(a.symmetric_difference(&BTreeSet::new()).max(), None);
+    assert_eq!(a.union(&a).min(), None);
+    assert_eq!(a.union(&a).max(), None);
+    a.insert(1);
+    a.insert(2);
+    assert_eq!(a.iter().min(), Some(&1));
+    assert_eq!(a.iter().max(), Some(&2));
+    assert_eq!(a.range(..).min(), Some(&1));
+    assert_eq!(a.range(..).max(), Some(&2));
+    assert_eq!(a.difference(&BTreeSet::new()).min(), Some(&1));
+    assert_eq!(a.difference(&BTreeSet::new()).max(), Some(&2));
+    assert_eq!(a.intersection(&a).min(), Some(&1));
+    assert_eq!(a.intersection(&a).max(), Some(&2));
+    assert_eq!(a.symmetric_difference(&BTreeSet::new()).min(), Some(&1));
+    assert_eq!(a.symmetric_difference(&BTreeSet::new()).max(), Some(&2));
+    assert_eq!(a.union(&a).min(), Some(&1));
+    assert_eq!(a.union(&a).max(), Some(&2));
+}
+
 fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F)
 where
     F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut dyn FnMut(&i32) -> bool) -> bool,
index f3da46bd0cc4ebf5470b0241f3687802d3aa8b09..e2dc816b0152647b89036796158a56c35ce3d024 100644 (file)
@@ -12,7 +12,6 @@
 #![feature(associated_type_bounds)]
 #![feature(binary_heap_into_iter_sorted)]
 #![feature(binary_heap_drain_sorted)]
-#![feature(vec_remove_item)]
 #![feature(split_inclusive)]
 #![feature(binary_heap_retain)]
 
index a9813a8704f30e93cfd3a93e695a8b078b75c552..ffff543b07fe52cb79ecfa0209b5bddc741beaad 100644 (file)
@@ -1,5 +1,6 @@
 use std::borrow::Cow;
 use std::collections::TryReserveError::*;
+use std::fmt::Debug;
 use std::mem::size_of;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::vec::{Drain, IntoIter};
@@ -131,21 +132,6 @@ fn test_extend_ref() {
     assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]);
 }
 
-#[test]
-fn test_remove_item() {
-    let mut v = vec![1, 2, 3];
-    v.remove_item(&1);
-
-    assert_eq!(v.len(), 2);
-    assert_eq!(v, [2, 3]);
-
-    let mut w = vec![1, 2, 3];
-    w.remove_item(&4);
-
-    assert_eq!(w.len(), 3);
-    w.remove_item(&4);
-}
-
 #[test]
 fn test_slice_from_mut() {
     let mut values = vec![1, 2, 3, 4, 5];
@@ -1588,3 +1574,56 @@ fn test_push_growth_strategy() {
         }
     }
 }
+
+macro_rules! generate_assert_eq_vec_and_prim {
+    ($name:ident<$B:ident>($type:ty)) => {
+        fn $name<A: PartialEq<$B> + Debug, $B: Debug>(a: Vec<A>, b: $type) {
+            assert!(a == b);
+            assert_eq!(a, b);
+        }
+    };
+}
+
+generate_assert_eq_vec_and_prim! { assert_eq_vec_and_slice  <B>(&[B])   }
+generate_assert_eq_vec_and_prim! { assert_eq_vec_and_array_3<B>([B; 3]) }
+
+#[test]
+fn partialeq_vec_and_prim() {
+    assert_eq_vec_and_slice(vec![1, 2, 3], &[1, 2, 3]);
+    assert_eq_vec_and_array_3(vec![1, 2, 3], [1, 2, 3]);
+}
+
+macro_rules! assert_partial_eq_valid {
+    ($a2:ident, $a3:ident; $b2:ident, $b3: ident) => {
+        assert!($a2 == $b2);
+        assert!($a2 != $b3);
+        assert!($a3 != $b2);
+        assert!($a3 == $b3);
+        assert_eq!($a2, $b2);
+        assert_ne!($a2, $b3);
+        assert_ne!($a3, $b2);
+        assert_eq!($a3, $b3);
+    };
+}
+
+#[test]
+fn partialeq_vec_full() {
+    let vec2: Vec<_> = vec![1, 2];
+    let vec3: Vec<_> = vec![1, 2, 3];
+    let slice2: &[_] = &[1, 2];
+    let slice3: &[_] = &[1, 2, 3];
+    let slicemut2: &[_] = &mut [1, 2];
+    let slicemut3: &[_] = &mut [1, 2, 3];
+    let array2: [_; 2] = [1, 2];
+    let array3: [_; 3] = [1, 2, 3];
+    let arrayref2: &[_; 2] = &[1, 2];
+    let arrayref3: &[_; 3] = &[1, 2, 3];
+
+    assert_partial_eq_valid!(vec2,vec3; vec2,vec3);
+    assert_partial_eq_valid!(vec2,vec3; slice2,slice3);
+    assert_partial_eq_valid!(vec2,vec3; slicemut2,slicemut3);
+    assert_partial_eq_valid!(slice2,slice3; vec2,vec3);
+    assert_partial_eq_valid!(slicemut2,slicemut3; vec2,vec3);
+    assert_partial_eq_valid!(vec2,vec3; array2,array3);
+    assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3);
+}
index 06462fd96d9a9d16a2e966bbf1a58677b88887fa..5db96a504a6a69a1a72c1181464d92a5b7f40e12 100644 (file)
@@ -62,7 +62,7 @@
 use core::array::LengthAtMost32;
 use core::cmp::{self, Ordering};
 use core::fmt;
-use core::hash::{self, Hash};
+use core::hash::{Hash, Hasher};
 use core::intrinsics::{arith_offset, assume};
 use core::iter::{FromIterator, FusedIterator, TrustedLen};
 use core::marker::PhantomData;
@@ -465,7 +465,7 @@ pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec<T> {
-        Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length }
+        unsafe { Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } }
     }
 
     /// Returns the number of elements the vector can hold without
@@ -491,7 +491,7 @@ pub fn capacity(&self) -> usize {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity overflows `usize`.
+    /// Panics if the new capacity exceeds `isize::MAX` bytes.
     ///
     /// # Examples
     ///
@@ -1188,7 +1188,7 @@ pub fn dedup_by<F>(&mut self, same_bucket: F)
     ///
     /// # Panics
     ///
-    /// Panics if the number of elements in the vector overflows a `usize`.
+    /// Panics if the new capacity exceeds `isize::MAX` bytes.
     ///
     /// # Examples
     ///
@@ -1264,10 +1264,10 @@ pub fn append(&mut self, other: &mut Self) {
     /// Appends elements to `Self` from other buffer.
     #[inline]
     unsafe fn append_elements(&mut self, other: *const [T]) {
-        let count = (*other).len();
+        let count = unsafe { (*other).len() };
         self.reserve(count);
         let len = self.len();
-        ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count);
+        unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
         self.len += count;
     }
 
@@ -1639,7 +1639,7 @@ pub fn resize_default(&mut self, new_len: usize) {
     }
 }
 
-// This code generalises `extend_with_{element,default}`.
+// This code generalizes `extend_with_{element,default}`.
 trait ExtendWith<T> {
     fn next(&mut self) -> T;
     fn last(self) -> T;
@@ -1760,17 +1760,15 @@ pub fn dedup(&mut self) {
 impl<T> Vec<T> {
     /// Removes the first instance of `item` from the vector if the item exists.
     ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(vec_remove_item)]
-    /// let mut vec = vec![1, 2, 3, 1];
-    ///
-    /// vec.remove_item(&1);
-    ///
-    /// assert_eq!(vec, vec![2, 3, 1]);
-    /// ```
+    /// This method will be removed soon.
     #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
+    #[rustc_deprecated(
+        reason = "Removing the first item equal to a needle is already easily possible \
+            with iterators and the current Vec methods. Furthermore, having a method for \
+            one particular case of removal (linear search, only the first item, no swap remove) \
+            but not for others is inconsistent. This method will be removed soon.",
+        since = "1.46.0"
+    )]
     pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
     where
         T: PartialEq<V>,
@@ -1803,6 +1801,21 @@ impl<T: Clone> SpecFromElem for T {
     }
 }
 
+impl SpecFromElem for i8 {
+    #[inline]
+    fn from_elem(elem: i8, n: usize) -> Vec<i8> {
+        if elem == 0 {
+            return Vec { buf: RawVec::with_capacity_zeroed(n), len: n };
+        }
+        unsafe {
+            let mut v = Vec::with_capacity(n);
+            ptr::write_bytes(v.as_mut_ptr(), elem as u8, n);
+            v.set_len(n);
+            v
+        }
+    }
+}
+
 impl SpecFromElem for u8 {
     #[inline]
     fn from_elem(elem: u8, n: usize) -> Vec<u8> {
@@ -1837,7 +1850,7 @@ unsafe trait IsZero {
 }
 
 macro_rules! impl_is_zero {
-    ($t: ty, $is_zero: expr) => {
+    ($t:ty, $is_zero:expr) => {
         unsafe impl IsZero for $t {
             #[inline]
             fn is_zero(&self) -> bool {
@@ -1847,7 +1860,6 @@ fn is_zero(&self) -> bool {
     };
 }
 
-impl_is_zero!(i8, |x| x == 0);
 impl_is_zero!(i16, |x| x == 0);
 impl_is_zero!(i32, |x| x == 0);
 impl_is_zero!(i64, |x| x == 0);
@@ -1945,7 +1957,7 @@ fn clone_from(&mut self, other: &Vec<T>) {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Hash> Hash for Vec<T> {
     #[inline]
-    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+    fn hash<H: Hasher>(&self, state: &mut H) {
         Hash::hash(&**self, state)
     }
 }
@@ -2344,12 +2356,12 @@ fn extend_reserve(&mut self, additional: usize) {
 }
 
 macro_rules! __impl_slice_eq1 {
-    ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => {
-        #[stable(feature = "rust1", since = "1.0.0")]
+    ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?, #[$stability:meta]) => {
+        #[$stability]
         impl<A, B, $($vars)*> PartialEq<$rhs> for $lhs
         where
             A: PartialEq<B>,
-            $($constraints)*
+            $($ty: $bound)?
         {
             #[inline]
             fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
@@ -2359,18 +2371,23 @@ fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
     }
 }
 
-__impl_slice_eq1! { [] Vec<A>, Vec<B>, }
-__impl_slice_eq1! { [] Vec<A>, &[B], }
-__impl_slice_eq1! { [] Vec<A>, &mut [B], }
-__impl_slice_eq1! { [] Cow<'_, [A]>, &[B], A: Clone }
-__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B], A: Clone }
-__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B>, A: Clone }
-__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N], [B; N]: LengthAtMost32 }
-__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N], [B; N]: LengthAtMost32 }
+__impl_slice_eq1! { [] Vec<A>, Vec<B>, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Vec<A>, &[B], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Vec<A>, &mut [B], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] &[A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [] &mut [A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B> where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [A]>, &[B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N] where [B; N]: LengthAtMost32, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N] where [B; N]: LengthAtMost32, #[stable(feature = "rust1", since = "1.0.0")] }
 
 // NOTE: some less important impls are omitted to reduce code bloat
 // FIXME(Centril): Reconsider this?
 //__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], [B; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, [A; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, [A; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, [A; N]: LengthAtMost32 }
 //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], [B; N]: LengthAtMost32 }
 //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], [B; N]: LengthAtMost32 }
 //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], [B; N]: LengthAtMost32 }
@@ -2965,15 +2982,16 @@ impl<T> Drain<'_, T> {
     /// Fill that range as much as possible with new elements from the `replace_with` iterator.
     /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
     unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
-        let vec = self.vec.as_mut();
+        let vec = unsafe { self.vec.as_mut() };
         let range_start = vec.len;
         let range_end = self.tail_start;
-        let range_slice =
-            slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start);
+        let range_slice = unsafe {
+            slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
+        };
 
         for place in range_slice {
             if let Some(new_item) = replace_with.next() {
-                ptr::write(place, new_item);
+                unsafe { ptr::write(place, new_item) };
                 vec.len += 1;
             } else {
                 return false;
@@ -2984,14 +3002,16 @@ unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
 
     /// Makes room for inserting more elements before the tail.
     unsafe fn move_tail(&mut self, additional: usize) {
-        let vec = self.vec.as_mut();
+        let vec = unsafe { self.vec.as_mut() };
         let len = self.tail_start + self.tail_len;
         vec.buf.reserve(len, additional);
 
         let new_tail_start = self.tail_start + additional;
-        let src = vec.as_ptr().add(self.tail_start);
-        let dst = vec.as_mut_ptr().add(new_tail_start);
-        ptr::copy(src, dst, self.tail_len);
+        unsafe {
+            let src = vec.as_ptr().add(self.tail_start);
+            let dst = vec.as_mut_ptr().add(new_tail_start);
+            ptr::copy(src, dst, self.tail_len);
+        }
         self.tail_start = new_tail_start;
     }
 }
index ac07ffb14febdd8ba0f74a7d1a319b1f0ea5f1f4..42c555cafac86f187ddeb681fe62eecf85e86c9d 100644 (file)
@@ -19,6 +19,7 @@ path = "../libcore/tests/lib.rs"
 [[bench]]
 name = "corebenches"
 path = "../libcore/benches/lib.rs"
+test = true
 
 [dev-dependencies]
 rand = "0.7"
index 570fc4ab93390ecba7eb509c0be49cbd5ebba634..de4ef7949f344a6842fe1d7c8d2a3214f59e18a1 100644 (file)
@@ -1,3 +1,5 @@
+// wasm32 does not support benches (no time).
+#![cfg(not(target_arch = "wasm32"))]
 #![feature(flt2dec)]
 #![feature(test)]
 
index eef9ee7cb0093d811e92c6d3f5b9034e6ffc83e8..8ff1ced53b071840f45edad5e3c3184804fb90c2 100644 (file)
@@ -374,6 +374,7 @@ pub trait Into<T>: Sized {
 /// [`Into`]: trait.Into.html
 /// [`from`]: trait.From.html#tymethod.from
 /// [book]: ../../book/ch09-00-error-handling.html
+#[rustc_diagnostic_item = "from_trait"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(on(
     all(_Self = "&str", T = "std::string::String"),
index 5ff52a9a11b5a348bd543f2907130f52f63d833e..46ba0a279b7fff00462f9cb88309ab1a5f826f12 100644 (file)
@@ -445,3 +445,42 @@ fn from(small: $Small) -> Self {
 nzint_impl_from! { NonZeroU32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
 nzint_impl_from! { NonZeroU32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
 nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+
+macro_rules! nzint_impl_try_from_int {
+    ($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => {
+        #[$attr]
+        #[doc = $doc]
+        impl TryFrom<$Int> for $NonZeroInt {
+            type Error = TryFromIntError;
+
+            #[inline]
+            fn try_from(value: $Int) -> Result<Self, Self::Error> {
+                Self::new(value).ok_or(TryFromIntError(()))
+            }
+        }
+    };
+    ($Int: ty, $NonZeroInt: ty, #[$attr:meta]) => {
+        nzint_impl_try_from_int!($Int,
+                                 $NonZeroInt,
+                                 #[$attr],
+                                 concat!("Attempts to convert `",
+                                         stringify!($Int),
+                                         "` to `",
+                                         stringify!($NonZeroInt),
+                                         "`."));
+    }
+}
+
+// Int -> Non-zero Int
+nzint_impl_try_from_int! { u8, NonZeroU8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u16, NonZeroU16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u32, NonZeroU32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u64, NonZeroU64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { u128, NonZeroU128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { usize, NonZeroUsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i8, NonZeroI8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i16, NonZeroI16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i32, NonZeroI32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i64, NonZeroI64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { i128, NonZeroI128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
index 00a171e6b5fb11b19b2bbae03d45da32c2f187f4..abf461338d80a95137e6c1e8f2715ccfdd8e27a4 100644 (file)
@@ -27,6 +27,7 @@
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[lang = "future_trait"]
+#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
 pub trait Future {
     /// The type of value produced on completion.
     #[stable(feature = "futures_api", since = "1.36.0")]
index d80101753cbef4b554c1a536fcebd4a47523d2c7..6abe19dc155d1d96bedc14946942f6604dacff51 100644 (file)
@@ -333,31 +333,31 @@ fn write_i8(&mut self, i: i8) {
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_i16(&mut self, i: i16) {
-        self.write(&i.to_ne_bytes())
+        self.write_u16(i as u16)
     }
     /// Writes a single `i32` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_i32(&mut self, i: i32) {
-        self.write(&i.to_ne_bytes())
+        self.write_u32(i as u32)
     }
     /// Writes a single `i64` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_i64(&mut self, i: i64) {
-        self.write(&i.to_ne_bytes())
+        self.write_u64(i as u64)
     }
     /// Writes a single `i128` into this hasher.
     #[inline]
     #[stable(feature = "i128", since = "1.26.0")]
     fn write_i128(&mut self, i: i128) {
-        self.write(&i.to_ne_bytes())
+        self.write_u128(i as u128)
     }
     /// Writes a single `isize` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_isize(&mut self, i: isize) {
-        self.write(&i.to_ne_bytes())
+        self.write_usize(i as usize)
     }
 }
 
index 85076a573b5282b5f5e5c021fd825cf40414ef71..5d09018759191806f8d157385aa68763a4cd94ca 100644 (file)
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::any::type_name`](../../std/any/fn.type_name.html)
-    #[rustc_const_unstable(feature = "const_type_name", issue = "none")]
+    #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
     pub fn type_name<T: ?Sized>() -> &'static str;
 
     /// Gets an identifier which is globally unique to the specified type. This
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::any::TypeId::of`](../../std/any/struct.TypeId.html#method.of)
-    #[rustc_const_unstable(feature = "const_type_id", issue = "none")]
+    #[rustc_const_unstable(feature = "const_type_id", issue = "41875")]
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
     /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
     /// implements `Copy`.
     ///
     /// If the actual type neither requires drop glue nor implements
-    /// `Copy`, then may return `true` or `false`.
+    /// `Copy`, then the return value of this function is unspecified.
     ///
     /// The stabilized version of this intrinsic is
     /// [`std::mem::needs_drop`](../../std/mem/fn.needs_drop.html).
     #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
     pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
 
+    /// Returns the number of variants of the type `T` cast to a `usize`;
+    /// if `T` has no variants, returns 0. Uninhabited variants will be counted.
+    ///
+    /// The to-be-stabilized version of this intrinsic is
+    /// [`std::mem::variant_count`](../../std/mem/fn.variant_count.html)
+    #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+    #[cfg(not(bootstrap))]
+    pub fn variant_count<T>() -> usize;
+
     /// Rust's "try catch" construct which invokes the function pointer `try_fn`
     /// with the data pointer `data`.
     ///
     pub fn nontemporal_store<T>(ptr: *mut T, val: T);
 
     /// See documentation of `<*const T>::offset_from` for details.
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "none")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
     /// Internal hook used by Miri to implement unwinding.
     ///
     /// Perma-unstable: do not use.
     pub fn miri_start_panic(payload: *mut u8) -> !;
+
+    /// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
+    /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
+    /// generation.
+    #[cfg(not(bootstrap))]
+    #[lang = "count_code_region"]
+    pub fn count_code_region(index: u32);
+
+    /// See documentation of `<*const T>::guaranteed_eq` for details.
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(not(bootstrap))]
+    pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
+
+    /// See documentation of `<*const T>::guaranteed_ne` for details.
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[cfg(not(bootstrap))]
+    pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
+}
+
+#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+#[cfg(bootstrap)]
+pub const fn variant_count<T>() -> usize {
+    0
 }
 
 // Some functions are defined here because they accidentally got made
@@ -2057,9 +2089,14 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
         fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
-    debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
-    debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory");
+    if cfg!(debug_assertions)
+        && !(is_aligned_and_not_null(src)
+            && is_aligned_and_not_null(dst)
+            && is_nonoverlapping(src, dst, count))
+    {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }
     copy_nonoverlapping(src, dst, count)
 }
 
@@ -2122,8 +2159,10 @@ pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
-    debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
+    if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }
     copy(src, dst, count)
 }
 
index fbfcdc3c1a9ea32177f9ec9735fec79c2d276d42..530cf881f29da54dc8bede98ea50bcfdc3b696a5 100644 (file)
@@ -2265,7 +2265,7 @@ fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> LoopSt
     }
 
     /// Applies function to the elements of iterator and returns
-    /// the first non-none result or the first error.
+    /// the first true result or the first error.
     ///
     /// # Examples
     ///
@@ -2286,19 +2286,26 @@ fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> LoopSt
     /// ```
     #[inline]
     #[unstable(feature = "try_find", reason = "new API", issue = "63178")]
-    fn try_find<F, E, R>(&mut self, mut f: F) -> Result<Option<Self::Item>, E>
+    fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
     where
         Self: Sized,
         F: FnMut(&Self::Item) -> R,
-        R: Try<Ok = bool, Error = E>,
-    {
-        self.try_fold((), move |(), x| match f(&x).into_result() {
-            Ok(false) => LoopState::Continue(()),
-            Ok(true) => LoopState::Break(Ok(x)),
-            Err(x) => LoopState::Break(Err(x)),
-        })
-        .break_value()
-        .transpose()
+        R: Try<Ok = bool>,
+    {
+        #[inline]
+        fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result<T, R::Error>>
+        where
+            F: FnMut(&T) -> R,
+            R: Try<Ok = bool>,
+        {
+            move |(), x| match f(&x).into_result() {
+                Ok(false) => LoopState::Continue(()),
+                Ok(true) => LoopState::Break(Ok(x)),
+                Err(x) => LoopState::Break(Err(x)),
+            }
+        }
+
+        self.try_fold((), check(f)).break_value().transpose()
     }
 
     /// Searches for an element in an iterator, returning its index.
index fe05e914e6d440cccad3964011f5978c49655402..aeb52bffbf24c2ed92a2011788dd5bc19486d6cf 100644 (file)
@@ -73,8 +73,8 @@
 #![feature(const_ascii_ctype_on_intrinsics)]
 #![feature(const_alloc_layout)]
 #![feature(const_discriminant)]
-#![feature(const_if_match)]
-#![feature(const_loop)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
+#![cfg_attr(bootstrap, feature(const_loop))]
 #![feature(const_checked_int_methods)]
 #![feature(const_euclidean_int_methods)]
 #![feature(const_overflowing_int_methods)]
@@ -87,6 +87,7 @@
 #![feature(const_generics)]
 #![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
+#![cfg_attr(not(bootstrap), feature(const_raw_ptr_comparison))]
 #![feature(const_result)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_slice_ptr_len)]
 #![feature(unsized_locals)]
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
+#![feature(variant_count)]
 #![feature(doc_alias)]
 #![feature(mmx_target_feature)]
 #![feature(tbm_target_feature)]
 // crate uses the this crate as its libcore.
 #[path = "../stdarch/crates/core_arch/src/mod.rs"]
 #[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)]
+// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
+// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
+#[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
 #[unstable(feature = "stdsimd", issue = "48556")]
 mod core_arch;
 
index 8bce980cadd1e46221d7c915625248a54cb68d7f..46e6ea7cd18660a35cbec63c115314805a2f4fb0 100644 (file)
@@ -358,12 +358,13 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
 ///     - an (unstable) [extern type], then this function is always safe to
 ///       call, but may panic or otherwise return the wrong value, as the
 ///       extern type's layout is not known. This is the same behavior as
-///       [`size_of_val`] on a reference to an extern type tail.
+///       [`size_of_val`] on a reference to a type with an extern type tail.
 ///     - otherwise, it is conservatively not allowed to call this function.
 ///
 /// [slice]: ../../std/primitive.slice.html
 /// [trait object]: ../../book/ch17-02-trait-objects.html
 /// [extern type]: ../../unstable-book/language-features/extern-types.html
+/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html
 ///
 /// # Examples
 ///
@@ -492,12 +493,13 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
 ///     - an (unstable) [extern type], then this function is always safe to
 ///       call, but may panic or otherwise return the wrong value, as the
 ///       extern type's layout is not known. This is the same behavior as
-///       [`align_of_val`] on a reference to an extern type tail.
+///       [`align_of_val`] on a reference to a type with an extern type tail.
 ///     - otherwise, it is conservatively not allowed to call this function.
 ///
 /// [slice]: ../../std/primitive.slice.html
 /// [trait object]: ../../book/ch17-02-trait-objects.html
 /// [extern type]: ../../unstable-book/language-features/extern-types.html
+/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html
 ///
 /// # Examples
 ///
@@ -581,11 +583,12 @@ pub const fn needs_drop<T>() -> bool {
 /// This means that, for example, the padding byte in `(u8, u16)` is not
 /// necessarily zeroed.
 ///
-/// There is no guarantee that an all-zero byte-pattern represents a valid value of
-/// some type `T`. For example, the all-zero byte-pattern is not a valid value
-/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types
-/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv]
-/// that there always is a valid value in a variable it considers initialized.
+/// There is no guarantee that an all-zero byte-pattern represents a valid value
+/// of some type `T`. For example, the all-zero byte-pattern is not a valid value
+/// for reference types (`&T`, `&mut T`) and functions pointers. Using `zeroed`
+/// on such types causes immediate [undefined behavior][ub] because [the Rust
+/// compiler assumes][inv] that there always is a valid value in a variable it
+/// considers initialized.
 ///
 /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
 /// It is useful for FFI sometimes, but should generally be avoided.
@@ -612,6 +615,7 @@ pub const fn needs_drop<T>() -> bool {
 /// use std::mem;
 ///
 /// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!
+/// let _y: fn() = unsafe { mem::zeroed() }; // And again!
 /// ```
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -997,3 +1001,33 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
     Discriminant(intrinsics::discriminant_value(v))
 }
+
+/// Returns the number of variants in the enum type `T`.
+///
+/// If `T` is not an enum, calling this function will not result in undefined behavior, but the
+/// return value is unspecified. Equally, if `T` is an enum with more variants than `usize::MAX`
+/// the return value is unspecified. Uninhabited variants will be counted.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(never_type)]
+/// # #![feature(variant_count)]
+///
+/// use std::mem;
+///
+/// enum Void {}
+/// enum Foo { A(&'static str), B(i32), C(i32) }
+///
+/// assert_eq!(mem::variant_count::<Void>(), 0);
+/// assert_eq!(mem::variant_count::<Foo>(), 3);
+///
+/// assert_eq!(mem::variant_count::<Option<!>>(), 2);
+/// assert_eq!(mem::variant_count::<Result<!, !>>(), 2);
+/// ```
+#[inline(always)]
+#[unstable(feature = "variant_count", issue = "73662")]
+#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+pub const fn variant_count<T>() -> usize {
+    intrinsics::variant_count::<T>()
+}
index b1317bc2121f6bb496949ee118f088c96ed0b414..d36da90f2adc919a2b9f7a9b5d2a27106e8d9e6a 100644 (file)
@@ -457,13 +457,13 @@ pub const fn trailing_zeros(self) -> u32 {
 Basic usage:
 
 ```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = -1", stringify!($SelfT), ";
+", $Feature, "let n = -1", stringify!($SelfT), ";
 
 assert_eq!(n.leading_ones(), ", stringify!($BITS), ");",
 $EndFeature, "
 ```"),
-            #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
             #[inline]
             pub const fn leading_ones(self) -> u32 {
                 (self as $UnsignedT).leading_ones()
@@ -478,13 +478,13 @@ pub const fn leading_ones(self) -> u32 {
 Basic usage:
 
 ```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = 3", stringify!($SelfT), ";
+", $Feature, "let n = 3", stringify!($SelfT), ";
 
 assert_eq!(n.trailing_ones(), 2);",
 $EndFeature, "
 ```"),
-            #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
             #[inline]
             pub const fn trailing_ones(self) -> u32 {
                 (self as $UnsignedT).trailing_ones()
@@ -1578,7 +1578,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)]
+            #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
             #[inline]
             pub const fn wrapping_abs(self) -> Self {
                  if self.is_negative() {
@@ -1867,7 +1867,7 @@ pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
             #[stable(feature = "wrapping", since = "1.7.0")]
             #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[allow(unused_attributes)]
-            #[allow_internal_unstable(const_if_match)]
+            #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
             pub const fn overflowing_neg(self) -> (Self, bool) {
                 if self == Self::MIN {
                     (Self::MIN, true)
@@ -2160,7 +2160,7 @@ pub const fn rem_euclid(self, rhs: Self) -> Self {
             #[stable(feature = "rust1", since = "1.0.0")]
             #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[allow(unused_attributes)]
-            #[allow_internal_unstable(const_if_match)]
+            #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))]
             #[inline]
             #[rustc_inherit_overflow_checks]
             pub const fn abs(self) -> Self {
@@ -2695,12 +2695,12 @@ pub const fn trailing_zeros(self) -> u32 {
 Basic usage:
 
 ```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = !(", stringify!($SelfT), "::MAX >> 2);
+", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2);
 
 assert_eq!(n.leading_ones(), 2);", $EndFeature, "
 ```"),
-            #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
             #[inline]
             pub const fn leading_ones(self) -> u32 {
                 (!self).leading_zeros()
@@ -2716,12 +2716,12 @@ pub const fn leading_ones(self) -> u32 {
 Basic usage:
 
 ```
-", $Feature, "#![feature(leading_trailing_ones)]
-let n = 0b1010111", stringify!($SelfT), ";
+", $Feature, "let n = 0b1010111", stringify!($SelfT), ";
 
 assert_eq!(n.trailing_ones(), 3);", $EndFeature, "
 ```"),
-            #[unstable(feature = "leading_trailing_ones", issue = "57969")]
+            #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
+            #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
             #[inline]
             pub const fn trailing_ones(self) -> u32 {
                 (!self).trailing_zeros()
index 04c7789fa4ff498bad2e56e6aca49116f4137a31..2cdfee87a3546ab97637817a25f5c35744bc6959 100644 (file)
@@ -224,6 +224,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
 #[must_use = "closures are lazy and do nothing unless called"]
 pub trait FnOnce<Args> {
     /// The returned type after the call operator is used.
+    #[cfg_attr(not(bootstrap), lang = "fn_once_output")]
     #[stable(feature = "fn_once_output", since = "1.12.0")]
     type Output;
 
index 5f0a12678ff432a00b501a0419670a2540ab1694..7aca6af3de6f3641f5daefcf0b0b9b3b422c3e55 100644 (file)
     ops::{self, Deref, DerefMut},
 };
 
-// Note that this is not a lang item per se, but it has a hidden dependency on
-// `Iterator`, which is one. The compiler assumes that the `next` method of
-// `Iterator` is an enumeration with one type parameter and two variants,
-// which basically means it must be `Option`.
-
 /// The `Option` type. See [the module level documentation](index.html) for more.
 #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
 #[rustc_diagnostic_item = "option_type"]
index e39d18d7733a239f98f97d7b1257c72e5516fe6c..64a506a6377f2790a473b826fe1babc56c0e12c2 100644 (file)
@@ -295,6 +295,70 @@ pub const fn wrapping_offset(self, count: isize) -> *const T
         intrinsics::ptr_offset_from(self, origin)
     }
 
+    /// Returns whether two pointers are guaranteed to be equal.
+    ///
+    /// At runtime this function behaves like `self == other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine equality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be equal.
+    /// But when it returns `true`, the pointers are guaranteed to be equal.
+    ///
+    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_ne`]: #method.guaranteed_ne
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_eq(self, other: *const T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_eq(self, other)
+    }
+
+    /// Returns whether two pointers are guaranteed to be inequal.
+    ///
+    /// At runtime this function behaves like `self != other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine the inequality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be inequal.
+    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    ///
+    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_eq`]: #method.guaranteed_eq
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_ne(self, other: *const T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_ne(self, other)
+    }
+
     /// Calculates the distance between two pointers. The returned value is in
     /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
     ///
@@ -330,6 +394,12 @@ pub const fn wrapping_offset(self, count: isize) -> *const T
     /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
     /// ```
     #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
+    #[rustc_deprecated(
+        since = "1.46.0",
+        reason = "Pointer distances across allocation \
+        boundaries are not typically meaningful. \
+        Use integer subtraction if you really need this."
+    )]
     #[inline]
     pub fn wrapping_offset_from(self, origin: *const T) -> isize
     where
index 1be05d5effff343658535971dab896c169143a08..ca2b0c85ec12172e72fdca0680e1d4cb1337e918 100644 (file)
@@ -70,7 +70,7 @@
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::hash;
-use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping};
+use crate::intrinsics::{self, abort, is_aligned_and_not_null, is_nonoverlapping};
 use crate::mem::{self, MaybeUninit};
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -420,9 +420,14 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
 #[inline]
 #[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
 pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
-    debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer");
-    debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer");
-    debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory");
+    if cfg!(debug_assertions)
+        && !(is_aligned_and_not_null(x)
+            && is_aligned_and_not_null(y)
+            && is_nonoverlapping(x, y, count))
+    {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }
 
     let x = x as *mut u8;
     let y = y as *mut u8;
@@ -838,7 +843,10 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn write<T>(dst: *mut T, src: T) {
-    debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
+    if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }
     intrinsics::move_val_init(&mut *dst, src)
 }
 
@@ -1003,7 +1011,10 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 #[inline]
 #[stable(feature = "volatile", since = "1.9.0")]
 pub unsafe fn read_volatile<T>(src: *const T) -> T {
-    debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer");
+    if cfg!(debug_assertions) && !is_aligned_and_not_null(src) {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }
     intrinsics::volatile_load(src)
 }
 
@@ -1072,7 +1083,10 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "volatile", since = "1.9.0")]
 pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
-    debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
+    if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }
     intrinsics::volatile_store(dst, src);
 }
 
@@ -1399,3 +1413,70 @@ macro_rules! fnptr_impls_args {
 fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J }
 fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K }
 fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
+
+/// Create a `const` raw pointer to a place, without creating an intermediate reference.
+///
+/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
+/// and points to initialized data. For cases where those requirements do not hold,
+/// raw pointers should be used instead. However, `&expr as *const _` creates a reference
+/// before casting it to a raw pointer, and that reference is subject to the same rules
+/// as all other references. This macro can create a raw pointer *without* creating
+/// a reference first.
+///
+/// # Example
+///
+/// ```
+/// #![feature(raw_ref_macros)]
+/// use std::ptr;
+///
+/// #[repr(packed)]
+/// struct Packed {
+///     f1: u8,
+///     f2: u16,
+/// }
+///
+/// let packed = Packed { f1: 1, f2: 2 };
+/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
+/// let raw_f2 = ptr::raw_const!(packed.f2);
+/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
+/// ```
+#[unstable(feature = "raw_ref_macros", issue = "73394")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(raw_ref_op)]
+pub macro raw_const($e:expr) {
+    &raw const $e
+}
+
+/// Create a `mut` raw pointer to a place, without creating an intermediate reference.
+///
+/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
+/// and points to initialized data. For cases where those requirements do not hold,
+/// raw pointers should be used instead. However, `&mut expr as *mut _` creates a reference
+/// before casting it to a raw pointer, and that reference is subject to the same rules
+/// as all other references. This macro can create a raw pointer *without* creating
+/// a reference first.
+///
+/// # Example
+///
+/// ```
+/// #![feature(raw_ref_macros)]
+/// use std::ptr;
+///
+/// #[repr(packed)]
+/// struct Packed {
+///     f1: u8,
+///     f2: u16,
+/// }
+///
+/// let mut packed = Packed { f1: 1, f2: 2 };
+/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
+/// let raw_f2 = ptr::raw_mut!(packed.f2);
+/// unsafe { raw_f2.write_unaligned(42); }
+/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference.
+/// ```
+#[unstable(feature = "raw_ref_macros", issue = "73394")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(raw_ref_op)]
+pub macro raw_mut($e:expr) {
+    &raw mut $e
+}
index 40b5e4e22340e9844ae05862645811a2c110980b..6b5cd9fdb854d550186c8f70c895eac52eeaef20 100644 (file)
@@ -273,6 +273,70 @@ pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
         if self.is_null() { None } else { Some(&mut *self) }
     }
 
+    /// Returns whether two pointers are guaranteed to be equal.
+    ///
+    /// At runtime this function behaves like `self == other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine equality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be equal.
+    /// But when it returns `true`, the pointers are guaranteed to be equal.
+    ///
+    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_ne`]: #method.guaranteed_ne
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const fn guaranteed_eq(self, other: *mut T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
+    }
+
+    /// Returns whether two pointers are guaranteed to be inequal.
+    ///
+    /// At runtime this function behaves like `self != other`.
+    /// However, in some contexts (e.g., compile-time evaluation),
+    /// it is not always possible to determine the inequality of two pointers, so this function may
+    /// spuriously return `false` for pointers that later actually turn out to be inequal.
+    /// But when it returns `true`, the pointers are guaranteed to be inequal.
+    ///
+    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
+    /// comparisons for which both functions return `false`.
+    ///
+    /// [`guaranteed_eq`]: #method.guaranteed_eq
+    ///
+    /// The return value may change depending on the compiler version and unsafe code may not
+    /// rely on the result of this function for soundness. It is suggested to only use this function
+    /// for performance optimizations where spurious `false` return values by this function do not
+    /// affect the outcome, but just the performance.
+    /// The consequences of using this method to make runtime and compile-time code behave
+    /// differently have not been explored. This method should not be used to introduce such
+    /// differences, and it should also not be stabilized before we have a better understanding
+    /// of this issue.
+    #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+    #[inline]
+    #[cfg(not(bootstrap))]
+    pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
+    where
+        T: Sized,
+    {
+        intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
+    }
+
     /// Calculates the distance between two pointers. The returned value is in
     /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
     ///
@@ -380,11 +444,18 @@ pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
     /// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2);
     /// ```
     #[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
+    #[rustc_deprecated(
+        since = "1.46.0",
+        reason = "Pointer distances across allocation \
+        boundaries are not typically meaningful. \
+        Use integer subtraction if you really need this."
+    )]
     #[inline]
     pub fn wrapping_offset_from(self, origin: *const T) -> isize
     where
         T: Sized,
     {
+        #[allow(deprecated_in_future, deprecated)]
         (self as *const T).wrapping_offset_from(origin)
     }
 
index c7b5777a16e7f7459c8d89f4f9b3b5a5f3d1f3ee..0c0e6d291bb92ee60999cc14f2c5d608b673136f 100644 (file)
@@ -1145,45 +1145,73 @@ pub fn into_ok(self) -> T {
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", issue = "50264")]
 impl<T: Deref, E> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E>`.
+    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`.
     ///
-    /// Leaves the original `Result` in-place, creating a new one containing a reference to the
-    /// `Ok` type's `Deref::Target` type.
+    /// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
+    /// and returns the new [`Result`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(inner_deref)]
+    /// let x: Result<String, u32> = Ok("hello".to_string());
+    /// let y: Result<&str, &u32> = Ok("hello");
+    /// assert_eq!(x.as_deref(), y);
+    ///
+    /// let x: Result<String, u32> = Err(42);
+    /// let y: Result<&str, &u32> = Err(&42);
+    /// assert_eq!(x.as_deref(), y);
+    /// ```
     pub fn as_deref(&self) -> Result<&T::Target, &E> {
         self.as_ref().map(|t| t.deref())
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", issue = "50264")]
 impl<T, E: Deref> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &E::Target>`.
+    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &<E as Deref>::Target>`.
     ///
-    /// Leaves the original `Result` in-place, creating a new one containing a reference to the
-    /// `Err` type's `Deref::Target` type.
+    /// Coerces the [`Err`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
+    /// and returns the new [`Result`].
     pub fn as_deref_err(&self) -> Result<&T, &E::Target> {
         self.as_ref().map_err(|e| e.deref())
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", 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>`.
+    /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::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.
+    /// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
+    /// and returns the new [`Result`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(inner_deref)]
+    /// let mut s = "HELLO".to_string();
+    /// let mut x: Result<String, u32> = Ok("hello".to_string());
+    /// let y: Result<&mut str, &mut u32> = Ok(&mut s);
+    /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
+    ///
+    /// let mut i = 42;
+    /// let mut x: Result<String, u32> = Err(42);
+    /// let y: Result<&mut str, &mut u32> = Err(&mut i);
+    /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
+    /// ```
     pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {
         self.as_mut().map(|t| t.deref_mut())
     }
 }
 
-#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
+#[unstable(feature = "inner_deref", issue = "50264")]
 impl<T, E: DerefMut> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut E::Target>`.
+    /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut <E as DerefMut>::Target>`.
     ///
-    /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
-    /// the `Err` type's `Deref::Target` type.
+    /// Coerces the [`Err`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
+    /// and returns the new [`Result`].
     pub fn as_deref_mut_err(&mut self) -> Result<&mut T, &mut E::Target> {
         self.as_mut().map_err(|e| e.deref_mut())
     }
index 21ba2b5abcfb672a1c1cfa07b1f39a312884cb7e..6a50cdbc1d9fb78b5ec9379afe980e6069b38e69 100644 (file)
@@ -2663,6 +2663,60 @@ pub fn is_sorted_by_key<F, K>(&self, f: F) -> bool
     {
         self.iter().is_sorted_by_key(f)
     }
+
+    /// Returns the index of the partition point according to the given predicate
+    /// (the index of the first element of the second partition).
+    ///
+    /// The slice is assumed to be partitioned according to the given predicate.
+    /// This means that all elements for which the predicate returns true are at the start of the slice
+    /// and all elements for which the predicate returns false are at the end.
+    /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
+    /// (all odd numbers are at the start, all even at the end).
+    ///
+    /// If this slice is not partitioned, the returned result is unspecified and meaningless,
+    /// as this method performs a kind of binary search.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(partition_point)]
+    ///
+    /// let v = [1, 2, 3, 3, 5, 6, 7];
+    /// let i = v.partition_point(|&x| x < 5);
+    ///
+    /// assert_eq!(i, 4);
+    /// assert!(v[..i].iter().all(|&x| x < 5));
+    /// assert!(v[i..].iter().all(|&x| !(x < 5)));
+    /// ```
+    #[unstable(feature = "partition_point", reason = "new API", issue = "73831")]
+    pub fn partition_point<P>(&self, mut pred: P) -> usize
+    where
+        P: FnMut(&T) -> bool,
+    {
+        let mut left = 0;
+        let mut right = self.len();
+
+        while left != right {
+            let mid = left + (right - left) / 2;
+            // SAFETY:
+            // When left < right, left <= mid < right.
+            // Therefore left always increases and right always decreases,
+            // and eigher of them is selected.
+            // In both cases left <= right is satisfied.
+            // Therefore if left < right in a step,
+            // left <= right is satisfied in the next step.
+            // Therefore as long as left != right, 0 <= left < right <= len is satisfied
+            // and if this case 0 <= mid < len is satisfied too.
+            let value = unsafe { self.get_unchecked(mid) };
+            if pred(value) {
+                left = mid + 1;
+            } else {
+                right = mid;
+            }
+        }
+
+        left
+    }
 }
 
 #[lang = "slice_u8"]
@@ -2817,6 +2871,7 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
     /// performing any bounds checking.
     /// Calling this method with an out-of-bounds index is *[undefined behavior]*
     /// even if the resulting reference is not used.
+    ///
     /// [undefined behavior]: ../../reference/behavior-considered-undefined.html
     #[unstable(feature = "slice_index_methods", issue = "none")]
     unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;
@@ -2825,6 +2880,7 @@ pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
     /// performing any bounds checking.
     /// Calling this method with an out-of-bounds index is *[undefined behavior]*
     /// even if the resulting reference is not used.
+    ///
     /// [undefined behavior]: ../../reference/behavior-considered-undefined.html
     #[unstable(feature = "slice_index_methods", issue = "none")]
     unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output;
@@ -5956,10 +6012,18 @@ impl<A> SlicePartialEq<A> for [A]
             return false;
         }
 
+        #[cfg(bootstrap)]
         if self.as_ptr() == other.as_ptr() {
             return true;
         }
 
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        #[cfg(not(bootstrap))]
+        if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+            return true;
+        }
+
         self.iter().zip(other.iter()).all(|(x, y)| x == y)
     }
 }
@@ -5973,9 +6037,18 @@ fn equal(&self, other: &[A]) -> bool {
         if self.len() != other.len() {
             return false;
         }
+
+        #[cfg(bootstrap)]
         if self.as_ptr() == other.as_ptr() {
             return true;
         }
+
+        // While performance would suffer if `guaranteed_eq` just returned `false`
+        // for all arguments, correctness and return value of this function are not affected.
+        #[cfg(not(bootstrap))]
+        if self.as_ptr().guaranteed_eq(other.as_ptr()) {
+            return true;
+        }
         unsafe {
             let size = mem::size_of_val(self);
             memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
index be3e7aaa2e89a678fbd297d70a3b67874b65817e..8b2ac294764ff5aa49fc17796b45a1a8f651910d 100644 (file)
@@ -1,6 +1,6 @@
 //! Slice sorting
 //!
-//! This module contains an sort algorithm based on Orson Peters' pattern-defeating quicksort,
+//! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort,
 //! published at: https://github.com/orlp/pdqsort
 //!
 //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our
@@ -20,6 +20,9 @@ struct CopyOnDrop<T> {
 
 impl<T> Drop for CopyOnDrop<T> {
     fn drop(&mut self) {
+        // SAFETY:  This is a helper class.
+        //          Please refer to its usage for correctness.
+        //          Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`.
         unsafe {
             ptr::copy_nonoverlapping(self.src, self.dest, 1);
         }
@@ -32,6 +35,21 @@ fn shift_head<T, F>(v: &mut [T], is_less: &mut F)
     F: FnMut(&T, &T) -> bool,
 {
     let len = v.len();
+    // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`)
+    // and copying memory (`ptr::copy_nonoverlapping`).
+    //
+    // a. Indexing:
+    //  1. We checked the size of the array to >=2.
+    //  2. All the indexing that we will do is always between {0 <= index < len} at most.
+    //
+    // b. Memory copying
+    //  1. We are obtaining pointers to references which are guaranteed to be valid.
+    //  2. They cannot overlap because we obtain pointers to difference indices of the slice.
+    //     Namely, `i` and `i-1`.
+    //  3. If the slice is properly aligned, the elements are properly aligned.
+    //     It is the caller's responsibility to make sure the slice is properly aligned.
+    //
+    // See comments below for further detail.
     unsafe {
         // If the first two elements are out-of-order...
         if len >= 2 && is_less(v.get_unchecked(1), v.get_unchecked(0)) {
@@ -62,6 +80,21 @@ fn shift_tail<T, F>(v: &mut [T], is_less: &mut F)
     F: FnMut(&T, &T) -> bool,
 {
     let len = v.len();
+    // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`)
+    // and copying memory (`ptr::copy_nonoverlapping`).
+    //
+    // a. Indexing:
+    //  1. We checked the size of the array to >= 2.
+    //  2. All the indexing that we will do is always between `0 <= index < len-1` at most.
+    //
+    // b. Memory copying
+    //  1. We are obtaining pointers to references which are guaranteed to be valid.
+    //  2. They cannot overlap because we obtain pointers to difference indices of the slice.
+    //     Namely, `i` and `i+1`.
+    //  3. If the slice is properly aligned, the elements are properly aligned.
+    //     It is the caller's responsibility to make sure the slice is properly aligned.
+    //
+    // See comments below for further detail.
     unsafe {
         // If the last two elements are out-of-order...
         if len >= 2 && is_less(v.get_unchecked(len - 1), v.get_unchecked(len - 2)) {
@@ -103,6 +136,8 @@ fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool
     let mut i = 1;
 
     for _ in 0..MAX_STEPS {
+        // SAFETY: We already explicitly did the bound checking with `i < len`.
+        // All our subsequent indexing is only in the range `0 <= index < len`
         unsafe {
             // Find the next pair of adjacent out-of-order elements.
             while i < len && !is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) {
@@ -220,6 +255,7 @@ fn partition_in_blocks<T, F>(v: &mut [T], pivot: &T, is_less: &mut F) -> usize
     let mut offsets_l = [MaybeUninit::<u8>::uninit(); BLOCK];
 
     // The current block on the right side (from `r.sub(block_r)` to `r`).
+    // SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe`
     let mut r = unsafe { l.add(v.len()) };
     let mut block_r = BLOCK;
     let mut start_r = ptr::null_mut();
@@ -268,6 +304,16 @@ fn width<T>(l: *mut T, r: *mut T) -> usize {
             let mut elem = l;
 
             for i in 0..block_l {
+                // SAFETY: The unsafety operations below involve the usage of the `offset`.
+                //         According to the conditions required by the function, we satisfy them because:
+                //         1. `offsets_l` is stack-allocated, and thus considered separate allocated object.
+                //         2. The function `is_less` returns a `bool`.
+                //            Casting a `bool` will never overflow `isize`.
+                //         3. We have guaranteed that `block_l` will be `<= BLOCK`.
+                //            Plus, `end_l` was initially set to the begin pointer of `offsets_` which was declared on the stack.
+                //            Thus, we know that even in the worst case (all invocations of `is_less` returns false) we will only be at most 1 byte pass the end.
+                //        Another unsafety operation here is dereferencing `elem`.
+                //        However, `elem` was initially the begin pointer to the slice which is always valid.
                 unsafe {
                     // Branchless comparison.
                     *end_l = i as u8;
@@ -284,6 +330,17 @@ fn width<T>(l: *mut T, r: *mut T) -> usize {
             let mut elem = r;
 
             for i in 0..block_r {
+                // SAFETY: The unsafety operations below involve the usage of the `offset`.
+                //         According to the conditions required by the function, we satisfy them because:
+                //         1. `offsets_r` is stack-allocated, and thus considered separate allocated object.
+                //         2. The function `is_less` returns a `bool`.
+                //            Casting a `bool` will never overflow `isize`.
+                //         3. We have guaranteed that `block_r` will be `<= BLOCK`.
+                //            Plus, `end_r` was initially set to the begin pointer of `offsets_` which was declared on the stack.
+                //            Thus, we know that even in the worst case (all invocations of `is_less` returns true) we will only be at most 1 byte pass the end.
+                //        Another unsafety operation here is dereferencing `elem`.
+                //        However, `elem` was initially `1 * sizeof(T)` past the end and we decrement it by `1 * sizeof(T)` before accessing it.
+                //        Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice.
                 unsafe {
                     // Branchless comparison.
                     elem = elem.offset(-1);
@@ -404,8 +461,13 @@ fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
         // Find the first pair of out-of-order elements.
         let mut l = 0;
         let mut r = v.len();
+
+        // SAFETY: The unsafety below involves indexing an array.
+        // For the first one: We already do the bounds checking here with `l < r`.
+        // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation.
+        //                     From here we know that `r` must be at least `r == l` which was shown to be valid from the first one.
         unsafe {
-            // Find the first element greater then or equal to the pivot.
+            // Find the first element greater than or equal to the pivot.
             while l < r && is_less(v.get_unchecked(l), pivot) {
                 l += 1;
             }
@@ -444,6 +506,7 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
 
     // Read the pivot into a stack-allocated variable for efficiency. If a following comparison
     // operation panics, the pivot will be automatically written back into the slice.
+    // SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
     let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
     let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
     let pivot = &*tmp;
@@ -452,8 +515,12 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
     let mut l = 0;
     let mut r = v.len();
     loop {
+        // SAFETY: The unsafety below involves indexing an array.
+        // For the first one: We already do the bounds checking here with `l < r`.
+        // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation.
+        //                     From here we know that `r` must be at least `r == l` which was shown to be valid from the first one.
         unsafe {
-            // Find the first element greater that the pivot.
+            // Find the first element greater than the pivot.
             while l < r && !is_less(pivot, v.get_unchecked(l)) {
                 l += 1;
             }
index c2a816f0a7d90acc2017924ff8b115c80261c866..4bc44e98fc802a7efee5106bac8409c3b0cfa9e7 100644 (file)
@@ -241,3 +241,52 @@ fn drop(&mut self) {
     }
     assert_eq!(i.get(), 5);
 }
+
+// This test does not work on targets without panic=unwind support.
+// To work around this problem, test is marked is should_panic, so it will
+// be automagically skipped on unsuitable targets, such as
+// wasm32-unknown-unkown.
+//
+// It means that we use panic for indicating success.
+#[test]
+#[should_panic(expected = "test succeeded")]
+fn array_default_impl_avoids_leaks_on_panic() {
+    use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+    static COUNTER: AtomicUsize = AtomicUsize::new(0);
+    #[derive(Debug)]
+    struct Bomb(usize);
+
+    impl Default for Bomb {
+        fn default() -> Bomb {
+            if COUNTER.load(Relaxed) == 3 {
+                panic!("bomb limit exceeded");
+            }
+
+            COUNTER.fetch_add(1, Relaxed);
+            Bomb(COUNTER.load(Relaxed))
+        }
+    }
+
+    impl Drop for Bomb {
+        fn drop(&mut self) {
+            COUNTER.fetch_sub(1, Relaxed);
+        }
+    }
+
+    let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default());
+    let panic_msg = match res {
+        Ok(_) => unreachable!(),
+        Err(p) => p.downcast::<&'static str>().unwrap(),
+    };
+    assert_eq!(*panic_msg, "bomb limit exceeded");
+    // check that all bombs are successfully dropped
+    assert_eq!(COUNTER.load(Relaxed), 0);
+    panic!("test succeeded")
+}
+
+#[test]
+fn empty_array_is_always_default() {
+    struct DoesNotImplDefault;
+
+    let _arr = <[DoesNotImplDefault; 0]>::default();
+}
index 37ebf4112808e77ecfeb193acb91e3887ea5e28a..c60ce8ec837d5a952c87a81f83cd6dab57f8863e 100644 (file)
@@ -19,7 +19,7 @@
 #![feature(raw)]
 #![feature(sort_internals)]
 #![feature(slice_partition_at_index)]
-#![feature(specialization)]
+#![feature(min_specialization)]
 #![feature(step_trait)]
 #![feature(step_trait_ext)]
 #![feature(str_internals)]
 #![feature(const_raw_ptr_deref)]
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
-#![feature(leading_trailing_ones)]
 #![feature(const_forget)]
 #![feature(option_unwrap_none)]
 #![feature(peekable_next_if)]
+#![feature(partition_point)]
 
 extern crate test;
 
index 0227a66b8633a704137287e33ca8486b01dcade7..48aec6d718d3d3c0c7ac472c9b895cc159d3dea1 100644 (file)
@@ -1,3 +1,4 @@
+use core::convert::TryFrom;
 use core::num::{IntErrorKind, NonZeroI32, NonZeroI8, NonZeroU32, NonZeroU8};
 use core::option::Option::{self, None, Some};
 use std::mem::size_of;
@@ -176,3 +177,21 @@ fn test_nonzero_bitor_assign() {
     target |= 0;
     assert_eq!(target.get(), 0b1011_1111);
 }
+
+#[test]
+fn test_nonzero_from_int_on_success() {
+    assert_eq!(NonZeroU8::try_from(5), Ok(NonZeroU8::new(5).unwrap()));
+    assert_eq!(NonZeroU32::try_from(5), Ok(NonZeroU32::new(5).unwrap()));
+
+    assert_eq!(NonZeroI8::try_from(-5), Ok(NonZeroI8::new(-5).unwrap()));
+    assert_eq!(NonZeroI32::try_from(-5), Ok(NonZeroI32::new(-5).unwrap()));
+}
+
+#[test]
+fn test_nonzero_from_int_on_err() {
+    assert!(NonZeroU8::try_from(0).is_err());
+    assert!(NonZeroU32::try_from(0).is_err());
+
+    assert!(NonZeroI8::try_from(0).is_err());
+    assert!(NonZeroI32::try_from(0).is_err());
+}
index cd46117f76322ad214d6d1acdc50ada453940396..fba73be92be09b527971a4e410dbf302106ce498 100644 (file)
@@ -81,6 +81,46 @@ fn test_binary_search_implementation_details() {
     assert_eq!(b.binary_search(&3), Ok(8));
 }
 
+#[test]
+fn test_partition_point() {
+    let b: [i32; 0] = [];
+    assert_eq!(b.partition_point(|&x| x < 5), 0);
+
+    let b = [4];
+    assert_eq!(b.partition_point(|&x| x < 3), 0);
+    assert_eq!(b.partition_point(|&x| x < 4), 0);
+    assert_eq!(b.partition_point(|&x| x < 5), 1);
+
+    let b = [1, 2, 4, 6, 8, 9];
+    assert_eq!(b.partition_point(|&x| x < 5), 3);
+    assert_eq!(b.partition_point(|&x| x < 6), 3);
+    assert_eq!(b.partition_point(|&x| x < 7), 4);
+    assert_eq!(b.partition_point(|&x| x < 8), 4);
+
+    let b = [1, 2, 4, 5, 6, 8];
+    assert_eq!(b.partition_point(|&x| x < 9), 6);
+
+    let b = [1, 2, 4, 6, 7, 8, 9];
+    assert_eq!(b.partition_point(|&x| x < 6), 3);
+    assert_eq!(b.partition_point(|&x| x < 5), 3);
+    assert_eq!(b.partition_point(|&x| x < 8), 5);
+
+    let b = [1, 2, 4, 5, 6, 8, 9];
+    assert_eq!(b.partition_point(|&x| x < 7), 5);
+    assert_eq!(b.partition_point(|&x| x < 0), 0);
+
+    let b = [1, 3, 3, 3, 7];
+    assert_eq!(b.partition_point(|&x| x < 0), 0);
+    assert_eq!(b.partition_point(|&x| x < 1), 0);
+    assert_eq!(b.partition_point(|&x| x < 2), 1);
+    assert_eq!(b.partition_point(|&x| x < 3), 1);
+    assert_eq!(b.partition_point(|&x| x < 4), 4);
+    assert_eq!(b.partition_point(|&x| x < 5), 4);
+    assert_eq!(b.partition_point(|&x| x < 6), 4);
+    assert_eq!(b.partition_point(|&x| x < 7), 4);
+    assert_eq!(b.partition_point(|&x| x < 8), 5);
+}
+
 #[test]
 fn test_iterator_nth() {
     let v: &[_] = &[0, 1, 2, 3, 4];
index e2ceaf80c0cda6770f30083a8d1bcdc05d70b61b..3b6dafeee25404b151a80d898cc5866545e0114a 100644 (file)
@@ -31,7 +31,7 @@
 /// the number of nanoseconds.
 ///
 /// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
-/// [`ops`] traits.
+/// [`ops`] traits. It implements `Default` by returning a zero-length `Duration`.
 ///
 /// [`Add`]: ../../std/ops/trait.Add.html
 /// [`Sub`]: ../../std/ops/trait.Sub.html
@@ -138,6 +138,24 @@ pub fn new(secs: u64, nanos: u32) -> Duration {
         Duration { secs, nanos }
     }
 
+    /// Creates a new `Duration` that spans no time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_zero)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::zero();
+    /// assert!(duration.is_zero());
+    /// assert_eq!(duration.as_nanos(), 0);
+    /// ```
+    #[unstable(feature = "duration_zero", issue = "73544")]
+    #[inline]
+    pub const fn zero() -> Duration {
+        Duration { secs: 0, nanos: 0 }
+    }
+
     /// Creates a new `Duration` from the specified number of whole seconds.
     ///
     /// # Examples
@@ -223,6 +241,29 @@ pub const fn from_nanos(nanos: u64) -> Duration {
         }
     }
 
+    /// Returns true if this `Duration` spans no time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_zero)]
+    /// use std::time::Duration;
+    ///
+    /// assert!(Duration::zero().is_zero());
+    /// assert!(Duration::new(0, 0).is_zero());
+    /// assert!(Duration::from_nanos(0).is_zero());
+    /// assert!(Duration::from_secs(0).is_zero());
+    ///
+    /// assert!(!Duration::new(1, 1).is_zero());
+    /// assert!(!Duration::from_nanos(1).is_zero());
+    /// assert!(!Duration::from_secs(1).is_zero());
+    /// ```
+    #[unstable(feature = "duration_zero", issue = "73544")]
+    #[inline]
+    pub const fn is_zero(&self) -> bool {
+        self.secs == 0 && self.nanos == 0
+    }
+
     /// Returns the number of _whole_ seconds contained by this `Duration`.
     ///
     /// The returned value does not include the fractional (nanosecond) part of the
index fd3e11858cef67719f1acb85a8d217d670573e0a..27056d5f934fdc1c4f503ab294ba7803dbab2d17 100644 (file)
@@ -21,6 +21,7 @@
 use core::any::Any;
 
 #[rustc_std_internal_symbol]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
 pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
     unreachable!()
 }
index f791fe82a27e7dcf7182111f50f0eda14ee53a8f..f361354da2ac2ff59081a778e10b4fcfb67edec6 100644 (file)
@@ -81,6 +81,7 @@
 mod dwarf;
 
 #[rustc_std_internal_symbol]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
 pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
     Box::into_raw(imp::cleanup(payload))
 }
index e23e2f2c1306f6a4caece4226eba825a4b9bbd63..bb7d59e113c08a29fc9c61e26383c668adb577e7 100644 (file)
@@ -24,6 +24,12 @@ fn main() {
         "InstrProfilingUtil.c",
         "InstrProfilingValue.c",
         "InstrProfilingWriter.c",
+        // This file was renamed in LLVM 10.
+        "InstrProfilingRuntime.cc",
+        "InstrProfilingRuntime.cpp",
+        // These files were added in LLVM 11.
+        "InstrProfilingInternal.c",
+        "InstrProfilingBiasVar.c",
     ];
 
     if target.contains("msvc") {
@@ -69,14 +75,12 @@ fn main() {
 
     let src_root = root.join("lib").join("profile");
     for src in profile_sources {
-        cfg.file(src_root.join(src));
+        let path = src_root.join(src);
+        if path.exists() {
+            cfg.file(path);
+        }
     }
 
-    // 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 66c31cbebcc1efbea0181492aad8a29bcf312231..5cf4f97fb886394d5754016d3fb99d6e095ccc12 100644 (file)
@@ -22,6 +22,7 @@
 use rustc_data_structures::cold_path;
 use smallvec::SmallVec;
 
+use std::alloc::Layout;
 use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::intrinsics;
@@ -363,13 +364,15 @@ fn grow(&self, additional: usize) {
         }
     }
 
-    /// Allocates a byte slice with specified size and alignment from the
-    /// current memory chunk. Returns `None` if there is no free space left to
-    /// satisfy the request.
+    /// Allocates a byte slice with specified layout from the current memory
+    /// chunk. Returns `None` if there is no free space left to satisfy the
+    /// request.
     #[inline]
-    fn alloc_raw_without_grow(&self, bytes: usize, align: usize) -> Option<*mut u8> {
+    fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
         let ptr = self.ptr.get() as usize;
         let end = self.end.get() as usize;
+        let align = layout.align();
+        let bytes = layout.size();
         // The allocation request fits into the current chunk iff:
         //
         // let aligned = align_to(ptr, align);
@@ -390,15 +393,15 @@ fn alloc_raw_without_grow(&self, bytes: usize, align: usize) -> Option<*mut u8>
     }
 
     #[inline]
-    pub fn alloc_raw(&self, bytes: usize, align: usize) -> *mut u8 {
-        assert!(bytes != 0);
+    pub fn alloc_raw(&self, layout: Layout) -> *mut u8 {
+        assert!(layout.size() != 0);
         loop {
-            if let Some(a) = self.alloc_raw_without_grow(bytes, align) {
+            if let Some(a) = self.alloc_raw_without_grow(layout) {
                 break a;
             }
             // No free space left. Allocate a new chunk to satisfy the request.
             // On failure the grow will panic or abort.
-            self.grow(bytes);
+            self.grow(layout.size());
         }
     }
 
@@ -406,7 +409,7 @@ pub fn alloc_raw(&self, bytes: usize, align: usize) -> *mut u8 {
     pub fn alloc<T>(&self, object: T) -> &mut T {
         assert!(!mem::needs_drop::<T>());
 
-        let mem = self.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
+        let mem = self.alloc_raw(Layout::for_value::<T>(&object)) as *mut T;
 
         unsafe {
             // Write into uninitialized memory.
@@ -431,7 +434,7 @@ pub fn alloc_slice<T>(&self, slice: &[T]) -> &mut [T]
         assert!(mem::size_of::<T>() != 0);
         assert!(!slice.is_empty());
 
-        let mem = self.alloc_raw(slice.len() * mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
+        let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T;
 
         unsafe {
             mem.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
@@ -477,8 +480,8 @@ pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T]
                 if len == 0 {
                     return &mut [];
                 }
-                let size = len.checked_mul(mem::size_of::<T>()).unwrap();
-                let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut T;
+
+                let mem = self.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
                 unsafe { self.write_from_iter(iter, len, mem) }
             }
             (_, _) => {
@@ -491,9 +494,8 @@ pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T]
                     // the content of the SmallVec
                     unsafe {
                         let len = vec.len();
-                        let start_ptr = self
-                            .alloc_raw(len * mem::size_of::<T>(), mem::align_of::<T>())
-                            as *mut T;
+                        let start_ptr =
+                            self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
                         vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
                         vec.set_len(0);
                         slice::from_raw_parts_mut(start_ptr, len)
@@ -537,7 +539,7 @@ pub struct DropArena {
 impl DropArena {
     #[inline]
     pub unsafe fn alloc<T>(&self, object: T) -> &mut T {
-        let mem = self.arena.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut T;
+        let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T;
         // Write into uninitialized memory.
         ptr::write(mem, object);
         let result = &mut *mem;
@@ -557,10 +559,7 @@ pub unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &
         }
         let len = vec.len();
 
-        let start_ptr = self
-            .arena
-            .alloc_raw(len.checked_mul(mem::size_of::<T>()).unwrap(), mem::align_of::<T>())
-            as *mut T;
+        let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
 
         let mut destructors = self.destructors.borrow_mut();
         // Reserve space for the destructors so we can't panic while adding them
@@ -612,7 +611,11 @@ macro_rules! which_arena_for_type {
 
 #[macro_export]
 macro_rules! declare_arena {
-    ([], [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => {
+    // This macro has to take the same input as
+    // `impl_arena_allocatable_decoders` which requires a second version of
+    // each type. We ignore that type until we can fix
+    // `impl_arena_allocatable_decoders`.
+    ([], [$($a:tt $name:ident: $ty:ty, $_gen_ty:ty;)*], $tcx:lifetime) => {
         #[derive(Default)]
         pub struct Arena<$tcx> {
             pub dropless: $crate::DroplessArena,
@@ -620,39 +623,56 @@ pub struct Arena<$tcx> {
             $($name: $crate::arena_for_type!($a[$ty]),)*
         }
 
-        #[marker]
-        pub trait ArenaAllocatable<'tcx> {}
-
-        impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T {}
-
-        unsafe trait ArenaField<'tcx>: Sized + ArenaAllocatable<'tcx> {
-            /// Returns a specific arena to allocate from.
-            /// If `None` is returned, the `DropArena` will be used.
-            fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>>;
+        pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
+            fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
+            fn allocate_from_iter<'a>(
+                arena: &'a Arena<'tcx>,
+                iter: impl ::std::iter::IntoIterator<Item = Self>,
+            ) -> &'a mut [Self];
         }
 
-        unsafe impl<'tcx, T: ArenaAllocatable<'tcx>> ArenaField<'tcx> for T {
+        impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
             #[inline]
-            default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>> {
-                panic!()
+            fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
+                arena.dropless.alloc(self)
+            }
+            #[inline]
+            fn allocate_from_iter<'a>(
+                arena: &'a Arena<'tcx>,
+                iter: impl ::std::iter::IntoIterator<Item = Self>,
+            ) -> &'a mut [Self] {
+                arena.dropless.alloc_from_iter(iter)
             }
-        }
 
+        }
         $(
-            #[allow(unused_lifetimes)]
-            impl<$tcx> ArenaAllocatable<$tcx> for $ty {}
-            unsafe impl<$tcx, '_x, '_y, '_z, '_w> ArenaField<$tcx> for $gen_ty where Self: ArenaAllocatable<$tcx> {
+            impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
                 #[inline]
-                fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena<Self>> {
-                    // SAFETY: We only implement `ArenaAllocatable<$tcx>` for
-                    // `$ty`, so `$ty` and Self are the same type
-                    unsafe {
-                        ::std::mem::transmute::<
-                            Option<&'a $crate::TypedArena<$ty>>,
-                            Option<&'a $crate::TypedArena<Self>>,
-                        >(
-                            $crate::which_arena_for_type!($a[&_arena.$name])
-                        )
+                fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
+                    if !::std::mem::needs_drop::<Self>() {
+                        return arena.dropless.alloc(self);
+                    }
+                    match $crate::which_arena_for_type!($a[&arena.$name]) {
+                        ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+                            ty_arena.alloc(self)
+                        }
+                        ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
+                    }
+                }
+
+                #[inline]
+                fn allocate_from_iter<'a>(
+                    arena: &'a Arena<$tcx>,
+                    iter: impl ::std::iter::IntoIterator<Item = Self>,
+                ) -> &'a mut [Self] {
+                    if !::std::mem::needs_drop::<Self>() {
+                        return arena.dropless.alloc_from_iter(iter);
+                    }
+                    match $crate::which_arena_for_type!($a[&arena.$name]) {
+                        ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+                            ty_arena.alloc_from_iter(iter)
+                        }
+                        ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
                     }
                 }
             }
@@ -660,14 +680,8 @@ fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena<Self>> {
 
         impl<'tcx> Arena<'tcx> {
             #[inline]
-            pub fn alloc<T: ArenaAllocatable<'tcx>>(&self, value: T) -> &mut T {
-                if !::std::mem::needs_drop::<T>() {
-                    return self.dropless.alloc(value);
-                }
-                match <T as ArenaField<'tcx>>::arena(self) {
-                    ::std::option::Option::Some(arena) => arena.alloc(value),
-                    ::std::option::Option::None => unsafe { self.drop.alloc(value) },
-                }
+            pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
+                value.allocate_on(self)
             }
 
             #[inline]
@@ -678,17 +692,11 @@ pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
                 self.dropless.alloc_slice(value)
             }
 
-            pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx>>(
+            pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
                 &'a self,
                 iter: impl ::std::iter::IntoIterator<Item = T>,
             ) -> &'a mut [T] {
-                if !::std::mem::needs_drop::<T>() {
-                    return self.dropless.alloc_from_iter(iter);
-                }
-                match <T as ArenaField<'tcx>>::arena(self) {
-                    ::std::option::Option::Some(arena) => arena.alloc_from_iter(iter),
-                    ::std::option::Option::None => unsafe { self.drop.alloc_from_iter(iter) },
-                }
+                T::allocate_from_iter(self, iter)
             }
         }
     }
index 62406552e318f1e6a7b07905a5db01acfd2fb0b0..99fbb1ee3ea834ddb73c0e7cfea0aeb19dcc7525 100644 (file)
@@ -5,7 +5,7 @@
 //! additional metadata), and [`ItemKind`] (which represents a concrete type and contains
 //! information specific to the type of the item).
 //!
-//! Other module items that worth mentioning:
+//! Other module items worth mentioning:
 //! - [`Ty`] and [`TyKind`]: A parsed Rust type.
 //! - [`Expr`] and [`ExprKind`]: A parsed Rust expression.
 //! - [`Pat`] and [`PatKind`]: A parsed Rust pattern. Patterns are often dual to expressions.
@@ -335,6 +335,8 @@ pub enum GenericParamKind {
     },
     Const {
         ty: P<Ty>,
+        /// Span of the `const` keyword.
+        kw_span: Span,
     },
 }
 
@@ -1905,7 +1907,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     match c {
                         '{' => f.write_str("{{")?,
                         '}' => f.write_str("}}")?,
-                        _ => write!(f, "{}", c.escape_debug())?,
+                        _ => c.fmt(f)?,
                     }
                 }
                 Ok(())
index b812f2dadf6d40321e22740da1c7dad7047c3471..6c128f0176f6699a21e625f105ce82e780079946 100644 (file)
@@ -475,7 +475,7 @@ fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
                 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
                 Path { span, segments }
             }
-            Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
+            Some(TokenTree::Token(Token { kind: token::Interpolated(nt, _), .. })) => match *nt {
                 token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
                 token::Nonterminal::NtPath(ref path) => path.clone(),
                 _ => return None,
index cb3118cba23dd9a0a1b378f09055dc0275561f98..5c1c9d6ab906e6964f62aceafaa1bbca4ad062ec 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_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)] // For the `transmute` in `P::new`
 #![feature(const_panic)]
 #![feature(const_transmute)]
index 2ffef9d48c181685e5cd8e8d6aedeba251691400..3fd2815daa14fcb165074e0545e1a9115b1cc2ac 100644 (file)
@@ -656,7 +656,7 @@ pub fn noop_visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
             *span = ident.span;
             return; // Avoid visiting the span for the second time.
         }
-        token::Interpolated(nt) => {
+        token::Interpolated(nt, _) => {
             let mut nt = Lrc::make_mut(nt);
             vis.visit_interpolated(&mut nt);
         }
@@ -762,7 +762,7 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
         GenericParamKind::Type { default } => {
             visit_opt(default, |default| vis.visit_ty(default));
         }
-        GenericParamKind::Const { ty } => {
+        GenericParamKind::Const { ty, kw_span: _ } => {
             vis.visit_ty(ty);
         }
     }
index a5b9c2a95bbea14074f4fbf7d03257bf65432cde..89be3e6e212ccb4d9b6a2335795047d8b98c745e 100644 (file)
@@ -182,6 +182,15 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
             .contains(&name)
 }
 
+/// A hack used to pass AST fragments to attribute and derive macros
+/// as a single nonterminal token instead of a token stream.
+/// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+pub enum FlattenGroup {
+    Yes,
+    No,
+}
+
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
 pub enum TokenKind {
     /* Expression-operator symbols. */
@@ -236,7 +245,7 @@ pub enum TokenKind {
     /// treat regular and interpolated lifetime identifiers in the same way.
     Lifetime(Symbol),
 
-    Interpolated(Lrc<Nonterminal>),
+    Interpolated(Lrc<Nonterminal>, FlattenGroup),
 
     // Can be expanded into several tokens.
     /// A doc comment.
@@ -343,7 +352,7 @@ pub fn take(&mut self) -> Self {
     /// if they keep spans or perform edition checks.
     pub fn uninterpolated_span(&self) -> Span {
         match &self.kind {
-            Interpolated(nt) => nt.span(),
+            Interpolated(nt, _) => nt.span(),
             _ => self.span,
         }
     }
@@ -382,7 +391,7 @@ pub fn can_begin_expr(&self) -> bool {
             ModSep                            | // global path
             Lifetime(..)                      | // labeled loop
             Pound                             => true, // expression attributes
-            Interpolated(ref nt) => match **nt {
+            Interpolated(ref nt, _) => match **nt {
                 NtLiteral(..) |
                 NtExpr(..)    |
                 NtBlock(..)   |
@@ -408,7 +417,7 @@ pub fn can_begin_type(&self) -> bool {
             Lifetime(..)                | // lifetime bound in trait object
             Lt | BinOp(Shl)             | // associated path
             ModSep                      => true, // global path
-            Interpolated(ref nt) => match **nt {
+            Interpolated(ref nt, _) => match **nt {
                 NtTy(..) | NtPath(..) => true,
                 _ => false,
             },
@@ -420,7 +429,7 @@ pub fn can_begin_type(&self) -> bool {
     pub fn can_begin_const_arg(&self) -> bool {
         match self.kind {
             OpenDelim(Brace) => true,
-            Interpolated(ref nt) => match **nt {
+            Interpolated(ref nt, _) => match **nt {
                 NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
                 _ => false,
             },
@@ -455,7 +464,7 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
         match self.uninterpolate().kind {
             Literal(..) | BinOp(Minus) => true,
             Ident(name, false) if name.is_bool_lit() => true,
-            Interpolated(ref nt) => match &**nt {
+            Interpolated(ref nt, _) => match &**nt {
                 NtLiteral(_) => true,
                 NtExpr(e) => match &e.kind {
                     ast::ExprKind::Lit(_) => true,
@@ -476,7 +485,7 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
     // otherwise returns the original token.
     pub fn uninterpolate(&self) -> Cow<'_, Token> {
         match &self.kind {
-            Interpolated(nt) => match **nt {
+            Interpolated(nt, _) => match **nt {
                 NtIdent(ident, is_raw) => {
                     Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
                 }
@@ -523,7 +532,7 @@ pub fn is_ident_named(&self, name: Symbol) -> bool {
 
     /// Returns `true` if the token is an interpolated path.
     fn is_path(&self) -> bool {
-        if let Interpolated(ref nt) = self.kind {
+        if let Interpolated(ref nt, _) = self.kind {
             if let NtPath(..) = **nt {
                 return true;
             }
@@ -535,7 +544,7 @@ fn is_path(&self) -> bool {
     /// That is, is this a pre-parsed expression dropped into the token stream
     /// (which happens while parsing the result of macro expansion)?
     pub fn is_whole_expr(&self) -> bool {
-        if let Interpolated(ref nt) = self.kind {
+        if let Interpolated(ref nt, _) = self.kind {
             if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
                 return true;
             }
@@ -546,7 +555,7 @@ pub fn is_whole_expr(&self) -> bool {
 
     // Is the token an interpolated block (`$b:block`)?
     pub fn is_whole_block(&self) -> bool {
-        if let Interpolated(ref nt) = self.kind {
+        if let Interpolated(ref nt, _) = self.kind {
             if let NtBlock(..) = **nt {
                 return true;
             }
@@ -724,7 +733,7 @@ pub fn glue(&self, joint: &Token) -> Option<Token> {
                 b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
             }
 
-            (&Interpolated(_), &Interpolated(_)) => false,
+            (&Interpolated(..), &Interpolated(..)) => false,
 
             _ => panic!("forgot to add a token?"),
         }
index 4428d09902b92d6b8a3360e130737b33eb66b32d..ea59f867c59d24aaf7241c1284d4a50b48fda602 100644 (file)
@@ -205,7 +205,7 @@ pub fn from_token(token: &Token) -> Result<Lit, LitError> {
                 token::Lit::new(token::Bool, name, None)
             }
             token::Literal(lit) => lit,
-            token::Interpolated(ref nt) => {
+            token::Interpolated(ref nt, _) => {
                 if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
                     if let ast::ExprKind::Lit(lit) = &expr.kind {
                         return Ok(lit.clone());
index d8b44a22f2c92b340ea03a3644943e5df358a2e0..e5bcc571d417637a7c5c64cbe65f3c98b4e57575 100644 (file)
@@ -5,7 +5,7 @@
 /// Associative operator with precedence.
 ///
 /// This is the enum which specifies operator precedence and fixity to the parser.
-#[derive(PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum AssocOp {
     /// `+`
     Add,
index e59cacfffc9264b60f7e29ee54168771feb29d31..90a3a5ec64e0e56ba973720bc30932a8e9ffd267 100644 (file)
@@ -25,7 +25,6 @@ pub(super) fn lower_expr(&mut self, e: &Expr) -> &'hir hir::Expr<'hir> {
     }
 
     pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
-        let mut span = e.span;
         ensure_sufficient_stack(|| {
             let kind = match e.kind {
                 ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
@@ -54,7 +53,6 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                     hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
                 }
                 ExprKind::Binary(binop, ref lhs, ref rhs) => {
-                    span = self.mark_span_with_reason(DesugaringKind::Operator, e.span, None);
                     let binop = self.lower_binop(binop);
                     let lhs = self.lower_expr(lhs);
                     let rhs = self.lower_expr(rhs);
@@ -224,7 +222,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
             hir::Expr {
                 hir_id: self.lower_node_id(e.id),
                 kind,
-                span,
+                span: e.span,
                 attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(),
             }
         })
@@ -239,7 +237,6 @@ fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
     }
 
     fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
-        let span = self.mark_span_with_reason(DesugaringKind::Operator, b.span, None);
         Spanned {
             node: match b.node {
                 BinOpKind::Add => hir::BinOpKind::Add,
@@ -261,7 +258,7 @@ fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
                 BinOpKind::Ge => hir::BinOpKind::Ge,
                 BinOpKind::Gt => hir::BinOpKind::Gt,
             },
-            span,
+            span: b.span,
         }
     }
 
@@ -1004,6 +1001,7 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
                             asm::InlineAsmReg::parse(
                                 sess.asm_arch?,
                                 |feature| sess.target_features.contains(&Symbol::intern(feature)),
+                                &sess.target.target,
                                 s,
                             )
                             .map_err(|e| {
index 8cfbd408e22b3878078f479eb88d249a2cfd929c..00665c4cafb6b4d24d23c180cddeecaa52cd0414 100644 (file)
@@ -253,7 +253,7 @@ fn lower_item_kind(
                 hir::ItemKind::Const(ty, body_id)
             }
             ItemKind::Fn(_, FnSig { ref decl, header }, ref generics, ref body) => {
-                let fn_def_id = self.resolver.definitions().local_def_id(id);
+                let fn_def_id = self.resolver.local_def_id(id);
                 self.with_new_scopes(|this| {
                     this.current_item = Some(ident.span);
 
@@ -342,7 +342,7 @@ fn lower_item_kind(
                 self_ty: ref ty,
                 items: ref impl_items,
             } => {
-                let def_id = self.resolver.definitions().local_def_id(id);
+                let def_id = self.resolver.local_def_id(id);
 
                 // Lower the "impl header" first. This ordering is important
                 // for in-band lifetimes! Consider `'a` here:
@@ -646,7 +646,7 @@ fn rebuild_vis(&mut self, vis: &hir::Visibility<'hir>) -> hir::Visibility<'hir>
     }
 
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
-        let def_id = self.resolver.definitions().local_def_id(i.id);
+        let def_id = self.resolver.local_def_id(i.id);
         hir::ForeignItem {
             hir_id: self.lower_node_id(i.id),
             ident: i.ident,
@@ -747,7 +747,7 @@ fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::Stru
     }
 
     fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> {
-        let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
+        let trait_item_def_id = self.resolver.local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
             AssocItemKind::Const(_, ref ty, ref default) => {
@@ -812,7 +812,7 @@ fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> {
-        let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
+        let impl_item_def_id = self.resolver.local_def_id(i.id);
 
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
@@ -1320,12 +1320,7 @@ pub(super) fn lower_generics_mut(
                                     if let Some(def_id) = def_id.as_local() {
                                         for param in &generics.params {
                                             if let GenericParamKind::Type { .. } = param.kind {
-                                                if def_id
-                                                    == self
-                                                        .resolver
-                                                        .definitions()
-                                                        .local_def_id(param.id)
-                                                {
+                                                if def_id == self.resolver.local_def_id(param.id) {
                                                     add_bounds
                                                         .entry(param.id)
                                                         .or_default()
index a722a88a7a1026a5a8cdfbbdfd9a06da24113869..bc0980f041b942df466067e7901429feaada3053 100644 (file)
@@ -32,8 +32,6 @@
 
 #![feature(array_value_iter)]
 #![feature(crate_visibility_modifier)]
-#![feature(marker_trait_attr)]
-#![feature(min_specialization)]
 #![feature(or_patterns)]
 #![recursion_limit = "256"]
 
@@ -56,7 +54,7 @@
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ParamName};
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::config::nightly_options;
 use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::ParseSess;
@@ -93,7 +91,7 @@ struct LoweringContext<'a, 'hir: 'a> {
     /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
     sess: &'a Session,
 
-    resolver: &'a mut dyn Resolver,
+    resolver: &'a mut dyn ResolverAstLowering,
 
     /// HACK(Centril): there is a cyclic dependency between the parser and lowering
     /// if we don't have this function pointer. To avoid that dependency so that
@@ -174,7 +172,7 @@ struct LoweringContext<'a, 'hir: 'a> {
     allow_gen_future: Option<Lrc<[Symbol]>>,
 }
 
-pub trait Resolver {
+pub trait ResolverAstLowering {
     fn def_key(&mut self, id: DefId) -> DefKey;
 
     fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize;
@@ -205,6 +203,21 @@ fn resolve_str_path(
     fn lint_buffer(&mut self) -> &mut LintBuffer;
 
     fn next_node_id(&mut self) -> NodeId;
+
+    fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
+
+    fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
+
+    fn local_def_id(&self, node: NodeId) -> LocalDefId;
+
+    fn create_def(
+        &mut self,
+        parent: LocalDefId,
+        node_id: ast::NodeId,
+        data: DefPathData,
+        expn_id: ExpnId,
+        span: Span,
+    ) -> LocalDefId;
 }
 
 type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
@@ -286,7 +299,7 @@ fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
 pub fn lower_crate<'a, 'hir>(
     sess: &'a Session,
     krate: &'a Crate,
-    resolver: &'a mut dyn Resolver,
+    resolver: &'a mut dyn ResolverAstLowering,
     nt_to_tokenstream: NtToTokenstream,
     arena: &'hir Arena<'hir>,
 ) -> hir::Crate<'hir> {
@@ -436,7 +449,7 @@ fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: LocalDefI
                 match tree.kind {
                     UseTreeKind::Simple(_, id1, id2) => {
                         for &id in &[id1, id2] {
-                            self.lctx.resolver.definitions().create_def_with_parent(
+                            self.lctx.resolver.create_def(
                                 owner,
                                 id,
                                 DefPathData::Misc,
@@ -488,7 +501,7 @@ fn visit_item(&mut self, item: &'tcx Item) {
                     | ItemKind::Enum(_, ref generics)
                     | ItemKind::TyAlias(_, ref generics, ..)
                     | ItemKind::Trait(_, _, ref generics, ..) => {
-                        let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
+                        let def_id = self.lctx.resolver.local_def_id(item.id);
                         let count = generics
                             .params
                             .iter()
@@ -557,7 +570,25 @@ fn visit_ty(&mut self, t: &'tcx Ty) {
         let proc_macros =
             c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
 
-        self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
+        let trait_map = self
+            .resolver
+            .trait_map()
+            .iter()
+            .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone()))
+            .collect();
+
+        let mut def_id_to_hir_id = IndexVec::default();
+
+        for (node_id, hir_id) in self.node_id_to_hir_id.into_iter_enumerated() {
+            if let Some(def_id) = self.resolver.opt_local_def_id(node_id) {
+                if def_id_to_hir_id.len() <= def_id.index() {
+                    def_id_to_hir_id.resize(def_id.index() + 1, None);
+                }
+                def_id_to_hir_id[def_id] = hir_id;
+            }
+        }
+
+        self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
 
         hir::Crate {
             item: hir::CrateItem { module, attrs, span: c.span },
@@ -571,6 +602,7 @@ fn visit_ty(&mut self, t: &'tcx Ty) {
             trait_impls: self.trait_impls,
             modules: self.modules,
             proc_macros,
+            trait_map,
         }
     }
 
@@ -620,7 +652,7 @@ fn with_hir_id_owner<T>(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T
             .item_local_id_counters
             .insert(owner, HIR_ID_COUNTER_LOCKED)
             .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
-        let def_id = self.resolver.definitions().local_def_id(owner);
+        let def_id = self.resolver.local_def_id(owner);
         self.current_hir_id_owner.push((def_id, counter));
         let ret = f(self);
         let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap();
@@ -663,8 +695,8 @@ fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> hi
             debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
 
             *local_id_counter += 1;
-            let owner = this.resolver.definitions().opt_local_def_id(owner).expect(
-                "you forgot to call `create_def_with_parent` or are lowering node-IDs \
+            let owner = this.resolver.opt_local_def_id(owner).expect(
+                "you forgot to call `create_def` or are lowering node-IDs \
                  that do not belong to the current owner",
             );
 
@@ -792,7 +824,7 @@ fn lifetime_to_generic_param(
         };
 
         // Add a definition for the in-band lifetime def.
-        self.resolver.definitions().create_def_with_parent(
+        self.resolver.create_def(
             parent_def_id,
             node_id,
             DefPathData::LifetimeNs(str_name),
@@ -995,7 +1027,7 @@ fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
 
     fn lower_token(&mut self, token: Token) -> TokenStream {
         match token.kind {
-            token::Interpolated(nt) => {
+            token::Interpolated(nt, _) => {
                 let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span);
                 self.lower_token_stream(tts)
             }
@@ -1080,7 +1112,7 @@ fn lower_assoc_ty_constraint(
 
                     let impl_trait_node_id = self.resolver.next_node_id();
                     let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
-                    self.resolver.definitions().create_def_with_parent(
+                    self.resolver.create_def(
                         parent_def_id,
                         impl_trait_node_id,
                         DefPathData::ImplTrait,
@@ -1146,7 +1178,7 @@ fn lower_generic_arg(
                             let node_id = self.resolver.next_node_id();
 
                             // Add a definition for the in-band const def.
-                            self.resolver.definitions().create_def_with_parent(
+                            self.resolver.create_def(
                                 parent_def_id,
                                 node_id,
                                 DefPathData::AnonConst,
@@ -1331,7 +1363,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                     }
                     ImplTraitContext::Universal(in_band_ty_params) => {
                         // Add a definition for the in-band `Param`.
-                        let def_id = self.resolver.definitions().local_def_id(def_node_id);
+                        let def_id = self.resolver.local_def_id(def_node_id);
 
                         let hir_bounds = self.lower_param_bounds(
                             bounds,
@@ -1420,7 +1452,7 @@ fn lower_opaque_impl_trait(
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let opaque_ty_def_id = self.resolver.definitions().local_def_id(opaque_ty_node_id);
+        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
 
         self.allocate_hir_id_counter(opaque_ty_node_id);
 
@@ -1612,7 +1644,7 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
                     let def_node_id = self.context.resolver.next_node_id();
                     let hir_id =
                         self.context.lower_node_id_with_owner(def_node_id, self.opaque_ty_id);
-                    self.context.resolver.definitions().create_def_with_parent(
+                    self.context.resolver.create_def(
                         self.parent,
                         def_node_id,
                         DefPathData::LifetimeNs(name.ident().name),
@@ -1862,7 +1894,7 @@ fn lower_async_fn_ret_ty(
 
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let opaque_ty_def_id = self.resolver.definitions().local_def_id(opaque_ty_node_id);
+        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
 
         self.allocate_hir_id_counter(opaque_ty_node_id);
 
@@ -2198,7 +2230,7 @@ fn lower_generic_param(
 
                 (hir::ParamName::Plain(param.ident), kind)
             }
-            GenericParamKind::Const { ref ty } => {
+            GenericParamKind::Const { ref ty, kw_span: _ } => {
                 let ty = self
                     .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
                         this.lower_ty(&ty, ImplTraitContext::disallowed())
index 8eb125e444053d0191da9b7021cedd97b5bfa7ec..975881d9a0ac0c898895c5318320f3dd6f9660a0 100644 (file)
@@ -1135,9 +1135,9 @@ fn visit_generics(&mut self, generics: &'a Generics) {
             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 } => {
+                    GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
+                    GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
+                    GenericParamKind::Const { ref ty, kw_span: _ } => {
                         let ty = pprust::ty_to_string(ty);
                         (ParamKindOrd::Const, Some(format!("const {}: {}", param.ident, ty)))
                     }
index b1abc08aa67b0a1a29b4268a45e2575f47da3289..86faa1f086ce2bf4edbac2fba0dc58626b811465 100644 (file)
@@ -266,7 +266,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>)
         token::Shebang(s) => format!("/* shebang: {}*/", s),
         token::Unknown(s) => s.to_string(),
 
-        token::Interpolated(ref nt) => nonterminal_to_string(nt),
+        token::Interpolated(ref nt, _) => nonterminal_to_string(nt),
     }
 }
 
@@ -2578,7 +2578,7 @@ pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::Generic
                         s.print_type(default)
                     }
                 }
-                ast::GenericParamKind::Const { ref ty } => {
+                ast::GenericParamKind::Const { ref ty, kw_span: _ } => {
                     s.word_space("const");
                     s.print_ident(param.ident);
                     s.s.space();
index f51439f89ffbe9a5f2cfcba73294339095e0eb0b..f92e40ed6ffabf0541c03cfbb7093214a2c94412 100644 (file)
@@ -2,7 +2,6 @@
 
 use rustc_ast::ast;
 use rustc_ast::with_default_globals;
-use rustc_span;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::Ident;
 
index 480ee97f20552c7e2b2a1d33980859734e3b3c4f..52f86aa7e06b97f1b62a57213ce00a0c585cfaa7 100644 (file)
 use rustc_span::{InnerSpan, Span};
 
 struct AsmArgs {
-    template: P<ast::Expr>,
+    templates: Vec<P<ast::Expr>>,
     operands: Vec<(ast::InlineAsmOperand, Span)>,
     named_args: FxHashMap<Symbol, usize>,
     reg_args: FxHashSet<usize>,
     options: ast::InlineAsmOptions,
-    options_span: Option<Span>,
+    options_spans: Vec<Span>,
 }
 
 fn parse_args<'a>(
@@ -52,21 +52,21 @@ fn parse_args<'a>(
         return Err(err);
     }
 
-    let template = p.parse_expr()?;
+    let first_template = p.parse_expr()?;
     let mut args = AsmArgs {
-        template,
+        templates: vec![first_template],
         operands: vec![],
         named_args: FxHashMap::default(),
         reg_args: FxHashSet::default(),
         options: ast::InlineAsmOptions::empty(),
-        options_span: None,
+        options_spans: vec![],
     };
 
-    let mut first = true;
+    let mut allow_templates = true;
     while p.token != token::Eof {
         if !p.eat(&token::Comma) {
-            if first {
-                // After `asm!(""` we always expect *only* a comma...
+            if allow_templates {
+                // After a template string, we always expect *only* a comma...
                 let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
                 err.span_label(p.token.span, "expected `,`");
                 p.maybe_annotate_with_ascription(&mut err, false);
@@ -76,7 +76,6 @@ fn parse_args<'a>(
                 return Err(p.expect(&token::Comma).err().unwrap());
             }
         }
-        first = false;
         if p.token == token::Eof {
             break;
         } // accept trailing commas
@@ -84,6 +83,7 @@ fn parse_args<'a>(
         // Parse options
         if p.eat(&token::Ident(sym::options, false)) {
             parse_options(&mut p, &mut args)?;
+            allow_templates = false;
             continue;
         }
 
@@ -94,6 +94,7 @@ fn parse_args<'a>(
             let (ident, _) = p.token.ident().unwrap();
             p.bump();
             p.expect(&token::Eq)?;
+            allow_templates = false;
             Some(ident.name)
         } else {
             None
@@ -135,8 +136,7 @@ fn parse_args<'a>(
         } else if p.eat(&token::Ident(kw::Const, false)) {
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::Const { expr }
-        } else {
-            p.expect(&token::Ident(sym::sym, false))?;
+        } else if p.eat(&token::Ident(sym::sym, false)) {
             let expr = p.parse_expr()?;
             match expr.kind {
                 ast::ExprKind::Path(..) => {}
@@ -147,17 +147,36 @@ fn parse_args<'a>(
                 }
             }
             ast::InlineAsmOperand::Sym { expr }
+        } else if allow_templates {
+            let template = p.parse_expr()?;
+            // If it can't possibly expand to a string, provide diagnostics here to include other
+            // things it could have been.
+            match template.kind {
+                ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {}
+                ast::ExprKind::MacCall(..) => {}
+                _ => {
+                    let errstr = "expected operand, options, or additional template string";
+                    let mut err = ecx.struct_span_err(template.span, errstr);
+                    err.span_label(template.span, errstr);
+                    return Err(err);
+                }
+            }
+            args.templates.push(template);
+            continue;
+        } else {
+            return Err(p.expect_one_of(&[], &[]).unwrap_err());
         };
 
+        allow_templates = false;
         let span = span_start.to(p.prev_token.span);
         let slot = args.operands.len();
         args.operands.push((op, span));
 
         // Validate the order of named, positional & explicit register operands and options. We do
         // this at the end once we have the full span of the argument available.
-        if let Some(options_span) = args.options_span {
+        if !args.options_spans.is_empty() {
             ecx.struct_span_err(span, "arguments are not allowed after options")
-                .span_label(options_span, "previous options")
+                .span_labels(args.options_spans.clone(), "previous options")
                 .span_label(span, "argument")
                 .emit();
         }
@@ -208,23 +227,23 @@ fn parse_args<'a>(
     if args.options.contains(ast::InlineAsmOptions::NOMEM)
         && args.options.contains(ast::InlineAsmOptions::READONLY)
     {
-        let span = args.options_span.unwrap();
-        ecx.struct_span_err(span, "the `nomem` and `readonly` options are mutually exclusive")
+        let spans = args.options_spans.clone();
+        ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && args.options.contains(ast::InlineAsmOptions::NORETURN)
     {
-        let span = args.options_span.unwrap();
-        ecx.struct_span_err(span, "the `pure` and `noreturn` options are mutually exclusive")
+        let spans = args.options_spans.clone();
+        ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
     {
-        let span = args.options_span.unwrap();
+        let spans = args.options_spans.clone();
         ecx.struct_span_err(
-            span,
+            spans,
             "the `pure` option must be combined with either `nomem` or `readonly`",
         )
         .emit();
@@ -248,7 +267,7 @@ fn parse_args<'a>(
     }
     if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
         ecx.struct_span_err(
-            args.options_span.unwrap(),
+            args.options_spans.clone(),
             "asm with `pure` option must have at least one output",
         )
         .emit();
@@ -264,6 +283,50 @@ fn parse_args<'a>(
     Ok(args)
 }
 
+/// Report a duplicate option error.
+///
+/// This function must be called immediately after the option token is parsed.
+/// Otherwise, the suggestion will be incorrect.
+fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) {
+    let mut err = p
+        .sess
+        .span_diagnostic
+        .struct_span_err(span, &format!("the `{}` option was already provided", symbol));
+    err.span_label(span, "this option was already provided");
+
+    // Tool-only output
+    let mut full_span = span;
+    if p.token.kind == token::Comma {
+        full_span = full_span.to(p.token.span);
+    }
+    err.tool_only_span_suggestion(
+        full_span,
+        "remove this option",
+        String::new(),
+        Applicability::MachineApplicable,
+    );
+
+    err.emit();
+}
+
+/// Try to set the provided option in the provided `AsmArgs`.
+/// If it is already set, report a duplicate option error.
+///
+/// This function must be called immediately after the option token is parsed.
+/// Otherwise, the error will not point to the correct spot.
+fn try_set_option<'a>(
+    p: &mut Parser<'a>,
+    args: &mut AsmArgs,
+    symbol: Symbol,
+    option: ast::InlineAsmOptions,
+) {
+    if !args.options.contains(option) {
+        args.options |= option;
+    } else {
+        err_duplicate_option(p, symbol, p.prev_token.span);
+    }
+}
+
 fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), DiagnosticBuilder<'a>> {
     let span_start = p.prev_token.span;
 
@@ -271,20 +334,20 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn
 
     while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
         if p.eat(&token::Ident(sym::pure, false)) {
-            args.options |= ast::InlineAsmOptions::PURE;
+            try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
         } else if p.eat(&token::Ident(sym::nomem, false)) {
-            args.options |= ast::InlineAsmOptions::NOMEM;
+            try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
         } else if p.eat(&token::Ident(sym::readonly, false)) {
-            args.options |= ast::InlineAsmOptions::READONLY;
+            try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
         } else if p.eat(&token::Ident(sym::preserves_flags, false)) {
-            args.options |= ast::InlineAsmOptions::PRESERVES_FLAGS;
+            try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
         } else if p.eat(&token::Ident(sym::noreturn, false)) {
-            args.options |= ast::InlineAsmOptions::NORETURN;
+            try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
         } else if p.eat(&token::Ident(sym::nostack, false)) {
-            args.options |= ast::InlineAsmOptions::NOSTACK;
+            try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
         } else {
             p.expect(&token::Ident(sym::att_syntax, false))?;
-            args.options |= ast::InlineAsmOptions::ATT_SYNTAX;
+            try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
         }
 
         // Allow trailing commas
@@ -295,14 +358,7 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn
     }
 
     let new_span = span_start.to(p.prev_token.span);
-    if let Some(options_span) = args.options_span {
-        p.struct_span_err(new_span, "asm options cannot be specified multiple times")
-            .span_label(options_span, "previously here")
-            .span_label(new_span, "duplicate options")
-            .emit();
-    } else {
-        args.options_span = Some(new_span);
-    }
+    args.options_spans.push(new_span);
 
     Ok(())
 }
@@ -330,155 +386,180 @@ fn parse_reg<'a>(
 }
 
 fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast::Expr> {
-    let msg = "asm template must be a string literal";
-    let template_sp = args.template.span;
-    let (template_str, template_style, template_span) =
-        match expr_to_spanned_string(ecx, args.template, msg) {
-            Ok(template) => template,
-            Err(err) => {
-                if let Some(mut err) = err {
-                    err.emit();
-                }
-                return DummyResult::raw_expr(sp, true);
-            }
-        };
-
-    let str_style = match template_style {
-        ast::StrStyle::Cooked => None,
-        ast::StrStyle::Raw(raw) => Some(raw as usize),
-    };
-
-    let template_str = &template_str.as_str();
-    let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
-    let mut parser = parse::Parser::new(
-        template_str,
-        str_style,
-        template_snippet,
-        false,
-        parse::ParseMode::InlineAsm,
-    );
-
-    let mut unverified_pieces = Vec::new();
-    while let Some(piece) = parser.next() {
-        if !parser.errors.is_empty() {
-            break;
-        } else {
-            unverified_pieces.push(piece);
-        }
-    }
-
-    if !parser.errors.is_empty() {
-        let err = parser.errors.remove(0);
-        let err_sp = template_span.from_inner(err.span);
-        let mut e = ecx
-            .struct_span_err(err_sp, &format!("invalid asm template string: {}", err.description));
-        e.span_label(err_sp, err.label + " in asm template string");
-        if let Some(note) = err.note {
-            e.note(&note);
-        }
-        if let Some((label, span)) = err.secondary_label {
-            let err_sp = template_span.from_inner(span);
-            e.span_label(err_sp, label);
-        }
-        e.emit();
-        return DummyResult::raw_expr(sp, true);
-    }
-
+    let mut template = vec![];
     // Register operands are implicitly used since they are not allowed to be
     // referenced in the template string.
     let mut used = vec![false; args.operands.len()];
     for pos in &args.reg_args {
         used[*pos] = true;
     }
-
     let named_pos: FxHashMap<usize, Symbol> =
         args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect();
-    let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
-    let mut template = vec![];
-    for piece in unverified_pieces {
-        match piece {
-            parse::Piece::String(s) => {
-                template.push(ast::InlineAsmTemplatePiece::String(s.to_string()))
+    let mut line_spans = Vec::with_capacity(args.templates.len());
+    let mut curarg = 0;
+
+    for template_expr in args.templates.into_iter() {
+        if !template.is_empty() {
+            template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
+        }
+
+        let msg = "asm template must be a string literal";
+        let template_sp = template_expr.span;
+        let (template_str, template_style, template_span) =
+            match expr_to_spanned_string(ecx, template_expr, msg) {
+                Ok(template_part) => template_part,
+                Err(err) => {
+                    if let Some(mut err) = err {
+                        err.emit();
+                    }
+                    return DummyResult::raw_expr(sp, true);
+                }
+            };
+
+        let str_style = match template_style {
+            ast::StrStyle::Cooked => None,
+            ast::StrStyle::Raw(raw) => Some(raw as usize),
+        };
+
+        let template_str = &template_str.as_str();
+        let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
+        let mut parser = parse::Parser::new(
+            template_str,
+            str_style,
+            template_snippet,
+            false,
+            parse::ParseMode::InlineAsm,
+        );
+        parser.curarg = curarg;
+
+        let mut unverified_pieces = Vec::new();
+        while let Some(piece) = parser.next() {
+            if !parser.errors.is_empty() {
+                break;
+            } else {
+                unverified_pieces.push(piece);
+            }
+        }
+
+        if !parser.errors.is_empty() {
+            let err = parser.errors.remove(0);
+            let err_sp = template_span.from_inner(err.span);
+            let msg = &format!("invalid asm template string: {}", err.description);
+            let mut e = ecx.struct_span_err(err_sp, msg);
+            e.span_label(err_sp, err.label + " in asm template string");
+            if let Some(note) = err.note {
+                e.note(&note);
+            }
+            if let Some((label, span)) = err.secondary_label {
+                let err_sp = template_span.from_inner(span);
+                e.span_label(err_sp, label);
             }
-            parse::Piece::NextArgument(arg) => {
-                let span = arg_spans.next().unwrap_or(template_sp);
-
-                let operand_idx = match arg.position {
-                    parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
-                        if idx >= args.operands.len()
-                            || named_pos.contains_key(&idx)
-                            || args.reg_args.contains(&idx)
-                        {
-                            let msg = format!("invalid reference to argument at index {}", idx);
-                            let mut err = ecx.struct_span_err(span, &msg);
-                            err.span_label(span, "from here");
-
-                            let positional_args =
-                                args.operands.len() - args.named_args.len() - args.reg_args.len();
-                            let positional = if positional_args != args.operands.len() {
-                                "positional "
+            e.emit();
+            return DummyResult::raw_expr(sp, true);
+        }
+
+        curarg = parser.curarg;
+
+        let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
+        for piece in unverified_pieces {
+            match piece {
+                parse::Piece::String(s) => {
+                    template.push(ast::InlineAsmTemplatePiece::String(s.to_string()))
+                }
+                parse::Piece::NextArgument(arg) => {
+                    let span = arg_spans.next().unwrap_or(template_sp);
+
+                    let operand_idx = match arg.position {
+                        parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
+                            if idx >= args.operands.len()
+                                || named_pos.contains_key(&idx)
+                                || args.reg_args.contains(&idx)
+                            {
+                                let msg = format!("invalid reference to argument at index {}", idx);
+                                let mut err = ecx.struct_span_err(span, &msg);
+                                err.span_label(span, "from here");
+
+                                let positional_args = args.operands.len()
+                                    - args.named_args.len()
+                                    - args.reg_args.len();
+                                let positional = if positional_args != args.operands.len() {
+                                    "positional "
+                                } else {
+                                    ""
+                                };
+                                let msg = match positional_args {
+                                    0 => format!("no {}arguments were given", positional),
+                                    1 => format!("there is 1 {}argument", positional),
+                                    x => format!("there are {} {}arguments", x, positional),
+                                };
+                                err.note(&msg);
+
+                                if named_pos.contains_key(&idx) {
+                                    err.span_label(args.operands[idx].1, "named argument");
+                                    err.span_note(
+                                        args.operands[idx].1,
+                                        "named arguments cannot be referenced by position",
+                                    );
+                                } else if args.reg_args.contains(&idx) {
+                                    err.span_label(
+                                        args.operands[idx].1,
+                                        "explicit register argument",
+                                    );
+                                    err.span_note(
+                                        args.operands[idx].1,
+                                        "explicit register arguments cannot be used in the asm template",
+                                    );
+                                }
+                                err.emit();
+                                None
                             } else {
-                                ""
-                            };
-                            let msg = match positional_args {
-                                0 => format!("no {}arguments were given", positional),
-                                1 => format!("there is 1 {}argument", positional),
-                                x => format!("there are {} {}arguments", x, positional),
-                            };
-                            err.note(&msg);
-
-                            if named_pos.contains_key(&idx) {
-                                err.span_label(args.operands[idx].1, "named argument");
-                                err.span_note(
-                                    args.operands[idx].1,
-                                    "named arguments cannot be referenced by position",
-                                );
-                            } else if args.reg_args.contains(&idx) {
-                                err.span_label(args.operands[idx].1, "explicit register argument");
-                                err.span_note(
-                                    args.operands[idx].1,
-                                    "explicit register arguments cannot be used in the asm template",
-                                );
+                                Some(idx)
                             }
-                            err.emit();
-                            None
-                        } else {
-                            Some(idx)
-                        }
-                    }
-                    parse::ArgumentNamed(name) => match args.named_args.get(&name) {
-                        Some(&idx) => Some(idx),
-                        None => {
-                            let msg = format!("there is no argument named `{}`", name);
-                            ecx.struct_span_err(span, &msg[..]).emit();
-                            None
                         }
-                    },
-                };
-
-                let mut chars = arg.format.ty.chars();
-                let mut modifier = chars.next();
-                if chars.next().is_some() {
-                    let span = arg
-                        .format
-                        .ty_span
-                        .map(|sp| template_sp.from_inner(sp))
-                        .unwrap_or(template_sp);
-                    ecx.struct_span_err(span, "asm template modifier must be a single character")
+                        parse::ArgumentNamed(name) => match args.named_args.get(&name) {
+                            Some(&idx) => Some(idx),
+                            None => {
+                                let msg = format!("there is no argument named `{}`", name);
+                                ecx.struct_span_err(span, &msg[..]).emit();
+                                None
+                            }
+                        },
+                    };
+
+                    let mut chars = arg.format.ty.chars();
+                    let mut modifier = chars.next();
+                    if chars.next().is_some() {
+                        let span = arg
+                            .format
+                            .ty_span
+                            .map(|sp| template_sp.from_inner(sp))
+                            .unwrap_or(template_sp);
+                        ecx.struct_span_err(
+                            span,
+                            "asm template modifier must be a single character",
+                        )
                         .emit();
-                    modifier = None;
-                }
+                        modifier = None;
+                    }
 
-                if let Some(operand_idx) = operand_idx {
-                    used[operand_idx] = true;
-                    template.push(ast::InlineAsmTemplatePiece::Placeholder {
-                        operand_idx,
-                        modifier,
-                        span,
-                    });
+                    if let Some(operand_idx) = operand_idx {
+                        used[operand_idx] = true;
+                        template.push(ast::InlineAsmTemplatePiece::Placeholder {
+                            operand_idx,
+                            modifier,
+                            span,
+                        });
+                    }
                 }
             }
         }
+
+        if parser.line_spans.is_empty() {
+            let template_num_lines = 1 + template_str.matches('\n').count();
+            line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
+        } else {
+            line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span)));
+        };
     }
 
     let mut unused_operands = vec![];
@@ -525,12 +606,6 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast
         }
     }
 
-    let line_spans = if parser.line_spans.is_empty() {
-        vec![template_sp]
-    } else {
-        parser.line_spans.iter().map(|span| template_span.from_inner(*span)).collect()
-    };
-
     let inline_asm =
         ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans };
     P(ast::Expr {
index 9660cade3824115cd58565a4e29564fc6eb82b60..dc21be3b296aa16db1a128158501efbda5637dd4 100644 (file)
@@ -123,7 +123,7 @@ fn inject_impl_of_structural_trait(
                 *default = None;
                 ast::GenericArg::Type(cx.ty_ident(span, param.ident))
             }
-            ast::GenericParamKind::Const { ty: _ } => {
+            ast::GenericParamKind::Const { ty: _, kw_span: _ } => {
                 ast::GenericArg::Const(cx.const_ident(span, param.ident))
             }
         })
index d769ebb1f5520d621ef27b299eccee1217607d49..6c3a1ce0958ec5d1f90a90f3cdf34ef1f9462a74 100644 (file)
@@ -22,8 +22,10 @@ pub fn expand_option_env<'cx>(
     };
 
     let sp = cx.with_def_site_ctxt(sp);
-    let e = match env::var(&var.as_str()) {
-        Err(..) => {
+    let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern);
+    cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
+    let e = match value {
+        None => {
             let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
             cx.expr_path(cx.path_all(
                 sp,
@@ -37,10 +39,10 @@ pub fn expand_option_env<'cx>(
                 ))],
             ))
         }
-        Ok(s) => cx.expr_call_global(
+        Some(value) => cx.expr_call_global(
             sp,
             cx.std_path(&[sym::option, sym::Option, sym::Some]),
-            vec![cx.expr_str(sp, Symbol::intern(&s))],
+            vec![cx.expr_str(sp, value)],
         ),
     };
     MacEager::expr(e)
@@ -78,12 +80,14 @@ pub fn expand_env<'cx>(
     }
 
     let sp = cx.with_def_site_ctxt(sp);
-    let e = match env::var(&*var.as_str()) {
-        Err(_) => {
+    let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern);
+    cx.parse_sess.env_depinfo.borrow_mut().insert((var, value));
+    let e = match value {
+        None => {
             cx.span_err(sp, &msg.as_str());
             return DummyResult::any(sp);
         }
-        Ok(s) => cx.expr_str(sp, Symbol::intern(&s)),
+        Some(value) => cx.expr_str(sp, value),
     };
     MacEager::expr(e)
 }
index a0f82d65618f460d8313510c5f38683711fdf8d0..173a823dc7d524c75b2a6b5ffa04397dd35f2913 100644 (file)
@@ -5,6 +5,7 @@
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
+#![feature(inner_deref)]
 #![feature(nll)]
 #![feature(or_patterns)]
 #![feature(proc_macro_internals)]
@@ -14,7 +15,7 @@
 
 use crate::deriving::*;
 
-use rustc_expand::base::{MacroExpanderFn, Resolver, SyntaxExtension, SyntaxExtensionKind};
+use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{sym, Ident};
@@ -44,7 +45,7 @@
 pub mod standard_library_imports;
 pub mod test_harness;
 
-pub fn register_builtin_macros(resolver: &mut dyn Resolver, edition: Edition) {
+pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand, edition: Edition) {
     let mut register = |name, kind| {
         resolver.register_builtin_macro(
             Ident::with_dummy_span(name),
index adaf5f03079eb061096323c8bb36679d4be6ff3c..7cc9c1f76631e1b80290bd9659489af32dc5c433 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, Visitor};
 use rustc_ast_pretty::pprust;
-use rustc_expand::base::{ExtCtxt, Resolver};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_session::parse::ParseSess;
 use rustc_span::hygiene::AstPass;
@@ -52,7 +52,7 @@ struct CollectProcMacros<'a> {
 
 pub fn inject(
     sess: &ParseSess,
-    resolver: &mut dyn Resolver,
+    resolver: &mut dyn ResolverExpand,
     mut krate: ast::Crate,
     is_proc_macro_crate: bool,
     has_proc_macro_decls: bool,
index cd3773c76c483ec5dcfaa968f81a5f4b9a9ef3f2..671ff8ce54f0e9fda51711ea693f4b27cefbadc3 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_ast::ptr::P;
 use rustc_ast::{ast, attr};
-use rustc_expand::base::{ExtCtxt, Resolver};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::ExpansionConfig;
 use rustc_session::parse::ParseSess;
 use rustc_span::edition::Edition;
@@ -10,7 +10,7 @@
 
 pub fn inject(
     mut krate: ast::Crate,
-    resolver: &mut dyn Resolver,
+    resolver: &mut dyn ResolverExpand,
     sess: &ParseSess,
     alt_std_name: Option<Symbol>,
 ) -> (ast::Crate, Option<Symbol>) {
index 34ed4c800e04ff62d0deefb960a2defc83546bd3..da8bf2b8b5169990a2c989684ea5090b936793fc 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_ast::entry::{self, EntryPointType};
 use rustc_ast::mut_visit::{ExpectOne, *};
 use rustc_ast::ptr::P;
-use rustc_expand::base::{ExtCtxt, Resolver};
+use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
 use rustc_session::parse::ParseSess;
@@ -37,7 +37,7 @@ struct TestCtxt<'a> {
 // existing main functions, and synthesizing a main test harness
 pub fn inject(
     sess: &ParseSess,
-    resolver: &mut dyn Resolver,
+    resolver: &mut dyn ResolverExpand,
     should_test: bool,
     krate: &mut ast::Crate,
     span_diagnostic: &rustc_errors::Handler,
@@ -192,7 +192,7 @@ fn visit_mac(&mut self, _mac: &mut ast::MacCall) {
 /// Crawl over the crate, inserting test reexports and the test main function
 fn generate_test_harness(
     sess: &ParseSess,
-    resolver: &mut dyn Resolver,
+    resolver: &mut dyn ResolverExpand,
     reexport_test_harness_main: Option<Symbol>,
     krate: &mut ast::Crate,
     features: &Features,
index 9d4a30f23a20934286ffa491a4710f098da2de78..2f9e49591c3811f45195ade7e7caccac3905e5b7 100644 (file)
@@ -255,6 +255,7 @@ fn codegen_inline_asm(
                 }
                 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
                 InlineAsmArch::Nvptx64 => {}
+                InlineAsmArch::Hexagon => {}
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -427,6 +428,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String {
             | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x",
             InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
             | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
+            InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
@@ -472,6 +474,7 @@ fn modifier_to_llvm(
                 modifier
             }
         }
+        InlineAsmRegClass::Hexagon(_) => None,
         InlineAsmRegClass::Nvptx(_) => None,
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
         | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
@@ -523,6 +526,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
         | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
             cx.type_vector(cx.type_i64(), 2)
         }
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
index a4e17a5f675be355115099f04ec98899bf38bb01..6234ade8a161205165309340872ea6d00ad5e3c6 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::config::{OptLevel, Sanitizer};
+use rustc_session::config::{OptLevel, SanitizerSet};
 use rustc_session::Session;
 
 use crate::attributes;
@@ -45,26 +45,16 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
 
 /// Apply LLVM sanitize attributes.
 #[inline]
-pub fn sanitize(cx: &CodegenCx<'ll, '_>, codegen_fn_flags: CodegenFnAttrFlags, llfn: &'ll Value) {
-    if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer {
-        match *sanitizer {
-            Sanitizer::Address => {
-                if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
-                    llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
-                }
-            }
-            Sanitizer::Memory => {
-                if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
-                    llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
-                }
-            }
-            Sanitizer::Thread => {
-                if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
-                    llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
-                }
-            }
-            Sanitizer::Leak => {}
-        }
+pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll Value) {
+    let enabled = cx.tcx.sess.opts.debugging_opts.sanitizer - no_sanitize;
+    if enabled.contains(SanitizerSet::ADDRESS) {
+        llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
+    }
+    if enabled.contains(SanitizerSet::MEMORY) {
+        llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
+    }
+    if enabled.contains(SanitizerSet::THREAD) {
+        llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
     }
 }
 
@@ -123,9 +113,14 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     // Currently stack probes seem somewhat incompatible with the address
     // sanitizer and thread sanitizer. With asan we're already protected from
     // stack overflow anyway so we don't really need stack probes regardless.
-    match cx.sess().opts.debugging_opts.sanitizer {
-        Some(Sanitizer::Address | Sanitizer::Thread) => return,
-        _ => {}
+    if cx
+        .sess()
+        .opts
+        .debugging_opts
+        .sanitizer
+        .intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
+    {
+        return;
     }
 
     // probestack doesn't play nice either with `-C profile-generate`.
@@ -296,7 +291,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
         Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
     }
-    sanitize(cx, codegen_fn_attrs.flags, llfn);
+    sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
 
     // Always annotate functions with the target-cpu they are compiled for.
     // Without this, ThinLTO won't inline Rust functions into Clang generated
index d3e3441b087c21e61ecba2d044f802e4ef7d36eb..9764c9a102e8a43fd7541678b9cf4f5b5c1235dd 100644 (file)
@@ -797,6 +797,7 @@ pub unsafe fn optimize_thin_module(
         kind: ModuleKind::Regular,
     };
     {
+        let target = &*module.module_llvm.tm;
         let llmod = module.module_llvm.llmod();
         save_temp_bitcode(&cgcx, &module, "thin-lto-input");
 
@@ -833,7 +834,7 @@ pub unsafe fn optimize_thin_module(
         {
             let _timer =
                 cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
-            if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) {
+            if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
                 let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg));
             }
@@ -865,7 +866,7 @@ pub unsafe fn optimize_thin_module(
         {
             let _timer =
                 cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
-            if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
+            if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) {
                 let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg));
             }
index 26f5334668b8fd0d5cb5a5fc57d012ca179696e1..54271d3dd04919e61a9fad93c31e8d1007ba2c59 100644 (file)
@@ -21,8 +21,9 @@
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath};
+use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
 use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
 use rustc_target::spec::{CodeModel, RelocModel};
 
@@ -140,7 +141,7 @@ pub fn target_machine_factory(
     // lower atomic operations to single-threaded operations.
     if singlethread
         && sess.target.target.llvm_target.contains("wasm32")
-        && features.iter().any(|s| *s == "+atomics")
+        && sess.target_features.contains(&sym::atomics)
     {
         singlethread = false;
     }
@@ -394,12 +395,13 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
     let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
     // Sanitizer instrumentation is only inserted during the pre-link optimization stage.
     let sanitizer_options = if !is_lto {
-        config.sanitizer.as_ref().map(|s| llvm::SanitizerOptions {
-            sanitize_memory: *s == Sanitizer::Memory,
-            sanitize_thread: *s == Sanitizer::Thread,
-            sanitize_address: *s == Sanitizer::Address,
-            sanitize_recover: config.sanitizer_recover.contains(s),
+        Some(llvm::SanitizerOptions {
+            sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
+            sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
+            sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
+            sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
             sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
+            sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
         })
     } else {
         None
@@ -600,25 +602,18 @@ pub(crate) unsafe fn optimize(
 }
 
 unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
-    let sanitizer = match &config.sanitizer {
-        None => return,
-        Some(s) => s,
-    };
-
-    let recover = config.sanitizer_recover.contains(sanitizer);
-    match sanitizer {
-        Sanitizer::Address => {
-            passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
-            passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
-        }
-        Sanitizer::Memory => {
-            let track_origins = config.sanitizer_memory_track_origins as c_int;
-            passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
-        }
-        Sanitizer::Thread => {
-            passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
-        }
-        Sanitizer::Leak => {}
+    if config.sanitizer.contains(SanitizerSet::ADDRESS) {
+        let recover = config.sanitizer_recover.contains(SanitizerSet::ADDRESS);
+        passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover));
+        passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover));
+    }
+    if config.sanitizer.contains(SanitizerSet::MEMORY) {
+        let track_origins = config.sanitizer_memory_track_origins as c_int;
+        let recover = config.sanitizer_recover.contains(SanitizerSet::MEMORY);
+        passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover));
+    }
+    if config.sanitizer.contains(SanitizerSet::THREAD) {
+        passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
     }
 }
 
index 3e17a51528e3eb70a368c9855e4023fc658b5f15..e99fb8dcae1e512d41048d144e3db5c788b8a882 100644 (file)
 use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_middle::dep_graph;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::middle::exported_symbols;
 use rustc_middle::mir::mono::{Linkage, Visibility};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::DebugInfo;
+use rustc_session::config::{DebugInfo, SanitizerSet};
 use rustc_span::symbol::Symbol;
 
 use std::ffi::CString;
@@ -132,7 +132,7 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm
             // If this codegen unit contains the main function, also create the
             // wrapper here
             if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
-                attributes::sanitize(&cx, CodegenFnAttrFlags::empty(), entry);
+                attributes::sanitize(&cx, SanitizerSet::empty(), entry);
             }
 
             // Run replace-all-uses-with for statics that need it
index f5ae9824df8946b108527ec757d59a5bc840c261..ba285b5ef38d12efa9c72d75794080ef9848fa49 100644 (file)
@@ -997,6 +997,33 @@ fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
         self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
     }
 
+    fn instrprof_increment(
+        &mut self,
+        fn_name: &'ll Value,
+        hash: &'ll Value,
+        num_counters: &'ll Value,
+        index: &'ll Value,
+    ) -> &'ll Value {
+        debug!(
+            "instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})",
+            fn_name, hash, num_counters, index
+        );
+
+        let llfn = unsafe { llvm::LLVMRustGetInstrprofIncrementIntrinsic(self.cx().llmod) };
+        let args = &[fn_name, hash, num_counters, index];
+        let args = self.check_call("call", llfn, args);
+
+        unsafe {
+            llvm::LLVMRustBuildCall(
+                self.llbuilder,
+                llfn,
+                args.as_ptr() as *const &llvm::Value,
+                args.len() as c_uint,
+                None,
+            )
+        }
+    }
+
     fn call(
         &mut self,
         llfn: &'ll Value,
index a5cda5949eec3971d737d39b56ea4fc280613da1..64140747871fec68ca8b27a2ebdb516ad2f004e7 100644 (file)
@@ -206,7 +206,7 @@ fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
         let len = s.as_str().len();
         let cs = consts::ptrcast(
             self.const_cstr(s, false),
-            self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)),
+            self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
         );
         (cs, self.const_usize(len as u64))
     }
index 4c810a37d418068bf441597173d9c69bd7f6649f..7ff5ac5cbdc10082bbdc7b54d1115784fd20addf 100644 (file)
@@ -749,6 +749,8 @@ macro_rules! vector_types {
         ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void);
         ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void);
 
+        ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
+
         ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
         ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
         ifn!("llvm.localescape", fn(...) -> void);
index 333eb805221ff0fda5ec6b462fde4dd76a60c0b2..dab85b8fb864debbe46ccb0c4e29691e6850b37d 100644 (file)
@@ -1,4 +1,4 @@
-use self::EnumDiscriminantInfo::*;
+use self::EnumTagInfo::*;
 use self::MemberDescriptionFactory::*;
 use self::RecursiveTypeDescription::*;
 
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::ich::NodeIdHashingMode;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::truncate;
 use rustc_middle::mir::{self, Field, GeneratorLayout};
 use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout};
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{self, DebugInfo};
 use rustc_span::symbol::{Interner, Symbol};
 use rustc_span::{self, SourceFile, SourceFileHash, Span};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf};
+use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
 
@@ -392,6 +391,7 @@ fn vec_slice_metadata(
             align: pointer_align,
             flags: DIFlags::FlagZero,
             discriminant: None,
+            source_info: None,
         },
         MemberDescription {
             name: "length".to_owned(),
@@ -401,6 +401,7 @@ fn vec_slice_metadata(
             align: usize_align,
             flags: DIFlags::FlagZero,
             discriminant: None,
+            source_info: None,
         },
     ];
 
@@ -508,6 +509,7 @@ fn trait_pointer_metadata(
             align: data_ptr_field.align.abi,
             flags: DIFlags::FlagArtificial,
             discriminant: None,
+            source_info: None,
         },
         MemberDescription {
             name: "vtable".to_owned(),
@@ -517,6 +519,7 @@ fn trait_pointer_metadata(
             align: vtable_field.align.abi,
             flags: DIFlags::FlagArtificial,
             discriminant: None,
+            source_info: None,
         },
     ];
 
@@ -859,7 +862,7 @@ fn foreign_type_metadata(
     debug!("foreign_type_metadata: {:?}", t);
 
     let name = compute_debuginfo_type_name(cx.tcx, t, false);
-    create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA)
+    create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
 }
 
 fn pointer_type_metadata(
@@ -1026,6 +1029,12 @@ fn new(metadata: &'ll DIType, already_stored_in_typemap: bool) -> Self {
     }
 }
 
+#[derive(Debug)]
+struct SourceInfo<'ll> {
+    file: &'ll DIFile,
+    line: u32,
+}
+
 /// Description of a type member, which can either be a regular field (as in
 /// structs or tuples) or an enum variant.
 #[derive(Debug)]
@@ -1037,6 +1046,7 @@ struct MemberDescription<'ll> {
     align: Align,
     flags: DIFlags,
     discriminant: Option<u64>,
+    source_info: Option<SourceInfo<'ll>>,
 }
 
 impl<'ll> MemberDescription<'ll> {
@@ -1045,14 +1055,18 @@ fn into_metadata(
         cx: &CodegenCx<'ll, '_>,
         composite_type_metadata: &'ll DIScope,
     ) -> &'ll DIType {
+        let (file, line) = self
+            .source_info
+            .map(|info| (info.file, info.line))
+            .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
         unsafe {
             llvm::LLVMRustDIBuilderCreateVariantMemberType(
                 DIB(cx),
                 composite_type_metadata,
                 self.name.as_ptr().cast(),
                 self.name.len(),
-                unknown_file_metadata(cx),
-                UNKNOWN_LINE_NUMBER,
+                file,
+                line,
                 self.size.bits(),
                 self.align.bits() as u32,
                 self.offset.bits(),
@@ -1124,6 +1138,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     align: field.align.abi,
                     flags: DIFlags::FlagZero,
                     discriminant: None,
+                    source_info: None,
                 }
             })
             .collect()
@@ -1145,8 +1160,14 @@ fn prepare_struct_metadata(
 
     let containing_scope = get_namespace_for_item(cx, struct_def_id);
 
-    let struct_metadata_stub =
-        create_struct_stub(cx, struct_type, &struct_name, unique_type_id, Some(containing_scope));
+    let struct_metadata_stub = create_struct_stub(
+        cx,
+        struct_type,
+        &struct_name,
+        unique_type_id,
+        Some(containing_scope),
+        DIFlags::FlagZero,
+    );
 
     create_and_register_recursive_type_forward_declaration(
         cx,
@@ -1185,6 +1206,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     align,
                     flags: DIFlags::FlagZero,
                     discriminant: None,
+                    source_info: None,
                 }
             })
             .collect()
@@ -1201,8 +1223,14 @@ fn prepare_tuple_metadata(
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
 
-    let struct_stub =
-        create_struct_stub(cx, tuple_type, &tuple_name[..], unique_type_id, containing_scope);
+    let struct_stub = create_struct_stub(
+        cx,
+        tuple_type,
+        &tuple_name[..],
+        unique_type_id,
+        containing_scope,
+        DIFlags::FlagZero,
+    );
 
     create_and_register_recursive_type_forward_declaration(
         cx,
@@ -1244,6 +1272,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     align: field.align.abi,
                     flags: DIFlags::FlagZero,
                     discriminant: None,
+                    source_info: None,
                 }
             })
             .collect()
@@ -1335,7 +1364,7 @@ fn generator_layout_and_saved_local_names(
 struct EnumMemberDescriptionFactory<'ll, 'tcx> {
     enum_type: Ty<'tcx>,
     layout: TyAndLayout<'tcx>,
-    discriminant_type_metadata: Option<&'ll DIType>,
+    tag_type_metadata: Option<&'ll DIType>,
     containing_scope: &'ll DIScope,
     span: Span,
 }
@@ -1351,11 +1380,11 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
 
         let variant_info_for = |index: VariantIdx| match self.enum_type.kind {
             ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]),
-            ty::Generator(_, substs, _) => {
+            ty::Generator(def_id, _, _) => {
                 let (generator_layout, generator_saved_local_names) =
                     generator_variant_info_data.as_ref().unwrap();
                 VariantInfo::Generator {
-                    substs,
+                    def_id,
                     generator_layout: *generator_layout,
                     generator_saved_local_names,
                     variant_index: index,
@@ -1371,6 +1400,10 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
         } else {
             type_metadata(cx, self.enum_type, self.span)
         };
+        let flags = match self.enum_type.kind {
+            ty::Generator(..) => DIFlags::FlagArtificial,
+            _ => DIFlags::FlagZero,
+        };
 
         match self.layout.variants {
             Variants::Single { index } => {
@@ -1385,7 +1418,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     cx,
                     self.layout,
                     variant_info,
-                    NoDiscriminant,
+                    NoTag,
                     self_metadata,
                     self.span,
                 );
@@ -1404,24 +1437,25 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     offset: Size::ZERO,
                     size: self.layout.size,
                     align: self.layout.align.abi,
-                    flags: DIFlags::FlagZero,
+                    flags,
                     discriminant: None,
+                    source_info: variant_info.source_info(cx),
                 }]
             }
             Variants::Multiple {
-                discr_kind: DiscriminantKind::Tag,
-                discr_index,
+                tag_encoding: TagEncoding::Direct,
+                tag_field,
                 ref variants,
                 ..
             } => {
-                let discriminant_info = if fallback {
-                    RegularDiscriminant {
-                        discr_field: Field::from(discr_index),
-                        discr_type_metadata: self.discriminant_type_metadata.unwrap(),
+                let tag_info = if fallback {
+                    RegularTag {
+                        tag_field: Field::from(tag_field),
+                        tag_type_metadata: self.tag_type_metadata.unwrap(),
                     }
                 } else {
                     // This doesn't matter in this case.
-                    NoDiscriminant
+                    NoTag
                 };
                 variants
                     .iter_enumerated()
@@ -1432,7 +1466,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                             cx,
                             variant,
                             variant_info,
-                            discriminant_info,
+                            tag_info,
                             self_metadata,
                             self.span,
                         );
@@ -1457,21 +1491,22 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                             offset: Size::ZERO,
                             size: self.layout.size,
                             align: self.layout.align.abi,
-                            flags: DIFlags::FlagZero,
+                            flags,
                             discriminant: Some(
                                 self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val
                                     as u64,
                             ),
+                            source_info: variant_info.source_info(cx),
                         }
                     })
                     .collect()
             }
             Variants::Multiple {
-                discr_kind:
-                    DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant },
-                ref discr,
+                tag_encoding:
+                    TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
+                ref tag,
                 ref variants,
-                discr_index,
+                tag_field,
             } => {
                 if fallback {
                     let variant = self.layout.for_variant(cx, dataful_variant);
@@ -1480,7 +1515,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                         cx,
                         variant,
                         variant_info_for(dataful_variant),
-                        OptimizedDiscriminant,
+                        OptimizedTag,
                         self.containing_scope,
                         self.span,
                     );
@@ -1524,10 +1559,11 @@ fn compute_field_path<'a, 'tcx>(
                         cx,
                         &mut name,
                         self.layout,
-                        self.layout.fields.offset(discr_index),
-                        self.layout.field(cx, discr_index).size,
+                        self.layout.fields.offset(tag_field),
+                        self.layout.field(cx, tag_field).size,
                     );
-                    variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| {
+                    let variant_info = variant_info_for(*niche_variants.start());
+                    variant_info.map_struct_name(|variant_name| {
                         name.push_str(variant_name);
                     });
 
@@ -1538,8 +1574,9 @@ fn compute_field_path<'a, 'tcx>(
                         offset: Size::ZERO,
                         size: variant.size,
                         align: variant.align.abi,
-                        flags: DIFlags::FlagZero,
+                        flags,
                         discriminant: None,
+                        source_info: variant_info.source_info(cx),
                     }]
                 } else {
                     variants
@@ -1552,7 +1589,7 @@ fn compute_field_path<'a, 'tcx>(
                                     cx,
                                     variant,
                                     variant_info,
-                                    OptimizedDiscriminant,
+                                    OptimizedTag,
                                     self_metadata,
                                     self.span,
                                 );
@@ -1573,7 +1610,7 @@ fn compute_field_path<'a, 'tcx>(
                                 let value = (i.as_u32() as u128)
                                     .wrapping_sub(niche_variants.start().as_u32() as u128)
                                     .wrapping_add(niche_start);
-                                let value = truncate(value, discr.value.size(cx));
+                                let value = truncate(value, tag.value.size(cx));
                                 // NOTE(eddyb) do *NOT* remove this assert, until
                                 // we pass the full 128-bit value to LLVM, otherwise
                                 // truncation will be silent and remain undetected.
@@ -1587,8 +1624,9 @@ fn compute_field_path<'a, 'tcx>(
                                 offset: Size::ZERO,
                                 size: self.layout.size,
                                 align: self.layout.align.abi,
-                                flags: DIFlags::FlagZero,
+                                flags,
                                 discriminant: niche_value,
+                                source_info: variant_info.source_info(cx),
                             }
                         })
                         .collect()
@@ -1603,7 +1641,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> {
     /// Cloned from the `layout::Struct` describing the variant.
     offsets: Vec<Size>,
     args: Vec<(String, Ty<'tcx>)>,
-    discriminant_type_metadata: Option<&'ll DIType>,
+    tag_type_metadata: Option<&'ll DIType>,
     span: Span,
 }
 
@@ -1613,42 +1651,48 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
             .iter()
             .enumerate()
             .map(|(i, &(ref name, ty))| {
+                // Discriminant is always the first field of our variant
+                // when using the enum fallback.
+                let is_artificial_discr = use_enum_fallback(cx) && i == 0;
                 let (size, align) = cx.size_and_align_of(ty);
                 MemberDescription {
                     name: name.to_string(),
-                    type_metadata: if use_enum_fallback(cx) {
-                        match self.discriminant_type_metadata {
-                            // Discriminant is always the first field of our variant
-                            // when using the enum fallback.
-                            Some(metadata) if i == 0 => metadata,
-                            _ => type_metadata(cx, ty, self.span),
-                        }
+                    type_metadata: if is_artificial_discr {
+                        self.tag_type_metadata.unwrap_or_else(|| type_metadata(cx, ty, self.span))
                     } else {
                         type_metadata(cx, ty, self.span)
                     },
                     offset: self.offsets[i],
                     size,
                     align,
-                    flags: DIFlags::FlagZero,
+                    flags: if is_artificial_discr {
+                        DIFlags::FlagArtificial
+                    } else {
+                        DIFlags::FlagZero
+                    },
                     discriminant: None,
+                    source_info: None,
                 }
             })
             .collect()
     }
 }
 
+// FIXME: terminology here should be aligned with `abi::TagEncoding`.
+// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
+// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
 #[derive(Copy, Clone)]
-enum EnumDiscriminantInfo<'ll> {
-    RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType },
-    OptimizedDiscriminant,
-    NoDiscriminant,
+enum EnumTagInfo<'ll> {
+    RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+    OptimizedTag,
+    NoTag,
 }
 
 #[derive(Copy, Clone)]
 enum VariantInfo<'a, 'tcx> {
     Adt(&'tcx ty::VariantDef),
     Generator {
-        substs: SubstsRef<'tcx>,
+        def_id: DefId,
         generator_layout: &'tcx GeneratorLayout<'tcx>,
         generator_saved_local_names: &'a IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>,
         variant_index: VariantIdx,
@@ -1659,8 +1703,8 @@ impl<'tcx> VariantInfo<'_, 'tcx> {
     fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
         match self {
             VariantInfo::Adt(variant) => f(&variant.ident.as_str()),
-            VariantInfo::Generator { substs, variant_index, .. } => {
-                f(&substs.as_generator().variant_name(*variant_index))
+            VariantInfo::Generator { variant_index, .. } => {
+                f(&GeneratorSubsts::variant_name(*variant_index))
             }
         }
     }
@@ -1696,6 +1740,32 @@ fn field_name(&self, i: usize) -> String {
         };
         field_name.map(|name| name.to_string()).unwrap_or_else(|| format!("__{}", i))
     }
+
+    fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
+        match self {
+            VariantInfo::Generator { def_id, variant_index, .. } => {
+                let span =
+                    cx.tcx.generator_layout(*def_id).variant_source_info[*variant_index].span;
+                if !span.is_dummy() {
+                    let loc = cx.lookup_debug_loc(span.lo());
+                    return Some(SourceInfo {
+                        file: file_metadata(cx, &loc.file, def_id.krate),
+                        line: loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
+                    });
+                }
+            }
+            _ => {}
+        }
+        None
+    }
+
+    #[allow(dead_code)]
+    fn is_artificial(&self) -> bool {
+        match self {
+            VariantInfo::Generator { .. } => true,
+            VariantInfo::Adt(..) => false,
+        }
+    }
 }
 
 /// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a
@@ -1706,7 +1776,7 @@ fn describe_enum_variant(
     cx: &CodegenCx<'ll, 'tcx>,
     layout: layout::TyAndLayout<'tcx>,
     variant: VariantInfo<'_, 'tcx>,
-    discriminant_info: EnumDiscriminantInfo<'ll>,
+    discriminant_info: EnumTagInfo<'ll>,
     containing_scope: &'ll DIScope,
     span: Span,
 ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
@@ -1715,19 +1785,27 @@ fn describe_enum_variant(
             .type_map
             .borrow_mut()
             .get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name);
-        create_struct_stub(cx, layout.ty, &variant_name, unique_type_id, Some(containing_scope))
+        create_struct_stub(
+            cx,
+            layout.ty,
+            &variant_name,
+            unique_type_id,
+            Some(containing_scope),
+            // FIXME(tmandry): This doesn't seem to have any effect.
+            if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero },
+        )
     });
 
     // Build an array of (field name, field type) pairs to be captured in the factory closure.
     let (offsets, args) = if use_enum_fallback(cx) {
         // If this is not a univariant enum, there is also the discriminant field.
         let (discr_offset, discr_arg) = match discriminant_info {
-            RegularDiscriminant { discr_field, .. } => {
+            RegularTag { tag_field, .. } => {
                 // We have the layout of an enum variant, we need the layout of the outer enum
                 let enum_layout = cx.layout_of(layout.ty);
-                let offset = enum_layout.fields.offset(discr_field.as_usize());
+                let offset = enum_layout.fields.offset(tag_field.as_usize());
                 let args =
-                    ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, discr_field.as_usize()).ty);
+                    ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
                 (Some(offset), Some(args))
             }
             _ => (None, None),
@@ -1757,8 +1835,8 @@ fn describe_enum_variant(
     let member_description_factory = VariantMDF(VariantMemberDescriptionFactory {
         offsets,
         args,
-        discriminant_type_metadata: match discriminant_info {
-            RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata),
+        tag_type_metadata: match discriminant_info {
+            RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
             _ => None,
         },
         span,
@@ -1775,7 +1853,13 @@ fn prepare_enum_metadata(
     span: Span,
     outer_field_tys: Vec<Ty<'tcx>>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
-    let enum_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
+    let tcx = cx.tcx;
+    let enum_name = compute_debuginfo_type_name(tcx, enum_type, false);
+    // FIXME(tmandry): This doesn't seem to have any effect.
+    let enum_flags = match enum_type.kind {
+        ty::Generator(..) => DIFlags::FlagArtificial,
+        _ => DIFlags::FlagZero,
+    };
 
     let containing_scope = get_namespace_for_item(cx, enum_def_id);
     // FIXME: This should emit actual file metadata for the enum, but we
@@ -1789,7 +1873,7 @@ fn prepare_enum_metadata(
     let discriminant_type_metadata = |discr: Primitive| {
         let enumerators_metadata: Vec<_> = match enum_type.kind {
             ty::Adt(def, _) => def
-                .discriminants(cx.tcx)
+                .discriminants(tcx)
                 .zip(&def.variants)
                 .map(|((_, discr), v)| {
                     let name = v.ident.as_str();
@@ -1812,15 +1896,16 @@ fn prepare_enum_metadata(
                 .collect(),
             ty::Generator(_, substs, _) => substs
                 .as_generator()
-                .variant_range(enum_def_id, cx.tcx)
+                .variant_range(enum_def_id, tcx)
                 .map(|variant_index| {
-                    let name = substs.as_generator().variant_name(variant_index);
+                    debug_assert_eq!(tcx.types.u32, substs.as_generator().discr_ty(tcx));
+                    let name = GeneratorSubsts::variant_name(variant_index);
                     unsafe {
                         Some(llvm::LLVMRustDIBuilderCreateEnumerator(
                             DIB(cx),
                             name.as_ptr().cast(),
                             name.len(),
-                            // Generators use u32 as discriminant type.
+                            // Generators use u32 as discriminant type, verified above.
                             variant_index.as_u32().into(),
                             true, // IsUnsigned
                         ))
@@ -1838,12 +1923,12 @@ fn prepare_enum_metadata(
             None => {
                 let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx));
                 let discriminant_base_type_metadata =
-                    type_metadata(cx, discr.to_ty(cx.tcx), rustc_span::DUMMY_SP);
+                    type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP);
 
                 let item_name;
                 let discriminant_name = match enum_type.kind {
                     ty::Adt(..) => {
-                        item_name = cx.tcx.item_name(enum_def_id).as_str();
+                        item_name = tcx.item_name(enum_def_id).as_str();
                         &*item_name
                     }
                     ty::Generator(..) => enum_name.as_str(),
@@ -1880,18 +1965,18 @@ fn prepare_enum_metadata(
 
     if let (
         &Abi::Scalar(_),
-        &Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. },
+        &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
     ) = (&layout.abi, &layout.variants)
     {
-        return FinalMetadata(discriminant_type_metadata(discr.value));
+        return FinalMetadata(discriminant_type_metadata(tag.value));
     }
 
     if use_enum_fallback(cx) {
         let discriminant_type_metadata = match layout.variants {
             Variants::Single { .. }
-            | Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None,
-            Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => {
-                Some(discriminant_type_metadata(discr.value))
+            | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
+            Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+                Some(discriminant_type_metadata(tag.value))
             }
         };
 
@@ -1909,7 +1994,7 @@ fn prepare_enum_metadata(
                     UNKNOWN_LINE_NUMBER,
                     layout.size.bits(),
                     layout.align.abi.bits() as u32,
-                    DIFlags::FlagZero,
+                    enum_flags,
                     None,
                     0, // RuntimeLang
                     unique_type_id_str.as_ptr().cast(),
@@ -1927,7 +2012,7 @@ fn prepare_enum_metadata(
             EnumMDF(EnumMemberDescriptionFactory {
                 enum_type,
                 layout,
-                discriminant_type_metadata,
+                tag_type_metadata: discriminant_type_metadata,
                 containing_scope,
                 span,
             }),
@@ -1943,16 +2028,13 @@ fn prepare_enum_metadata(
         Variants::Single { .. } => None,
 
         Variants::Multiple {
-            discr_kind: DiscriminantKind::Niche { .. },
-            ref discr,
-            discr_index,
-            ..
+            tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
         } => {
             // Find the integer type of the correct size.
-            let size = discr.value.size(cx);
-            let align = discr.value.align(cx);
+            let size = tag.value.size(cx);
+            let align = tag.value.align(cx);
 
-            let discr_type = match discr.value {
+            let tag_type = match tag.value {
                 Int(t, _) => t,
                 F32 => Integer::I32,
                 F64 => Integer::I64,
@@ -1960,7 +2042,7 @@ fn prepare_enum_metadata(
             }
             .to_ty(cx.tcx, false);
 
-            let discr_metadata = basic_type_metadata(cx, discr_type);
+            let tag_metadata = basic_type_metadata(cx, tag_type);
             unsafe {
                 Some(llvm::LLVMRustDIBuilderCreateMemberType(
                     DIB(cx),
@@ -1971,17 +2053,15 @@ fn prepare_enum_metadata(
                     UNKNOWN_LINE_NUMBER,
                     size.bits(),
                     align.abi.bits() as u32,
-                    layout.fields.offset(discr_index).bits(),
+                    layout.fields.offset(tag_field).bits(),
                     DIFlags::FlagArtificial,
-                    discr_metadata,
+                    tag_metadata,
                 ))
             }
         }
 
-        Variants::Multiple {
-            discr_kind: DiscriminantKind::Tag, ref discr, discr_index, ..
-        } => {
-            let discr_type = discr.value.to_ty(cx.tcx);
+        Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
+            let discr_type = tag.value.to_ty(cx.tcx);
             let (size, align) = cx.size_and_align_of(discr_type);
 
             let discr_metadata = basic_type_metadata(cx, discr_type);
@@ -1995,7 +2075,7 @@ fn prepare_enum_metadata(
                     UNKNOWN_LINE_NUMBER,
                     size.bits(),
                     align.bits() as u32,
-                    layout.fields.offset(discr_index).bits(),
+                    layout.fields.offset(tag_field).bits(),
                     DIFlags::FlagArtificial,
                     discr_metadata,
                 ))
@@ -2035,7 +2115,7 @@ fn prepare_enum_metadata(
             UNKNOWN_LINE_NUMBER,
             layout.size.bits(),
             layout.align.abi.bits() as u32,
-            DIFlags::FlagZero,
+            enum_flags,
             discriminator_metadata,
             empty_array,
             variant_part_unique_type_id_str.as_ptr().cast(),
@@ -2061,7 +2141,7 @@ fn prepare_enum_metadata(
                 UNKNOWN_LINE_NUMBER,
                 layout.size.bits(),
                 layout.align.abi.bits() as u32,
-                DIFlags::FlagZero,
+                enum_flags,
                 None,
                 type_array,
                 0,
@@ -2081,7 +2161,7 @@ fn prepare_enum_metadata(
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type,
             layout,
-            discriminant_type_metadata: None,
+            tag_type_metadata: None,
             containing_scope,
             span,
         }),
@@ -2112,6 +2192,7 @@ fn composite_type_metadata(
         composite_type_name,
         composite_type_unique_id,
         containing_scope,
+        DIFlags::FlagZero,
     );
     // ... and immediately create and add the member descriptions.
     set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions);
@@ -2213,6 +2294,7 @@ fn create_struct_stub(
     struct_type_name: &str,
     unique_type_id: UniqueTypeId,
     containing_scope: Option<&'ll DIScope>,
+    flags: DIFlags,
 ) -> &'ll DICompositeType {
     let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
 
@@ -2234,7 +2316,7 @@ fn create_struct_stub(
             UNKNOWN_LINE_NUMBER,
             struct_size.bits(),
             struct_align.bits() as u32,
-            DIFlags::FlagZero,
+            flags,
             None,
             empty_array,
             0,
@@ -2299,9 +2381,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
     }
 
     let tcx = cx.tcx;
-    let attrs = tcx.codegen_fn_attrs(def_id);
 
-    let no_mangle = attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE);
     // We may want to remove the namespace scope if we're in an extern block (see
     // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952).
     let var_scope = get_namespace_for_item(cx, def_id);
@@ -2318,14 +2398,11 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
     let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx);
     let type_metadata = type_metadata(cx, variable_type, span);
     let var_name = tcx.item_name(def_id).as_str();
-    let linkage_name = if no_mangle {
-        None
-    } else {
-        Some(mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name.as_str())
-    };
+    let linkage_name: &str =
+        &mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name.as_str();
     // When empty, linkage_name field is omitted,
     // which is what we want for no_mangle statics
-    let linkage_name = linkage_name.as_deref().unwrap_or("");
+    let linkage_name = if var_name == linkage_name { "" } else { linkage_name };
 
     let global_align = cx.align_of(variable_type);
 
index 8c580847ef8fdad866019975ef219134b26efa0a..b5434298805f3cb35b3537064a1c2025755b621c 100644 (file)
@@ -267,9 +267,9 @@ fn create_function_debug_context(
         let substs = instance.substs.truncate_to(self.tcx(), generics);
         let template_parameters = get_template_parameters(self, &generics, substs, &mut name);
 
-        // Get the linkage_name, which is just the symbol name
-        let linkage_name = mangled_name_of_instance(self, instance);
-        let linkage_name = linkage_name.name.as_str();
+        let linkage_name: &str = &mangled_name_of_instance(self, instance).name.as_str();
+        // Omit the linkage_name if it is the same as subprogram name.
+        let linkage_name = if &name == linkage_name { "" } else { linkage_name };
 
         // FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
         let scope_line = loc.line;
index 1e6d2e3dbb74ef1c8758a920f32f479776f9ba6f..130c0cf1877c667c02a0258961eb1b6bb1e63e82 100644 (file)
@@ -7,10 +7,12 @@
 use crate::va_arg::emit_va_arg;
 use crate::value::Value;
 
+use log::debug;
+
 use rustc_ast::ast;
 use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
-use rustc_codegen_ssa::common::TypeKind;
+use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc_codegen_ssa::glue;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -86,6 +88,7 @@ fn codegen_intrinsic_call(
         args: &[OperandRef<'tcx, &'ll Value>],
         llresult: &'ll Value,
         span: Span,
+        caller_instance: ty::Instance<'tcx>,
     ) {
         let tcx = self.tcx;
         let callee_ty = instance.monomorphic_ty(tcx);
@@ -136,6 +139,22 @@ fn codegen_intrinsic_call(
                 let llfn = self.get_intrinsic(&("llvm.debugtrap"));
                 self.call(llfn, &[], None)
             }
+            "count_code_region" => {
+                // FIXME(richkadel): The current implementation assumes the MIR for the given
+                // caller_instance represents a single function. Validate and/or correct if inlining
+                // and/or monomorphization invalidates these assumptions.
+                let coverage_data = tcx.coverage_data(caller_instance.def_id());
+                let mangled_fn = tcx.symbol_name(caller_instance);
+                let (mangled_fn_name, _len_val) = self.const_str(mangled_fn.name);
+                let hash = self.const_u64(coverage_data.hash);
+                let num_counters = self.const_u32(coverage_data.num_counters);
+                let index = args[0].immediate();
+                debug!(
+                    "count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})",
+                    mangled_fn.name, hash, num_counters, index
+                );
+                self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
+            }
             "va_start" => self.va_start(args[0].immediate()),
             "va_end" => self.va_end(args[0].immediate()),
             "va_copy" => {
@@ -187,7 +206,7 @@ fn codegen_intrinsic_call(
                 }
             }
             "size_of" | "pref_align_of" | "min_align_of" | "needs_drop" | "type_id"
-            | "type_name" => {
+            | "type_name" | "variant_count" => {
                 let value = self
                     .tcx
                     .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
@@ -705,6 +724,16 @@ fn codegen_intrinsic_call(
                 return;
             }
 
+            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+                let a = args[0].immediate();
+                let b = args[1].immediate();
+                if name == "ptr_guaranteed_eq" {
+                    self.icmp(IntPredicate::IntEQ, a, b)
+                } else {
+                    self.icmp(IntPredicate::IntNE, a, b)
+                }
+            }
+
             "ptr_offset_from" => {
                 let ty = substs.type_at(0);
                 let pointee_size = self.size_of(ty);
index 54cf99e1c6d6cfdf5d3b48313bdd4bc6c7774cfb..7beb4fc897472a6a79db7a12127a458abf7ff32a 100644 (file)
@@ -233,6 +233,8 @@ pub enum TypeKind {
     Metadata = 14,
     X86_MMX = 15,
     Token = 16,
+    ScalableVector = 17,
+    BFloat = 18,
 }
 
 impl TypeKind {
@@ -255,6 +257,8 @@ pub fn to_generic(self) -> rustc_codegen_ssa::common::TypeKind {
             TypeKind::Metadata => rustc_codegen_ssa::common::TypeKind::Metadata,
             TypeKind::X86_MMX => rustc_codegen_ssa::common::TypeKind::X86_MMX,
             TypeKind::Token => rustc_codegen_ssa::common::TypeKind::Token,
+            TypeKind::ScalableVector => rustc_codegen_ssa::common::TypeKind::ScalableVector,
+            TypeKind::BFloat => rustc_codegen_ssa::common::TypeKind::BFloat,
         }
     }
 }
@@ -439,11 +443,12 @@ pub enum OptStage {
 /// LLVMRustSanitizerOptions
 #[repr(C)]
 pub struct SanitizerOptions {
-    pub sanitize_memory: bool,
-    pub sanitize_thread: bool,
     pub sanitize_address: bool,
-    pub sanitize_recover: bool,
+    pub sanitize_address_recover: bool,
+    pub sanitize_memory: bool,
+    pub sanitize_memory_recover: bool,
     pub sanitize_memory_track_origins: c_int,
+    pub sanitize_thread: bool,
 }
 
 /// LLVMRelocMode
@@ -1360,6 +1365,7 @@ pub fn LLVMBuildFCmp(
 
     // Miscellaneous instructions
     pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+    pub fn LLVMRustGetInstrprofIncrementIntrinsic(M: &Module) -> &'a Value;
     pub fn LLVMRustBuildCall(
         B: &Builder<'a>,
         Fn: &'a Value,
@@ -2139,10 +2145,18 @@ pub fn LLVMRustCreateThinLTOData(
         PreservedSymbols: *const *const c_char,
         PreservedSymbolsLen: c_uint,
     ) -> Option<&'static mut ThinLTOData>;
-    pub fn LLVMRustPrepareThinLTORename(Data: &ThinLTOData, Module: &Module) -> bool;
+    pub fn LLVMRustPrepareThinLTORename(
+        Data: &ThinLTOData,
+        Module: &Module,
+        Target: &TargetMachine,
+    ) -> bool;
     pub fn LLVMRustPrepareThinLTOResolveWeak(Data: &ThinLTOData, Module: &Module) -> bool;
     pub fn LLVMRustPrepareThinLTOInternalize(Data: &ThinLTOData, Module: &Module) -> bool;
-    pub fn LLVMRustPrepareThinLTOImport(Data: &ThinLTOData, Module: &Module) -> bool;
+    pub fn LLVMRustPrepareThinLTOImport(
+        Data: &ThinLTOData,
+        Module: &Module,
+        Target: &TargetMachine,
+    ) -> bool;
     pub fn LLVMRustGetThinLTOModuleImports(
         Data: *const ThinLTOData,
         ModuleNameCallback: ThinLTOModuleNameCallback,
index 67a2251e8593ebb8ff211a0f0c315f1e18ce0424..80278bb9f53d8196b71d3c0ea64fe185844cdd4f 100644 (file)
@@ -156,6 +156,10 @@ pub fn time_trace_profiler_finish(file_name: &str) {
     ("vfp2", Some(sym::arm_target_feature)),
     ("vfp3", Some(sym::arm_target_feature)),
     ("vfp4", Some(sym::arm_target_feature)),
+    // This is needed for inline assembly, but shouldn't be stabilized as-is
+    // since it should be enabled per-function using #[instruction_set], not
+    // #[target_feature].
+    ("thumb-mode", Some(sym::arm_target_feature)),
 ];
 
 const AARCH64_WHITELIST: &[(&str, Option<Symbol>)] = &[
index 77009aca6d32edb195355c64475a61511db64c5f..5a0da6be5980ed8d1192e63bf7eae7d189df5762 100644 (file)
@@ -70,10 +70,10 @@ fn uncached_llvm_type<'a, 'tcx>(
                     write!(&mut name, "::{}", def.variants[index].ident).unwrap();
                 }
             }
-            if let (&ty::Generator(_, substs, _), &Variants::Single { index })
+            if let (&ty::Generator(_, _, _), &Variants::Single { index })
                  = (&layout.ty.kind, &layout.variants)
             {
-                write!(&mut name, "::{}", substs.as_generator().variant_name(index)).unwrap();
+                write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap();
             }
             Some(name)
         }
index 53e3da3c0baf0bc40c0e111e71c6b23d029d079a..a34029410784ac33efd70849d843fe2cb6984bcc 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
-use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, Sanitizer};
+use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet};
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
@@ -140,7 +140,12 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
 // The third parameter is for env vars, used on windows to set up the
 // path for MSVC to find its DLLs, and gcc to find its bundled
 // toolchain
-fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
+fn get_linker(
+    sess: &Session,
+    linker: &Path,
+    flavor: LinkerFlavor,
+    self_contained: bool,
+) -> Command {
     let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
 
     // If our linker looks like a batch script on Windows then to execute this
@@ -199,7 +204,7 @@ fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
 
     // The compiler's sysroot often has some bundled tools, so add it to the
     // PATH for the child.
-    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
+    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
     let mut msvc_changed_path = false;
     if sess.target.target.options.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
@@ -551,19 +556,25 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
                 "Linker does not support -static-pie command line option. Retrying with -static instead."
             );
             // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
-            let fallback = crt_objects_fallback(sess, crate_type);
+            let self_contained = crt_objects_fallback(sess, crate_type);
             let opts = &sess.target.target.options;
-            let pre_objects =
-                if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
-            let post_objects =
-                if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+            let pre_objects = if self_contained {
+                &opts.pre_link_objects_fallback
+            } else {
+                &opts.pre_link_objects
+            };
+            let post_objects = if self_contained {
+                &opts.post_link_objects_fallback
+            } else {
+                &opts.post_link_objects
+            };
             let get_objects = |objects: &CrtObjects, kind| {
                 objects
                     .get(&kind)
                     .iter()
                     .copied()
                     .flatten()
-                    .map(|obj| get_object_file_path(sess, obj).into_os_string())
+                    .map(|obj| get_object_file_path(sess, obj, self_contained).into_os_string())
                     .collect::<Vec<_>>()
             };
             let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe);
@@ -766,23 +777,26 @@ fn escape_string(s: &[u8]) -> String {
     }
 }
 
-fn link_sanitizer_runtime(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
-    let sanitizer = match &sess.opts.debugging_opts.sanitizer {
-        Some(s) => s,
-        None => return,
-    };
-
+fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
     if crate_type != CrateType::Executable {
         return;
     }
+    let sanitizer = sess.opts.debugging_opts.sanitizer;
+    if sanitizer.contains(SanitizerSet::ADDRESS) {
+        link_sanitizer_runtime(sess, linker, "asan");
+    }
+    if sanitizer.contains(SanitizerSet::LEAK) {
+        link_sanitizer_runtime(sess, linker, "lsan");
+    }
+    if sanitizer.contains(SanitizerSet::MEMORY) {
+        link_sanitizer_runtime(sess, linker, "msan");
+    }
+    if sanitizer.contains(SanitizerSet::THREAD) {
+        link_sanitizer_runtime(sess, linker, "tsan");
+    }
+}
 
-    let name = match sanitizer {
-        Sanitizer::Address => "asan",
-        Sanitizer::Leak => "lsan",
-        Sanitizer::Memory => "msan",
-        Sanitizer::Thread => "tsan",
-    };
-
+fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
     let default_sysroot = filesearch::get_or_default_sysroot();
     let default_tlib =
         filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
@@ -801,7 +815,10 @@ fn link_sanitizer_runtime(sess: &Session, crate_type: CrateType, linker: &mut dy
             linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
             linker.link_dylib(Symbol::intern(&libname));
         }
-        "x86_64-unknown-linux-gnu" | "x86_64-fuchsia" | "aarch64-fuchsia" => {
+        "aarch64-fuchsia"
+        | "aarch64-unknown-linux-gnu"
+        | "x86_64-fuchsia"
+        | "x86_64-unknown-linux-gnu" => {
             let filename = format!("librustc{}_rt.{}.a", channel, name);
             let path = default_tlib.join(&filename);
             linker.link_whole_rlib(&path);
@@ -1060,9 +1077,11 @@ fn probe(sess: &Session) -> Option<PathBuf> {
     }
 }
 
-fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
+fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf {
     // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details
-    if sess.target.target.llvm_target.contains("windows-gnu") {
+    if sess.opts.debugging_opts.link_self_contained.is_none()
+        && sess.target.target.llvm_target.contains("windows-gnu")
+    {
         if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
             let file_path = compiler_libs_path.join(name);
             if file_path.exists() {
@@ -1075,6 +1094,13 @@ fn get_object_file_path(sess: &Session, name: &str) -> PathBuf {
     if file_path.exists() {
         return file_path;
     }
+    // Special directory with objects used only in self-contained linkage mode
+    if self_contained {
+        let file_path = fs.get_self_contained_lib_path().join(name);
+        if file_path.exists() {
+            return file_path;
+        }
+    }
     for search_path in fs.search_paths() {
         let file_path = search_path.dir.join(name);
         if file_path.exists() {
@@ -1258,6 +1284,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
 /// Whether we link to our own CRT objects instead of relying on gcc to pull them.
 /// We only provide such support for a very limited number of targets.
 fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
+    if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained {
+        return self_contained;
+    }
+
     match sess.target.target.options.crt_objects_fallback {
         // FIXME: Find a better heuristic for "native musl toolchain is available",
         // based on host and linker path, for example.
@@ -1277,12 +1307,13 @@ fn add_pre_link_objects(
     cmd: &mut dyn Linker,
     sess: &Session,
     link_output_kind: LinkOutputKind,
-    fallback: bool,
+    self_contained: bool,
 ) {
     let opts = &sess.target.target.options;
-    let objects = if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
+    let objects =
+        if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
-        cmd.add_object(&get_object_file_path(sess, obj));
+        cmd.add_object(&get_object_file_path(sess, obj, self_contained));
     }
 }
 
@@ -1291,12 +1322,13 @@ fn add_post_link_objects(
     cmd: &mut dyn Linker,
     sess: &Session,
     link_output_kind: LinkOutputKind,
-    fallback: bool,
+    self_contained: bool,
 ) {
     let opts = &sess.target.target.options;
-    let objects = if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+    let objects =
+        if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
-        cmd.add_object(&get_object_file_path(sess, obj));
+        cmd.add_object(&get_object_file_path(sess, obj, self_contained));
     }
 }
 
@@ -1458,9 +1490,12 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'
 }
 
 /// Add sysroot and other globally set directories to the directory search list.
-fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
+fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
     // Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details.
-    if cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") {
+    if sess.opts.debugging_opts.link_self_contained.is_none()
+        && cfg!(windows)
+        && sess.target.target.llvm_target.contains("windows-gnu")
+    {
         if let Some(compiler_libs_path) = get_crt_libs_path(sess) {
             cmd.include_path(&compiler_libs_path);
         }
@@ -1470,6 +1505,12 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) {
     // The location of crates will be determined as needed.
     let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
     cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+
+    // Special directory with libraries used only in self-contained linkage mode
+    if self_contained {
+        let lib_path = sess.target_filesearch(PathKind::All).get_self_contained_lib_path();
+        cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+    }
 }
 
 /// Add options making relocation sections in the produced ELF files read-only
@@ -1532,13 +1573,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     codegen_results: &CodegenResults,
     target_cpu: &str,
 ) -> Command {
-    let base_cmd = get_linker(sess, path, flavor);
+    let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
+    let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback);
     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
     // to the linker args construction.
     assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp");
     let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
     let link_output_kind = link_output_kind(sess, crate_type);
-    let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
 
     // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
     add_pre_link_args(cmd, sess, flavor);
@@ -1548,9 +1589,10 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
-        let prefix = match sess.opts.debugging_opts.sanitizer {
-            Some(Sanitizer::Address) => "asan/",
-            _ => "",
+        let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
+            "asan/"
+        } else {
+            ""
         };
         cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
     }
@@ -1574,7 +1616,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     }
 
     // OBJECT-FILES-YES, AUDIT-ORDER
-    link_sanitizer_runtime(sess, crate_type, cmd);
+    link_sanitizers(sess, crate_type, cmd);
 
     // OBJECT-FILES-NO, AUDIT-ORDER
     // Linker plugins should be specified early in the list of arguments
@@ -1583,7 +1625,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     // FIXME: Order-dependent, at least relatively to other args adding searh directories.
-    add_library_search_dirs(cmd, sess);
+    add_library_search_dirs(cmd, sess, crt_objects_fallback);
 
     // OBJECT-FILES-YES
     add_local_crate_regular_objects(cmd, codegen_results);
index b17c36782074881f4dc47afffdb783cf80b5dbdf..d6ef94bfd1727352d154943afa1ef06bbf1510dd 100644 (file)
@@ -1,6 +1,7 @@
 use super::archive;
 use super::command::Command;
 use super::symbol_export;
+use rustc_span::symbol::sym;
 
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, File};
@@ -280,7 +281,7 @@ fn cmd(&mut self) -> &mut Command {
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe => {
-                if !self.is_ld {
+                if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -291,7 +292,7 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path)
             LinkOutputKind::StaticNoPicExe => {
                 // `-static` works for both gcc wrapper and ld.
                 self.cmd.arg("-static");
-                if !self.is_ld {
+                if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -721,12 +722,14 @@ fn link_framework(&mut self, _framework: Symbol) {
     }
 
     fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
-        // not supported?
         self.link_staticlib(lib);
+        self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
     }
     fn link_whole_rlib(&mut self, path: &Path) {
-        // not supported?
         self.link_rlib(path);
+        let mut arg = OsString::from("/WHOLEARCHIVE:");
+        arg.push(path);
+        self.cmd.arg(arg);
     }
     fn optimize(&mut self) {
         // Needs more investigation of `/OPT` arguments
@@ -1034,9 +1037,7 @@ fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a>
         //
         // * `--export=*tls*` - when `#[thread_local]` symbols are used these
         //   symbols are how the TLS segments are initialized and configured.
-        let atomics = sess.opts.cg.target_feature.contains("+atomics")
-            || sess.target.target.options.features.contains("+atomics");
-        if atomics {
+        if sess.target_features.contains(&sym::atomics) {
             cmd.arg("--shared-memory");
             cmd.arg("--max-memory=1073741824");
             cmd.arg("--import-memory");
index 970d13b30c04e28feb7a6ba41fd268627a2d0b1c..217ad57ddc9c399eb70607cbbeb51ec2ef65c5bd 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::{SymbolName, TyCtxt};
-use rustc_session::config::{CrateType, Sanitizer};
+use rustc_session::config::{CrateType, SanitizerSet};
 
 pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
     crates_export_threshold(&tcx.sess.crate_types())
@@ -89,10 +89,12 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
                 | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
                     let def_id = tcx.hir().local_def_id(hir_id);
                     let generics = tcx.generics_of(def_id);
-                    if !generics.requires_monomorphization(tcx) &&
-                        // Functions marked with #[inline] are only ever codegened
-                        // with "internal" linkage and are never exported.
-                        !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
+                    if !generics.requires_monomorphization(tcx)
+                        // Functions marked with #[inline] are codegened with "internal"
+                        // linkage and are not exported unless marked with an extern
+                        // inidicator
+                        && (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
+                            || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator())
                     {
                         Some(def_id)
                     } else {
@@ -202,7 +204,7 @@ fn exported_symbols_provider_local(
         }));
     }
 
-    if let Some(Sanitizer::Memory) = tcx.sess.opts.debugging_opts.sanitizer {
+    if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) {
         // Similar to profiling, preserve weak msan symbol during LTO.
         const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"];
 
index c118e5ebdb72d780d70aea6a90d4cf2feabc509a..23e0b9344ec91c2f0e3e8af4c8606a9694832714 100644 (file)
@@ -29,7 +29,7 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cgu_reuse_tracker::CguReuseTracker;
 use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
-use rustc_session::config::{Passes, Sanitizer, SwitchWithOptPath};
+use rustc_session::config::{Passes, SanitizerSet, SwitchWithOptPath};
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{sym, Symbol};
@@ -86,8 +86,8 @@ pub struct ModuleConfig {
     pub pgo_gen: SwitchWithOptPath,
     pub pgo_use: Option<PathBuf>,
 
-    pub sanitizer: Option<Sanitizer>,
-    pub sanitizer_recover: Vec<Sanitizer>,
+    pub sanitizer: SanitizerSet,
+    pub sanitizer_recover: SanitizerSet,
     pub sanitizer_memory_track_origins: usize,
 
     // Flags indicating which outputs to produce.
@@ -175,6 +175,12 @@ macro_rules! if_regular {
                     if sess.opts.debugging_opts.profile && !is_compiler_builtins {
                         passes.push("insert-gcov-profiling".to_owned());
                     }
+
+                    // The rustc option `-Zinstrument_coverage` injects intrinsic calls to
+                    // `llvm.instrprof.increment()`, which requires the LLVM `instrprof` pass.
+                    if sess.opts.debugging_opts.instrument_coverage {
+                        passes.push("instrprof".to_owned());
+                    }
                     passes
                 },
                 vec![]
@@ -189,10 +195,10 @@ macro_rules! if_regular {
             ),
             pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None),
 
-            sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer.clone(), None),
+            sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer, SanitizerSet::empty()),
             sanitizer_recover: if_regular!(
-                sess.opts.debugging_opts.sanitizer_recover.clone(),
-                vec![]
+                sess.opts.debugging_opts.sanitizer_recover,
+                SanitizerSet::empty()
             ),
             sanitizer_memory_track_origins: if_regular!(
                 sess.opts.debugging_opts.sanitizer_memory_track_origins,
index 0d0321ec4ae5e5099189a959a3acbb86b8e91adb..432b2f3bdc3c174987221d051dde6c616d2f8be3 100644 (file)
@@ -98,6 +98,8 @@ pub enum TypeKind {
     Metadata,
     X86_MMX,
     Token,
+    ScalableVector,
+    BFloat,
 }
 
 // FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
index 57a3d8b5edcafc0b30f47061ef1a5a69d0361794..a64489c04c81dc4e07df0656f11415f4c42b2060 100644 (file)
@@ -195,7 +195,7 @@ pub fn push_debuginfo_type_name<'tcx>(
                 tcx.def_key(def_id).disambiguated_data.disambiguator
             ));
         }
-        ty::Error
+        ty::Error(_)
         | ty::Infer(_)
         | ty::Placeholder(..)
         | ty::Projection(..)
index 61692280d2a775e3ef4b4a271a9a9c33eaf936af..db935c2b3e2658a027ba7525da21a38e90146a44 100644 (file)
@@ -234,8 +234,8 @@ fn visit_assign(
         self.visit_rvalue(rvalue, location);
     }
 
-    fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
-        let check = match *kind {
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
+        let check = match terminator.kind {
             mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
                 match c.literal.ty.kind {
                     ty::FnDef(did, _) => Some((did, args)),
@@ -259,7 +259,7 @@ fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location:
             }
         }
 
-        self.super_terminator_kind(kind, location);
+        self.super_terminator(terminator, location);
     }
 
     fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
index ef59ad486eefe5fa12be6cebef0f19de2fc282a1..480f9a5032087ad5d54249f4c1a49ca2dbb382ae 100644 (file)
@@ -200,6 +200,8 @@ fn codegen_switchint_terminator(
         targets: &Vec<mir::BasicBlock>,
     ) {
         let discr = self.codegen_operand(&mut bx, &discr);
+        // `switch_ty` is redundant, sanity-check that.
+        assert_eq!(discr.layout.ty, switch_ty);
         if targets.len() == 2 {
             // If there are two targets, emit br instead of switch
             let lltrue = helper.llblock(self, targets[0]);
@@ -378,7 +380,7 @@ fn codegen_assert_terminator(
         // checked operation, just a comparison with the minimum
         // value, so we have to check for the assert message.
         if !bx.check_overflow() {
-            if let AssertKind::OverflowNeg = *msg {
+            if let AssertKind::OverflowNeg(_) = *msg {
                 const_cond = Some(expected);
             }
         }
@@ -693,6 +695,7 @@ fn codegen_call_terminator(
                 &args,
                 dest,
                 terminator.source_info.span,
+                self.instance,
             );
 
             if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
@@ -998,8 +1001,8 @@ fn codegen_terminator(
                 bx.unreachable();
             }
 
-            mir::TerminatorKind::Drop { location, target, unwind } => {
-                self.codegen_drop_terminator(helper, bx, location, target, unwind);
+            mir::TerminatorKind::Drop { place, target, unwind } => {
+                self.codegen_drop_terminator(helper, bx, place, target, unwind);
             }
 
             mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => {
index 2be0679382900650e9494f3f5e71a77eeacb9f4a..0c8638b673d4fbdab5269a40588e22b2d458ba34 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape, Int};
+use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
 use rustc_target::abi::{LayoutOf, VariantIdx, Variants};
 
 #[derive(Copy, Clone, Debug)]
@@ -199,7 +199,7 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         if self.layout.abi.is_uninhabited() {
             return bx.cx().const_undef(cast_to);
         }
-        let (discr_scalar, discr_kind, discr_index) = match self.layout.variants {
+        let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
             Variants::Single { index } => {
                 let discr_val = self
                     .layout
@@ -208,33 +208,33 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                     .map_or(index.as_u32() as u128, |discr| discr.val);
                 return bx.cx().const_uint_big(cast_to, discr_val);
             }
-            Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
-                (discr, discr_kind, discr_index)
+            Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+                (tag, tag_encoding, tag_field)
             }
         };
 
         // Read the tag/niche-encoded discriminant from memory.
-        let encoded_discr = self.project_field(bx, discr_index);
-        let encoded_discr = bx.load_operand(encoded_discr);
+        let tag = self.project_field(bx, tag_field);
+        let tag = bx.load_operand(tag);
 
         // Decode the discriminant (specifically if it's niche-encoded).
-        match *discr_kind {
-            DiscriminantKind::Tag => {
-                let signed = match discr_scalar.value {
+        match *tag_encoding {
+            TagEncoding::Direct => {
+                let signed = match tag_scalar.value {
                     // We use `i1` for bytes that are always `0` or `1`,
                     // e.g., `#[repr(i8)] enum E { A, B }`, but we can't
                     // let LLVM interpret the `i1` as signed, because
                     // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`.
-                    Int(_, signed) => !discr_scalar.is_bool() && signed,
+                    Int(_, signed) => !tag_scalar.is_bool() && signed,
                     _ => false,
                 };
-                bx.intcast(encoded_discr.immediate(), cast_to, signed)
+                bx.intcast(tag.immediate(), cast_to, signed)
             }
-            DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
+            TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
                 // Rebase from niche values to discriminants, and check
                 // whether the result is in range for the niche variants.
-                let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout);
-                let encoded_discr = encoded_discr.immediate();
+                let niche_llty = bx.cx().immediate_backend_type(tag.layout);
+                let tag = tag.immediate();
 
                 // We first compute the "relative discriminant" (wrt `niche_variants`),
                 // that is, if `n = niche_variants.end() - niche_variants.start()`,
@@ -248,9 +248,9 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 let relative_discr = if niche_start == 0 {
                     // Avoid subtracting `0`, which wouldn't work for pointers.
                     // FIXME(eddyb) check the actual primitive type here.
-                    encoded_discr
+                    tag
                 } else {
-                    bx.sub(encoded_discr, bx.cx().const_uint_big(niche_llty, niche_start))
+                    bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
                 };
                 let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
                 let is_niche = {
@@ -312,8 +312,8 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
             Variants::Single { index } => {
                 assert_eq!(index, variant_index);
             }
-            Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => {
-                let ptr = self.project_field(bx, discr_index);
+            Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
+                let ptr = self.project_field(bx, tag_field);
                 let to =
                     self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val;
                 bx.store(
@@ -323,9 +323,9 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                 );
             }
             Variants::Multiple {
-                discr_kind:
-                    DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
-                discr_index,
+                tag_encoding:
+                    TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+                tag_field,
                 ..
             } => {
                 if variant_index != dataful_variant {
@@ -339,7 +339,7 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
                         bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty());
                     }
 
-                    let niche = self.project_field(bx, discr_index);
+                    let niche = self.project_field(bx, tag_field);
                     let niche_llty = bx.cx().immediate_backend_type(niche.layout);
                     let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                     let niche_value = (niche_value as u128).wrapping_add(niche_start);
index caba7ebef593b3897dc355125d6b4776eec87af1..7ffc9f15bffdc59fb6d529834ab7244b1fee5c06 100644 (file)
@@ -260,6 +260,14 @@ fn atomic_rmw(
     /// Called for `StorageDead`
     fn lifetime_end(&mut self, ptr: Self::Value, size: Size);
 
+    fn instrprof_increment(
+        &mut self,
+        fn_name: Self::Value,
+        hash: Self::Value,
+        num_counters: Self::Value,
+        index: Self::Value,
+    ) -> Self::Value;
+
     fn call(
         &mut self,
         llfn: Self::Value,
index 9d48e233de6558f251629bdf04641277ebfd61ff..f62019498511c48c166b9280c277948444965811 100644 (file)
@@ -15,6 +15,7 @@ fn codegen_intrinsic_call(
         args: &[OperandRef<'tcx, Self::Value>],
         llresult: Self::Value,
         span: Span,
+        caller_instance: ty::Instance<'tcx>,
     );
 
     fn abort(&mut self);
index 703479b74bef8a9d9514a8e1c3fb4ddf24a46a6f..c55bf9858b972450c4cd607ee630221dacb23f38 100644 (file)
@@ -74,7 +74,7 @@ fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
     }
 
     fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all(), DUMMY_SP)
+        ty.is_freeze(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
     }
 
     fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
index bf2ab0787cb7073bbabeebe0deb8de1dbf8047b2..1c2fb90b2d8b47da9f92ee54dee4451087dbd383 100644 (file)
@@ -23,7 +23,7 @@ crossbeam-utils = { version = "0.7", features = ["nightly"] }
 stable_deref_trait = "1.0.0"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
 rayon-core = { version = "0.3.0", package = "rustc-rayon-core" }
-rustc-hash = "1.0.1"
+rustc-hash = "1.1.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_index = { path = "../librustc_index", package = "rustc_index" }
 bitflags = "1.2.1"
index 39afb3d82ff5aae9ef943718051b9709ff5229c5..53d831749ceb7b401a66008222d301f96dcbed7c 100644 (file)
@@ -358,7 +358,6 @@ pub fn lock_mut(&self) -> LockGuard<'_, T> {
         use parking_lot::Mutex as InnerLock;
         use parking_lot::RwLock as InnerRwLock;
 
-        use std;
         use std::thread;
         pub use rayon::{join, scope};
 
index ccea041699ee18c6ff85acef69d34c94c5e7c739..b45ab0f80ffac4a4cd2c4b3b1c4068d3b0b32a26 100644 (file)
@@ -307,6 +307,7 @@ pub fn run_compiler(
                         compiler.output_file().as_ref().map(|p| &**p),
                     );
                 }
+                trace!("finished pretty-printing");
                 return early_exit();
             }
 
index 3fb5e04efc9227953ea9efd18215fc8aac0dc11c..162585360fbda823b2853314af66a460ae46a4d8 100644 (file)
 E0753: include_str!("./error_codes/E0753.md"),
 E0754: include_str!("./error_codes/E0754.md"),
 E0758: include_str!("./error_codes/E0758.md"),
+E0759: include_str!("./error_codes/E0759.md"),
 E0760: include_str!("./error_codes/E0760.md"),
 E0761: include_str!("./error_codes/E0761.md"),
 E0762: include_str!("./error_codes/E0762.md"),
+E0763: include_str!("./error_codes/E0763.md"),
+E0764: include_str!("./error_codes/E0764.md"),
+E0765: include_str!("./error_codes/E0765.md"),
+E0766: include_str!("./error_codes/E0766.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
index fd5eca68e21fd5dc24be35b92c4fa4fccd0b2765..b834a734cefc447202d5a0dd2b64636f98fdf637 100644 (file)
@@ -1,4 +1,4 @@
-A discrimant value is present more than once.
+A discriminant value is present more than once.
 
 Erroneous code example:
 
index 3b43a1bcae9e6003ecee6c8a40562e83e6af166b..b6fedfe53fce8ad44656ea4027f0168ae7eca780 100644 (file)
@@ -1,11 +1,7 @@
 Malformed inline assembly rejected by LLVM.
 
-LLVM checks the validity of the constraints and the assembly string passed to
-it. This error implies that LLVM seems something wrong with the inline
-assembly call.
+Erroneous code example:
 
-In particular, it can happen if you forgot the closing bracket of a register
-constraint (see issue #51430):
 ```compile_fail,E0668
 #![feature(llvm_asm)]
 
@@ -17,3 +13,10 @@ fn main() {
     }
 }
 ```
+
+LLVM checks the validity of the constraints and the assembly string passed to
+it. This error implies that LLVM seems something wrong with the inline
+assembly call.
+
+In particular, it can happen if you forgot the closing bracket of a register
+constraint (see issue #51430), like in the previous code example.
index 2026370bec3b8717a7bb8fdd4951b6ba3e296fee..74c1af06cf4ec6e48369905b79d671d1dbc2114a 100644 (file)
@@ -1,6 +1,6 @@
 Rust 2015 does not permit the use of `async fn`.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0670
 async fn foo() {}
index 26c2c15ccfaac41ea54d3ae63e115663b6246ea3..a680a204211274212a15939fa4324e8629fd45e3 100644 (file)
@@ -1,13 +1,16 @@
-This error indicates that the numeric value for the method being passed exists
-but the type of the numeric value or binding could not be identified.
+A method was called on an ambiguous numeric type.
 
-The error happens on numeric literals:
+Erroneous code example:
 
 ```compile_fail,E0689
-2.0.neg();
+2.0.neg(); // error!
 ```
 
-and on numeric bindings without an identified concrete type:
+This error indicates that the numeric value for the method being passed exists
+but the type of the numeric value or binding could not be identified.
+
+The error happens on numeric literals and on numeric bindings without an
+identified concrete type:
 
 ```compile_fail,E0689
 let x = 2.0;
@@ -19,8 +22,8 @@ Because of this, you must give the numeric literal or binding a type:
 ```
 use std::ops::Neg;
 
-let _ = 2.0_f32.neg();
+let _ = 2.0_f32.neg(); // ok!
 let x: f32 = 2.0;
-let _ = x.neg();
-let _ = (2.0 as f32).neg();
+let _ = x.neg(); // ok!
+let _ = (2.0 as f32).neg(); // ok!
 ```
index 208f7f4c7b16581306da54e0675e509d167be01a..5013e83ca03620d0a5ec6a6f19433bcd42559483 100644 (file)
@@ -1,6 +1,6 @@
 A `break` statement without a label appeared inside a labeled block.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0695
 # #![feature(label_break_value)]
index f90fd3b562469edd4420eb9a75e86e9f01b866ef..454d2507e5e2e2bf677d95a1c8f278f2e6f7686f 100644 (file)
@@ -1,14 +1,16 @@
 A method was called on a raw pointer whose inner type wasn't completely known.
 
-For example, you may have done something like:
+Erroneous code example:
 
-```compile_fail
+```compile_fail,edition2018,E0699
 # #![deny(warnings)]
+# fn main() {
 let foo = &1;
 let bar = foo as *const _;
 if bar.is_null() {
     // ...
 }
+# }
 ```
 
 Here, the type of `bar` isn't known; it could be a pointer to anything. Instead,
index 87f416ada1803a38b1900280f8f76ff176a297ec..4965e64310591f332beaeff4a8643434b07a88d4 100644 (file)
@@ -1,7 +1,7 @@
 This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed
 on something other than a struct or enum.
 
-Examples of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0701
 #[non_exhaustive]
diff --git a/src/librustc_error_codes/error_codes/E0759.md b/src/librustc_error_codes/error_codes/E0759.md
new file mode 100644 (file)
index 0000000..a74759b
--- /dev/null
@@ -0,0 +1,67 @@
+A `'static` requirement in a return type involving a trait is not fulfilled.
+
+Erroneous code examples:
+
+```compile_fail,E0759
+use std::fmt::Debug;
+
+fn foo(x: &i32) -> impl Debug {
+    x
+}
+```
+
+```compile_fail,E0759
+# use std::fmt::Debug;
+fn bar(x: &i32) -> Box<dyn Debug> {
+    Box::new(x)
+}
+```
+
+These examples have the same semantics as the following:
+
+```compile_fail,E0759
+# use std::fmt::Debug;
+fn foo(x: &i32) -> impl Debug + 'static {
+    x
+}
+```
+
+```compile_fail,E0759
+# use std::fmt::Debug;
+fn bar(x: &i32) -> Box<dyn Debug + 'static> {
+    Box::new(x)
+}
+```
+
+Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit
+`'static` requirement, meaning that the value implementing them that is being
+returned has to be either a `'static` borrow or an owned value.
+
+In order to change the requirement from `'static` to be a lifetime derived from
+its arguments, you can add an explicit bound, either to an anonymous lifetime
+`'_` or some appropriate named lifetime.
+
+```
+# use std::fmt::Debug;
+fn foo(x: &i32) -> impl Debug + '_ {
+    x
+}
+fn bar(x: &i32) -> Box<dyn Debug + '_> {
+    Box::new(x)
+}
+```
+
+These are equivalent to the following explicit lifetime annotations:
+
+```
+# use std::fmt::Debug;
+fn foo<'a>(x: &'a i32) -> impl Debug + 'a {
+    x
+}
+fn bar<'a>(x: &'a i32) -> Box<dyn Debug + 'a> {
+    Box::new(x)
+}
+```
+
+[`dyn Trait`]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types
+[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits
diff --git a/src/librustc_error_codes/error_codes/E0763.md b/src/librustc_error_codes/error_codes/E0763.md
new file mode 100644 (file)
index 0000000..095b779
--- /dev/null
@@ -0,0 +1,13 @@
+A byte constant wasn't correctly ended.
+
+Erroneous code example:
+
+```compile_fail,E0763
+let c = b'a; // error!
+```
+
+To fix this error, add the missing quote:
+
+```
+let c = b'a'; // ok!
+```
diff --git a/src/librustc_error_codes/error_codes/E0764.md b/src/librustc_error_codes/error_codes/E0764.md
new file mode 100644 (file)
index 0000000..e9061f9
--- /dev/null
@@ -0,0 +1,39 @@
+Mutable references (`&mut`) can only be used in constant functions, not statics
+or constants. This limitation exists to prevent the creation of constants that
+have a mutable reference in their final value. If you had a constant of `&mut
+i32` type, you could modify the value through that reference, making the
+constant essentially mutable. While there could be a more fine-grained scheme
+in the future that allows mutable references if they are not "leaked" to the
+final value, a more conservative approach was chosen for now. `const fn` do not
+have this problem, as the borrow checker will prevent the `const fn` from
+returning new mutable references.
+
+Erroneous code example:
+
+```compile_fail,E0764
+#![feature(const_fn)]
+#![feature(const_mut_refs)]
+
+fn main() {
+    const OH_NO: &'static mut usize = &mut 1; // error!
+}
+```
+
+Remember: you cannot use a function call inside a constant or static. However,
+you can totally use it in constant functions:
+
+```
+#![feature(const_fn)]
+#![feature(const_mut_refs)]
+
+const fn foo(x: usize) -> usize {
+    let mut y = 1;
+    let z = &mut y;
+    *z += x;
+    y
+}
+
+fn main() {
+    const FOO: usize = foo(10); // ok!
+}
+```
diff --git a/src/librustc_error_codes/error_codes/E0765.md b/src/librustc_error_codes/error_codes/E0765.md
new file mode 100644 (file)
index 0000000..456e3f3
--- /dev/null
@@ -0,0 +1,13 @@
+A double quote string (`"`) was not terminated.
+
+Erroneous code example:
+
+```compile_fail,E0765
+let s = "; // error!
+```
+
+To fix this error, add the missing double quote at the end of the string:
+
+```
+let s = ""; // ok!
+```
diff --git a/src/librustc_error_codes/error_codes/E0766.md b/src/librustc_error_codes/error_codes/E0766.md
new file mode 100644 (file)
index 0000000..4e775df
--- /dev/null
@@ -0,0 +1,13 @@
+A double quote byte string (`b"`) was not terminated.
+
+Erroneous code example:
+
+```compile_fail,E0766
+let s = b"; // error!
+```
+
+To fix this error, add the missing double quote at the end of the string:
+
+```
+let s = b""; // ok!
+```
index b22da86c091877ae80c6b2672f05e8ab800680bf..1362a1155bcdd358e68573809147005fe47d2b6d 100644 (file)
@@ -31,6 +31,9 @@
 use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream};
 use termcolor::{Buffer, Color, WriteColor};
 
+/// Default column width, used in tests and when terminal dimensions cannot be determined.
+const DEFAULT_COLUMN_WIDTH: usize = 140;
+
 /// Describes the way the content of the `rendered` field of the json output is generated
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum HumanReadableErrorType {
@@ -74,7 +77,8 @@ struct Margin {
     pub computed_left: usize,
     /// The end of the line to be displayed.
     pub computed_right: usize,
-    /// The current width of the terminal. 140 by default and in tests.
+    /// The current width of the terminal. Uses value of `DEFAULT_COLUMN_WIDTH` constant by default
+    /// and in tests.
     pub column_width: usize,
     /// The end column of a span label, including the span. Doesn't account for labels not in the
     /// same line as the span.
@@ -1414,11 +1418,11 @@ fn emit_message_default(
                 let column_width = if let Some(width) = self.terminal_width {
                     width.saturating_sub(code_offset)
                 } else if self.ui_testing {
-                    140
+                    DEFAULT_COLUMN_WIDTH
                 } else {
                     termize::dimensions()
                         .map(|(w, _)| w.saturating_sub(code_offset))
-                        .unwrap_or(usize::MAX)
+                        .unwrap_or(DEFAULT_COLUMN_WIDTH)
                 };
 
                 let margin = Margin::new(
index 1382825922b0edff9bc5526337fc70d5c5ec4bfd..24186198fd2b15b11c1d8ccd7e9b04b8347a6ebb 100644 (file)
@@ -36,6 +36,7 @@ pub struct JsonEmitter {
     pretty: bool,
     ui_testing: bool,
     json_rendered: HumanReadableErrorType,
+    terminal_width: Option<usize>,
     macro_backtrace: bool,
 }
 
@@ -45,6 +46,7 @@ pub fn stderr(
         source_map: Lrc<SourceMap>,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        terminal_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
@@ -54,6 +56,7 @@ pub fn stderr(
             pretty,
             ui_testing: false,
             json_rendered,
+            terminal_width,
             macro_backtrace,
         }
     }
@@ -61,6 +64,7 @@ pub fn stderr(
     pub fn basic(
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        terminal_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
@@ -69,6 +73,7 @@ pub fn basic(
             Lrc::new(SourceMap::new(file_path_mapping)),
             pretty,
             json_rendered,
+            terminal_width,
             macro_backtrace,
         )
     }
@@ -79,6 +84,7 @@ pub fn new(
         source_map: Lrc<SourceMap>,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
+        terminal_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
@@ -88,6 +94,7 @@ pub fn new(
             pretty,
             ui_testing: false,
             json_rendered,
+            terminal_width,
             macro_backtrace,
         }
     }
@@ -247,7 +254,13 @@ fn flush(&mut self) -> io::Result<()> {
         let buf = BufWriter::default();
         let output = buf.clone();
         je.json_rendered
-            .new_emitter(Box::new(buf), Some(je.sm.clone()), false, None, je.macro_backtrace)
+            .new_emitter(
+                Box::new(buf),
+                Some(je.sm.clone()),
+                false,
+                je.terminal_width,
+                je.macro_backtrace,
+            )
             .ui_testing(je.ui_testing)
             .emit_diagnostic(diag);
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
index 7261c638ce013985ebda6b92aa7dcf640ec4a56b..0c1418d3cad279ebe8d806b3dd9d62af87d1d6fe 100644 (file)
@@ -5,6 +5,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(crate_visibility_modifier)]
 #![feature(nll)]
+#![feature(track_caller)]
 
 pub use emitter::ColorConfig;
 
@@ -621,6 +622,7 @@ pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
         self.inner.borrow_mut().span_bug(span, msg)
     }
 
+    #[track_caller]
     pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
         self.inner.borrow_mut().delay_span_bug(span, msg)
     }
@@ -873,6 +875,7 @@ fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>)
         self.emit_diagnostic(diag.set_span(sp));
     }
 
+    #[track_caller]
     fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
         // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
         // incrementing `err_count` by one, so we need to +1 the comparing.
@@ -883,6 +886,7 @@ fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
         }
         let mut diagnostic = Diagnostic::new(Level::Bug, msg);
         diagnostic.set_span(sp.into());
+        diagnostic.note(&format!("delayed at {}", std::panic::Location::caller()));
         self.delay_as_bug(diagnostic)
     }
 
index a57ae798ffcebf34fe6d8bd87ac776c05f195105..757eee8bb46e1a2593793da6d37c08753a15dde5 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_ast::ast::{self, Attribute, NodeId, PatKind};
 use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::ptr::P;
-use rustc_ast::token;
+use rustc_ast::token::{self, FlattenGroup};
 use rustc_ast::tokenstream::{self, TokenStream, TokenTree};
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
@@ -142,7 +142,7 @@ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
             | Annotatable::StructField(..)
             | Annotatable::Variant(..) => panic!("unexpected annotatable"),
         };
-        TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into()
+        TokenTree::token(token::Interpolated(Lrc::new(nt), FlattenGroup::Yes), DUMMY_SP).into()
     }
 
     pub fn expect_item(self) -> P<ast::Item> {
@@ -374,7 +374,7 @@ fn expand<'cx>(
         impl MutVisitor for AvoidInterpolatedIdents {
             fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) {
                 if let tokenstream::TokenTree::Token(token) = tt {
-                    if let token::Interpolated(nt) = &token.kind {
+                    if let token::Interpolated(nt, _) = &token.kind {
                         if let token::NtIdent(ident, is_raw) = **nt {
                             *tt = tokenstream::TokenTree::token(
                                 token::Ident(ident.name, is_raw),
@@ -889,7 +889,7 @@ pub enum InvocationRes {
 /// Error type that denotes indeterminacy.
 pub struct Indeterminate;
 
-pub trait Resolver {
+pub trait ResolverExpand {
     fn next_node_id(&mut self) -> NodeId;
 
     fn resolve_dollar_crates(&mut self);
@@ -946,7 +946,7 @@ pub struct ExtCtxt<'a> {
     pub ecfg: expand::ExpansionConfig<'a>,
     pub reduced_recursion_limit: Option<Limit>,
     pub root_path: PathBuf,
-    pub resolver: &'a mut dyn Resolver,
+    pub resolver: &'a mut dyn ResolverExpand,
     pub current_expansion: ExpansionData,
     pub expansions: FxHashMap<Span, Vec<String>>,
     /// Called directly after having parsed an external `mod foo;` in expansion.
@@ -957,7 +957,7 @@ impl<'a> ExtCtxt<'a> {
     pub fn new(
         parse_sess: &'a ParseSess,
         ecfg: expand::ExpansionConfig<'a>,
-        resolver: &'a mut dyn Resolver,
+        resolver: &'a mut dyn ResolverExpand,
         extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
     ) -> ExtCtxt<'a> {
         ExtCtxt {
index db8258a77863b8c3d3043fa656dd8267f2decdfe..c90a438c25eceda37151a02b1ce4dfa928380f25 100644 (file)
@@ -785,12 +785,12 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
         sym::literal => token.can_begin_literal_maybe_minus(),
         sym::vis => match token.kind {
             // The follow-set of :vis + "priv" keyword + interpolated
-            token::Comma | token::Ident(..) | token::Interpolated(_) => true,
+            token::Comma | token::Ident(..) | token::Interpolated(..) => true,
             _ => token.can_begin_type(),
         },
         sym::block => match token.kind {
             token::OpenDelim(token::Brace) => true,
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt, _) => match **nt {
                 token::NtItem(_)
                 | token::NtPat(_)
                 | token::NtTy(_)
@@ -804,7 +804,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
         },
         sym::path | sym::meta => match token.kind {
             token::ModSep | token::Ident(..) => true,
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt, _) => match **nt {
                 token::NtPath(_) | token::NtMeta(_) => true,
                 _ => may_be_ident(&nt),
             },
@@ -823,12 +823,12 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
             token::ModSep |                     // path
             token::Lt |                         // path (UFCS constant)
             token::BinOp(token::Shl) => true,   // path (double UFCS)
-            token::Interpolated(ref nt) => may_be_ident(nt),
+            token::Interpolated(ref nt, _) => may_be_ident(nt),
             _ => false,
         },
         sym::lifetime => match token.kind {
             token::Lifetime(_) => true,
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt, _) => match **nt {
                 token::NtLifetime(_) | token::NtTT(_) => true,
                 _ => false,
             },
@@ -866,10 +866,23 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Result<Nonterminal, (
 }
 
 fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a, Nonterminal> {
+    // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
+    // needs to have them force-captured here.
+    // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
+    // which requires having captured tokens available. Since we cannot determine
+    // in advance whether or not a proc-macro will be (transitively) invoked,
+    // we always capture tokens for any `Nonterminal` which needs them.
     Ok(match name {
-        sym::item => match p.parse_item()? {
-            Some(i) => token::NtItem(i),
-            None => return Err(p.struct_span_err(p.token.span, "expected an item keyword")),
+        sym::item => match p.collect_tokens(|this| this.parse_item())? {
+            (Some(mut item), tokens) => {
+                // If we captured tokens during parsing (due to outer attributes),
+                // use those.
+                if item.tokens.is_none() {
+                    item.tokens = Some(tokens);
+                }
+                token::NtItem(item)
+            }
+            (None, _) => return Err(p.struct_span_err(p.token.span, "expected an item keyword")),
         },
         sym::block => token::NtBlock(p.parse_block()?),
         sym::stmt => match p.parse_stmt()? {
@@ -877,7 +890,15 @@ fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a,
             None => return Err(p.struct_span_err(p.token.span, "expected a statement")),
         },
         sym::pat => token::NtPat(p.parse_pat(None)?),
-        sym::expr => token::NtExpr(p.parse_expr()?),
+        sym::expr => {
+            let (mut expr, tokens) = p.collect_tokens(|this| this.parse_expr())?;
+            // If we captured tokens during parsing (due to outer attributes),
+            // use those.
+            if expr.tokens.is_none() {
+                expr.tokens = Some(tokens);
+            }
+            token::NtExpr(expr)
+        }
         sym::literal => token::NtLiteral(p.parse_literal_maybe_minus()?),
         sym::ty => token::NtTy(p.parse_ty()?),
         // this could be handled like a token, since it is one
index e2d3d5c4d644e04076ac1fbb31ac672bdfa7f29e..486f0a6420d6e1c7e172bb6229a754975adbe35d 100644 (file)
@@ -4,7 +4,7 @@
 
 use rustc_ast::ast::MacCall;
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::{self, NtTT, Token};
+use rustc_ast::token::{self, FlattenGroup, NtTT, Token};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
@@ -240,7 +240,10 @@ pub(super) fn transcribe<'a>(
                             result.push(tt.clone().into());
                         } else {
                             marker.visit_span(&mut sp);
-                            let token = TokenTree::token(token::Interpolated(nt.clone()), sp);
+                            let token = TokenTree::token(
+                                token::Interpolated(nt.clone(), FlattenGroup::No),
+                                sp,
+                            );
                             result.push(token.into());
                         }
                     } else {
index df7bf9438c3d03c2d175105b4b88175506c0b74e..1e26c832a2621c0416e5fb90279c832a3bab0bc6 100644 (file)
@@ -2,7 +2,7 @@
 use crate::proc_macro_server;
 
 use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
-use rustc_ast::token;
+use rustc_ast::token::{self, FlattenGroup};
 use rustc_ast::tokenstream::{self, TokenStream};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, ErrorReported};
@@ -102,7 +102,7 @@ fn expand(
             }
         }
 
-        let token = token::Interpolated(Lrc::new(token::NtItem(item)));
+        let token = token::Interpolated(Lrc::new(token::NtItem(item)), FlattenGroup::Yes);
         let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
 
         let server = proc_macro_server::Rustc::new(ecx);
index ea55674045c0f73ed49019ffa94c4693a29c6a58..c88b5a37f718a0f5db4a838963946405ac277888 100644 (file)
@@ -1,7 +1,7 @@
 use crate::base::ExtCtxt;
 
 use rustc_ast::ast;
-use rustc_ast::token;
+use rustc_ast::token::{self, FlattenGroup};
 use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
 use rustc_ast::util::comments;
 use rustc_ast_pretty::pprust;
@@ -60,7 +60,12 @@ fn from_internal(
         let Token { kind, span } = match tree {
             tokenstream::TokenTree::Delimited(span, delim, tts) => {
                 let delimiter = Delimiter::from_internal(delim);
-                return TokenTree::Group(Group { delimiter, stream: tts, span });
+                return TokenTree::Group(Group {
+                    delimiter,
+                    stream: tts,
+                    span,
+                    flatten: FlattenGroup::No,
+                });
             }
             tokenstream::TokenTree::Token(token) => token,
         };
@@ -167,6 +172,7 @@ macro_rules! op {
                     delimiter: Delimiter::Bracket,
                     stream,
                     span: DelimSpan::from_single(span),
+                    flatten: FlattenGroup::No,
                 }));
                 if style == ast::AttrStyle::Inner {
                     stack.push(tt!(Punct::new('!', false)));
@@ -174,12 +180,13 @@ macro_rules! op {
                 tt!(Punct::new('#', false))
             }
 
-            Interpolated(nt) => {
+            Interpolated(nt, flatten) => {
                 let stream = nt_to_tokenstream(&nt, sess, span);
                 TokenTree::Group(Group {
                     delimiter: Delimiter::None,
                     stream,
                     span: DelimSpan::from_single(span),
+                    flatten,
                 })
             }
 
@@ -195,7 +202,7 @@ fn to_internal(self) -> TokenStream {
 
         let (ch, joint, span) = match self {
             TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
-            TokenTree::Group(Group { delimiter, stream, span }) => {
+            TokenTree::Group(Group { delimiter, stream, span, .. }) => {
                 return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream)
                     .into();
             }
@@ -283,6 +290,10 @@ pub struct Group {
     delimiter: Delimiter,
     stream: TokenStream,
     span: DelimSpan,
+    /// A hack used to pass AST fragments to attribute and derive macros
+    /// as a single nonterminal token instead of a token stream.
+    /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
+    flatten: FlattenGroup,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -437,14 +448,12 @@ fn next(
                 let next = iter.cursor.next_with_joint()?;
                 Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
             })?;
-            // HACK: The condition "dummy span + group with empty delimiter" represents an AST
-            // fragment approximately converted into a token stream. This may happen, for
-            // example, with inputs to proc macro attributes, including derives. Such "groups"
-            // need to flattened during iteration over stream's token trees.
-            // Eventually this needs to be removed in favor of keeping original token trees
-            // and not doing the roundtrip through AST.
+            // A hack used to pass AST fragments to attribute and derive macros
+            // as a single nonterminal token instead of a token stream.
+            // Such token needs to be "unwrapped" and not represented as a delimited group.
+            // FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
             if let TokenTree::Group(ref group) = tree {
-                if group.delimiter == Delimiter::None && group.span.entire().is_dummy() {
+                if matches!(group.flatten, FlattenGroup::Yes) {
                     iter.cursor.append(group.stream.clone());
                     continue;
                 }
@@ -456,7 +465,12 @@ fn next(
 
 impl server::Group for Rustc<'_> {
     fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
-        Group { delimiter, stream, span: DelimSpan::from_single(server::Span::call_site(self)) }
+        Group {
+            delimiter,
+            stream,
+            span: DelimSpan::from_single(server::Span::call_site(self)),
+            flatten: FlattenGroup::No,
+        }
     }
     fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
         group.delimiter
index 18dc3e30db1d4727b97dedb15d470da5017b29e5..b164b21913d6e7361a9ff0c356ce178129391e28 100644 (file)
@@ -261,6 +261,10 @@ macro_rules! declare_features {
     (accepted, transparent_enums, "1.42.0", Some(60405), None),
     /// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
     (accepted, slice_patterns, "1.42.0", Some(62254), None),
+    /// Allows the use of `if` and `match` in constants.
+    (accepted, const_if_match, "1.45.0", Some(49146), None),
+    /// Allows the use of `loop` and `while` in constants.
+    (accepted, const_loop, "1.45.0", Some(52000), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index d186f35a12b5a1f9566ea39b2aa4e05a532af4d0..8660d6a8d64105aacffc69392eb6b579c213e611 100644 (file)
@@ -401,9 +401,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows dereferencing raw pointers during const eval.
     (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
 
-    /// Allows comparing raw pointers during const eval.
-    (active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
-
     /// Allows `#[doc(alias = "...")]`.
     (active, doc_alias, "1.27.0", Some(50146), None),
 
@@ -521,9 +518,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows using the `#[register_tool]` attribute.
     (active, register_tool, "1.41.0", Some(66079), None),
 
-    /// Allows the use of `if` and `match` in constants.
-    (active, const_if_match, "1.41.0", Some(49146), None),
-
     /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
     (active, cfg_sanitize, "1.41.0", Some(39699), None),
 
@@ -533,9 +527,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows using `&mut` in constant functions.
     (active, const_mut_refs, "1.41.0", Some(57349), None),
 
-    /// Allows the use of `loop` and `while` in constants.
-    (active, const_loop, "1.41.0", Some(52000), None),
-
     /// Allows bindings in the subpattern of a binding pattern.
     /// For example, you can write `x @ Some(y)`.
     (active, bindings_after_at, "1.41.0", Some(65490), None),
@@ -596,4 +587,5 @@ pub fn set(&self, features: &mut Features, span: Span) {
     sym::raw_dylib,
     sym::const_trait_impl,
     sym::const_trait_bound_opt_out,
+    sym::specialization,
 ];
index 4e348054fbd4b1eea17226fc15275bd120f85cfe..8d410894e8b190083028dac2ac8acdc394ab1f23 100644 (file)
@@ -113,6 +113,11 @@ macro_rules! declare_features {
      Some("removed in favor of `#![feature(marker_trait_attr)]`")),
     /// Allows `#[no_debug]`.
     (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
+
+    /// Allows comparing raw pointers during const eval.
+    (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
+     Some("cannot be allowed in const eval in any meaningful way")),
+
     // -------------------------------------------------------------------------
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
index b63dd653c4dd8a5209447745508ffc1421c8aab2..79b70682739326b1ea18c4254e7cbc83fbade8d1 100644 (file)
@@ -8,14 +8,12 @@
 use crate::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use crate::hir;
 
-use rustc_ast::ast;
 use rustc_ast::crate_disambiguator::CrateDisambiguator;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_index::vec::IndexVec;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
 
 use log::debug;
 use std::fmt::Write;
@@ -73,34 +71,22 @@ pub fn size(&self) -> usize {
 }
 
 /// The definition table containing node definitions.
-/// It holds the `DefPathTable` for local `DefId`s/`DefPath`s and it also stores a
-/// mapping from `NodeId`s to local `DefId`s.
-#[derive(Clone, Default)]
+/// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s.
+/// It also stores mappings to convert `LocalDefId`s to/from `HirId`s.
+#[derive(Clone)]
 pub struct Definitions {
     table: DefPathTable,
 
-    def_id_to_span: IndexVec<LocalDefId, Span>,
-
-    // FIXME(eddyb) don't go through `ast::NodeId` to convert between `HirId`
-    // and `LocalDefId` - ideally all `LocalDefId`s would be HIR owners.
-    node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
-    def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
-
-    pub(super) node_id_to_hir_id: IndexVec<ast::NodeId, Option<hir::HirId>>,
-    /// The reverse mapping of `node_id_to_hir_id`.
-    pub(super) hir_id_to_node_id: FxHashMap<hir::HirId, ast::NodeId>,
+    // FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners.
+    pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
+    /// The reverse mapping of `def_id_to_hir_id`.
+    pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
 
     /// If `ExpnId` is an ID of some macro expansion,
     /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
     parent_modules_of_macro_defs: FxHashMap<ExpnId, DefId>,
     /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
     expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
-    next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
-    /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
-    /// we know what parent node that fragment should be attached to thanks to this table.
-    invocation_parents: FxHashMap<ExpnId, LocalDefId>,
-    /// Indices of unnamed struct or variant fields with unresolved attributes.
-    placeholder_field_indices: FxHashMap<ast::NodeId, usize>,
 }
 
 /// A unique identifier that we can use to lookup a definition
@@ -320,68 +306,28 @@ pub fn def_path(&self, id: LocalDefId) -> DefPath {
         })
     }
 
-    #[inline]
-    pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<LocalDefId> {
-        self.node_id_to_def_id.get(&node).copied()
-    }
-
-    #[inline]
-    pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId {
-        self.opt_local_def_id(node).unwrap_or_else(|| {
-            panic!("no entry for node id: `{:?}` / `{:?}`", node, self.opt_node_id_to_hir_id(node))
-        })
-    }
-
     #[inline]
     pub fn as_local_hir_id(&self, def_id: LocalDefId) -> hir::HirId {
         self.local_def_id_to_hir_id(def_id)
     }
 
-    #[inline]
-    pub fn hir_id_to_node_id(&self, hir_id: hir::HirId) -> ast::NodeId {
-        self.hir_id_to_node_id[&hir_id]
-    }
-
-    #[inline]
-    pub fn node_id_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
-        self.node_id_to_hir_id[node_id].unwrap()
-    }
-
-    #[inline]
-    pub fn opt_node_id_to_hir_id(&self, node_id: ast::NodeId) -> Option<hir::HirId> {
-        self.node_id_to_hir_id[node_id]
-    }
-
     #[inline]
     pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
-        let node_id = self.def_id_to_node_id[id];
-        self.node_id_to_hir_id[node_id].unwrap()
+        self.def_id_to_hir_id[id].unwrap()
     }
 
     #[inline]
     pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option<hir::HirId> {
-        let node_id = self.def_id_to_node_id[id];
-        self.node_id_to_hir_id[node_id]
+        self.def_id_to_hir_id[id]
     }
 
     #[inline]
     pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
-        let node_id = self.hir_id_to_node_id(hir_id);
-        self.opt_local_def_id(node_id)
-    }
-
-    /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
-    #[inline]
-    pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
-        if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
+        self.hir_id_to_def_id.get(&hir_id).copied()
     }
 
     /// Adds a root definition (no parent) and a few other reserved definitions.
-    pub fn create_root_def(
-        &mut self,
-        crate_name: &str,
-        crate_disambiguator: CrateDisambiguator,
-    ) -> LocalDefId {
+    pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
         let key = DefKey {
             parent: None,
             disambiguated_data: DisambiguatedDefPathData {
@@ -393,52 +339,39 @@ pub fn create_root_def(
         let parent_hash = DefKey::root_parent_stable_hash(crate_name, crate_disambiguator);
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
-        // Create the definition.
-        let root = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
+        // Create the root definition.
+        let mut table = DefPathTable::default();
+        let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
         assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
 
-        assert_eq!(self.def_id_to_node_id.push(ast::CRATE_NODE_ID), root);
-        assert_eq!(self.def_id_to_span.push(rustc_span::DUMMY_SP), root);
-
-        self.node_id_to_def_id.insert(ast::CRATE_NODE_ID, root);
-        self.set_invocation_parent(ExpnId::root(), root);
+        Definitions {
+            table,
+            def_id_to_hir_id: Default::default(),
+            hir_id_to_def_id: Default::default(),
+            expansions_that_defined: Default::default(),
+            parent_modules_of_macro_defs: Default::default(),
+        }
+    }
 
-        root
+    /// Retrieves the root definition.
+    pub fn get_root_def(&self) -> LocalDefId {
+        LocalDefId { local_def_index: CRATE_DEF_INDEX }
     }
 
     /// Adds a definition with a parent definition.
-    pub fn create_def_with_parent(
+    pub fn create_def(
         &mut self,
         parent: LocalDefId,
-        node_id: ast::NodeId,
         data: DefPathData,
         expn_id: ExpnId,
-        span: Span,
+        mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
     ) -> LocalDefId {
-        debug!(
-            "create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
-            parent, node_id, data
-        );
-
-        assert!(
-            !self.node_id_to_def_id.contains_key(&node_id),
-            "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
-            node_id,
-            data,
-            self.table.def_key(self.node_id_to_def_id[&node_id].local_def_index),
-        );
+        debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
 
         // The root node must be created with `create_root_def()`.
         assert!(data != DefPathData::CrateRoot);
 
-        // Find the next free disambiguator for this key.
-        let disambiguator = {
-            let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
-            let disambiguator = *next_disamb;
-            *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
-            disambiguator
-        };
-
+        let disambiguator = next_disambiguator(parent, data);
         let key = DefKey {
             parent: Some(parent.local_def_index),
             disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
@@ -447,22 +380,11 @@ pub fn create_def_with_parent(
         let parent_hash = self.table.def_path_hash(parent.local_def_index);
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
-        debug!("create_def_with_parent: after disambiguation, key = {:?}", key);
+        debug!("create_def: after disambiguation, key = {:?}", key);
 
         // Create the definition.
         let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
 
-        assert_eq!(self.def_id_to_node_id.push(node_id), def_id);
-        assert_eq!(self.def_id_to_span.push(span), def_id);
-
-        // Some things for which we allocate `LocalDefId`s don't correspond to
-        // anything in the AST, so they don't have a `NodeId`. For these cases
-        // we don't need a mapping from `NodeId` to `LocalDefId`.
-        if node_id != ast::DUMMY_NODE_ID {
-            debug!("create_def_with_parent: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
-            self.node_id_to_def_id.insert(node_id, def_id);
-        }
-
         if expn_id != ExpnId::root() {
             self.expansions_that_defined.insert(def_id, expn_id);
         }
@@ -470,24 +392,24 @@ pub fn create_def_with_parent(
         def_id
     }
 
-    /// Initializes the `ast::NodeId` to `HirId` mapping once it has been generated during
+    /// Initializes the `LocalDefId` to `HirId` mapping once it has been generated during
     /// AST to HIR lowering.
-    pub fn init_node_id_to_hir_id_mapping(
+    pub fn init_def_id_to_hir_id_mapping(
         &mut self,
-        mapping: IndexVec<ast::NodeId, Option<hir::HirId>>,
+        mapping: IndexVec<LocalDefId, Option<hir::HirId>>,
     ) {
         assert!(
-            self.node_id_to_hir_id.is_empty(),
-            "trying to initialize `NodeId` -> `HirId` mapping twice"
+            self.def_id_to_hir_id.is_empty(),
+            "trying to initialize `LocalDefId` <-> `HirId` mappings twice"
         );
-        self.node_id_to_hir_id = mapping;
 
-        // Build the reverse mapping of `node_id_to_hir_id`.
-        self.hir_id_to_node_id = self
-            .node_id_to_hir_id
+        // Build the reverse mapping of `def_id_to_hir_id`.
+        self.hir_id_to_def_id = mapping
             .iter_enumerated()
-            .filter_map(|(node_id, &hir_id)| hir_id.map(|hir_id| (hir_id, node_id)))
+            .filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
             .collect();
+
+        self.def_id_to_hir_id = mapping;
     }
 
     pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
@@ -501,30 +423,6 @@ pub fn parent_module_of_macro_def(&self, expn_id: ExpnId) -> DefId {
     pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
         self.parent_modules_of_macro_defs.insert(expn_id, module);
     }
-
-    pub fn invocation_parent(&self, invoc_id: ExpnId) -> LocalDefId {
-        self.invocation_parents[&invoc_id]
-    }
-
-    pub fn set_invocation_parent(&mut self, invoc_id: ExpnId, parent: LocalDefId) {
-        let old_parent = self.invocation_parents.insert(invoc_id, parent);
-        assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
-    }
-
-    pub fn placeholder_field_index(&self, node_id: ast::NodeId) -> usize {
-        self.placeholder_field_indices[&node_id]
-    }
-
-    pub fn set_placeholder_field_index(&mut self, node_id: ast::NodeId, index: usize) {
-        let old_index = self.placeholder_field_indices.insert(node_id, index);
-        assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
-    }
-
-    pub fn lint_node_id(&mut self, expn_id: ExpnId) -> ast::NodeId {
-        self.invocation_parents
-            .get(&expn_id)
-            .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
-    }
 }
 
 impl DefPathData {
index 634ab32a285427f04902a80c12fa165e84b01282..f3dfec7ca72150386063bb74dacc5dd9df1508a1 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_macros::HashStable_Generic;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
@@ -638,6 +639,8 @@ pub struct Crate<'hir> {
     /// A list of proc macro HirIds, written out in the order in which
     /// they are declared in the static array generated by proc_macro_harness.
     pub proc_macros: Vec<HirId>,
+
+    pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
 }
 
 impl Crate<'hir> {
@@ -1508,13 +1511,7 @@ fn is_range_path(path: &Path<'_>) -> bool {
     // Check whether a span corresponding to a range expression is a
     // range literal, rather than an explicit struct or `new()` call.
     fn is_lit(sm: &SourceMap, span: &Span) -> bool {
-        let end_point = sm.end_point(*span);
-
-        if let Ok(end_string) = sm.span_to_snippet(end_point) {
-            !(end_string.ends_with('}') || end_string.ends_with(')'))
-        } else {
-            false
-        }
+        sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
     };
 
     match expr.kind {
@@ -2650,26 +2647,12 @@ pub struct Upvar {
 // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
 // has length > 0 if the trait is found through an chain of imports, starting with the
 // import/use statement in the scope where the trait is used.
-#[derive(Clone, Debug)]
-pub struct TraitCandidate<ID = HirId> {
+#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
+pub struct TraitCandidate {
     pub def_id: DefId,
-    pub import_ids: SmallVec<[ID; 1]>,
-}
-
-impl<ID> TraitCandidate<ID> {
-    pub fn map_import_ids<F, T>(self, f: F) -> TraitCandidate<T>
-    where
-        F: Fn(ID) -> T,
-    {
-        let TraitCandidate { def_id, import_ids } = self;
-        let import_ids = import_ids.into_iter().map(f).collect();
-        TraitCandidate { def_id, import_ids }
-    }
+    pub import_ids: SmallVec<[LocalDefId; 1]>,
 }
 
-// Trait method resolution
-pub type TraitMap<ID = HirId> = NodeMap<Vec<TraitCandidate<ID>>>;
-
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum Node<'hir> {
     Param(&'hir Param<'hir>),
@@ -2726,17 +2709,23 @@ pub fn fn_decl(&self) -> Option<&FnDecl<'_>> {
         }
     }
 
+    pub fn body_id(&self) -> Option<BodyId> {
+        match self {
+            Node::TraitItem(TraitItem {
+                kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+                ..
+            })
+            | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
+            | Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+            _ => None,
+        }
+    }
+
     pub fn generics(&self) -> Option<&Generics<'_>> {
         match self {
             Node::TraitItem(TraitItem { generics, .. })
-            | Node::ImplItem(ImplItem { generics, .. })
-            | Node::Item(Item {
-                kind:
-                    ItemKind::Trait(_, _, generics, ..)
-                    | ItemKind::Impl { generics, .. }
-                    | ItemKind::Fn(_, generics, _),
-                ..
-            }) => Some(generics),
+            | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
+            Node::Item(item) => item.kind.generics(),
             _ => None,
         }
     }
index 83bada4041963deec529489e623e952b9fc98939..5aaf219b315bdc22b69dca21de23531cc104c681 100644 (file)
 
 use lazy_static::lazy_static;
 
+pub enum LangItemGroup {
+    Op,
+}
+
+const NUM_GROUPS: usize = 1;
+
+macro_rules! expand_group {
+    () => {
+        None
+    };
+    ($group:expr) => {
+        Some($group)
+    };
+}
+
 // The actual lang items defined come at the end of this file in one handy table.
 // So you probably just want to nip down to the end.
 macro_rules! language_item_table {
     (
-        $( $variant:ident, $name:expr, $method:ident, $target:path; )*
+        $( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )*
     ) => {
 
         enum_from_u32! {
@@ -45,6 +60,13 @@ pub fn name(self) -> &'static str {
                     $( $variant => $name, )*
                 }
             }
+
+            pub fn group(self) -> Option<LangItemGroup> {
+                use LangItemGroup::*;
+                match self {
+                    $( $variant => expand_group!($($group)*), )*
+                }
+            }
         }
 
         #[derive(HashStable_Generic)]
@@ -54,6 +76,9 @@ pub struct LanguageItems {
             pub items: Vec<Option<DefId>>,
             /// Lang items that were not found during collection.
             pub missing: Vec<LangItem>,
+            /// Mapping from `LangItemGroup` discriminants to all
+            /// `DefId`s of lang items in that group.
+            pub groups: [Vec<DefId>; NUM_GROUPS],
         }
 
         impl LanguageItems {
@@ -64,6 +89,7 @@ fn init_none(_: LangItem) -> Option<DefId> { None }
                 Self {
                     items: vec![$(init_none($variant)),*],
                     missing: Vec::new(),
+                    groups: [vec![]; NUM_GROUPS],
                 }
             }
 
@@ -79,6 +105,10 @@ pub fn require(&self, it: LangItem) -> Result<DefId, String> {
                 self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
             }
 
+            pub fn group(&self, group: LangItemGroup) -> &[DefId] {
+                self.groups[group as usize].as_ref()
+            }
+
             $(
                 /// Returns the corresponding `DefId` for the lang item
                 #[doc = $name]
@@ -171,30 +201,30 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     CoerceUnsizedTraitLangItem,  "coerce_unsized",     coerce_unsized_trait,    Target::Trait;
     DispatchFromDynTraitLangItem,"dispatch_from_dyn",  dispatch_from_dyn_trait, Target::Trait;
 
-    AddTraitLangItem,            "add",                add_trait,               Target::Trait;
-    SubTraitLangItem,            "sub",                sub_trait,               Target::Trait;
-    MulTraitLangItem,            "mul",                mul_trait,               Target::Trait;
-    DivTraitLangItem,            "div",                div_trait,               Target::Trait;
-    RemTraitLangItem,            "rem",                rem_trait,               Target::Trait;
-    NegTraitLangItem,            "neg",                neg_trait,               Target::Trait;
-    NotTraitLangItem,            "not",                not_trait,               Target::Trait;
-    BitXorTraitLangItem,         "bitxor",             bitxor_trait,            Target::Trait;
-    BitAndTraitLangItem,         "bitand",             bitand_trait,            Target::Trait;
-    BitOrTraitLangItem,          "bitor",              bitor_trait,             Target::Trait;
-    ShlTraitLangItem,            "shl",                shl_trait,               Target::Trait;
-    ShrTraitLangItem,            "shr",                shr_trait,               Target::Trait;
-    AddAssignTraitLangItem,      "add_assign",         add_assign_trait,        Target::Trait;
-    SubAssignTraitLangItem,      "sub_assign",         sub_assign_trait,        Target::Trait;
-    MulAssignTraitLangItem,      "mul_assign",         mul_assign_trait,        Target::Trait;
-    DivAssignTraitLangItem,      "div_assign",         div_assign_trait,        Target::Trait;
-    RemAssignTraitLangItem,      "rem_assign",         rem_assign_trait,        Target::Trait;
-    BitXorAssignTraitLangItem,   "bitxor_assign",      bitxor_assign_trait,     Target::Trait;
-    BitAndAssignTraitLangItem,   "bitand_assign",      bitand_assign_trait,     Target::Trait;
-    BitOrAssignTraitLangItem,    "bitor_assign",       bitor_assign_trait,      Target::Trait;
-    ShlAssignTraitLangItem,      "shl_assign",         shl_assign_trait,        Target::Trait;
-    ShrAssignTraitLangItem,      "shr_assign",         shr_assign_trait,        Target::Trait;
-    IndexTraitLangItem,          "index",              index_trait,             Target::Trait;
-    IndexMutTraitLangItem,       "index_mut",          index_mut_trait,         Target::Trait;
+    AddTraitLangItem(Op),        "add",                add_trait,               Target::Trait;
+    SubTraitLangItem(Op),        "sub",                sub_trait,               Target::Trait;
+    MulTraitLangItem(Op),        "mul",                mul_trait,               Target::Trait;
+    DivTraitLangItem(Op),        "div",                div_trait,               Target::Trait;
+    RemTraitLangItem(Op),        "rem",                rem_trait,               Target::Trait;
+    NegTraitLangItem(Op),        "neg",                neg_trait,               Target::Trait;
+    NotTraitLangItem(Op),        "not",                not_trait,               Target::Trait;
+    BitXorTraitLangItem(Op),     "bitxor",             bitxor_trait,            Target::Trait;
+    BitAndTraitLangItem(Op),     "bitand",             bitand_trait,            Target::Trait;
+    BitOrTraitLangItem(Op),      "bitor",              bitor_trait,             Target::Trait;
+    ShlTraitLangItem(Op),        "shl",                shl_trait,               Target::Trait;
+    ShrTraitLangItem(Op),        "shr",                shr_trait,               Target::Trait;
+    AddAssignTraitLangItem(Op),  "add_assign",         add_assign_trait,        Target::Trait;
+    SubAssignTraitLangItem(Op),  "sub_assign",         sub_assign_trait,        Target::Trait;
+    MulAssignTraitLangItem(Op),  "mul_assign",         mul_assign_trait,        Target::Trait;
+    DivAssignTraitLangItem(Op),  "div_assign",         div_assign_trait,        Target::Trait;
+    RemAssignTraitLangItem(Op),  "rem_assign",         rem_assign_trait,        Target::Trait;
+    BitXorAssignTraitLangItem(Op),"bitxor_assign",     bitxor_assign_trait,     Target::Trait;
+    BitAndAssignTraitLangItem(Op),"bitand_assign",     bitand_assign_trait,     Target::Trait;
+    BitOrAssignTraitLangItem(Op),"bitor_assign",       bitor_assign_trait,      Target::Trait;
+    ShlAssignTraitLangItem(Op),  "shl_assign",         shl_assign_trait,        Target::Trait;
+    ShrAssignTraitLangItem(Op),  "shr_assign",         shr_assign_trait,        Target::Trait;
+    IndexTraitLangItem(Op),      "index",              index_trait,             Target::Trait;
+    IndexMutTraitLangItem(Op),   "index_mut",          index_mut_trait,         Target::Trait;
 
     UnsafeCellTypeLangItem,      "unsafe_cell",        unsafe_cell_type,        Target::Struct;
     VaListTypeLangItem,          "va_list",            va_list,                 Target::Struct;
@@ -207,6 +237,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     FnMutTraitLangItem,          "fn_mut",             fn_mut_trait,            Target::Trait;
     FnOnceTraitLangItem,         "fn_once",            fn_once_trait,           Target::Trait;
 
+    FnOnceOutputLangItem,        "fn_once_output",     fn_once_output,          Target::AssocTy;
+
     FutureTraitLangItem,         "future_trait",       future_trait,            Target::Trait;
     GeneratorStateLangItem,      "generator_state",    gen_state,               Target::Enum;
     GeneratorTraitLangItem,      "generator",          gen_trait,               Target::Trait;
@@ -242,6 +274,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
 
     StartFnLangItem,             "start",              start_fn,                Target::Fn;
 
+    CountCodeRegionFnLangItem,   "count_code_region",  count_code_region_fn,    Target::Fn;
+
     EhPersonalityLangItem,       "eh_personality",     eh_personality,          Target::Fn;
     EhCatchTypeinfoLangItem,     "eh_catch_typeinfo",  eh_catch_typeinfo,       Target::Static;
 
index b51c0a6e98840b3374c18747cf8d6c709f8e9289..20ac2a04b474fa7f690e831c9db3a85aaadb4e29 100644 (file)
@@ -3,7 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 #![feature(crate_visibility_modifier)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)] // For the unsizing cast on `&[]`
 #![feature(const_panic)]
 #![feature(in_band_lifetimes)]
index 46c38840516e2bc133ad393d7ed9f0d108bc25be..cb8b30830c5dec905b7b672804bf1d6837a9b043 100644 (file)
@@ -700,7 +700,7 @@ pub fn contains(&self, elem: T) -> bool {
 ///
 /// All operations that involve a row and/or column index will panic if the
 /// index exceeds the relevant bound.
-#[derive(Clone, Debug, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
 pub struct BitMatrix<R: Idx, C: Idx> {
     num_rows: usize,
     num_columns: usize,
@@ -876,6 +876,22 @@ pub fn count(&self, row: R) -> usize {
     }
 }
 
+impl<R: Idx, C: Idx> fmt::Debug for BitMatrix<R, C> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        /// Forces its contents to print in regular mode instead of alternate mode.
+        struct OneLinePrinter<T>(T);
+        impl<T: fmt::Debug> fmt::Debug for OneLinePrinter<T> {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(fmt, "{:?}", self.0)
+            }
+        }
+
+        write!(fmt, "BitMatrix({}x{}) ", self.num_rows, self.num_columns)?;
+        let items = self.rows().flat_map(|r| self.iter(r).map(move |c| (r, c)));
+        fmt.debug_set().entries(items.map(OneLinePrinter)).finish()
+    }
+}
+
 /// A fixed-column-size, variable-row-size 2D bit matrix with a moderately
 /// sparse representation.
 ///
index 3effc4164501155007c3006929201b2e9042d0d9..6fef49668da5fc38d7558dfccfebf0b72dee8d79 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(allow_internal_unstable)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(extend_one)]
index c2dae6ba4f83db32e9e5dfe0120e35f21d092950..2dc803b959533da68c74b26f9d0cfe64c5bb9140 100644 (file)
@@ -314,18 +314,19 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
             }
 
             ty::ReVar(vid) => {
-                let r = self
+                let resolved_vid = self
                     .infcx
                     .unwrap()
                     .inner
                     .borrow_mut()
                     .unwrap_region_constraints()
-                    .opportunistic_resolve_var(self.tcx, vid);
+                    .opportunistic_resolve_var(vid);
                 debug!(
                     "canonical: region var found with vid {:?}, \
                      opportunistically resolved to {:?}",
                     vid, r
                 );
+                let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
                 self.canonicalize_region_mode.canonicalize_free_region(self, r)
             }
 
@@ -403,7 +404,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             | ty::Float(..)
             | ty::Adt(..)
             | ty::Str
-            | ty::Error
+            | ty::Error(_)
             | ty::Array(..)
             | ty::Slice(..)
             | ty::RawPtr(..)
index 7310d2c3bdcf8318fc1d304069798bd98afa6331..2b8c46f1de42def2944d6e2af76d3b18bd56279e 100644 (file)
@@ -154,7 +154,7 @@ fn instantiate_canonical_var(
                 self.tcx
                     .mk_const(ty::Const {
                         val: ty::ConstKind::Placeholder(placeholder_mapped),
-                        ty: self.tcx.types.err, // FIXME(const_generics)
+                        ty: self.tcx.ty_error(), // FIXME(const_generics)
                     })
                     .into()
             }
index 12f7a9c0ca50228bc316da2cd03c8e860887a2a1..7fdcbd31df3c5085663428ea3fb2c1cafaeff250 100644 (file)
@@ -1256,7 +1256,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => {
                 let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
                 let mut values = self.cmp_fn_sig(&sig1, sig2);
-                values.0.push_normal(format!(
+                values.0.push_highlighted(format!(
                     " {{{}}}",
                     self.tcx.def_path_str_with_substs(*did1, substs1)
                 ));
@@ -2035,8 +2035,7 @@ fn report_inference_failure(
             self.tcx.sess,
             var_origin.span(),
             E0495,
-            "cannot infer an appropriate lifetime{} \
-             due to conflicting requirements",
+            "cannot infer an appropriate lifetime{} due to conflicting requirements",
             var_description
         )
     }
index 1361d5bede63bcb0b863ee9be66e56f47c7c30d1..1687bcc1556367900976f3ce64074720feceabba 100644 (file)
@@ -88,6 +88,17 @@ fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
         if let (None, Some(ty)) =
             (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
         {
+            // FIXME: There's a trade-off here - we can either check that our target span
+            // is contained in `local.span` or not. If we choose to check containment
+            // we can avoid some spurious suggestions (see #72690), but we lose
+            // the ability to report on things like:
+            //
+            // ```
+            // let x = vec![];
+            // ```
+            //
+            // because the target span will be in the macro expansion of `vec![]`.
+            // At present we choose not to check containment.
             self.found_local_pattern = Some(&*local.pat);
             self.found_node_ty = Some(ty);
         }
@@ -99,8 +110,10 @@ fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
             if let (None, Some(ty)) =
                 (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
             {
-                self.found_arg_pattern = Some(&*param.pat);
-                self.found_node_ty = Some(ty);
+                if self.target_span.contains(param.pat.span) {
+                    self.found_arg_pattern = Some(&*param.pat);
+                    self.found_node_ty = Some(ty);
+                }
             }
         }
         intravisit::walk_body(self, body);
index de71363cbde5ccfad45d91fa688d294f74666695..20617bb8bd8fc2aa84cfffef9be05b2960e0c3d3 100644 (file)
@@ -26,32 +26,29 @@ pub(super) fn find_anon_type(
         &self,
         region: Region<'tcx>,
         br: &ty::BoundRegion,
-    ) -> Option<(&hir::Ty<'_>, &hir::FnDecl<'_>)> {
+    ) -> Option<(&hir::Ty<'tcx>, &hir::FnDecl<'tcx>)> {
         if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
-            let def_id = anon_reg.def_id;
-            if let Some(def_id) = def_id.as_local() {
-                let hir_id = self.tcx().hir().as_local_hir_id(def_id);
-                let fndecl = match self.tcx().hir().get(hir_id) {
-                    Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
-                    | Node::TraitItem(&hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(ref m, ..),
-                        ..
-                    })
-                    | Node::ImplItem(&hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(ref m, ..),
-                        ..
-                    }) => &m.decl,
-                    _ => return None,
-                };
+            let hir_id = self.tcx().hir().as_local_hir_id(anon_reg.def_id);
+            let fndecl = match self.tcx().hir().get(hir_id) {
+                Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
+                | Node::TraitItem(&hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(ref m, ..),
+                    ..
+                })
+                | Node::ImplItem(&hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(ref m, ..), ..
+                }) => &m.decl,
+                _ => return None,
+            };
 
-                return fndecl
-                    .inputs
-                    .iter()
-                    .find_map(|arg| self.find_component_for_bound_region(arg, br))
-                    .map(|ty| (ty, &**fndecl));
-            }
+            fndecl
+                .inputs
+                .iter()
+                .find_map(|arg| self.find_component_for_bound_region(arg, br))
+                .map(|ty| (ty, &**fndecl))
+        } else {
+            None
         }
-        None
     }
 
     // This method creates a FindNestedTypeVisitor which returns the type corresponding
index a56401ebb90f089ecaecfe29bb2d18ff5f7c8b23..72deba990b0b5e5dc5dc6a629cfcede63cce94ab 100644 (file)
@@ -2,7 +2,8 @@
 //! where one region is named and the other is anonymous.
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_hir::{FnRetTy, TyKind};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::FnRetTy;
 use rustc_middle::ty;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -74,22 +75,26 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
         }
 
         if let Some((_, fndecl)) = self.find_anon_type(anon, &br) {
-            let is_self_anon = self.is_self_anon(is_first, scope_def_id);
-            if is_self_anon {
+            if self.is_self_anon(is_first, scope_def_id) {
                 return None;
             }
 
             if let FnRetTy::Return(ty) = &fndecl.output {
-                let mut v = ty::TraitObjectVisitor(vec![]);
-                rustc_hir::intravisit::walk_ty(&mut v, ty);
+                let mut v = ty::TraitObjectVisitor(vec![], self.tcx().hir());
+                v.visit_ty(ty);
 
                 debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
                 if sub == &ty::ReStatic
-                    && (matches!(ty.kind, TyKind::OpaqueDef(_, _)) || v.0.len() == 1)
+                    && v.0
+                        .into_iter()
+                        .filter(|t| t.span.desugaring_kind().is_none())
+                        .next()
+                        .is_some()
                 {
+                    // If the failure is due to a `'static` requirement coming from a `dyn` or
+                    // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
+                    // better in `static_impl_trait`.
                     debug!("try_report_named_anon_conflict: impl Trait + 'static");
-                    // This is an `impl Trait` or `dyn Trait` return that evaluates de need of
-                    // `'static`. We handle this case better in `static_impl_trait`.
                     return None;
                 }
             }
index f4c86ddae604e2b0297484bb6ee3b53a4505ddea..b6e971feb0e5fdc4043f45411baa2264ea13cc19 100644 (file)
 //! 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 rustc_errors::{Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
 use rustc_middle::ty::RegionKind;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the return type is a static impl Trait.
     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
-        if let Some(ref error) = self.error {
-            if let RegionResolutionError::SubSupConflict(
-                _,
-                var_origin,
-                sub_origin,
-                sub_r,
-                sup_origin,
-                sup_r,
-            ) = error.clone()
-            {
-                let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
-                let (fn_return_span, is_dyn) =
-                    self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?;
-                if sub_r == &RegionKind::ReStatic {
-                    let sp = var_origin.span();
-                    let return_sp = sub_origin.span();
-                    let mut err =
-                        self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime");
-                    let param_info = self.find_param_with_region(sup_r, sub_r)?;
-                    err.span_label(param_info.param_ty_span, "data with this lifetime...");
+        debug!("try_report_static_impl_trait(error={:?})", self.error);
+        if let Some(RegionResolutionError::SubSupConflict(
+            _,
+            var_origin,
+            ref sub_origin,
+            sub_r,
+            ref sup_origin,
+            sup_r,
+        )) = self.error
+        {
+            debug!(
+                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+                var_origin, sub_origin, sub_r, sup_origin, sup_r
+            );
+            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
+            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
+            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
+            if fn_returns.is_empty() {
+                return None;
+            }
+            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+            if *sub_r == RegionKind::ReStatic {
+                let sp = var_origin.span();
+                let return_sp = sub_origin.span();
+                let param_info = self.find_param_with_region(sup_r, sub_r)?;
+                let (lifetime_name, lifetime) = if sup_r.has_name() {
+                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+                } else {
+                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
+                };
+                let mut err = struct_span_err!(
+                    self.tcx().sess,
+                    sp,
+                    E0759,
+                    "cannot infer an appropriate lifetime"
+                );
+                err.span_label(
+                    param_info.param_ty_span,
+                    &format!("this data with {}...", lifetime),
+                );
+                debug!("try_report_static_impl_trait: param_info={:?}", param_info);
 
-                    // We try to make the output have fewer overlapping spans if possible.
-                    if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
-                        && sup_origin.span() != return_sp
-                    {
-                        // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+                // We try to make the output have fewer overlapping spans if possible.
+                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
+                    && sup_origin.span() != return_sp
+                {
+                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
 
-                        // Customize the spans and labels depending on their relative order so
-                        // that split sentences flow correctly.
-                        if sup_origin.span().shrink_to_hi() <= return_sp.shrink_to_lo() {
-                            err.span_label(sup_origin.span(), "...is captured here...");
-                            err.span_label(return_sp, "...and required to be `'static` by this");
-                        } else {
-                            err.span_label(return_sp, "...is required to be `'static` by this...");
-                            err.span_label(sup_origin.span(), "...and is captured here");
-                        }
-                    } else {
+                    // Customize the spans and labels depending on their relative order so
+                    // that split sentences flow correctly.
+                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
+                        // Avoid the following:
+                        //
+                        // error: cannot infer an appropriate lifetime
+                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+                        //    |
+                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+                        //    |           ----                      ---------^-
+                        //
+                        // and instead show:
+                        //
+                        // error: cannot infer an appropriate lifetime
+                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+                        //    |
+                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+                        //    |           ----                               ^
                         err.span_label(
-                            return_sp,
-                            "...is captured and required to be `'static` here",
+                            sup_origin.span(),
+                            "...is captured here, requiring it to live as long as `'static`",
                         );
+                    } else {
+                        err.span_label(sup_origin.span(), "...is captured here...");
+                        if return_sp < sup_origin.span() {
+                            err.span_note(
+                                return_sp,
+                                "...and is required to live as long as `'static` here",
+                            );
+                        } else {
+                            err.span_label(
+                                return_sp,
+                                "...and is required to live as long as `'static` here",
+                            );
+                        }
                     }
+                } else {
+                    err.span_label(
+                        return_sp,
+                        "...is captured and required to live as long as `'static` here",
+                    );
+                }
 
-                    let (lifetime, _) = msg_span_from_free_region(self.tcx(), sup_r);
+                // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+                let consider = "consider changing the";
+                let declare = "to declare that the";
+                let arg = match param_info.param.pat.simple_ident() {
+                    Some(simple_ident) => format!("argument `{}`", simple_ident),
+                    None => "the argument".to_string(),
+                };
+                let explicit =
+                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+                let explicit_static =
+                    format!("explicit `'static` bound to the lifetime of {}", arg);
+                let captures = format!("captures data from {}", arg);
+                let add_static_bound =
+                    "alternatively, add an explicit `'static` bound to this reference";
+                let plus_lt = format!(" + {}", lifetime_name);
+                for fn_return in fn_returns {
+                    if fn_return.span.desugaring_kind().is_some() {
+                        // Skip `async` desugaring `impl Future`.
+                        continue;
+                    }
+                    match fn_return.kind {
+                        TyKind::OpaqueDef(item_id, _) => {
+                            let item = self.tcx().hir().item(item_id.id);
+                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+                                opaque
+                            } else {
+                                err.emit();
+                                return Some(ErrorReported);
+                            };
 
-                    let lifetime_name =
-                        if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
-                    // only apply this suggestion onto functions with
-                    // explicit non-desugar'able return.
-                    if fn_return_span.desugaring_kind().is_none() {
-                        let msg = format!(
-                            "to permit non-static references in {} `{} Trait` value, you can add \
-                             an explicit bound for {}",
-                            if is_dyn { "a" } else { "an" },
-                            if is_dyn { "dyn" } else { "impl" },
-                            lifetime,
-                        );
-                        // FIXME: account for the need of parens in `&(dyn Trait + '_)`
-                        err.span_suggestion_verbose(
-                            fn_return_span.shrink_to_hi(),
-                            &msg,
-                            format!(" + {}", lifetime_name),
-                            Applicability::MaybeIncorrect,
-                        );
+                            if let Some(span) = opaque
+                                .bounds
+                                .iter()
+                                .filter_map(|arg| match arg {
+                                    GenericBound::Outlives(Lifetime {
+                                        name: LifetimeName::Static,
+                                        span,
+                                        ..
+                                    }) => Some(*span),
+                                    _ => None,
+                                })
+                                .next()
+                            {
+                                err.span_suggestion_verbose(
+                                    span,
+                                    &format!("{} `impl Trait`'s {}", consider, explicit_static),
+                                    lifetime_name.clone(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                err.span_suggestion_verbose(
+                                    param_info.param_ty_span,
+                                    add_static_bound,
+                                    param_info.param_ty.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else if let Some(_) = opaque
+                                .bounds
+                                .iter()
+                                .filter_map(|arg| match arg {
+                                    GenericBound::Outlives(Lifetime { name, span, .. })
+                                        if name.ident().to_string() == lifetime_name =>
+                                    {
+                                        Some(*span)
+                                    }
+                                    _ => None,
+                                })
+                                .next()
+                            {
+                            } else {
+                                err.span_suggestion_verbose(
+                                    fn_return.span.shrink_to_hi(),
+                                    &format!(
+                                        "{declare} `impl Trait` {captures}, {explicit}",
+                                        declare = declare,
+                                        captures = captures,
+                                        explicit = explicit,
+                                    ),
+                                    plus_lt.clone(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                        TyKind::TraitObject(_, lt) => match lt.name {
+                            LifetimeName::ImplicitObjectLifetimeDefault => {
+                                err.span_suggestion_verbose(
+                                    fn_return.span.shrink_to_hi(),
+                                    &format!(
+                                        "{declare} trait object {captures}, {explicit}",
+                                        declare = declare,
+                                        captures = captures,
+                                        explicit = explicit,
+                                    ),
+                                    plus_lt.clone(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            name if name.ident().to_string() != lifetime_name => {
+                                // With this check we avoid suggesting redundant bounds. This
+                                // would happen if there are nested impl/dyn traits and only
+                                // one of them has the bound we'd suggest already there, like
+                                // in `impl Foo<X = dyn Bar> + '_`.
+                                err.span_suggestion_verbose(
+                                    lt.span,
+                                    &format!("{} trait object's {}", consider, explicit_static),
+                                    lifetime_name.clone(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                err.span_suggestion_verbose(
+                                    param_info.param_ty_span,
+                                    add_static_bound,
+                                    param_info.param_ty.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            _ => {}
+                        },
+                        _ => {}
                     }
-                    err.emit();
-                    return Some(ErrorReported);
                 }
+                err.emit();
+                return Some(ErrorReported);
             }
         }
         None
index 22b130cdf5ffe2ffd3cf438997c744dced008fa3..fa999abb1a86c46b672c88b81b49d1efc36f5fea 100644 (file)
@@ -3,7 +3,7 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::{self, DefIdTree, Region, Ty};
 use rustc_span::Span;
 
@@ -92,7 +92,7 @@ pub(super) fn find_param_with_region(
     // FIXME(#42703) - Need to handle certain cases here.
     pub(super) fn is_return_type_anon(
         &self,
-        scope_def_id: DefId,
+        scope_def_id: LocalDefId,
         br: ty::BoundRegion,
         decl: &hir::FnDecl<'_>,
     ) -> Option<Span> {
@@ -112,9 +112,12 @@ pub(super) fn is_return_type_anon(
     // corresponds to self and if yes, we display E0312.
     // FIXME(#42700) - Need to format self properly to
     // enable E0621 for it.
-    pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
+    pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: LocalDefId) -> bool {
         is_first
-            && self.tcx().opt_associated_item(scope_def_id).map(|i| i.fn_has_self_parameter)
+            && self
+                .tcx()
+                .opt_associated_item(scope_def_id.to_def_id())
+                .map(|i| i.fn_has_self_parameter)
                 == Some(true)
     }
 }
index b4cfcb3a1c3256c708450472cad47b7cf2c9d33e..02bebe10ed04afa124c57bb82733c103d2c92b4e 100644 (file)
@@ -192,7 +192,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             | ty::Float(..)
             | ty::Adt(..)
             | ty::Str
-            | ty::Error
+            | ty::Error(_)
             | ty::Array(..)
             | ty::Slice(..)
             | ty::RawPtr(..)
@@ -250,7 +250,7 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
             ty::ConstKind::Param(_)
             | ty::ConstKind::Value(_)
             | ty::ConstKind::Unevaluated(..)
-            | ty::ConstKind::Error => {}
+            | ty::ConstKind::Error(_) => {}
         }
 
         ct.super_fold_with(self)
index ef18918c1772f7ddfccdda79da9c630d2abd7a4f..b6251e34008a36fe922e63b9cc4dd87cd9280857 100644 (file)
@@ -30,10 +30,10 @@ pub fn higher_ranked_sub<T>(
 
         let span = self.trace.cause.span;
 
-        self.infcx.commit_if_ok(|snapshot| {
+        self.infcx.commit_if_ok(|_| {
             // First, we instantiate each bound region in the supertype with a
             // fresh placeholder region.
-            let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b);
+            let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
 
             // Next, we instantiate each bound region in the subtype
             // with a fresh region variable. These region variables --
@@ -48,8 +48,6 @@ pub fn higher_ranked_sub<T>(
             // Compare types now that bound regions have been replaced.
             let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
 
-            self.infcx.leak_check(!a_is_expected, &placeholder_map, snapshot)?;
-
             debug!("higher_ranked_sub: OK result={:?}", result);
 
             Ok(ty::Binder::bind(result))
@@ -63,14 +61,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// placeholder region. This is the first step of checking subtyping
     /// when higher-ranked things are involved.
     ///
-    /// **Important:** you must call this function from within a snapshot.
-    /// Moreover, before committing the snapshot, you must eventually call
-    /// either `plug_leaks` or `pop_placeholders` to remove the placeholder
-    /// regions. If you rollback the snapshot (or are using a probe), then
-    /// the pop occurs as part of the rollback, so an explicit call is not
-    /// needed (but is also permitted).
-    ///
-    /// For more information about how placeholders and HRTBs work, see
+    /// **Important:** You have to be careful to not leak these placeholders,
+    /// for more information about how placeholders and HRTBs work, see
     /// the [rustc dev guide].
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
@@ -81,7 +73,12 @@ pub fn replace_bound_vars_with_placeholders<T>(
     where
         T: TypeFoldable<'tcx>,
     {
-        let next_universe = self.create_next_universe();
+        // Figure out what the next universe will be, but don't actually create
+        // it until after we've done the substitution (in particular there may
+        // be no bound variables). This is a performance optimization, since the
+        // leak check for example can be skipped if no new universes are created
+        // (i.e., if there are no placeholders).
+        let next_universe = self.universe().next_universe();
 
         let fld_r = |br| {
             self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
@@ -109,6 +106,13 @@ pub fn replace_bound_vars_with_placeholders<T>(
 
         let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
 
+        // If there were higher-ranked regions to replace, then actually create
+        // the next universe (this avoids needlessly creating universes).
+        if !map.is_empty() {
+            let n_u = self.create_next_universe();
+            assert_eq!(n_u, next_universe);
+        }
+
         debug!(
             "replace_bound_vars_with_placeholders(\
              next_universe={:?}, \
@@ -125,7 +129,6 @@ pub fn replace_bound_vars_with_placeholders<T>(
     pub fn leak_check(
         &self,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
         snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
         // If the user gave `-Zno-leak-check`, or we have been
@@ -141,7 +144,7 @@ pub fn leak_check(
         self.inner.borrow_mut().unwrap_region_constraints().leak_check(
             self.tcx,
             overly_polymorphic,
-            placeholder_map,
+            self.universe(),
             snapshot,
         )
     }
index 92387f753f55ecdea5ad7f3e59bcec5e72685409..76ac61c067280a901b03133513c871ab57f063f5 100644 (file)
@@ -570,7 +570,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// Necessary because we can't write the following bound:
 /// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`.
 pub struct InferCtxtBuilder<'tcx> {
-    global_tcx: TyCtxt<'tcx>,
+    tcx: TyCtxt<'tcx>,
     fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
 }
 
@@ -580,7 +580,7 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder { global_tcx: self, fresh_tables: None }
+        InferCtxtBuilder { tcx: self, fresh_tables: None }
     }
 }
 
@@ -616,24 +616,22 @@ pub fn enter_with_canonical<T, R>(
     }
 
     pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder { global_tcx, ref fresh_tables } = *self;
+        let InferCtxtBuilder { tcx, ref fresh_tables } = *self;
         let in_progress_tables = fresh_tables.as_ref();
-        global_tcx.enter_local(|tcx| {
-            f(InferCtxt {
-                tcx,
-                in_progress_tables,
-                inner: RefCell::new(InferCtxtInner::new()),
-                lexical_region_resolutions: RefCell::new(None),
-                selection_cache: Default::default(),
-                evaluation_cache: Default::default(),
-                reported_trait_errors: Default::default(),
-                reported_closure_mismatch: Default::default(),
-                tainted_by_errors_flag: Cell::new(false),
-                err_count_on_creation: tcx.sess.err_count(),
-                in_snapshot: Cell::new(false),
-                skip_leak_check: Cell::new(false),
-                universe: Cell::new(ty::UniverseIndex::ROOT),
-            })
+        f(InferCtxt {
+            tcx,
+            in_progress_tables,
+            inner: RefCell::new(InferCtxtInner::new()),
+            lexical_region_resolutions: RefCell::new(None),
+            selection_cache: Default::default(),
+            evaluation_cache: Default::default(),
+            reported_trait_errors: Default::default(),
+            reported_closure_mismatch: Default::default(),
+            tainted_by_errors_flag: Cell::new(false),
+            err_count_on_creation: tcx.sess.err_count(),
+            in_snapshot: Cell::new(false),
+            skip_leak_check: Cell::new(false),
+            universe: Cell::new(ty::UniverseIndex::ROOT),
         })
     }
 }
@@ -991,14 +989,12 @@ pub fn subtype_predicate(
             return None;
         }
 
-        Some(self.commit_if_ok(|snapshot| {
-            let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
+        Some(self.commit_if_ok(|_snapshot| {
+            let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
                 self.replace_bound_vars_with_placeholders(&predicate);
 
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
 
-            self.leak_check(false, &placeholder_map, snapshot)?;
-
             Ok(ok.unit())
         }))
     }
@@ -1008,14 +1004,13 @@ pub fn region_outlives_predicate(
         cause: &traits::ObligationCause<'tcx>,
         predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
     ) -> UnitResult<'tcx> {
-        self.commit_if_ok(|snapshot| {
-            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+        self.commit_if_ok(|_snapshot| {
+            let (ty::OutlivesPredicate(r_a, r_b), _) =
                 self.replace_bound_vars_with_placeholders(&predicate);
             let origin = SubregionOrigin::from_obligation_cause(cause, || {
                 RelateRegionParamBound(cause.span)
             });
             self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
-            self.leak_check(false, &placeholder_map, snapshot)?;
             Ok(())
         })
     }
@@ -1751,9 +1746,10 @@ pub fn consts(
     }
 
     pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
+        let err = tcx.ty_error();
         TypeTrace {
             cause: ObligationCause::dummy(),
-            values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }),
+            values: Types(ExpectedFound { expected: err, found: err }),
         }
     }
 }
index 8de892510060828e12c6ddc238a8650794178660..2350c28dfaaff6afc91da2b4c49c2d413e2bcaee 100644 (file)
@@ -522,7 +522,13 @@ fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>
         }
 
         if a == b {
-            return Ok(a);
+            // Subtle: if a or b has a bound variable that we are lazilly
+            // substituting, then even if a == b, it could be that the values we
+            // will substitute for those bound variables are *not* the same, and
+            // hence returning `Ok(a)` is incorrect.
+            if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
+                return Ok(a);
+            }
         }
 
         match (&a.kind, &b.kind) {
index 82d32b008088ddde01bfa257e0d8537aca3b12b8..383979f8640759e97640a69ee1d5db5a3652d226 100644 (file)
@@ -1,9 +1,8 @@
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::{GenericKind, VerifyBound};
-use crate::traits;
 use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
@@ -311,18 +310,14 @@ fn declared_projection_bounds_from_trait(
     fn region_bounds_declared_on_associated_item(
         &self,
         assoc_item_def_id: DefId,
-    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
+    ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let assoc_item = tcx.associated_item(assoc_item_def_id);
-        let trait_def_id = assoc_item.container.assert_trait();
-        let trait_predicates = tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p);
-        let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id);
-        let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
-        self.collect_outlives_from_predicate_list(
-            move |ty| ty == identity_proj,
-            traits::elaborate_predicates(tcx, trait_predicates).map(|o| o.predicate),
-        )
-        .map(|b| b.1)
+        let predicates = tcx.projection_predicates(assoc_item_def_id);
+        predicates
+            .into_iter()
+            .filter_map(|p| p.to_opt_type_outlives())
+            .filter_map(|p| p.no_bound_vars())
+            .map(|b| b.1)
     }
 
     /// Searches through a predicate list for a predicate `T: 'a`.
index 473550d5433df3c14e8a4ad95c9ec75cde957ede..32e708bf52b32fc2568ab8ad3f83e94a314a4878 100644 (file)
 use super::*;
-use crate::infer::{CombinedSnapshot, PlaceholderMap};
-use rustc_data_structures::undo_log::UndoLogs;
+use crate::infer::CombinedSnapshot;
+use rustc_data_structures::{
+    graph::{scc::Sccs, vec_graph::VecGraph},
+    undo_log::UndoLogs,
+};
+use rustc_index::vec::Idx;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::RelateResult;
 
 impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
-    /// Searches region constraints created since `snapshot` that
-    /// affect one of the placeholders in `placeholder_map`, returning
-    /// an error if any of the placeholders are related to another
-    /// placeholder or would have to escape into some parent universe
-    /// that cannot name them.
+    /// Searches new universes created during `snapshot`, looking for
+    /// placeholders that may "leak" out from the universes they are contained
+    /// in. If any leaking placeholders are found, then an `Err` is returned
+    /// (typically leading to the snapshot being reversed).
     ///
-    /// This is a temporary backwards compatibility measure to try and
-    /// retain the older (arguably incorrect) behavior of the
-    /// compiler.
+    /// The leak check *used* to be the only way we had to handle higher-ranked
+    /// obligations. Now that we have integrated universes into the region
+    /// solvers, this is no longer the case, but we retain the leak check for
+    /// backwards compatibility purposes. In particular, it lets us make "early"
+    /// decisions about whether a region error will be reported that are used in
+    /// coherence and elsewhere -- see #56105 and #59490 for more details. The
+    /// eventual fate of the leak checker is not yet settled.
     ///
-    /// NB. Although `_snapshot` isn't used, it's passed in to prove
-    /// that we are in a snapshot, which guarantees that we can just
-    /// search the "undo log" for edges. This is mostly an efficiency
-    /// thing -- we could search *all* region constraints, but that'd be
-    /// a bigger set and the data structures are not setup for that. If
-    /// we wind up keeping some form of this check long term, it would
-    /// probably be better to remove the snapshot parameter and to
-    /// refactor the constraint set.
+    /// The leak checker works by searching for the following error patterns:
+    ///
+    /// * P1: P2, where P1 != P2
+    /// * P1: R, where R is in some universe that cannot name P1
+    ///
+    /// The idea here is that each of these patterns represents something that
+    /// the region solver would eventually report as an error, so we can detect
+    /// the error early. There is a fly in the ointment, though, in that this is
+    /// not entirely true. In particular, in the future, we may extend the
+    /// environment with implied bounds or other info about how placeholders
+    /// relate to regions in outer universes. In that case, `P1: R` for example
+    /// might become solveable.
+    ///
+    /// # Summary of the implementation
+    ///
+    /// The leak checks as follows. First, we construct a graph where `R2: R1`
+    /// implies `R2 -> R1`, and we compute the SCCs.
+    ///
+    /// For each SCC S, we compute:
+    ///
+    /// * what placeholder P it must be equal to, if any
+    ///   * if there are multiple placeholders that must be equal, report an error because `P1: P2`
+    /// * the minimum universe of its constituents
+    ///
+    /// Then we walk the SCCs in dependency order and compute
+    ///
+    /// * what placeholder they must outlive transitively
+    ///   * if they must also be equal to a placeholder, report an error because `P1: P2`
+    /// * minimum universe U of all SCCs they must outlive
+    ///   * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
+    ///     indicates `P: R` and `R` is in an incompatible universe
+    ///
+    /// # Historical note
+    ///
+    /// Older variants of the leak check used to report errors for these
+    /// patterns, but we no longer do:
+    ///
+    /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n
+    /// * R: P1, R: P2, as above
     pub fn leak_check(
         &mut self,
         tcx: TyCtxt<'tcx>,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        _snapshot: &CombinedSnapshot<'_, 'tcx>,
+        max_universe: ty::UniverseIndex,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
-        debug!("leak_check(placeholders={:?})", placeholder_map);
+        debug!(
+            "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
+            max_universe, snapshot.universe, overly_polymorphic
+        );
 
         assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
 
-        // Go through each placeholder that we created.
-        for &placeholder_region in placeholder_map.values() {
-            // Find the universe this placeholder inhabits.
-            let placeholder = match placeholder_region {
-                ty::RePlaceholder(p) => p,
-                _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,),
-            };
-
-            // Find all regions that are related to this placeholder
-            // in some way. This means any region that either outlives
-            // or is outlived by a placeholder.
-            let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
-            taint_set.fixed_point(
-                tcx,
-                self.undo_log.region_constraints(),
-                &self.storage.data.verifys,
-            );
-            let tainted_regions = taint_set.into_set();
-
-            // Report an error if two placeholders in the same universe
-            // are related to one another, or if a placeholder is related
-            // to something from a parent universe.
-            for &tainted_region in &tainted_regions {
-                if let ty::RePlaceholder(_) = tainted_region {
-                    // Two placeholders cannot be related:
-                    if tainted_region == placeholder_region {
-                        continue;
-                    }
-                } else if self.universe(tainted_region).can_name(placeholder.universe) {
-                    continue;
-                }
-
-                return Err(if overly_polymorphic {
-                    debug!("overly polymorphic!");
-                    TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region)
-                } else {
-                    debug!("not as polymorphic!");
-                    TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region)
-                });
-            }
+        let universe_at_start_of_snapshot = snapshot.universe;
+        if universe_at_start_of_snapshot == max_universe {
+            return Ok(());
         }
 
+        let mini_graph =
+            &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys);
+
+        let mut leak_check = LeakCheck::new(
+            tcx,
+            universe_at_start_of_snapshot,
+            max_universe,
+            overly_polymorphic,
+            mini_graph,
+            self,
+        );
+        leak_check.assign_placeholder_values()?;
+        leak_check.propagate_scc_value()?;
         Ok(())
     }
 }
 
-#[derive(Debug)]
-struct TaintSet<'tcx> {
-    directions: TaintDirections,
-    regions: FxHashSet<ty::Region<'tcx>>,
+struct LeakCheck<'me, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    universe_at_start_of_snapshot: ty::UniverseIndex,
+    overly_polymorphic: bool,
+    mini_graph: &'me MiniGraph<'tcx>,
+    rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+
+    // Initially, for each SCC S, stores a placeholder `P` such that `S = P`
+    // must hold.
+    //
+    // Later, during the [`LeakCheck::propagate_scc_value`] function, this array
+    // is repurposed to store some placeholder `P` such that the weaker
+    // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1
+    // = P`.)
+    scc_placeholders: IndexVec<LeakCheckScc, Option<ty::PlaceholderRegion>>,
+
+    // For each SCC S, track the minimum universe that flows into it. Note that
+    // this is both the minimum of the universes for every region that is a
+    // member of the SCC, but also if you have `R1: R2`, then the universe of
+    // `R2` must be less than the universe of `R1` (i.e., `R1` flows `R2`). To
+    // see that, imagine that you have `P1: R` -- in that case, `R` must be
+    // either the placeholder `P1` or the empty region in that same universe.
+    //
+    // To detect errors, we look for an SCC S where the values in
+    // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`.
+    scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>,
 }
 
-impl<'tcx> TaintSet<'tcx> {
-    fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
-        let mut regions = FxHashSet::default();
-        regions.insert(initial_region);
-        TaintSet { directions, regions }
+impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        universe_at_start_of_snapshot: ty::UniverseIndex,
+        max_universe: ty::UniverseIndex,
+        overly_polymorphic: bool,
+        mini_graph: &'me MiniGraph<'tcx>,
+        rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+    ) -> Self {
+        let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
+        Self {
+            tcx,
+            universe_at_start_of_snapshot,
+            overly_polymorphic,
+            mini_graph,
+            rcc,
+            scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()),
+            scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()),
+        }
+    }
+
+    /// Compute what placeholders (if any) each SCC must be equal to.
+    /// Also compute the minimum universe of all the regions in each SCC.
+    fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
+        // First walk: find each placeholder that is from a newly created universe.
+        for (region, leak_check_node) in &self.mini_graph.nodes {
+            let scc = self.mini_graph.sccs.scc(*leak_check_node);
+
+            // Set the universe of each SCC to be the minimum of its constituent universes
+            let universe = self.rcc.universe(region);
+            debug!(
+                "assign_placeholder_values: scc={:?} universe={:?} region={:?}",
+                scc, universe, region
+            );
+            self.scc_universes[scc].take_min(universe, region);
+
+            // Detect those SCCs that directly contain a placeholder
+            if let ty::RePlaceholder(placeholder) = region {
+                if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
+                    self.assign_scc_value(scc, *placeholder)?;
+                }
+            }
+        }
+
+        Ok(())
     }
 
-    fn fixed_point<'a>(
+    // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
+    // This may create an error.
+    fn assign_scc_value(
         &mut self,
-        tcx: TyCtxt<'tcx>,
-        undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
-        verifys: &[Verify<'tcx>],
-    ) where
-        'tcx: 'a,
-    {
-        let mut prev_len = 0;
-        while prev_len < self.len() {
-            debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
-
-            prev_len = self.len();
-
-            for undo_entry in undo_log.clone() {
-                match undo_entry {
-                    &AddConstraint(Constraint::VarSubVar(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::RegSubVar(a, b)) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::VarSubReg(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), b);
-                    }
-                    &AddConstraint(Constraint::RegSubReg(a, b)) => {
-                        self.add_edge(a, b);
-                    }
-                    &AddGiven(a, b) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddVerify(i) => span_bug!(
-                        verifys[i].origin.span(),
-                        "we never add verifications while doing higher-ranked things",
-                    ),
-                    &Purged | &AddCombination(..) | &AddVar(..) => {}
+        scc: LeakCheckScc,
+        placeholder: ty::PlaceholderRegion,
+    ) -> RelateResult<'tcx, ()> {
+        match self.scc_placeholders[scc] {
+            Some(p) => {
+                assert_ne!(p, placeholder);
+                return Err(self.placeholder_error(p, placeholder));
+            }
+            None => {
+                self.scc_placeholders[scc] = Some(placeholder);
+            }
+        };
+
+        Ok(())
+    }
+
+    /// For each SCC S, iterate over each successor S1 where `S: S1`:
+    ///
+    /// * Compute
+    /// Iterate over each SCC `S` and ensure that, for each `S1` where `S1: S`,
+    /// `universe(S) <= universe(S1)`. This executes after
+    /// `assign_placeholder_values`, so `universe(S)` is already the minimum
+    /// universe of any of its direct constituents.
+    fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
+        // Loop invariants:
+        //
+        // On start of the loop iteration for `scc1`:
+        //
+        // * `scc_universes[scc1]` contains the minimum universe of the
+        //   constituents of `scc1`
+        // * `scc_placeholder[scc1]` stores the placeholder that `scc1` must
+        //   be equal to (if any)
+        //
+        // For each succssor `scc2` where `scc1: scc2`:
+        //
+        // * `scc_placeholder[scc2]` stores some placeholder `P` where
+        //   `scc2: P` (if any)
+        // * `scc_universes[scc2]` contains the minimum universe of the
+        //   constituents of `scc2` and any of its successors
+        for scc1 in self.mini_graph.sccs.all_sccs() {
+            debug!(
+                "propagate_scc_value: scc={:?} with universe {:?}",
+                scc1, self.scc_universes[scc1]
+            );
+
+            // Walk over each `scc2` such that `scc1: scc2` and compute:
+            //
+            // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
+            // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
+            //   we pick one arbitrarily)
+            let mut scc1_universe = self.scc_universes[scc1];
+            let mut succ_bound = None;
+            for &scc2 in self.mini_graph.sccs.successors(scc1) {
+                let SccUniverse { universe: scc2_universe, region: scc2_region } =
+                    self.scc_universes[scc2];
+
+                scc1_universe.take_min(scc2_universe, scc2_region.unwrap());
+
+                if let Some(b) = self.scc_placeholders[scc2] {
+                    succ_bound = Some(b);
                 }
             }
+
+            // Update minimum universe of scc1.
+            self.scc_universes[scc1] = scc1_universe;
+
+            // At this point, `scc_placholder[scc1]` stores the placeholder that
+            // `scc1` must be equal to, if any.
+            if let Some(scc1_placeholder) = self.scc_placeholders[scc1] {
+                debug!(
+                    "propagate_scc_value: scc1={:?} placeholder={:?} scc1_universe={:?}",
+                    scc1, scc1_placeholder, scc1_universe
+                );
+
+                // Check if `P1: R` for some `R` in a universe that cannot name
+                // P1. That's an error.
+                if scc1_universe.universe.cannot_name(scc1_placeholder.universe) {
+                    return Err(self.error(scc1_placeholder, scc1_universe.region.unwrap()));
+                }
+
+                // Check if we have some placeholder where `S: P2`
+                // (transitively). In that case, since `S = P1`, that implies
+                // `P1: P2`, which is an error condition.
+                if let Some(scc2_placeholder) = succ_bound {
+                    assert_ne!(scc1_placeholder, scc2_placeholder);
+                    return Err(self.placeholder_error(scc1_placeholder, scc2_placeholder));
+                }
+            } else {
+                // Otherwise, we can reach a placeholder if some successor can.
+                self.scc_placeholders[scc1] = succ_bound;
+            }
+
+            // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
         }
+        Ok(())
     }
 
-    fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
-        self.regions
+    fn placeholder_error(
+        &self,
+        placeholder1: ty::PlaceholderRegion,
+        placeholder2: ty::PlaceholderRegion,
+    ) -> TypeError<'tcx> {
+        self.error(placeholder1, self.tcx.mk_region(ty::RePlaceholder(placeholder2)))
     }
 
-    fn len(&self) -> usize {
-        self.regions.len()
+    fn error(
+        &self,
+        placeholder: ty::PlaceholderRegion,
+        other_region: ty::Region<'tcx>,
+    ) -> TypeError<'tcx> {
+        debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
+        if self.overly_polymorphic {
+            return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
+        } else {
+            return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
+        }
     }
+}
 
-    fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
-        if self.directions.incoming {
-            if self.regions.contains(&target) {
-                self.regions.insert(source);
-            }
+// States we need to distinguish:
+//
+// * must be equal to a placeholder (i.e., a placeholder is in the SCC)
+//     * it could conflict with some other regions in the SCC in different universes
+//     * or a different placeholder
+// * `P1: S` and `S` must be equal to a placeholder
+// * `P1: S` and `S` is in an incompatible universe
+//
+// So if we
+//
+// (a) compute which placeholder (if any) each SCC must be equal to
+// (b) compute its minimum universe
+// (c) compute *some* placeholder where `S: P1` (any one will do)
+//
+// then we get an error if:
+//
+// - it must be equal to a placeholder `P1` and minimum universe cannot name `P1`
+// - `S: P1` and minimum universe cannot name `P1`
+// - `S: P1` and we must be equal to `P2`
+//
+// So we want to track:
+//
+// * Equal placeholder (if any)
+// * Some bounding placeholder (if any)
+// * Minimum universe
+//
+// * We compute equal placeholder + minimum universe of constituents in first pass
+// * Then we walk in order and compute from our dependencies `S1` where `S: S1` (`S -> S1`)
+//   * bounding placeholder (if any)
+//   * minimum universe
+// * And if we must be equal to a placeholder then we check it against
+//   * minimum universe
+//   * no bounding placeholder
+
+/// Tracks the "minimum universe" for each SCC, along with some region that
+/// caused it to change.
+#[derive(Copy, Clone, Debug)]
+struct SccUniverse<'tcx> {
+    /// For some SCC S, the minimum universe of:
+    ///
+    /// * each region R in S
+    /// * each SCC S1 such that S: S1
+    universe: ty::UniverseIndex,
+
+    /// Some region that caused `universe` to be what it is.
+    region: Option<ty::Region<'tcx>>,
+}
+
+impl<'tcx> SccUniverse<'tcx> {
+    /// If `universe` is less than our current universe, then update
+    /// `self.universe` and `self.region`.
+    fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) {
+        if universe < self.universe || self.region.is_none() {
+            self.universe = universe;
+            self.region = Some(region);
         }
+    }
+}
+
+rustc_index::newtype_index! {
+    struct LeakCheckNode {
+        DEBUG_FORMAT = "LeakCheckNode({})"
+    }
+}
 
-        if self.directions.outgoing {
-            if self.regions.contains(&source) {
-                self.regions.insert(target);
+rustc_index::newtype_index! {
+    struct LeakCheckScc {
+        DEBUG_FORMAT = "LeakCheckScc({})"
+    }
+}
+
+/// Represents the graph of constraints. For each `R1: R2` constraint we create
+/// an edge `R1 -> R2` in the graph.
+struct MiniGraph<'tcx> {
+    /// Map from a region to the index of the node in the graph.
+    nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+
+    /// Map from node index to SCC, and stores the successors of each SCC. All
+    /// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
+    /// then `S1: S2`.
+    sccs: Sccs<LeakCheckNode, LeakCheckScc>,
+}
+
+impl<'tcx> MiniGraph<'tcx> {
+    fn new<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+    ) -> Self
+    where
+        'tcx: 'a,
+    {
+        let mut nodes = FxHashMap::default();
+        let mut edges = Vec::new();
+
+        // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
+        Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| {
+            let source_node = Self::add_node(&mut nodes, source);
+            let target_node = Self::add_node(&mut nodes, target);
+            edges.push((source_node, target_node));
+        });
+        let graph = VecGraph::new(nodes.len(), edges);
+        let sccs = Sccs::new(&graph);
+        Self { nodes, sccs }
+    }
+
+    /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1`
+    fn iterate_undo_log<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+        mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>),
+    ) where
+        'tcx: 'a,
+    {
+        for undo_entry in undo_log {
+            match undo_entry {
+                &AddConstraint(Constraint::VarSubVar(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::RegSubVar(a, b)) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::VarSubReg(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), b);
+                }
+                &AddConstraint(Constraint::RegSubReg(a, b)) => {
+                    each_edge(a, b);
+                }
+                &AddGiven(a, b) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddVerify(i) => span_bug!(
+                    verifys[i].origin.span(),
+                    "we never add verifications while doing higher-ranked things",
+                ),
+                &AddCombination(..) | &AddVar(..) => {}
             }
         }
     }
+
+    fn add_node(
+        nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+        r: ty::Region<'tcx>,
+    ) -> LeakCheckNode {
+        let l = nodes.len();
+        *nodes.entry(r).or_insert(LeakCheckNode::new(l))
+    }
 }
index 626774617a67a24c9dc50c807015db9da18638bb..2902c41a6bcae779c85d64979c53082c3a6b57d8 100644 (file)
@@ -50,10 +50,10 @@ pub struct RegionConstraintStorage<'tcx> {
     /// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this
     /// table. You can then call `opportunistic_resolve_var` early
     /// which will map R1 and R2 to some common region (i.e., either
-    /// R1 or R2). This is important when dropck and other such code
-    /// is iterating to a fixed point, because otherwise we sometimes
-    /// would wind up with a fresh stream of region variables that
-    /// have been equated but appear distinct.
+    /// R1 or R2). This is important when fulfillment, dropck and other such
+    /// code is iterating to a fixed point, because otherwise we sometimes
+    /// would wind up with a fresh stream of region variables that have been
+    /// equated but appear distinct.
     pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>,
 
     /// a flag set to true when we perform any unifications; this is used
@@ -289,14 +289,6 @@ pub(crate) enum UndoLog<'tcx> {
 
     /// We added a GLB/LUB "combination variable".
     AddCombination(CombineMapType, TwoRegions<'tcx>),
-
-    /// During skolemization, we sometimes purge entries from the undo
-    /// log in a kind of minisnapshot (unlike other snapshots, this
-    /// purging actually takes place *on success*). In that case, we
-    /// replace the corresponding entry with `Noop` so as to avoid the
-    /// need to do a bunch of swapping. (We can't use `swap_remove` as
-    /// the order of the vector is important.)
-    Purged,
 }
 
 #[derive(Copy, Clone, PartialEq)]
@@ -357,9 +349,6 @@ pub(crate) fn with_log<'a>(
 
     fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) {
         match undo_entry {
-            Purged => {
-                // nothing to do here
-            }
             AddVar(vid) => {
                 self.var_infos.pop().unwrap();
                 assert_eq!(self.var_infos.len(), vid.index() as usize);
@@ -488,62 +477,6 @@ pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
         self.var_infos[vid].origin
     }
 
-    /// Removes all the edges to/from the placeholder regions that are
-    /// in `skols`. This is used after a higher-ranked operation
-    /// completes to remove all trace of the placeholder regions
-    /// created in that time.
-    pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) {
-        debug!("pop_placeholders(placeholders={:?})", placeholders);
-
-        assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
-
-        let constraints_to_kill: Vec<usize> = self
-            .undo_log
-            .iter()
-            .enumerate()
-            .rev()
-            .filter(|&(_, undo_entry)| match undo_entry {
-                super::UndoLog::RegionConstraintCollector(undo_entry) => {
-                    kill_constraint(placeholders, undo_entry)
-                }
-                _ => false,
-            })
-            .map(|(index, _)| index)
-            .collect();
-
-        for index in constraints_to_kill {
-            let undo_entry = match &mut self.undo_log[index] {
-                super::UndoLog::RegionConstraintCollector(undo_entry) => {
-                    mem::replace(undo_entry, Purged)
-                }
-                _ => unreachable!(),
-            };
-            self.rollback_undo_entry(undo_entry);
-        }
-
-        return;
-
-        fn kill_constraint<'tcx>(
-            placeholders: &FxHashSet<ty::Region<'tcx>>,
-            undo_entry: &UndoLog<'tcx>,
-        ) -> bool {
-            match undo_entry {
-                &AddConstraint(Constraint::VarSubVar(..)) => false,
-                &AddConstraint(Constraint::RegSubVar(a, _)) => placeholders.contains(&a),
-                &AddConstraint(Constraint::VarSubReg(_, b)) => placeholders.contains(&b),
-                &AddConstraint(Constraint::RegSubReg(a, b)) => {
-                    placeholders.contains(&a) || placeholders.contains(&b)
-                }
-                &AddGiven(..) => false,
-                &AddVerify(_) => false,
-                &AddCombination(_, ref two_regions) => {
-                    placeholders.contains(&two_regions.a) || placeholders.contains(&two_regions.b)
-                }
-                &AddVar(..) | &Purged => false,
-            }
-        }
-    }
-
     fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
         // cannot add constraints once regions are resolved
         debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
@@ -714,13 +647,8 @@ pub fn glb_regions(
         }
     }
 
-    pub fn opportunistic_resolve_var(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        rid: RegionVid,
-    ) -> ty::Region<'tcx> {
-        let vid = self.unification_table().probe_value(rid).min_vid;
-        tcx.mk_region(ty::ReVar(vid))
+    pub fn opportunistic_resolve_var(&mut self, rid: RegionVid) -> ty::RegionVid {
+        self.unification_table().probe_value(rid).min_vid
     }
 
     fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
index e28cf49c7f2538f2facd4caad8c2670ae27d0b10..74f365ced2373e8fdaca01cc099fc34905bf112e 100644 (file)
@@ -46,51 +46,56 @@ fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
     }
 }
 
-/// The opportunistic type and region resolver is similar to the
-/// opportunistic type resolver, but also opportunistically resolves
-/// regions. It is useful for canonicalization.
-pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx> {
+/// The opportunistic region resolver opportunistically resolves regions
+/// variables to the variable with the least variable id. It is used when
+/// normlizing projections to avoid hitting the recursion limit by creating
+/// many versions of a predicate for types that in the end have to unify.
+///
+/// If you want to resolve type and const variables as well, call
+/// [InferCtxt::resolve_vars_if_possible] first.
+pub struct OpportunisticRegionResolver<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
 }
 
-impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> {
+impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
     pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
-        OpportunisticTypeAndRegionResolver { infcx }
+        OpportunisticRegionResolver { infcx }
     }
 }
 
-impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> {
+impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !t.needs_infer() {
+        if !t.has_infer_regions() {
             t // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
-            let t0 = self.infcx.shallow_resolve(t);
-            t0.super_fold_with(self)
+            t.super_fold_with(self)
         }
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
-            ty::ReVar(rid) => self
-                .infcx
-                .inner
-                .borrow_mut()
-                .unwrap_region_constraints()
-                .opportunistic_resolve_var(self.tcx(), rid),
+            ty::ReVar(rid) => {
+                let resolved = self
+                    .infcx
+                    .inner
+                    .borrow_mut()
+                    .unwrap_region_constraints()
+                    .opportunistic_resolve_var(rid);
+                self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
+            }
             _ => r,
         }
     }
 
     fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if !ct.needs_infer() {
+        if !ct.has_infer_regions() {
             ct // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
-            let c0 = self.infcx.shallow_resolve(ct);
-            c0.super_fold_with(self)
+            ct.super_fold_with(self)
         }
     }
 }
@@ -189,15 +194,15 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             match t.kind {
                 ty::Infer(ty::TyVar(vid)) => {
                     self.err = Some(FixupError::UnresolvedTy(vid));
-                    self.tcx().types.err
+                    self.tcx().ty_error()
                 }
                 ty::Infer(ty::IntVar(vid)) => {
                     self.err = Some(FixupError::UnresolvedIntTy(vid));
-                    self.tcx().types.err
+                    self.tcx().ty_error()
                 }
                 ty::Infer(ty::FloatVar(vid)) => {
                     self.err = Some(FixupError::UnresolvedFloatTy(vid));
-                    self.tcx().types.err
+                    self.tcx().ty_error()
                 }
                 ty::Infer(_) => {
                     bug!("Unexpected type in full type resolver: {:?}", t);
@@ -228,7 +233,7 @@ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
             match c.val {
                 ty::ConstKind::Infer(InferConst::Var(vid)) => {
                     self.err = Some(FixupError::UnresolvedConst(vid));
-                    return self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: c.ty });
+                    return self.tcx().const_error(c.ty);
                 }
                 ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                     bug!("Unexpected const in full const resolver: {:?}", c);
index b51af19883fdd82e4be7f0347b052d589e6a2e73..90962d210b5b48198f35f9e1391bda8cf16c6aeb 100644 (file)
@@ -119,9 +119,9 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 Ok(a)
             }
 
-            (&ty::Error, _) | (_, &ty::Error) => {
+            (&ty::Error(_), _) | (_, &ty::Error(_)) => {
                 infcx.set_tainted_by_errors();
-                Ok(self.tcx().types.err)
+                Ok(self.tcx().ty_error())
             }
 
             _ => {
index e7f1869955d20cd84944370a6908fc48326f8d64..2cfd6bb904c410558a310f727d1914cc45922e34 100644 (file)
@@ -198,10 +198,6 @@ fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
         assert!(self.logs.len() >= snapshot.undo_len);
         assert!(self.num_open_snapshots > 0);
     }
-
-    pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> {
-        self.logs.iter()
-    }
 }
 
 impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> {
index ed04ee02b7203c6028ec3329d4401e4250873867..27e086f1d5002f67521920f3552e5a0fcec040f0 100644 (file)
@@ -16,6 +16,9 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(const_fn)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
+#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(never_type)]
 #![feature(or_patterns)]
index a15ac819be966b3a1c2ee2680919c12703ffb305..8cd1eb9957bedc1ea56240dc3e8227a31c1e488a 100644 (file)
     Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
     ProjectionCacheStorage, Reveal,
 };
-crate use self::util::elaborate_predicates;
-
 pub use rustc_middle::traits::*;
 
-/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for
+/// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for
 /// which the "impl_source" must be found. The process of finding a "impl_source" is
 /// called "resolving" the `Obligation`. This process consists of
-/// either identifying an `impl` (e.g., `impl Eq for int`) that
+/// either identifying an `impl` (e.g., `impl Eq for i32`) that
 /// satisfies the obligation, or else finding a bound that is in
 /// scope. The eventual result is usually a `Selection` (defined below).
 #[derive(Clone, PartialEq, Eq, Hash)]
index ee9846c64b67c1033608b52baf62e00cf11061e1..4ae7e417a8f673d017da6ca897d3cebe910a7eec 100644 (file)
@@ -63,11 +63,11 @@ fn new(tcx: TyCtxt<'tcx>) -> Self {
     fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
         // We have to be careful here because we want
         //
-        //    for<'a> Foo<&'a int>
+        //    for<'a> Foo<&'a i32>
         //
         // and
         //
-        //    for<'b> Foo<&'b int>
+        //    for<'b> Foo<&'b i32>
         //
         // to be considered equivalent. So normalize all late-bound
         // regions before we throw things into the underlying set.
index 5aad64f84cee3ac9368307f318e52ecedbc7ac5c..920cc6021e68781d3933c7c697cc616019095c8f 100644 (file)
@@ -202,6 +202,7 @@ pub fn run_compiler_in_existing_thread_pool<R>(
 }
 
 pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
+    log::trace!("run_compiler");
     let stderr = config.stderr.take();
     util::spawn_thread_pool(
         config.opts.edition,
index 1ed9bc3f1f509d0ac20144cf5cb5246a7ee282d3..ed5e715ce7084a44e901c0211897e4936fd5c81f 100644 (file)
@@ -101,6 +101,7 @@ pub fn configure_and_expand(
     krate: ast::Crate,
     crate_name: &str,
 ) -> Result<(ast::Crate, BoxedResolver)> {
+    log::trace!("configure_and_expand");
     // Currently, we ignore the name resolution data structures for the purposes of dependency
     // tracking. Instead we will run name resolution and include its output in the hash of each
     // item, much like we do for macro expansion. In other words, the hash reflects not just
@@ -230,6 +231,7 @@ fn configure_and_expand_inner<'a>(
     resolver_arenas: &'a ResolverArenas<'a>,
     metadata_loader: &'a MetadataLoaderDyn,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
+    log::trace!("configure_and_expand_inner");
     pre_expansion_lint(sess, lint_store, &krate);
 
     let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
@@ -357,6 +359,7 @@ fn configure_and_expand_inner<'a>(
         should_loop |= true;
     }
     if should_loop {
+        log::debug!("replacing bodies with loop {{}}");
         util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
     }
 
@@ -546,6 +549,22 @@ fn escape_dep_filename(filename: &FileName) -> String {
     filename.to_string().replace(" ", "\\ ")
 }
 
+// Makefile comments only need escaping newlines and `\`.
+// The result can be unescaped by anything that can unescape `escape_default` and friends.
+fn escape_dep_env(symbol: Symbol) -> String {
+    let s = symbol.as_str();
+    let mut escaped = String::with_capacity(s.len());
+    for c in s.chars() {
+        match c {
+            '\n' => escaped.push_str(r"\n"),
+            '\r' => escaped.push_str(r"\r"),
+            '\\' => escaped.push_str(r"\\"),
+            _ => escaped.push(c),
+        }
+    }
+    escaped
+}
+
 fn write_out_deps(
     sess: &Session,
     boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
@@ -601,6 +620,25 @@ fn write_out_deps(
         for path in files {
             writeln!(file, "{}:", path)?;
         }
+
+        // Emit special comments with information about accessed environment variables.
+        let env_depinfo = sess.parse_sess.env_depinfo.borrow();
+        if !env_depinfo.is_empty() {
+            let mut envs: Vec<_> = env_depinfo
+                .iter()
+                .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
+                .collect();
+            envs.sort_unstable();
+            writeln!(file)?;
+            for (k, v) in envs {
+                write!(file, "# env-dep:{}", k)?;
+                if let Some(v) = v {
+                    write!(file, "={}", v)?;
+                }
+                writeln!(file)?;
+            }
+        }
+
         Ok(())
     })();
 
@@ -734,7 +772,10 @@ pub fn create_global_ctxt<'tcx>(
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
 ) -> QueryContext<'tcx> {
     let sess = &compiler.session();
-    let defs: &'tcx Definitions = arena.alloc(mem::take(&mut resolver_outputs.definitions));
+    let defs: &'tcx Definitions = arena.alloc(mem::replace(
+        &mut resolver_outputs.definitions,
+        Definitions::new(crate_name, sess.local_crate_disambiguator()),
+    ));
 
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
index 283be165c192c17ddd07d197bf27d794a06936fc..4a41c3e97cafc3c99ee59ad811c8d9a01688b9ac 100644 (file)
@@ -169,6 +169,7 @@ pub fn crate_name(&self) -> Result<&Query<String>> {
     pub fn expansion(
         &self,
     ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
+        log::trace!("expansion");
         self.expansion.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let (krate, lint_store) = self.register_plugins()?.take();
index 87647f3b0b017c84dadc9d46803043794f040cdd..d861b444c88164e5486c23da571c51ef91a4f77a 100644 (file)
@@ -6,7 +6,9 @@
 use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
 use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
 use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
-use rustc_session::config::{Externs, OutputType, OutputTypes, Sanitizer, SymbolManglingVersion};
+use rustc_session::config::{
+    Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion,
+};
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::NativeLibKind;
@@ -463,7 +465,6 @@ macro_rules! untracked {
     untracked!(ast_json_noexpand, true);
     untracked!(borrowck, String::from("other"));
     untracked!(borrowck_stats, true);
-    untracked!(control_flow_guard, CFGuard::Checks);
     untracked!(deduplicate_diagnostics, true);
     untracked!(dep_tasks, true);
     untracked!(dont_buffer_diagnostics, true);
@@ -537,6 +538,7 @@ macro_rules! tracked {
     tracked!(binary_dep_depinfo, true);
     tracked!(chalk, true);
     tracked!(codegen_backend, Some("abc".to_string()));
+    tracked!(control_flow_guard, CFGuard::Checks);
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
@@ -548,6 +550,7 @@ macro_rules! tracked {
     tracked!(human_readable_cgu_names, true);
     tracked!(inline_in_all_cgus, Some(true));
     tracked!(insert_sideeffect, true);
+    tracked!(instrument_coverage, true);
     tracked!(instrument_mcount, true);
     tracked!(link_only, true);
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
@@ -568,9 +571,9 @@ macro_rules! tracked {
     tracked!(relro_level, Some(RelroLevel::Full));
     tracked!(report_delayed_bugs, true);
     tracked!(run_dsymutil, false);
-    tracked!(sanitizer, Some(Sanitizer::Address));
+    tracked!(sanitizer, SanitizerSet::ADDRESS);
     tracked!(sanitizer_memory_track_origins, 2);
-    tracked!(sanitizer_recover, vec![Sanitizer::Address]);
+    tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
     tracked!(saturating_float_casts, Some(true));
     tracked!(share_generics, Some(true));
     tracked!(show_span, Some(String::from("abc")));
index 200e7acf802353f98efdb6f4793085605bef043b..77b3d26463dfe4aebeb1bca4df3b0eed5815f2ad 100644 (file)
@@ -179,21 +179,18 @@ pub enum Base {
 /// but shebang isn't a part of rust syntax.
 pub fn strip_shebang(input: &str) -> Option<usize> {
     // Shebang must start with `#!` literally, without any preceding whitespace.
-    if input.starts_with("#!") {
-        let input_tail = &input[2..];
-        // Shebang must have something non-whitespace after `#!` on the first line.
-        let first_line_tail = input_tail.lines().next()?;
-        if first_line_tail.contains(|c| !is_whitespace(c)) {
-            // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe
-            // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level),
-            // then it may be valid Rust code, so consider it Rust code.
-            let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok|
-                !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment { .. })
-            );
-            if next_non_whitespace_token != Some(TokenKind::OpenBracket) {
-                // No other choice than to consider this a shebang.
-                return Some(2 + first_line_tail.len());
-            }
+    // For simplicity we consider any line starting with `#!` a shebang,
+    // regardless of restrictions put on shebangs by specific platforms.
+    if let Some(input_tail) = input.strip_prefix("#!") {
+        // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe
+        // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level),
+        // then it may be valid Rust code, so consider it Rust code.
+        let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok|
+            !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment { .. })
+        );
+        if next_non_whitespace_token != Some(TokenKind::OpenBracket) {
+            // No other choice than to consider this a shebang.
+            return Some(2 + input_tail.lines().next().unwrap_or_default().len());
         }
     }
     None
index ada6f2a9381dc3db719a5f92b9fa18b1022dd084..58c15257326aeb20481869f3a161972b448d5e42 100644 (file)
@@ -10,7 +10,7 @@ path = "lib.rs"
 
 [dependencies]
 log = "0.4"
-unicode-security = "0.0.3"
+unicode-security = "0.0.5"
 rustc_middle = { path = "../librustc_middle" }
 rustc_ast_pretty = { path = "../librustc_ast_pretty" }
 rustc_attr = { path = "../librustc_attr" }
index 5b282c4203400bb2bec0e70a669c1c545f350845..82ac60be17c82115d4f72e7502b65f2e87f68acf 100644 (file)
@@ -31,7 +31,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>
 
             // Check if the method call actually calls the libcore
             // `IntoIterator::into_iter`.
-            let def_id = cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+            let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
             match cx.tcx.trait_of_item(def_id) {
                 Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
                 _ => return,
@@ -45,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>
             // `Box` is the only thing that values can be moved out of via
             // method call. `Box::new([1]).into_iter()` should trigger this
             // lint.
-            let mut recv_ty = cx.tables.expr_ty(receiver_arg);
+            let mut recv_ty = cx.tables().expr_ty(receiver_arg);
             let mut num_box_derefs = 0;
             while recv_ty.is_box() {
                 num_box_derefs += 1;
@@ -60,13 +60,13 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>
             // Make sure that there is an autoref coercion at the expected
             // position. The first `num_box_derefs` adjustments are the derefs
             // of the box.
-            match cx.tables.expr_adjustments(receiver_arg).get(num_box_derefs) {
+            match cx.tables().expr_adjustments(receiver_arg).get(num_box_derefs) {
                 Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
                 _ => return,
             }
 
             // Emit lint diagnostic.
-            let target = match cx.tables.expr_ty_adjusted(receiver_arg).kind {
+            let target = match cx.tables().expr_ty_adjusted(receiver_arg).kind {
                 ty::Ref(_, ty::TyS { kind: ty::Array(..), .. }, _) => "[T; N]",
                 ty::Ref(_, ty::TyS { kind: ty::Slice(..), .. }, _) => "[T]",
 
index efe60ce1b8889d83c21d82dd0694281bbca4b9db..36d2954ac6ef779a31abcb1e1d8fe6ed796ed4d1 100644 (file)
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
 use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
 use rustc_feature::{GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{GenericParamKind, PatKind};
-use rustc_hir::{HirIdSet, Node};
+use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
+use rustc_hir::{HirId, HirIdSet, Node};
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -48,7 +48,7 @@
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
-use log::debug;
+use log::{debug, trace};
 use std::fmt::Write;
 
 // hardwired lints from librustc_middle
@@ -144,7 +144,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) {
-        let ty = cx.tables.node_type(e.hir_id);
+        let ty = cx.tables().node_type(e.hir_id);
         self.check_heap_type(cx, e.span, ty);
     }
 }
@@ -161,11 +161,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns {
     fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
         if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind {
             let variant = cx
-                .tables
+                .tables()
                 .pat_ty(pat)
                 .ty_adt_def()
                 .expect("struct pattern type is not an ADT")
-                .variant_of_res(cx.tables.qpath_res(qpath, pat.hir_id));
+                .variant_of_res(cx.tables().qpath_res(qpath, pat.hir_id));
             for fieldpat in field_pats {
                 if fieldpat.is_shorthand {
                     continue;
@@ -178,7 +178,7 @@ fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
                 }
                 if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
                     if cx.tcx.find_field_index(ident, &variant)
-                        == Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables))
+                        == Some(cx.tcx.field_index(fieldpat.hir_id, cx.tables()))
                     {
                         cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
                             let mut err = lint
@@ -562,7 +562,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
             return;
         }
         let param_env = ty::ParamEnv::empty();
-        if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
+        if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
             return;
         }
         if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
@@ -901,7 +901,7 @@ fn get_transmute_from_to<'a, 'tcx>(
             expr: &hir::Expr<'_>,
         ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
             let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
-                cx.tables.qpath_res(qpath, expr.hir_id)
+                cx.tables().qpath_res(qpath, expr.hir_id)
             } else {
                 return None;
             };
@@ -909,7 +909,7 @@ fn get_transmute_from_to<'a, 'tcx>(
                 if !def_id_is_transmute(cx, did) {
                     return None;
                 }
-                let sig = cx.tables.node_type(expr.hir_id).fn_sig(cx.tcx);
+                let sig = cx.tables().node_type(expr.hir_id).fn_sig(cx.tcx);
                 let from = sig.inputs().skip_binder()[0];
                 let to = *sig.output().skip_binder();
                 return Some((from, to));
@@ -1891,7 +1891,7 @@ fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> Option<I
             if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
                 // Find calls to `mem::{uninitialized,zeroed}` methods.
                 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
-                    let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
+                    let def_id = cx.tables().qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
 
                     if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
                         return Some(InitKind::Zeroed);
@@ -1905,14 +1905,14 @@ fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> Option<I
                 }
             } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
                 // Find problematic calls to `MaybeUninit::assume_init`.
-                let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?;
+                let def_id = cx.tables().type_dependent_def_id(expr.hir_id)?;
                 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
                     // This is a call to *some* method named `assume_init`.
                     // See if the `self` parameter is one of the dangerous constructors.
                     if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
                         if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
                             let def_id =
-                                cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
+                                cx.tables().qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
 
                             if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
                                 return Some(InitKind::Zeroed);
@@ -2025,7 +2025,7 @@ fn ty_find_init_error<'tcx>(
             // This conjures an instance of a type out of nothing,
             // using zeroed or uninitialized memory.
             // We are extremely conservative with what we warn about.
-            let conjured_ty = cx.tables.expr_ty(expr);
+            let conjured_ty = cx.tables().expr_ty(expr);
             if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) {
                 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
                     let mut err = lint.build(&format!(
@@ -2053,3 +2053,224 @@ fn ty_find_init_error<'tcx>(
         }
     }
 }
+
+declare_lint! {
+    pub CLASHING_EXTERN_DECLARATIONS,
+    Warn,
+    "detects when an extern fn has been declared with the same name but different types"
+}
+
+pub struct ClashingExternDeclarations {
+    seen_decls: FxHashMap<Symbol, HirId>,
+}
+
+/// Differentiate between whether the name for an extern decl came from the link_name attribute or
+/// just from declaration itself. This is important because we don't want to report clashes on
+/// symbol name if they don't actually clash because one or the other links against a symbol with a
+/// different name.
+enum SymbolName {
+    /// The name of the symbol + the span of the annotation which introduced the link name.
+    Link(Symbol, Span),
+    /// No link name, so just the name of the symbol.
+    Normal(Symbol),
+}
+
+impl SymbolName {
+    fn get_name(&self) -> Symbol {
+        match self {
+            SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
+        }
+    }
+}
+
+impl ClashingExternDeclarations {
+    crate fn new() -> Self {
+        ClashingExternDeclarations { seen_decls: FxHashMap::default() }
+    }
+    /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
+    /// for the item, return its HirId without updating the set.
+    fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
+        let hid = fi.hir_id;
+
+        let name =
+            &tcx.codegen_fn_attrs(tcx.hir().local_def_id(hid)).link_name.unwrap_or(fi.ident.name);
+
+        if self.seen_decls.contains_key(name) {
+            // Avoid updating the map with the new entry when we do find a collision. We want to
+            // make sure we're always pointing to the first definition as the previous declaration.
+            // This lets us avoid emitting "knock-on" diagnostics.
+            Some(*self.seen_decls.get(name).unwrap())
+        } else {
+            self.seen_decls.insert(*name, hid)
+        }
+    }
+
+    /// Get the name of the symbol that's linked against for a given extern declaration. That is,
+    /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
+    /// symbol's name.
+    fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
+        let did = tcx.hir().local_def_id(fi.hir_id);
+        if let Some((overridden_link_name, overridden_link_name_span)) =
+            tcx.codegen_fn_attrs(did).link_name.map(|overridden_link_name| {
+                // FIXME: Instead of searching through the attributes again to get span
+                // information, we could have codegen_fn_attrs also give span information back for
+                // where the attribute was defined. However, until this is found to be a
+                // bottleneck, this does just fine.
+                (
+                    overridden_link_name,
+                    tcx.get_attrs(did.to_def_id())
+                        .iter()
+                        .find(|at| at.check_name(sym::link_name))
+                        .unwrap()
+                        .span,
+                )
+            })
+        {
+            SymbolName::Link(overridden_link_name, overridden_link_name_span)
+        } else {
+            SymbolName::Normal(fi.ident.name)
+        }
+    }
+
+    /// Checks whether two types are structurally the same enough that the declarations shouldn't
+    /// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
+    /// with the same members (as the declarations shouldn't clash).
+    fn structurally_same_type<'a, 'tcx>(
+        cx: &LateContext<'a, 'tcx>,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+    ) -> bool {
+        let tcx = cx.tcx;
+        if a == b || rustc_middle::ty::TyS::same_type(a, b) {
+            // All nominally-same types are structurally same, too.
+            true
+        } else {
+            // Do a full, depth-first comparison between the two.
+            use rustc_middle::ty::TyKind::*;
+            let a_kind = &a.kind;
+            let b_kind = &b.kind;
+
+            match (a_kind, b_kind) {
+                (Adt(..), Adt(..)) => {
+                    // Adts are pretty straightforward: just compare the layouts.
+                    use rustc_target::abi::LayoutOf;
+                    let a_layout = cx.layout_of(a).unwrap().layout;
+                    let b_layout = cx.layout_of(b).unwrap().layout;
+                    a_layout == b_layout
+                }
+                (Array(a_ty, a_const), Array(b_ty, b_const)) => {
+                    // For arrays, we also check the constness of the type.
+                    a_const.val == b_const.val
+                        && Self::structurally_same_type(cx, a_const.ty, b_const.ty)
+                        && Self::structurally_same_type(cx, a_ty, b_ty)
+                }
+                (Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty),
+                (RawPtr(a_tymut), RawPtr(b_tymut)) => {
+                    a_tymut.mutbl == a_tymut.mutbl
+                        && Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty)
+                }
+                (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
+                    // For structural sameness, we don't need the region to be same.
+                    a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty)
+                }
+                (FnDef(..), FnDef(..)) => {
+                    // As we don't compare regions, skip_binder is fine.
+                    let a_poly_sig = a.fn_sig(tcx);
+                    let b_poly_sig = b.fn_sig(tcx);
+
+                    let a_sig = a_poly_sig.skip_binder();
+                    let b_sig = b_poly_sig.skip_binder();
+
+                    (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
+                        == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+                        && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
+                            Self::structurally_same_type(cx, a, b)
+                        })
+                        && Self::structurally_same_type(cx, a_sig.output(), b_sig.output())
+                }
+                (Tuple(a_substs), Tuple(b_substs)) => {
+                    a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
+                        Self::structurally_same_type(cx, a_ty, b_ty)
+                    })
+                }
+                // For these, it's not quite as easy to define structural-sameness quite so easily.
+                // For the purposes of this lint, take the conservative approach and mark them as
+                // not structurally same.
+                (Dynamic(..), Dynamic(..))
+                | (Error(..), Error(..))
+                | (Closure(..), Closure(..))
+                | (Generator(..), Generator(..))
+                | (GeneratorWitness(..), GeneratorWitness(..))
+                | (Projection(..), Projection(..))
+                | (Opaque(..), Opaque(..)) => false,
+                // These definitely should have been caught above.
+                (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
+                _ => false,
+            }
+        }
+    }
+}
+
+impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ClashingExternDeclarations {
+    fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, this_fi: &hir::ForeignItem<'_>) {
+        trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi);
+        if let ForeignItemKind::Fn(..) = this_fi.kind {
+            let tcx = *&cx.tcx;
+            if let Some(existing_hid) = self.insert(tcx, this_fi) {
+                let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
+                let this_decl_ty = tcx.type_of(tcx.hir().local_def_id(this_fi.hir_id));
+                debug!(
+                    "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
+                    existing_hid, existing_decl_ty, this_fi.hir_id, this_decl_ty
+                );
+                // Check that the declarations match.
+                if !Self::structurally_same_type(cx, existing_decl_ty, this_decl_ty) {
+                    let orig_fi = tcx.hir().expect_foreign_item(existing_hid);
+                    let orig = Self::name_of_extern_decl(tcx, orig_fi);
+
+                    // We want to ensure that we use spans for both decls that include where the
+                    // name was defined, whether that was from the link_name attribute or not.
+                    let get_relevant_span =
+                        |fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) {
+                            SymbolName::Normal(_) => fi.span,
+                            SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
+                        };
+                    // Finally, emit the diagnostic.
+                    tcx.struct_span_lint_hir(
+                        CLASHING_EXTERN_DECLARATIONS,
+                        this_fi.hir_id,
+                        get_relevant_span(this_fi),
+                        |lint| {
+                            let mut expected_str = DiagnosticStyledString::new();
+                            expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
+                            let mut found_str = DiagnosticStyledString::new();
+                            found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
+
+                            lint.build(&format!(
+                                "`{}` redeclare{} with a different signature",
+                                this_fi.ident.name,
+                                if orig.get_name() == this_fi.ident.name {
+                                    "d".to_string()
+                                } else {
+                                    format!("s `{}`", orig.get_name())
+                                }
+                            ))
+                            .span_label(
+                                get_relevant_span(orig_fi),
+                                &format!("`{}` previously declared here", orig.get_name()),
+                            )
+                            .span_label(
+                                get_relevant_span(this_fi),
+                                "this signature doesn't match the previous declaration",
+                            )
+                            .note_expected_found(&"", expected_str, &"", found_str)
+                            .emit()
+                        },
+                    );
+                }
+            }
+        }
+    }
+}
index e5d3227d5afd461e4e27d6b44043e63e54c2ade0..0b4ae131af0fc2c5793ab4f46f7f55631205c9a9 100644 (file)
@@ -37,6 +37,7 @@
 use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
 use rustc_target::abi::LayoutOf;
 
+use std::cell::Cell;
 use std::slice;
 
 /// Information about the registered lints.
@@ -423,9 +424,17 @@ 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>,
+    /// Current body, or `None` if outside a body.
+    pub enclosing_body: Option<hir::BodyId>,
+
+    /// Type-checking side-tables for the current body. Access using the
+    /// `tables` method, which handles querying the tables on demand.
+    // FIXME(eddyb) move all the code accessing internal fields like this,
+    // to this module, to avoid exposing it to lint logic.
+    pub(super) cached_typeck_tables: Cell<Option<&'tcx ty::TypeckTables<'tcx>>>,
+
+    // HACK(eddyb) replace this with having `Option` around `&TypeckTables`.
+    pub(super) empty_typeck_tables: &'a ty::TypeckTables<'tcx>,
 
     /// Parameter environment for the item we are in.
     pub param_env: ty::ParamEnv<'tcx>,
@@ -667,6 +676,22 @@ fn lookup<S: Into<MultiSpan>>(
 }
 
 impl<'a, 'tcx> LateContext<'a, 'tcx> {
+    /// Gets the type-checking side-tables for the current body,
+    /// or empty `TypeckTables` if outside a body.
+    // FIXME(eddyb) return `Option<&'tcx ty::TypeckTables<'tcx>>`,
+    // where `None` indicates we're outside a body.
+    pub fn tables(&self) -> &'a ty::TypeckTables<'tcx> {
+        if let Some(body) = self.enclosing_body {
+            self.cached_typeck_tables.get().unwrap_or_else(|| {
+                let tables = self.tcx.body_tables(body);
+                self.cached_typeck_tables.set(Some(tables));
+                tables
+            })
+        } else {
+            self.empty_typeck_tables
+        }
+    }
+
     pub fn current_lint_root(&self) -> hir::HirId {
         self.last_node_with_lint_attrs
     }
index 06987ffa3d569c77588fb7b1b2ba884e0d38da76..d891466611ad379611cd2ce32db66ec2761e8ec8 100644 (file)
@@ -55,7 +55,8 @@ fn with_lint_attrs<F>(&mut self, id: ast::NodeId, attrs: &'a [ast::Attribute], f
     where
         F: FnOnce(&mut Self),
     {
-        let push = self.context.builder.push(attrs, &self.context.lint_store);
+        let is_crate_node = id == ast::CRATE_NODE_ID;
+        let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node);
         self.check_id(id);
         self.enter_attrs(attrs);
         f(self);
index c8f827b1f5cedf23681e876a2e8bff4a4551c4d2..ef62d44c4026bf578dfefc741e489015aa3c3847 100644 (file)
@@ -30,6 +30,7 @@
 
 use log::debug;
 use std::any::Any;
+use std::cell::Cell;
 use std::slice;
 
 /// Extract the `LintStore` from the query context.
@@ -104,12 +105,25 @@ fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
         hir_visit::NestedVisitorMap::All(self.context.tcx.hir())
     }
 
-    fn visit_nested_body(&mut self, body: hir::BodyId) {
-        let old_tables = self.context.tables;
-        self.context.tables = self.context.tcx.body_tables(body);
-        let body = self.context.tcx.hir().body(body);
+    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
+        let old_enclosing_body = self.context.enclosing_body.replace(body_id);
+        let old_cached_typeck_tables = self.context.cached_typeck_tables.get();
+
+        // HACK(eddyb) avoid trashing `cached_typeck_tables` when we're
+        // nested in `visit_fn`, which may have already resulted in them
+        // being queried.
+        if old_enclosing_body != Some(body_id) {
+            self.context.cached_typeck_tables.set(None);
+        }
+
+        let body = self.context.tcx.hir().body(body_id);
         self.visit_body(body);
-        self.context.tables = old_tables;
+        self.context.enclosing_body = old_enclosing_body;
+
+        // See HACK comment above.
+        if old_enclosing_body != Some(body_id) {
+            self.context.cached_typeck_tables.set(old_cached_typeck_tables);
+        }
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
@@ -181,13 +195,14 @@ fn visit_fn(
     ) {
         // Wrap in tables here, not just in visit_nested_body,
         // in order for `check_fn` to be able to use them.
-        let old_tables = self.context.tables;
-        self.context.tables = self.context.tcx.body_tables(body_id);
+        let old_enclosing_body = self.context.enclosing_body.replace(body_id);
+        let old_cached_typeck_tables = self.context.cached_typeck_tables.take();
         let body = self.context.tcx.hir().body(body_id);
         lint_callback!(self, check_fn, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
         lint_callback!(self, check_fn_post, fk, decl, body, span, id);
-        self.context.tables = old_tables;
+        self.context.enclosing_body = old_enclosing_body;
+        self.context.cached_typeck_tables.set(old_cached_typeck_tables);
     }
 
     fn visit_variant_data(
@@ -361,7 +376,9 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
 
     let context = LateContext {
         tcx,
-        tables: &ty::TypeckTables::empty(None),
+        enclosing_body: None,
+        cached_typeck_tables: Cell::new(None),
+        empty_typeck_tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
         lint_store: unerased_lint_store(tcx),
@@ -408,7 +425,9 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
 
     let context = LateContext {
         tcx,
-        tables: &ty::TypeckTables::empty(None),
+        enclosing_body: None,
+        cached_typeck_tables: Cell::new(None),
+        empty_typeck_tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
         lint_store: unerased_lint_store(tcx),
index 05e7c9a0c780de86898cb28e32a1118872a05495..f875e2750a5c56fa9b4464937ed1cb899910ac00 100644 (file)
@@ -29,7 +29,7 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> LintLevelMap {
     let mut builder = LintLevelMapBuilder { levels, tcx, store };
     let krate = tcx.hir().krate();
 
-    let push = builder.levels.push(&krate.item.attrs, &store);
+    let push = builder.levels.push(&krate.item.attrs, &store, true);
     builder.levels.register_id(hir::CRATE_HIR_ID);
     for macro_def in krate.exported_macros {
         builder.levels.register_id(macro_def.hir_id);
@@ -109,7 +109,12 @@ fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
     ///   `#[allow]`
     ///
     /// Don't forget to call `pop`!
-    pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
+    pub fn push(
+        &mut self,
+        attrs: &[ast::Attribute],
+        store: &LintStore,
+        is_crate_node: bool,
+    ) -> BuilderPush {
         let mut specs = FxHashMap::default();
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
@@ -333,6 +338,40 @@ pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPu
             }
         }
 
+        if !is_crate_node {
+            for (id, &(level, ref src)) in specs.iter() {
+                if !id.lint.crate_level_only {
+                    continue;
+                }
+
+                let (lint_attr_name, lint_attr_span) = match *src {
+                    LintSource::Node(name, span, _) => (name, span),
+                    _ => continue,
+                };
+
+                let lint = builtin::UNUSED_ATTRIBUTES;
+                let (lint_level, lint_src) =
+                    self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                struct_lint_level(
+                    self.sess,
+                    lint,
+                    lint_level,
+                    lint_src,
+                    Some(lint_attr_span.into()),
+                    |lint| {
+                        let mut db = lint.build(&format!(
+                            "{}({}) is ignored unless specified at crate level",
+                            level.as_str(),
+                            lint_attr_name
+                        ));
+                        db.emit();
+                    },
+                );
+                // don't set a separate error for every lint in the group
+                break;
+            }
+        }
+
         for (id, &(level, ref src)) in specs.iter() {
             if level == Level::Forbid {
                 continue;
@@ -449,7 +488,8 @@ fn with_lint_attrs<F>(&mut self, id: hir::HirId, attrs: &[ast::Attribute], f: F)
     where
         F: FnOnce(&mut Self),
     {
-        let push = self.levels.push(attrs, self.store);
+        let is_crate_hir = id == hir::CRATE_HIR_ID;
+        let push = self.levels.push(attrs, self.store, is_crate_hir);
         if push.changed {
             self.levels.register_id(id);
         }
index b791d313fc4f438a47e0e850da80401770ab3a6b..4da98d201593b1dbf6715dba90076c2907e51086 100644 (file)
@@ -30,6 +30,7 @@
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
+#![feature(iter_order_by)]
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(or_patterns)]
@@ -154,6 +155,7 @@ macro_rules! late_lint_passes {
                 // and change this to a module lint pass
                 MissingDebugImplementations: MissingDebugImplementations::default(),
                 ArrayIntoIter: ArrayIntoIter,
+                ClashingExternDeclarations: ClashingExternDeclarations::new(),
             ]
         );
     };
@@ -165,7 +167,8 @@ macro_rules! late_lint_mod_passes {
             $args,
             [
                 HardwiredLints: HardwiredLints,
-                ImproperCTypes: ImproperCTypes,
+                ImproperCTypesDeclarations: ImproperCTypesDeclarations,
+                ImproperCTypesDefinitions: ImproperCTypesDefinitions,
                 VariantSizeDifferences: VariantSizeDifferences,
                 BoxPointers: BoxPointers,
                 PathStatements: PathStatements,
index ad02b2637d22f1da7b6832aa08c9008271d8a689..30dbd069c29bd2d847050b2955c477997040fdc0 100644 (file)
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast::ast;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::{Ident, SymbolStr};
-use std::hash::{Hash, Hasher};
-use std::ops::Deref;
+use rustc_span::symbol::SymbolStr;
 
 declare_lint! {
     pub NON_ASCII_IDENTS,
     Allow,
-    "detects non-ASCII identifiers"
+    "detects non-ASCII identifiers",
+    crate_level_only
 }
 
 declare_lint! {
     pub UNCOMMON_CODEPOINTS,
     Warn,
-    "detects uncommon Unicode codepoints in identifiers"
+    "detects uncommon Unicode codepoints in identifiers",
+    crate_level_only
 }
 
-// FIXME: Change this to warn.
 declare_lint! {
     pub CONFUSABLE_IDENTS,
-    Allow,
-    "detects visually confusable pairs between identifiers"
-}
-
-declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]);
-
-enum CowBoxSymStr {
-    Interned(SymbolStr),
-    Owned(Box<str>),
-}
-
-impl Deref for CowBoxSymStr {
-    type Target = str;
-
-    fn deref(&self) -> &str {
-        match self {
-            CowBoxSymStr::Interned(interned) => interned,
-            CowBoxSymStr::Owned(ref owned) => owned,
-        }
-    }
-}
-
-impl Hash for CowBoxSymStr {
-    #[inline]
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        Hash::hash(&**self, state)
-    }
-}
-
-impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
-    #[inline]
-    fn eq(&self, other: &CowBoxSymStr) -> bool {
-        PartialEq::eq(&**self, &**other)
-    }
-}
-
-impl Eq for CowBoxSymStr {}
-
-fn calc_skeleton(symbol_str: SymbolStr, buffer: &'_ mut String) -> CowBoxSymStr {
-    use std::mem::swap;
-    use unicode_security::confusable_detection::skeleton;
-    buffer.clear();
-    buffer.extend(skeleton(&symbol_str));
-    if symbol_str == *buffer {
-        CowBoxSymStr::Interned(symbol_str)
-    } else {
-        let mut owned = String::new();
-        swap(buffer, &mut owned);
-        CowBoxSymStr::Owned(owned.into_boxed_str())
-    }
+    Warn,
+    "detects visually confusable pairs between identifiers",
+    crate_level_only
 }
 
-fn is_in_ascii_confusable_closure(c: char) -> bool {
-    // FIXME: move this table to `unicode_security` crate.
-    // data here corresponds to Unicode 13.
-    const ASCII_CONFUSABLE_CLOSURE: &[(u64, u64)] = &[(0x00, 0x7f), (0xba, 0xba), (0x2080, 0x2080)];
-    let c = c as u64;
-    for &(range_start, range_end) in ASCII_CONFUSABLE_CLOSURE {
-        if c >= range_start && c <= range_end {
-            return true;
-        }
-    }
-    false
+declare_lint! {
+    pub MIXED_SCRIPT_CONFUSABLES,
+    Warn,
+    "detects Unicode scripts whose mixed script confusables codepoints are solely used",
+    crate_level_only
 }
 
-fn is_in_ascii_confusable_closure_relevant_list(c: char) -> bool {
-    // FIXME: move this table to `unicode_security` crate.
-    // data here corresponds to Unicode 13.
-    const ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST: &[u64] = &[
-        0x22, 0x25, 0x27, 0x2f, 0x30, 0x31, 0x49, 0x4f, 0x60, 0x6c, 0x6d, 0x6e, 0x72, 0x7c, 0xba,
-        0x2080,
-    ];
-    let c = c as u64;
-    for &item in ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST {
-        if c == item {
-            return true;
-        }
-    }
-    false
-}
+declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS, MIXED_SCRIPT_CONFUSABLES]);
 
 impl EarlyLintPass for NonAsciiIdents {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
         use rustc_session::lint::Level;
-        if cx.builder.lint_level(CONFUSABLE_IDENTS).0 == Level::Allow {
+        use rustc_span::Span;
+        use std::collections::BTreeMap;
+        use unicode_security::GeneralSecurityProfile;
+        use utils::CowBoxSymStr;
+
+        let check_non_ascii_idents = cx.builder.lint_level(NON_ASCII_IDENTS).0 != Level::Allow;
+        let check_uncommon_codepoints =
+            cx.builder.lint_level(UNCOMMON_CODEPOINTS).0 != Level::Allow;
+        let check_confusable_idents = cx.builder.lint_level(CONFUSABLE_IDENTS).0 != Level::Allow;
+        let check_mixed_script_confusables =
+            cx.builder.lint_level(MIXED_SCRIPT_CONFUSABLES).0 != Level::Allow;
+
+        if !check_non_ascii_idents
+            && !check_uncommon_codepoints
+            && !check_confusable_idents
+            && !check_mixed_script_confusables
+        {
             return;
         }
+
+        let mut has_non_ascii_idents = false;
         let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
-        let mut symbol_strs_and_spans = Vec::with_capacity(symbols.len());
-        let mut in_fast_path = true;
-        for (symbol, sp) in symbols.iter() {
-            // fast path
+        for (symbol, &sp) in symbols.iter() {
             let symbol_str = symbol.as_str();
-            if !symbol_str.chars().all(is_in_ascii_confusable_closure) {
-                // fallback to slow path.
-                symbol_strs_and_spans.clear();
-                in_fast_path = false;
-                break;
+            if symbol_str.is_ascii() {
+                continue;
             }
-            if symbol_str.chars().any(is_in_ascii_confusable_closure_relevant_list) {
-                symbol_strs_and_spans.push((symbol_str, *sp));
+            has_non_ascii_idents = true;
+            cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
+                lint.build("identifier contains non-ASCII characters").emit()
+            });
+            if check_uncommon_codepoints
+                && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
+            {
+                cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
+                    lint.build("identifier contains uncommon Unicode codepoints").emit()
+                })
             }
         }
-        if !in_fast_path {
-            // slow path
-            for (symbol, sp) in symbols.iter() {
+
+        if has_non_ascii_idents && check_confusable_idents {
+            let mut skeleton_map: FxHashMap<CowBoxSymStr, (SymbolStr, Span, bool)> =
+                FxHashMap::with_capacity_and_hasher(symbols.len(), Default::default());
+            let mut str_buf = String::new();
+            for (symbol, &sp) in symbols.iter() {
+                fn calc_skeleton(symbol_str: &SymbolStr, buffer: &mut String) -> CowBoxSymStr {
+                    use std::mem::replace;
+                    use unicode_security::confusable_detection::skeleton;
+                    buffer.clear();
+                    buffer.extend(skeleton(symbol_str));
+                    if *symbol_str == *buffer {
+                        CowBoxSymStr::Interned(symbol_str.clone())
+                    } else {
+                        let owned = replace(buffer, String::new());
+                        CowBoxSymStr::Owned(owned.into_boxed_str())
+                    }
+                }
                 let symbol_str = symbol.as_str();
-                symbol_strs_and_spans.push((symbol_str, *sp));
+                let is_ascii = symbol_str.is_ascii();
+                let skeleton = calc_skeleton(&symbol_str, &mut str_buf);
+                skeleton_map
+                    .entry(skeleton)
+                    .and_modify(|(existing_symbolstr, existing_span, existing_is_ascii)| {
+                        if !*existing_is_ascii || !is_ascii {
+                            cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
+                                lint.build(&format!(
+                                    "identifier pair considered confusable between `{}` and `{}`",
+                                    existing_symbolstr, symbol_str
+                                ))
+                                .span_label(
+                                    *existing_span,
+                                    "this is where the previous identifier occurred",
+                                )
+                                .emit();
+                            });
+                        }
+                        if *existing_is_ascii && !is_ascii {
+                            *existing_symbolstr = symbol_str.clone();
+                            *existing_span = sp;
+                            *existing_is_ascii = is_ascii;
+                        }
+                    })
+                    .or_insert((symbol_str, sp, is_ascii));
             }
         }
-        drop(symbols);
-        symbol_strs_and_spans.sort_by_key(|x| x.0.clone());
-        let mut skeleton_map =
-            FxHashMap::with_capacity_and_hasher(symbol_strs_and_spans.len(), Default::default());
-        let mut str_buf = String::new();
-        for (symbol_str, sp) in symbol_strs_and_spans {
-            let skeleton = calc_skeleton(symbol_str.clone(), &mut str_buf);
-            skeleton_map
-                .entry(skeleton)
-                .and_modify(|(existing_symbolstr, existing_span)| {
-                    cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
-                        lint.build(&format!(
-                            "identifier pair considered confusable between `{}` and `{}`",
-                            existing_symbolstr, symbol_str
-                        ))
-                        .span_label(
-                            *existing_span,
-                            "this is where the previous identifier occurred",
-                        )
-                        .emit();
+
+        if has_non_ascii_idents && check_mixed_script_confusables {
+            use unicode_security::is_potential_mixed_script_confusable_char;
+            use unicode_security::mixed_script::AugmentedScriptSet;
+
+            #[derive(Clone)]
+            enum ScriptSetUsage {
+                Suspicious(Vec<char>, Span),
+                Verified,
+            }
+
+            let mut script_states: FxHashMap<AugmentedScriptSet, ScriptSetUsage> =
+                FxHashMap::default();
+            let latin_augmented_script_set = AugmentedScriptSet::for_char('A');
+            script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified);
+
+            let mut has_suspicous = false;
+            for (symbol, &sp) in symbols.iter() {
+                let symbol_str = symbol.as_str();
+                for ch in symbol_str.chars() {
+                    if ch.is_ascii() {
+                        // all ascii characters are covered by exception.
+                        continue;
+                    }
+                    if !GeneralSecurityProfile::identifier_allowed(ch) {
+                        // this character is covered by `uncommon_codepoints` lint.
+                        continue;
+                    }
+                    let augmented_script_set = AugmentedScriptSet::for_char(ch);
+                    script_states
+                        .entry(augmented_script_set)
+                        .and_modify(|existing_state| {
+                            if let ScriptSetUsage::Suspicious(ch_list, _) = existing_state {
+                                if is_potential_mixed_script_confusable_char(ch) {
+                                    ch_list.push(ch);
+                                } else {
+                                    *existing_state = ScriptSetUsage::Verified;
+                                }
+                            }
+                        })
+                        .or_insert_with(|| {
+                            if !is_potential_mixed_script_confusable_char(ch) {
+                                ScriptSetUsage::Verified
+                            } else {
+                                has_suspicous = true;
+                                ScriptSetUsage::Suspicious(vec![ch], sp)
+                            }
+                        });
+                }
+            }
+
+            if has_suspicous {
+                let verified_augmented_script_sets = script_states
+                    .iter()
+                    .flat_map(|(k, v)| match v {
+                        ScriptSetUsage::Verified => Some(*k),
+                        _ => None,
+                    })
+                    .collect::<Vec<_>>();
+
+                // we're sorting the output here.
+                let mut lint_reports: BTreeMap<(Span, Vec<char>), AugmentedScriptSet> =
+                    BTreeMap::new();
+
+                'outerloop: for (augment_script_set, usage) in script_states {
+                    let (mut ch_list, sp) = match usage {
+                        ScriptSetUsage::Verified => continue,
+                        ScriptSetUsage::Suspicious(ch_list, sp) => (ch_list, sp),
+                    };
+
+                    if augment_script_set.is_all() {
+                        continue;
+                    }
+
+                    for existing in verified_augmented_script_sets.iter() {
+                        if existing.is_all() {
+                            continue;
+                        }
+                        let mut intersect = *existing;
+                        intersect.intersect_with(augment_script_set);
+                        if !intersect.is_empty() && !intersect.is_all() {
+                            continue 'outerloop;
+                        }
+                    }
+
+                    ch_list.sort();
+                    ch_list.dedup();
+                    lint_reports.insert((sp, ch_list), augment_script_set);
+                }
+
+                for ((sp, ch_list), script_set) in lint_reports {
+                    cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
+                        let message = format!(
+                            "The usage of Script Group `{}` in this crate consists solely of mixed script confusables",
+                            script_set);
+                        let mut note = "The usage includes ".to_string();
+                        for (idx, ch) in ch_list.into_iter().enumerate() {
+                            if idx != 0 {
+                                note += ", ";
+                            }
+                            let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
+                            note += &char_info;
+                        }
+                        note += ".";
+                        lint.build(&message).note(&note).note("Please recheck to make sure their usages are indeed what you want.").emit()
                     });
-                })
-                .or_insert((symbol_str, sp));
+                }
+            }
         }
     }
-    fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
-        use unicode_security::GeneralSecurityProfile;
-        let name_str = ident.name.as_str();
-        if name_str.is_ascii() {
-            return;
+}
+
+mod utils {
+    use rustc_span::symbol::SymbolStr;
+    use std::hash::{Hash, Hasher};
+    use std::ops::Deref;
+
+    pub(super) enum CowBoxSymStr {
+        Interned(SymbolStr),
+        Owned(Box<str>),
+    }
+
+    impl Deref for CowBoxSymStr {
+        type Target = str;
+
+        fn deref(&self) -> &str {
+            match self {
+                CowBoxSymStr::Interned(interned) => interned,
+                CowBoxSymStr::Owned(ref owned) => owned,
+            }
         }
-        cx.struct_span_lint(NON_ASCII_IDENTS, ident.span, |lint| {
-            lint.build("identifier contains non-ASCII characters").emit()
-        });
-        if !name_str.chars().all(GeneralSecurityProfile::identifier_allowed) {
-            cx.struct_span_lint(UNCOMMON_CODEPOINTS, ident.span, |lint| {
-                lint.build("identifier contains uncommon Unicode codepoints").emit()
-            })
+    }
+
+    impl Hash for CowBoxSymStr {
+        #[inline]
+        fn hash<H: Hasher>(&self, state: &mut H) {
+            Hash::hash(&**self, state)
         }
     }
+
+    impl PartialEq<CowBoxSymStr> for CowBoxSymStr {
+        #[inline]
+        fn eq(&self, other: &CowBoxSymStr) -> bool {
+            PartialEq::eq(&**self, &**other)
+        }
+    }
+
+    impl Eq for CowBoxSymStr {}
 }
index a8ecfdd0f3d4523a139bb4e07726d2daff04d07d..d0275a0dd0dcbf72d451822f4e6f2d09bf3ea117 100644 (file)
 use rustc_middle::mir::interpret::{sign_extend, truncate};
 use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
-use rustc_span::Span;
-use rustc_target::abi::{DiscriminantKind, Integer, LayoutOf, VariantIdx, Variants};
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
 use rustc_target::spec::abi::Abi;
 
 use log::debug;
@@ -167,7 +167,8 @@ fn report_bin_hex_error(
              the type `{}` and will become `{}{}`",
             repr_str, val, t, actually, t
         ));
-        if let Some(sugg_ty) = get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative)
+        if let Some(sugg_ty) =
+            get_type_suggestion(&cx.tables().node_type(expr.hir_id), val, negative)
         {
             if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
                 let (sans_suffix, _) = repr_str.split_at(pos);
@@ -301,7 +302,7 @@ fn lint_uint_literal<'a, 'tcx>(
         if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) {
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
-                    if let ty::Char = cx.tables.expr_ty(par_e).kind {
+                    if let ty::Char = cx.tables().expr_ty(par_e).kind {
                         cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
                             lint.build("only `u8` can be cast into `char`")
                                 .span_suggestion(
@@ -352,7 +353,7 @@ fn lint_literal<'a, 'tcx>(
     e: &'tcx hir::Expr<'tcx>,
     lit: &hir::Lit,
 ) {
-    match cx.tables.node_type(e.hir_id).kind {
+    match cx.tables().node_type(e.hir_id).kind {
         ty::Int(t) => {
             match lit.node {
                 ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => {
@@ -448,7 +449,7 @@ fn check_limits(
             // Normalize the binop so that the literal is always on the RHS in
             // the comparison
             let norm_binop = if swap { rev_binop(binop) } else { binop };
-            match cx.tables.node_type(expr.hir_id).kind {
+            match cx.tables().node_type(expr.hir_id).kind {
                 ty::Int(int_ty) => {
                     let (min, max) = int_ty_range(int_ty);
                     let lit_val: i128 = match lit.kind {
@@ -498,90 +499,108 @@ fn is_comparison(binop: hir::BinOp) -> bool {
     "proper use of libc types in foreign modules"
 }
 
-declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]);
+declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
+
+declare_lint! {
+    IMPROPER_CTYPES_DEFINITIONS,
+    Warn,
+    "proper use of libc types in foreign item definitions"
+}
+
+declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
+
+enum ImproperCTypesMode {
+    Declarations,
+    Definitions,
+}
 
 struct ImproperCTypesVisitor<'a, 'tcx> {
     cx: &'a LateContext<'a, 'tcx>,
+    mode: ImproperCTypesMode,
 }
 
 enum FfiResult<'tcx> {
     FfiSafe,
     FfiPhantom(Ty<'tcx>),
-    FfiUnsafe { ty: Ty<'tcx>, reason: &'static str, help: Option<&'static str> },
+    FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
 }
 
-fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    match ty.kind {
-        ty::FnPtr(_) => true,
-        ty::Ref(..) => true,
-        ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
-            for field in field_def.all_fields() {
-                let field_ty =
-                    tcx.normalize_erasing_regions(ParamEnv::reveal_all(), field.ty(tcx, substs));
-                if field_ty.is_zst(tcx, field.did) {
-                    continue;
-                }
+impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
+    /// Is type known to be non-null?
+    fn ty_is_known_nonnull(&self, ty: Ty<'tcx>) -> bool {
+        match ty.kind {
+            ty::FnPtr(_) => true,
+            ty::Ref(..) => true,
+            ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
+                for field in field_def.all_fields() {
+                    let field_ty = self.cx.tcx.normalize_erasing_regions(
+                        self.cx.param_env,
+                        field.ty(self.cx.tcx, substs),
+                    );
+                    if field_ty.is_zst(self.cx.tcx, field.did) {
+                        continue;
+                    }
 
-                let attrs = tcx.get_attrs(field_def.did);
-                if attrs.iter().any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
-                    || ty_is_known_nonnull(tcx, field_ty)
-                {
-                    return true;
+                    let attrs = self.cx.tcx.get_attrs(field_def.did);
+                    if attrs
+                        .iter()
+                        .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
+                        || self.ty_is_known_nonnull(field_ty)
+                    {
+                        return true;
+                    }
                 }
-            }
 
-            false
+                false
+            }
+            _ => false,
         }
-        _ => false,
     }
-}
 
-/// Check if this enum can be safely exported based on the
-/// "nullable pointer optimization". Currently restricted
-/// to function pointers, references, core::num::NonZero*,
-/// core::ptr::NonNull, and #[repr(transparent)] newtypes.
-/// FIXME: This duplicates code in codegen.
-fn is_repr_nullable_ptr<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-    ty_def: &'tcx ty::AdtDef,
-    substs: SubstsRef<'tcx>,
-) -> bool {
-    if ty_def.variants.len() != 2 {
-        return false;
-    }
+    /// Check if this enum can be safely exported based on the "nullable pointer optimization".
+    /// Currently restricted to function pointers, references, `core::num::NonZero*`,
+    /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
+    fn is_repr_nullable_ptr(
+        &self,
+        ty: Ty<'tcx>,
+        ty_def: &'tcx ty::AdtDef,
+        substs: SubstsRef<'tcx>,
+    ) -> bool {
+        if ty_def.variants.len() != 2 {
+            return false;
+        }
 
-    let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
-    let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
-    let fields = if variant_fields[0].is_empty() {
-        &variant_fields[1]
-    } else if variant_fields[1].is_empty() {
-        &variant_fields[0]
-    } else {
-        return false;
-    };
+        let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
+        let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
+        let fields = if variant_fields[0].is_empty() {
+            &variant_fields[1]
+        } else if variant_fields[1].is_empty() {
+            &variant_fields[0]
+        } else {
+            return false;
+        };
 
-    if fields.len() != 1 {
-        return false;
-    }
+        if fields.len() != 1 {
+            return false;
+        }
 
-    let field_ty = fields[0].ty(tcx, substs);
-    if !ty_is_known_nonnull(tcx, field_ty) {
-        return false;
-    }
+        let field_ty = fields[0].ty(self.cx.tcx, substs);
+        if !self.ty_is_known_nonnull(field_ty) {
+            return false;
+        }
 
-    // At this point, the field's type is known to be nonnull and the parent enum is Option-like.
-    // If the computed size for the field and the enum are different, the nonnull optimization isn't
-    // being applied (and we've got a problem somewhere).
-    let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, ParamEnv::reveal_all()).unwrap();
-    if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
-        bug!("improper_ctypes: Option nonnull optimization not applied?");
-    }
+        // At this point, the field's type is known to be nonnull and the parent enum is
+        // Option-like. If the computed size for the field and the enum are different, the non-null
+        // optimization isn't being applied (and we've got a problem somewhere).
+        let compute_size_skeleton =
+            |t| SizeSkeleton::compute(t, self.cx.tcx, self.cx.param_env).unwrap();
+        if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
+            bug!("improper_ctypes: Option nonnull optimization not applied?");
+        }
 
-    true
-}
+        true
+    }
 
-impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the type is array and emit an unsafe type lint.
     fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         if let ty::Array(..) = ty.kind {
@@ -597,6 +616,66 @@ fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         }
     }
 
+    /// Checks if the given field's type is "ffi-safe".
+    fn check_field_type_for_ffi(
+        &self,
+        cache: &mut FxHashSet<Ty<'tcx>>,
+        field: &ty::FieldDef,
+        substs: SubstsRef<'tcx>,
+    ) -> FfiResult<'tcx> {
+        let field_ty = field.ty(self.cx.tcx, substs);
+        if field_ty.has_opaque_types() {
+            self.check_type_for_ffi(cache, field_ty)
+        } else {
+            let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty);
+            self.check_type_for_ffi(cache, field_ty)
+        }
+    }
+
+    /// Checks if the given `VariantDef`'s field types are "ffi-safe".
+    fn check_variant_for_ffi(
+        &self,
+        cache: &mut FxHashSet<Ty<'tcx>>,
+        ty: Ty<'tcx>,
+        def: &ty::AdtDef,
+        variant: &ty::VariantDef,
+        substs: SubstsRef<'tcx>,
+    ) -> FfiResult<'tcx> {
+        use FfiResult::*;
+
+        if def.repr.transparent() {
+            // Can assume that only one field is not a ZST, so only check
+            // that field's type for FFI-safety.
+            if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) {
+                self.check_field_type_for_ffi(cache, field, substs)
+            } else {
+                bug!("malformed transparent type");
+            }
+        } else {
+            // We can't completely trust repr(C) markings; make sure the fields are
+            // actually safe.
+            let mut all_phantom = !variant.fields.is_empty();
+            for field in &variant.fields {
+                match self.check_field_type_for_ffi(cache, &field, substs) {
+                    FfiSafe => {
+                        all_phantom = false;
+                    }
+                    FfiPhantom(..) if def.is_enum() => {
+                        return FfiUnsafe {
+                            ty,
+                            reason: "this enum contains a PhantomData field".into(),
+                            help: None,
+                        };
+                    }
+                    FfiPhantom(..) => {}
+                    r => return r,
+                }
+            }
+
+            if all_phantom { FfiPhantom(ty) } else { FfiSafe }
+        }
+    }
+
     /// Checks if the given type is "ffi-safe" (has a stable, well-defined
     /// representation which can be exported to C code).
     fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult<'tcx> {
@@ -618,15 +697,18 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                     return FfiPhantom(ty);
                 }
                 match def.adt_kind() {
-                    AdtKind::Struct => {
+                    AdtKind::Struct | AdtKind::Union => {
+                        let kind = if def.is_struct() { "struct" } else { "union" };
+
                         if !def.repr.c() && !def.repr.transparent() {
                             return FfiUnsafe {
                                 ty,
-                                reason: "this struct has unspecified layout",
-                                help: Some(
+                                reason: format!("this {} has unspecified layout", kind),
+                                help: Some(format!(
                                     "consider adding a `#[repr(C)]` or \
-                                            `#[repr(transparent)]` attribute to this struct",
-                                ),
+                                             `#[repr(transparent)]` attribute to this {}",
+                                    kind
+                                )),
                             };
                         }
 
@@ -635,7 +717,7 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                         if is_non_exhaustive && !def.did.is_local() {
                             return FfiUnsafe {
                                 ty,
-                                reason: "this struct is non-exhaustive",
+                                reason: format!("this {} is non-exhaustive", kind),
                                 help: None,
                             };
                         }
@@ -643,93 +725,12 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                         if def.non_enum_variant().fields.is_empty() {
                             return FfiUnsafe {
                                 ty,
-                                reason: "this struct has no fields",
-                                help: Some("consider adding a member to this struct"),
+                                reason: format!("this {} has no fields", kind),
+                                help: Some(format!("consider adding a member to this {}", kind)),
                             };
                         }
 
-                        if def.repr.transparent() {
-                            // Can assume that only one field is not a ZST, so only check
-                            // that field's type for FFI-safety.
-                            if let Some(field) =
-                                def.transparent_newtype_field(cx, self.cx.param_env)
-                            {
-                                let field_ty = cx.normalize_erasing_regions(
-                                    self.cx.param_env,
-                                    field.ty(cx, substs),
-                                );
-                                self.check_type_for_ffi(cache, field_ty)
-                            } else {
-                                FfiSafe
-                            }
-                        } else {
-                            // We can't completely trust repr(C) markings; make sure the fields are
-                            // actually safe.
-                            let mut all_phantom = true;
-                            for field in &def.non_enum_variant().fields {
-                                let field_ty = cx.normalize_erasing_regions(
-                                    self.cx.param_env,
-                                    field.ty(cx, substs),
-                                );
-                                let r = self.check_type_for_ffi(cache, field_ty);
-                                match r {
-                                    FfiSafe => {
-                                        all_phantom = false;
-                                    }
-                                    FfiPhantom(..) => {}
-                                    FfiUnsafe { .. } => {
-                                        return r;
-                                    }
-                                }
-                            }
-
-                            if all_phantom { FfiPhantom(ty) } else { FfiSafe }
-                        }
-                    }
-                    AdtKind::Union => {
-                        if !def.repr.c() && !def.repr.transparent() {
-                            return FfiUnsafe {
-                                ty,
-                                reason: "this union has unspecified layout",
-                                help: Some(
-                                    "consider adding a `#[repr(C)]` or \
-                                            `#[repr(transparent)]` attribute to this union",
-                                ),
-                            };
-                        }
-
-                        if def.non_enum_variant().fields.is_empty() {
-                            return FfiUnsafe {
-                                ty,
-                                reason: "this union has no fields",
-                                help: Some("consider adding a field to this union"),
-                            };
-                        }
-
-                        let mut all_phantom = true;
-                        for field in &def.non_enum_variant().fields {
-                            let field_ty = cx.normalize_erasing_regions(
-                                ParamEnv::reveal_all(),
-                                field.ty(cx, substs),
-                            );
-                            // repr(transparent) types are allowed to have arbitrary ZSTs, not just
-                            // PhantomData -- skip checking all ZST fields.
-                            if def.repr.transparent() && field_ty.is_zst(cx, field.did) {
-                                continue;
-                            }
-                            let r = self.check_type_for_ffi(cache, field_ty);
-                            match r {
-                                FfiSafe => {
-                                    all_phantom = false;
-                                }
-                                FfiPhantom(..) => {}
-                                FfiUnsafe { .. } => {
-                                    return r;
-                                }
-                            }
-                        }
-
-                        if all_phantom { FfiPhantom(ty) } else { FfiSafe }
+                        self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), substs)
                     }
                     AdtKind::Enum => {
                         if def.variants.is_empty() {
@@ -741,14 +742,15 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                         // discriminant.
                         if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
                             // Special-case types like `Option<extern fn()>`.
-                            if !is_repr_nullable_ptr(cx, ty, def, substs) {
+                            if !self.is_repr_nullable_ptr(ty, def, substs) {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: "enum has no representation hint",
+                                    reason: "enum has no representation hint".into(),
                                     help: Some(
                                         "consider adding a `#[repr(C)]`, \
                                                 `#[repr(transparent)]`, or integer `#[repr(...)]` \
-                                                attribute to this enum",
+                                                attribute to this enum"
+                                            .into(),
                                     ),
                                 };
                             }
@@ -757,7 +759,7 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                         if def.is_variant_list_non_exhaustive() && !def.did.is_local() {
                             return FfiUnsafe {
                                 ty,
-                                reason: "this enum is non-exhaustive",
+                                reason: "this enum is non-exhaustive".into(),
                                 help: None,
                             };
                         }
@@ -768,37 +770,17 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                             if is_non_exhaustive && !variant.def_id.is_local() {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: "this enum has non-exhaustive variants",
+                                    reason: "this enum has non-exhaustive variants".into(),
                                     help: None,
                                 };
                             }
 
-                            for field in &variant.fields {
-                                let field_ty = cx.normalize_erasing_regions(
-                                    ParamEnv::reveal_all(),
-                                    field.ty(cx, substs),
-                                );
-                                // repr(transparent) types are allowed to have arbitrary ZSTs, not
-                                // just PhantomData -- skip checking all ZST fields.
-                                if def.repr.transparent() && field_ty.is_zst(cx, field.did) {
-                                    continue;
-                                }
-                                let r = self.check_type_for_ffi(cache, field_ty);
-                                match r {
-                                    FfiSafe => {}
-                                    FfiUnsafe { .. } => {
-                                        return r;
-                                    }
-                                    FfiPhantom(..) => {
-                                        return FfiUnsafe {
-                                            ty,
-                                            reason: "this enum contains a PhantomData field",
-                                            help: None,
-                                        };
-                                    }
-                                }
+                            match self.check_variant_for_ffi(cache, ty, def, variant, substs) {
+                                FfiSafe => (),
+                                r => return r,
                             }
                         }
+
                         FfiSafe
                     }
                 }
@@ -806,13 +788,13 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
 
             ty::Char => FfiUnsafe {
                 ty,
-                reason: "the `char` type has no C equivalent",
-                help: Some("consider using `u32` or `libc::wchar_t` instead"),
+                reason: "the `char` type has no C equivalent".into(),
+                help: Some("consider using `u32` or `libc::wchar_t` instead".into()),
             },
 
             ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe {
                 ty,
-                reason: "128-bit integers don't currently have a known stable ABI",
+                reason: "128-bit integers don't currently have a known stable ABI".into(),
                 help: None,
             },
 
@@ -821,26 +803,35 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
 
             ty::Slice(_) => FfiUnsafe {
                 ty,
-                reason: "slices have no C equivalent",
-                help: Some("consider using a raw pointer instead"),
+                reason: "slices have no C equivalent".into(),
+                help: Some("consider using a raw pointer instead".into()),
             },
 
             ty::Dynamic(..) => {
-                FfiUnsafe { ty, reason: "trait objects have no C equivalent", help: None }
+                FfiUnsafe { ty, reason: "trait objects have no C equivalent".into(), help: None }
             }
 
             ty::Str => FfiUnsafe {
                 ty,
-                reason: "string slices have no C equivalent",
-                help: Some("consider using `*const u8` and a length instead"),
+                reason: "string slices have no C equivalent".into(),
+                help: Some("consider using `*const u8` and a length instead".into()),
             },
 
             ty::Tuple(..) => FfiUnsafe {
                 ty,
-                reason: "tuples have unspecified layout",
-                help: Some("consider using a struct instead"),
+                reason: "tuples have unspecified layout".into(),
+                help: Some("consider using a struct instead".into()),
             },
 
+            ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
+                if {
+                    matches!(self.mode, ImproperCTypesMode::Definitions)
+                        && ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env)
+                } =>
+            {
+                FfiSafe
+            }
+
             ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
                 self.check_type_for_ffi(cache, ty)
             }
@@ -848,18 +839,16 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
             ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
 
             ty::FnPtr(sig) => {
-                match sig.abi() {
-                    Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
-                        return FfiUnsafe {
-                            ty,
-                            reason: "this function pointer has Rust-specific calling convention",
-                            help: Some(
-                                "consider using an `extern fn(...) -> ...` \
-                                        function pointer instead",
-                            ),
-                        };
-                    }
-                    _ => {}
+                if self.is_internal_abi(sig.abi()) {
+                    return FfiUnsafe {
+                        ty,
+                        reason: "this function pointer has Rust-specific calling convention".into(),
+                        help: Some(
+                            "consider using an `extern fn(...) -> ...` \
+                                    function pointer instead"
+                                .into(),
+                        ),
+                    };
                 }
 
                 let sig = cx.erase_late_bound_regions(&sig);
@@ -886,16 +875,29 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
 
             ty::Foreign(..) => FfiSafe,
 
+            // While opaque types are checked for earlier, if a projection in a struct field
+            // normalizes to an opaque type, then it will reach this branch.
+            ty::Opaque(..) => {
+                FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
+            }
+
+            // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
+            //  so they are currently ignored for the purposes of this lint.
+            ty::Param(..) | ty::Projection(..)
+                if matches!(self.mode, ImproperCTypesMode::Definitions) =>
+            {
+                FfiSafe
+            }
+
             ty::Param(..)
+            | ty::Projection(..)
             | ty::Infer(..)
             | ty::Bound(..)
-            | ty::Error
+            | ty::Error(_)
             | ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
             | ty::Placeholder(..)
-            | ty::Projection(..)
-            | ty::Opaque(..)
             | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
         }
     }
@@ -907,9 +909,20 @@ fn emit_ffi_unsafe_type_lint(
         note: &str,
         help: Option<&str>,
     ) {
-        self.cx.struct_span_lint(IMPROPER_CTYPES, sp, |lint| {
-            let mut diag =
-                lint.build(&format!("`extern` block uses type `{}`, which is not FFI-safe", ty));
+        let lint = match self.mode {
+            ImproperCTypesMode::Declarations => IMPROPER_CTYPES,
+            ImproperCTypesMode::Definitions => IMPROPER_CTYPES_DEFINITIONS,
+        };
+
+        self.cx.struct_span_lint(lint, sp, |lint| {
+            let item_description = match self.mode {
+                ImproperCTypesMode::Declarations => "block",
+                ImproperCTypesMode::Definitions => "fn",
+            };
+            let mut diag = lint.build(&format!(
+                "`extern` {} uses type `{}`, which is not FFI-safe",
+                item_description, ty
+            ));
             diag.span_label(sp, "not FFI-safe");
             if let Some(help) = help {
                 diag.help(help);
@@ -925,24 +938,33 @@ fn emit_ffi_unsafe_type_lint(
     }
 
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
-        use rustc_middle::ty::TypeFoldable;
-
-        struct ProhibitOpaqueTypes<'tcx> {
+        struct ProhibitOpaqueTypes<'a, 'tcx> {
+            cx: &'a LateContext<'a, 'tcx>,
             ty: Option<Ty<'tcx>>,
         };
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
+        impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
-                if let ty::Opaque(..) = ty.kind {
-                    self.ty = Some(ty);
-                    true
-                } else {
-                    ty.super_visit_with(self)
+                match ty.kind {
+                    ty::Opaque(..) => {
+                        self.ty = Some(ty);
+                        true
+                    }
+                    // Consider opaque types within projections FFI-safe if they do not normalize
+                    // to more opaque types.
+                    ty::Projection(..) => {
+                        let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
+
+                        // If `ty` is a opaque type directly then `super_visit_with` won't invoke
+                        // this function again.
+                        if ty.has_opaque_types() { self.visit_ty(ty) } else { false }
+                    }
+                    _ => ty.super_visit_with(self),
                 }
             }
         }
 
-        let mut visitor = ProhibitOpaqueTypes { ty: None };
+        let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None };
         ty.visit_with(&mut visitor);
         if let Some(ty) = visitor.ty {
             self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
@@ -968,7 +990,7 @@ fn check_type_for_ffi_and_report_errors(
 
         // it is only OK to use this function because extern fns cannot have
         // any generic types right now:
-        let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+        let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
 
         // C doesn't really support passing arrays by value - the only way to pass an array by value
         // is through a struct. So, first test that the top level isn't an array, and then
@@ -993,7 +1015,7 @@ fn check_type_for_ffi_and_report_errors(
             // argument, which after substitution, is `()`, then this branch can be hit.
             FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => return,
             FfiResult::FfiUnsafe { ty, reason, help } => {
-                self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
+                self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref());
             }
         }
     }
@@ -1018,15 +1040,22 @@ fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
         let ty = self.cx.tcx.type_of(def_id);
         self.check_type_for_ffi_and_report_errors(span, ty, true, false);
     }
+
+    fn is_internal_abi(&self, abi: Abi) -> bool {
+        if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
+            true
+        } else {
+            false
+        }
+    }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDeclarations {
     fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem<'_>) {
-        let mut vis = ImproperCTypesVisitor { cx };
+        let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Declarations };
         let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
-        if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
-            // Don't worry about types in internal ABIs.
-        } else {
+
+        if !vis.is_internal_abi(abi) {
             match it.kind {
                 hir::ForeignItemKind::Fn(ref decl, _, _) => {
                     vis.check_foreign_fn(it.hir_id, decl);
@@ -1040,6 +1069,31 @@ fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem
     }
 }
 
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDefinitions {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        kind: hir::intravisit::FnKind<'tcx>,
+        decl: &'tcx hir::FnDecl<'_>,
+        _: &'tcx hir::Body<'_>,
+        _: Span,
+        hir_id: hir::HirId,
+    ) {
+        use hir::intravisit::FnKind;
+
+        let abi = match kind {
+            FnKind::ItemFn(_, _, header, ..) => header.abi,
+            FnKind::Method(_, sig, ..) => sig.header.abi,
+            _ => return,
+        };
+
+        let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Definitions };
+        if !vis.is_internal_abi(abi) {
+            vis.check_foreign_fn(hir_id, decl);
+        }
+    }
+}
+
 declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
@@ -1056,15 +1110,15 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
             };
             let (variants, tag) = match layout.variants {
                 Variants::Multiple {
-                    discr_kind: DiscriminantKind::Tag,
-                    ref discr,
+                    tag_encoding: TagEncoding::Direct,
+                    ref tag,
                     ref variants,
                     ..
-                } => (variants, discr),
+                } => (variants, tag),
                 _ => return,
             };
 
-            let discr_size = tag.value.size(&cx.tcx).bytes();
+            let tag_size = tag.value.size(&cx.tcx).bytes();
 
             debug!(
                 "enum `{}` is {} bytes large with layout:\n{:#?}",
@@ -1078,8 +1132,8 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item<'_>) {
                 .iter()
                 .zip(variants)
                 .map(|(variant, variant_layout)| {
-                    // Subtract the size of the enum discriminant.
-                    let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
+                    // Subtract the size of the enum tag.
+                    let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
 
                     debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
                     bytes
index 8196b37391b21cdb044fd25df5ef32c1c48eedc5..506ac77894a41f36a40b2a7ed42c77165b852880 100644 (file)
@@ -46,7 +46,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt<'_>) {
             return;
         }
 
-        let ty = cx.tables.expr_ty(&expr);
+        let ty = cx.tables().expr_ty(&expr);
         let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1);
 
         let mut fn_warned = false;
@@ -55,7 +55,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt<'_>) {
             hir::ExprKind::Call(ref callee, _) => {
                 match callee.kind {
                     hir::ExprKind::Path(ref qpath) => {
-                        match cx.tables.qpath_res(qpath, callee.hir_id) {
+                        match cx.tables().qpath_res(qpath, callee.hir_id) {
                             Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
                             // `Res::Local` if it was a closure, for which we
                             // do not currently support must-use linting
@@ -65,7 +65,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt<'_>) {
                     _ => None,
                 }
             }
-            hir::ExprKind::MethodCall(..) => cx.tables.type_dependent_def_id(expr.hir_id),
+            hir::ExprKind::MethodCall(..) => cx.tables().type_dependent_def_id(expr.hir_id),
             _ => None,
         };
         if let Some(def_id) = maybe_def_id {
@@ -950,7 +950,7 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) {
             _ => return,
         }
 
-        for adj in cx.tables.expr_adjustments(e) {
+        for adj in cx.tables().expr_adjustments(e) {
             if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
                 cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
                     let msg = match m {
index ada48bc147e47866750a725b1c35f57e1a0b58b9..d25f8bd1b8c58c9bbbc78ab1e1d920c436f7a910 100644 (file)
@@ -293,11 +293,9 @@ fn main() {
         }
     }
 
-    // LLVM requires symbols from this library, but apparently they're not printed
-    // during llvm-config?
+    // Libstdc++ depends on pthread which Rust doesn't link on MinGW
+    // since nothing else requires it.
     if target.contains("windows-gnu") {
-        println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
         println!("cargo:rustc-link-lib=static-nobundle=pthread");
-        println!("cargo:rustc-link-lib=dylib=uuid");
     }
 }
index 79e1a6cc5dcdb7e3cb3024948bad3541bdbb6b9d..f54ed9b92029ecbb0e34f511356432e9c05f91aa 100644 (file)
@@ -15,6 +15,7 @@ pub struct RustString {
 
 /// Appending to a Rust string -- used by RawRustStringOstream.
 #[no_mangle]
+#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
 pub unsafe extern "C" fn LLVMRustStringWriteImpl(
     sr: &RustString,
     ptr: *const c_char,
index b8ebcd6c8a8fffb138ad51c2e46dd95190f95351..2c80c846681a66e60eba35f04fca53d0e5f40289 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_expand::base::SyntaxExtension;
-use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
 use rustc_middle::middle::cstore::DepKind;
@@ -452,6 +452,14 @@ fn resolve_crate<'b>(
         if dep.is_none() {
             self.used_extern_options.insert(name);
         }
+        if !name.as_str().is_ascii() {
+            self.sess
+                .struct_span_err(
+                    span,
+                    &format!("cannot load a crate with a non-ascii name `{}`", name,),
+                )
+                .emit();
+        }
         self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
     }
 
@@ -698,7 +706,9 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
     }
 
     fn inject_profiler_runtime(&mut self) {
-        if (self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled())
+        if (self.sess.opts.debugging_opts.instrument_coverage
+            || self.sess.opts.debugging_opts.profile
+            || self.sess.opts.cg.profile_generate.enabled())
             && !self.sess.opts.debugging_opts.no_profiler_runtime
         {
             info!("loading profiler");
@@ -886,6 +896,7 @@ pub fn process_extern_crate(
         &mut self,
         item: &ast::Item,
         definitions: &Definitions,
+        def_id: LocalDefId,
     ) -> CrateNum {
         match item.kind {
             ast::ItemKind::ExternCrate(orig_name) => {
@@ -908,7 +919,6 @@ pub fn process_extern_crate(
 
                 let cnum = self.resolve_crate(name, item.span, dep_kind, None);
 
-                let def_id = definitions.opt_local_def_id(item.id).unwrap();
                 let path_len = definitions.def_path(def_id).data.len();
                 self.update_extern_crate(
                     cnum,
index 5a4862d4521833f38c12ead3abf493d8ca4c770b..1bdac1039b55a48e07bb179599993968857b0fdf 100644 (file)
@@ -488,6 +488,8 @@ impl<'a> CrateLocator<'a> {
                 && self.triple != TargetTriple::from_triple(config::host_triple())
             {
                 err.note(&format!("the `{}` target may not be installed", self.triple));
+            } else if self.crate_name == sym::profiler_builtins {
+                err.note(&"the compiler may have been built without the profiler runtime");
             }
             err.span_label(self.span, "can't find crate");
             err
index 0335aa8358c3c9a6fb1adeffbbaf4e7bad7da7b2..2254d553337d5fed65d94daa7b19b3d40311af0f 100644 (file)
@@ -294,15 +294,36 @@ fn cached_ty_for_shorthand<F>(
 
         let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
 
-        if let Some(&ty) = tcx.rcache.borrow().get(&key) {
+        if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
             return Ok(ty);
         }
 
         let ty = or_insert_with(self)?;
-        tcx.rcache.borrow_mut().insert(key, ty);
+        tcx.ty_rcache.borrow_mut().insert(key, ty);
         Ok(ty)
     }
 
+    fn cached_predicate_for_shorthand<F>(
+        &mut self,
+        shorthand: usize,
+        or_insert_with: F,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error>
+    where
+        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
+    {
+        let tcx = self.tcx();
+
+        let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
+
+        if let Some(&pred) = tcx.pred_rcache.borrow().get(&key) {
+            return Ok(pred);
+        }
+
+        let pred = or_insert_with(self)?;
+        tcx.pred_rcache.borrow_mut().insert(key, pred);
+        Ok(pred)
+    }
+
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
@@ -565,6 +586,7 @@ impl MetadataBlob {
 impl EntryKind {
     fn def_kind(&self) -> DefKind {
         match *self {
+            EntryKind::AnonConst(..) => DefKind::AnonConst,
             EntryKind::Const(..) => DefKind::Const,
             EntryKind::AssocConst(..) => DefKind::AssocConst,
             EntryKind::ImmStatic
@@ -1121,7 +1143,8 @@ fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted
 
     fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs {
         match self.kind(id) {
-            EntryKind::Const(qualif, _)
+            EntryKind::AnonConst(qualif, _)
+            | EntryKind::Const(qualif, _)
             | EntryKind::AssocConst(
                 AssocContainer::ImplDefault
                 | AssocContainer::ImplFinal
@@ -1340,7 +1363,9 @@ fn exported_symbols(
 
     fn get_rendered_const(&self, id: DefIndex) -> String {
         match self.kind(id) {
-            EntryKind::Const(_, data) | EntryKind::AssocConst(_, _, data) => data.decode(self).0,
+            EntryKind::AnonConst(_, data)
+            | EntryKind::Const(_, data)
+            | EntryKind::AssocConst(_, _, data) => data.decode(self).0,
             _ => bug!(),
         }
     }
index d797e6d4a34af6d0ed57c7948997657b3bd45d1e..d01c767e2bc044219b9c74695c9370e69c90e33c 100644 (file)
@@ -239,6 +239,17 @@ fn specialized_encode(&mut self, ty: &&'a ty::TyS<'b>) -> Result<(), Self::Error
     }
 }
 
+impl<'b, 'tcx> SpecializedEncoder<ty::Predicate<'b>> for EncodeContext<'tcx> {
+    fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> {
+        debug_assert!(self.tcx.lift(predicate).is_some());
+        let predicate =
+            unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) };
+        ty_codec::encode_with_shorthand(self, predicate, |encoder| {
+            &mut encoder.predicate_shorthands
+        })
+    }
+}
+
 impl<'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'tcx> {
     fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
         use std::collections::hash_map::Entry;
@@ -256,22 +267,6 @@ fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Se
     }
 }
 
-impl<'a, 'b, 'tcx> SpecializedEncoder<&'a [(ty::Predicate<'b>, Span)]> for EncodeContext<'tcx> {
-    fn specialized_encode(
-        &mut self,
-        predicates: &&'a [(ty::Predicate<'b>, Span)],
-    ) -> Result<(), Self::Error> {
-        debug_assert!(self.tcx.lift(*predicates).is_some());
-        let predicates = unsafe {
-            std::mem::transmute::<
-                &&'a [(ty::Predicate<'b>, Span)],
-                &&'tcx [(ty::Predicate<'tcx>, Span)],
-            >(predicates)
-        };
-        ty_codec::encode_spanned_predicates(self, &predicates, |ecx| &mut ecx.predicate_shorthands)
-    }
-}
-
 impl<'tcx> SpecializedEncoder<Fingerprint> for EncodeContext<'tcx> {
     fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
         f.encode_opaque(&mut self.opaque)
@@ -1358,7 +1353,7 @@ fn encode_info_for_anon_const(&mut self, def_id: LocalDefId) {
         let const_data = self.encode_rendered_const_for_body(body_id);
         let qualifs = self.tcx.mir_const_qualif(def_id);
 
-        record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Const(qualifs, const_data));
+        record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data));
         record!(self.tables.visibility[def_id.to_def_id()] <- ty::Visibility::Public);
         record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
         self.encode_item_type(def_id.to_def_id());
index ec80a2b6171edf7f2f5e65f9355fd8887c39bde5..381e7ee115e173ceac4a535c6b8bf621513b663f 100644 (file)
@@ -281,6 +281,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 enum EntryKind {
+    AnonConst(mir::ConstQualifs, Lazy<RenderedConst>),
     Const(mir::ConstQualifs, Lazy<RenderedConst>),
     ImmStatic,
     MutStatic,
index 0c22672d5fb7d90fb20371b9054519012cad23a9..02d82c6793386ab8b3ba7fa1fc9ca72bea49219a 100644 (file)
@@ -30,7 +30,7 @@ rustc_serialize = { path = "../librustc_serialize" }
 rustc_ast = { path = "../librustc_ast" }
 rustc_span = { path = "../librustc_span" }
 byteorder = { version = "1.3" }
-chalk-ir = "0.10.0"
+chalk-ir = "0.14.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 measureme = "0.7.1"
 rustc_session = { path = "../librustc_session" }
index f861d63aba0f3c4f77cf6927c732b0bb3624ef61..4f1889aeb162a4a4cc6b2824bdf5034a1ea86557 100644 (file)
@@ -100,6 +100,7 @@ macro_rules! arena_types {
 
             // Interned types
             [] tys: rustc_middle::ty::TyS<$tcx>, rustc_middle::ty::TyS<'_x>;
+            [] predicates: rustc_middle::ty::PredicateInner<$tcx>, rustc_middle::ty::PredicateInner<'_x>;
 
             // HIR query types
             [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, rustc_middle::hir::map::IndexedHir<'_x>;
@@ -114,6 +115,7 @@ macro_rules! arena_types {
 
             // This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
             [decode] span: rustc_span::Span, rustc_span::Span;
+            [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>;
         ], $tcx);
     )
 }
index 2906da437abac1c10b4ae6841ef9a6223c9c57a0..dce06a5f7eeecd12125045c78a4613a40b59c04d 100644 (file)
@@ -117,6 +117,7 @@ pub(super) fn root(
                 body_ids: _,
                 modules: _,
                 proc_macros: _,
+                trait_map: _,
             } = *krate;
 
             hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes)
@@ -241,11 +242,8 @@ fn insert_with_hash(&mut self, span: Span, hir_id: HirId, node: Node<'hir>, hash
         // Make sure that the DepNode of some node coincides with the HirId
         // owner of that node.
         if cfg!(debug_assertions) {
-            let node_id = self.definitions.hir_id_to_node_id(hir_id);
-            assert_eq!(self.definitions.node_id_to_hir_id(node_id), hir_id);
-
             if hir_id.owner != self.current_dep_node_owner {
-                let node_str = match self.definitions.opt_local_def_id(node_id) {
+                let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
                     Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(),
                     None => format!("{:?}", node),
                 };
@@ -335,9 +333,7 @@ fn visit_item(&mut self, i: &'hir Item<'hir>) {
         debug!("visit_item: {:?}", i);
         debug_assert_eq!(
             i.hir_id.owner,
-            self.definitions
-                .opt_local_def_id(self.definitions.hir_id_to_node_id(i.hir_id))
-                .unwrap()
+            self.definitions.opt_hir_id_to_local_def_id(i.hir_id).unwrap()
         );
         self.with_dep_node_owner(i.hir_id.owner, i, |this, hash| {
             this.insert_with_hash(i.span, i.hir_id, Node::Item(i), hash);
@@ -369,9 +365,7 @@ fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) {
     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
         debug_assert_eq!(
             ti.hir_id.owner,
-            self.definitions
-                .opt_local_def_id(self.definitions.hir_id_to_node_id(ti.hir_id))
-                .unwrap()
+            self.definitions.opt_hir_id_to_local_def_id(ti.hir_id).unwrap()
         );
         self.with_dep_node_owner(ti.hir_id.owner, ti, |this, hash| {
             this.insert_with_hash(ti.span, ti.hir_id, Node::TraitItem(ti), hash);
@@ -385,9 +379,7 @@ fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
         debug_assert_eq!(
             ii.hir_id.owner,
-            self.definitions
-                .opt_local_def_id(self.definitions.hir_id_to_node_id(ii.hir_id))
-                .unwrap()
+            self.definitions.opt_hir_id_to_local_def_id(ii.hir_id).unwrap()
         );
         self.with_dep_node_owner(ii.hir_id.owner, ii, |this, hash| {
             this.insert_with_hash(ii.span, ii.hir_id, Node::ImplItem(ii), hash);
index e3e0856ffc52ea5ac4f72ac536e43528cc0d2399..75c10de9bbe5ef29e38e4f707464ad3075c6f332 100644 (file)
@@ -56,7 +56,7 @@ fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> {
     }
 }
 
-fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
+pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
     match node {
         Node::Item(Item {
             kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
@@ -458,11 +458,11 @@ pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
         }
     }
 
-    pub fn visit_item_likes_in_module<V>(&self, module: DefId, visitor: &mut V)
+    pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V)
     where
         V: ItemLikeVisitor<'hir>,
     {
-        let module = self.tcx.hir_module_items(module.expect_local());
+        let module = self.tcx.hir_module_items(module);
 
         for id in &module.items {
             visitor.visit_item(self.expect_item(*id));
index 69b4adb3a0e1d7ed2e5b1f8f7ea5d2b843d32401..f5b0b73c49de1cf7230f100bfd2e3d53a377d7c5 100644 (file)
@@ -67,13 +67,15 @@ impl<'a> StableHashingContext<'a> {
     /// Don't use it for anything else or you'll run the risk of
     /// leaking data out of the tracking system.
     #[inline]
-    pub fn new(
+    fn new_with_or_without_spans(
         sess: &'a Session,
         krate: &'a hir::Crate<'a>,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
+        always_ignore_spans: bool,
     ) -> Self {
-        let hash_spans_initial = !sess.opts.debugging_opts.incremental_ignore_spans;
+        let hash_spans_initial =
+            !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
 
         StableHashingContext {
             sess,
@@ -88,6 +90,33 @@ pub fn new(
         }
     }
 
+    #[inline]
+    pub fn new(
+        sess: &'a Session,
+        krate: &'a hir::Crate<'a>,
+        definitions: &'a Definitions,
+        cstore: &'a dyn CrateStore,
+    ) -> Self {
+        Self::new_with_or_without_spans(
+            sess,
+            krate,
+            definitions,
+            cstore,
+            /*always_ignore_spans=*/ false,
+        )
+    }
+
+    #[inline]
+    pub fn ignore_spans(
+        sess: &'a Session,
+        krate: &'a hir::Crate<'a>,
+        definitions: &'a Definitions,
+        cstore: &'a dyn CrateStore,
+    ) -> Self {
+        let always_ignore_spans = true;
+        Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
+    }
+
     #[inline]
     pub fn sess(&self) -> &'a Session {
         self.sess
index f668cc99754f4e2265c20841b490fbcb75cafd91..78b9167ddd9679ca96b4f9da13b4bfd28259fe37 100644 (file)
@@ -210,16 +210,15 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
 }
 
 impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
-    type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>);
+    type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>);
 
     fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType {
         let hir::TraitCandidate { def_id, import_ids } = self;
 
-        let import_keys = import_ids
-            .iter()
-            .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), hir_id.local_id))
-            .collect();
-        (hcx.def_path_hash(*def_id), import_keys)
+        (
+            hcx.def_path_hash(*def_id),
+            import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(),
+        )
     }
 }
 
index 62c92e988ba60b12c18ab26996d91dea103d58be..676346fbebdd19bad462e63605d8b089d3c68208 100644 (file)
@@ -27,7 +27,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(const_transmute)]
@@ -36,7 +36,6 @@
 #![feature(drain_filter)]
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
-#![feature(marker_trait_attr)]
 #![feature(extern_types)]
 #![feature(nll)]
 #![feature(option_expect_none)]
@@ -45,7 +44,6 @@
 #![feature(min_specialization)]
 #![feature(track_caller)]
 #![feature(trusted_len)]
-#![feature(vec_remove_item)]
 #![feature(stmt_expr_attributes)]
 #![feature(test)]
 #![feature(in_band_lifetimes)]
index 923119e359c4749c00556006bfcabb991969c816..bb62c1bb82428d2bd19dcce8419e393d1d4433f5 100644 (file)
@@ -339,9 +339,7 @@ fn struct_lint_level_impl(
 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(_))
-        | ExpnKind::Desugaring(DesugaringKind::Operator) => false,
+        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false,
         ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
         ExpnKind::Macro(MacroKind::Bang, _) => {
             // Dummy span for the `def_site` means it's an external macro.
index c480944069efbed2339591899ccfea1984b71fd9..d2749f8529bed5b34baf7aa92ef5cff4b93d17ab 100644 (file)
@@ -1,5 +1,6 @@
 use crate::mir::mono::Linkage;
 use rustc_attr::{InlineAttr, OptimizeAttr};
+use rustc_session::config::SanitizerSet;
 use rustc_span::symbol::Symbol;
 
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
@@ -30,6 +31,9 @@ pub struct CodegenFnAttrs {
     /// The `#[link_section = "..."]` attribute, or what executable section this
     /// should be placed in.
     pub link_section: Option<Symbol>,
+    /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
+    /// instrumentation should be disabled inside the annotated function.
+    pub no_sanitize: SanitizerSet,
 }
 
 bitflags! {
@@ -69,20 +73,12 @@ pub struct CodegenFnAttrFlags: u32 {
         const FFI_RETURNS_TWICE         = 1 << 10;
         /// `#[track_caller]`: allow access to the caller location
         const TRACK_CALLER              = 1 << 11;
-        /// `#[no_sanitize(address)]`: disables address sanitizer instrumentation
-        const NO_SANITIZE_ADDRESS = 1 << 12;
-        /// `#[no_sanitize(memory)]`: disables memory sanitizer instrumentation
-        const NO_SANITIZE_MEMORY  = 1 << 13;
-        /// `#[no_sanitize(thread)]`: disables thread sanitizer instrumentation
-        const NO_SANITIZE_THREAD  = 1 << 14;
-        /// All `#[no_sanitize(...)]` attributes.
-        const NO_SANITIZE_ANY = Self::NO_SANITIZE_ADDRESS.bits | Self::NO_SANITIZE_MEMORY.bits | Self::NO_SANITIZE_THREAD.bits;
         /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
         /// declaration.
-        const FFI_PURE = 1 << 15;
+        const FFI_PURE                  = 1 << 12;
         /// #[ffi_const]: applies clang's `const` attribute to a foreign function
         /// declaration.
-        const FFI_CONST = 1 << 16;
+        const FFI_CONST                 = 1 << 13;
     }
 }
 
@@ -98,6 +94,7 @@ pub fn new() -> CodegenFnAttrs {
             target_features: vec![],
             linkage: None,
             link_section: None,
+            no_sanitize: SanitizerSet::empty(),
         }
     }
 
index 1b3ede40f023a002b98182f4f07364035c1fecc0..abbbbf7fbd6a46bc3fde0b300403334fda4983d6 100644 (file)
@@ -390,8 +390,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     InvalidBool(u8),
     /// Using a non-character `u32` as character.
     InvalidChar(u32),
-    /// An enum discriminant was set to a value which was outside the range of valid values.
-    InvalidDiscriminant(Scalar),
+    /// The tag of an enum does not encode an actual discriminant.
+    InvalidTag(Scalar),
     /// Using a pointer-not-to-a-function as function pointer.
     InvalidFunctionPointer(Pointer),
     /// Using a string that is not valid UTF-8,
@@ -463,7 +463,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             InvalidChar(c) => {
                 write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
             }
-            InvalidDiscriminant(val) => write!(f, "enum value has invalid discriminant: {}", val),
+            InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
             InvalidFunctionPointer(p) => {
                 write!(f, "using {} as function pointer but it does not point to a function", p)
             }
index 27848684706d6d824e34e6f8debb769d95f32769..0ed0d9050078c04e34e61a6139e948f71833d343 100644 (file)
@@ -29,6 +29,7 @@
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
 use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::borrow::Cow;
 use std::fmt::{self, Debug, Display, Formatter, Write};
@@ -145,14 +146,6 @@ pub struct Body<'tcx> {
     /// Debug information pertaining to user variables, including captures.
     pub var_debug_info: Vec<VarDebugInfo<'tcx>>,
 
-    /// Mark this MIR of a const context other than const functions as having converted a `&&` or
-    /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop
-    /// this conversion from happening and use short circuiting, we will cause the following code
-    /// to change the value of `x`: `let mut x = 42; false && { x = 55; true };`
-    ///
-    /// List of places where control flow was destroyed. Used for error reporting.
-    pub control_flow_destroyed: Vec<(Span, String)>,
-
     /// A span representing this MIR, for error reporting.
     pub span: Span,
 
@@ -163,8 +156,8 @@ pub struct Body<'tcx> {
     /// 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
+    /// `&[(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.
@@ -182,7 +175,6 @@ pub fn new(
         arg_count: usize,
         var_debug_info: Vec<VarDebugInfo<'tcx>>,
         span: Span,
-        control_flow_destroyed: Vec<(Span, String)>,
         generator_kind: Option<GeneratorKind>,
     ) -> Self {
         // We need `arg_count` locals, and one for the return place.
@@ -209,7 +201,6 @@ pub fn new(
             span,
             required_consts: Vec::new(),
             ignore_interior_mut_in_const_validation: false,
-            control_flow_destroyed,
             predecessor_cache: PredecessorCache::new(),
         }
     }
@@ -233,7 +224,6 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) ->
             spread_arg: None,
             span: DUMMY_SP,
             required_consts: Vec::new(),
-            control_flow_destroyed: Vec::new(),
             generator_kind: None,
             var_debug_info: Vec::new(),
             ignore_interior_mut_in_const_validation: false,
@@ -1074,6 +1064,8 @@ pub enum TerminatorKind<'tcx> {
         discr: Operand<'tcx>,
 
         /// The type of value being tested.
+        /// This is always the same as the type of `discr`.
+        /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
         switch_ty: Ty<'tcx>,
 
         /// Possible values. The locations to branch to in each case
@@ -1112,7 +1104,7 @@ pub enum TerminatorKind<'tcx> {
     Unreachable,
 
     /// Drop the `Place`.
-    Drop { location: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
+    Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
 
     /// Drop the `Place` and assign the new value over it. This ensures
     /// that the assignment to `P` occurs *even if* the destructor for
@@ -1141,7 +1133,7 @@ pub enum TerminatorKind<'tcx> {
     /// }
     /// ```
     DropAndReplace {
-        location: Place<'tcx>,
+        place: Place<'tcx>,
         value: Operand<'tcx>,
         target: BasicBlock,
         unwind: Option<BasicBlock>,
@@ -1243,10 +1235,10 @@ pub enum TerminatorKind<'tcx> {
 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
 pub enum AssertKind<O> {
     BoundsCheck { len: O, index: O },
-    Overflow(BinOp),
-    OverflowNeg,
-    DivisionByZero,
-    RemainderByZero,
+    Overflow(BinOp, O, O),
+    OverflowNeg(O),
+    DivisionByZero(O),
+    RemainderByZero(O),
     ResumedAfterReturn(GeneratorKind),
     ResumedAfterPanic(GeneratorKind),
 }
@@ -1519,17 +1511,17 @@ impl<O> AssertKind<O> {
     pub fn description(&self) -> &'static str {
         use AssertKind::*;
         match self {
-            Overflow(BinOp::Add) => "attempt to add with overflow",
-            Overflow(BinOp::Sub) => "attempt to subtract with overflow",
-            Overflow(BinOp::Mul) => "attempt to multiply with overflow",
-            Overflow(BinOp::Div) => "attempt to divide with overflow",
-            Overflow(BinOp::Rem) => "attempt to calculate the remainder with overflow",
-            OverflowNeg => "attempt to negate with overflow",
-            Overflow(BinOp::Shr) => "attempt to shift right with overflow",
-            Overflow(BinOp::Shl) => "attempt to shift left with overflow",
-            Overflow(op) => bug!("{:?} cannot overflow", op),
-            DivisionByZero => "attempt to divide by zero",
-            RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
+            Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
+            Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
+            Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
+            Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
+            Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
+            OverflowNeg(_) => "attempt to negate with overflow",
+            Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
+            Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
+            Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
+            DivisionByZero(_) => "attempt to divide by zero",
+            RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
             ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
             ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
             ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
@@ -1543,12 +1535,54 @@ fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
     where
         O: Debug,
     {
+        use AssertKind::*;
         match self {
-            AssertKind::BoundsCheck { ref len, ref index } => write!(
+            BoundsCheck { ref len, ref index } => write!(
                 f,
                 "\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}",
                 len, index
             ),
+
+            OverflowNeg(op) => {
+                write!(f, "\"attempt to negate {{}} which would overflow\", {:?}", op)
+            }
+            DivisionByZero(op) => write!(f, "\"attempt to divide {{}} by zero\", {:?}", op),
+            RemainderByZero(op) => write!(
+                f,
+                "\"attempt to calculate the remainder of {{}} with a divisor of zero\", {:?}",
+                op
+            ),
+            Overflow(BinOp::Add, l, r) => write!(
+                f,
+                "\"attempt to compute `{{}} + {{}}` which would overflow\", {:?}, {:?}",
+                l, r
+            ),
+            Overflow(BinOp::Sub, l, r) => write!(
+                f,
+                "\"attempt to compute `{{}} - {{}}` which would overflow\", {:?}, {:?}",
+                l, r
+            ),
+            Overflow(BinOp::Mul, l, r) => write!(
+                f,
+                "\"attempt to compute `{{}} * {{}}` which would overflow\", {:?}, {:?}",
+                l, r
+            ),
+            Overflow(BinOp::Div, l, r) => write!(
+                f,
+                "\"attempt to compute `{{}} / {{}}` which would overflow\", {:?}, {:?}",
+                l, r
+            ),
+            Overflow(BinOp::Rem, l, r) => write!(
+                f,
+                "\"attempt to compute the remainder of `{{}} % {{}}` which would overflow\", {:?}, {:?}",
+                l, r
+            ),
+            Overflow(BinOp::Shr, _, r) => {
+                write!(f, "\"attempt to shift right by {{}} which would overflow\", {:?}", r)
+            }
+            Overflow(BinOp::Shl, _, r) => {
+                write!(f, "\"attempt to shift left by {{}} which would overflow\", {:?}", r)
+            }
             _ => write!(f, "\"{}\"", self.description()),
         }
     }
@@ -1561,6 +1595,34 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             BoundsCheck { ref len, ref index } => {
                 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index)
             }
+            OverflowNeg(op) => write!(f, "attempt to negate {:#?} which would overflow", op),
+            DivisionByZero(op) => write!(f, "attempt to divide {:#?} by zero", op),
+            RemainderByZero(op) => {
+                write!(f, "attempt to calculate the remainder of {:#?} with a divisor of zero", op)
+            }
+            Overflow(BinOp::Add, l, r) => {
+                write!(f, "attempt to compute `{:#?} + {:#?}` which would overflow", l, r)
+            }
+            Overflow(BinOp::Sub, l, r) => {
+                write!(f, "attempt to compute `{:#?} - {:#?}` which would overflow", l, r)
+            }
+            Overflow(BinOp::Mul, l, r) => {
+                write!(f, "attempt to compute `{:#?} * {:#?}` which would overflow", l, r)
+            }
+            Overflow(BinOp::Div, l, r) => {
+                write!(f, "attempt to compute `{:#?} / {:#?}` which would overflow", l, r)
+            }
+            Overflow(BinOp::Rem, l, r) => write!(
+                f,
+                "attempt to compute the remainder of `{:#?} % {:#?}` which would overflow",
+                l, r
+            ),
+            Overflow(BinOp::Shr, _, r) => {
+                write!(f, "attempt to shift right by {:#?} which would overflow", r)
+            }
+            Overflow(BinOp::Shl, _, r) => {
+                write!(f, "attempt to shift left by {:#?} which would overflow", r)
+            }
             _ => write!(f, "{}", self.description()),
         }
     }
@@ -1607,9 +1669,9 @@ pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
             Abort => write!(fmt, "abort"),
             Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
             Unreachable => write!(fmt, "unreachable"),
-            Drop { location, .. } => write!(fmt, "drop({:?})", location),
-            DropAndReplace { location, value, .. } => {
-                write!(fmt, "replace({:?} <- {:?})", location, value)
+            Drop { place, .. } => write!(fmt, "drop({:?})", place),
+            DropAndReplace { place, value, .. } => {
+                write!(fmt, "replace({:?} <- {:?})", place, value)
             }
             Call { func, args, destination, .. } => {
                 if let Some((destination, _)) = destination {
@@ -2218,6 +2280,33 @@ pub fn function_handle(
         })
     }
 
+    /// Convenience helper to make a literal-like constant from a given scalar value.
+    /// Since this is used to synthesize MIR, assumes `user_ty` is None.
+    pub fn const_from_scalar(
+        tcx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+        val: Scalar,
+        span: Span,
+    ) -> Operand<'tcx> {
+        debug_assert!({
+            let param_env_and_ty = ty::ParamEnv::empty().and(ty);
+            let type_size = tcx
+                .layout_of(param_env_and_ty)
+                .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
+                .size;
+            let scalar_size = abi::Size::from_bytes(match val {
+                Scalar::Raw { size, .. } => size,
+                _ => panic!("Invalid scalar type {:?}", val),
+            });
+            scalar_size == type_size
+        });
+        Operand::Constant(box Constant {
+            span,
+            user_ty: None,
+            literal: ty::Const::from_scalar(tcx, val, ty),
+        })
+    }
+
     pub fn to_copy(&self) -> Self {
         match *self {
             Operand::Copy(_) | Operand::Constant(_) => self.clone(),
@@ -2891,3 +2980,18 @@ pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) ->
         }
     }
 }
+
+/// Coverage data associated with each function (MIR) instrumented with coverage counters, when
+/// compiled with `-Zinstrument_coverage`. The query `tcx.coverage_data(DefId)` computes these
+/// values on demand (during code generation). This query is only valid after executing the MIR pass
+/// `InstrumentCoverage`.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub struct CoverageData {
+    /// A hash value that can be used by the consumer of the coverage profile data to detect
+    /// changes to the instrumented source of the associated MIR body (typically, for an
+    /// individual function).
+    pub hash: u64,
+
+    /// The total number of coverage region counters added to the MIR `Body`.
+    pub num_counters: u32,
+}
index c889dbc0a449848603e6c7901b209fb374376982..f1c1b962ab997fbbd698cd6380083aa851240444 100644 (file)
@@ -91,9 +91,9 @@ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
         match *self {
             MonoItem::Fn(ref instance) => {
                 let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
-                // If this function isn't inlined or otherwise has explicit
-                // linkage, then we'll be creating a globally shared version.
-                if self.explicit_linkage(tcx).is_some()
+                // If this function isn't inlined or otherwise has an extern
+                // indicator, then we'll be creating a globally shared version.
+                if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
                     || !instance.def.generates_cgu_internal_copy(tcx)
                     || Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
                 {
@@ -102,7 +102,7 @@ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
 
                 // At this point we don't have explicit linkage and we're an
                 // inlined function. If we're inlining into all CGUs then we'll
-                // be creating a local copy per CGU
+                // be creating a local copy per CGU.
                 if generate_cgu_internal_copies {
                     return InstantiationMode::LocalCopy;
                 }
index d82faf3e5fbaa4a89d4ece92bd233869a4faf12b..9ad79230a4f6d73851be217cd7ac4f9d87f054ad 100644 (file)
@@ -10,6 +10,8 @@
 use rustc_span::{Span, Symbol};
 use rustc_target::abi::VariantIdx;
 use smallvec::SmallVec;
+use std::cell::Cell;
+use std::fmt::{self, Debug};
 
 use super::{Field, SourceInfo};
 
@@ -58,7 +60,7 @@ pub struct GeneratorSavedLocal {
 }
 
 /// The layout of generator state.
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
 pub struct GeneratorLayout<'tcx> {
     /// The type of every local stored inside the generator.
     pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>,
@@ -67,12 +69,72 @@ pub struct GeneratorLayout<'tcx> {
     /// be stored in multiple variants.
     pub variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>>,
 
+    /// The source that led to each variant being created (usually, a yield or
+    /// await).
+    pub variant_source_info: IndexVec<VariantIdx, SourceInfo>,
+
     /// 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>,
 }
 
+impl Debug for GeneratorLayout<'_> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        /// Prints an iterator of (key, value) tuples as a map.
+        struct MapPrinter<'a, K, V>(Cell<Option<Box<dyn Iterator<Item = (K, V)> + 'a>>>);
+        impl<'a, K, V> MapPrinter<'a, K, V> {
+            fn new(iter: impl Iterator<Item = (K, V)> + 'a) -> Self {
+                Self(Cell::new(Some(Box::new(iter))))
+            }
+        }
+        impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map().entries(self.0.take().unwrap()).finish()
+            }
+        }
+
+        /// Prints the generator variant name.
+        struct GenVariantPrinter(VariantIdx);
+        impl From<VariantIdx> for GenVariantPrinter {
+            fn from(idx: VariantIdx) -> Self {
+                GenVariantPrinter(idx)
+            }
+        }
+        impl Debug for GenVariantPrinter {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                let variant_name = ty::GeneratorSubsts::variant_name(self.0);
+                if fmt.alternate() {
+                    write!(fmt, "{:9}({:?})", variant_name, self.0)
+                } else {
+                    write!(fmt, "{}", variant_name)
+                }
+            }
+        }
+
+        /// Forces its contents to print in regular mode instead of alternate mode.
+        struct OneLinePrinter<T>(T);
+        impl<T: Debug> Debug for OneLinePrinter<T> {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                write!(fmt, "{:?}", self.0)
+            }
+        }
+
+        fmt.debug_struct("GeneratorLayout")
+            .field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated()))
+            .field(
+                "variant_fields",
+                &MapPrinter::new(
+                    self.variant_fields
+                        .iter_enumerated()
+                        .map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))),
+                ),
+            )
+            .field("storage_conflicts", &self.storage_conflicts)
+            .finish()
+    }
+}
+
 #[derive(Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct BorrowCheckResult<'tcx> {
     /// All the opaque types that are restricted to concrete types
@@ -244,6 +306,6 @@ pub enum ClosureOutlivesSubject<'tcx> {
 /// The constituent parts of an ADT or array.
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct DestructuredConst<'tcx> {
-    pub variant: VariantIdx,
+    pub variant: Option<VariantIdx>,
     pub fields: &'tcx [&'tcx ty::Const<'tcx>],
 }
index 3f5d528d9e7c4a3219b3c315970331bfc4ab9daf..6bb6abe0289108064e108bb14b7d835154b9324f 100644 (file)
@@ -27,11 +27,11 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
                 values: values.clone(),
                 targets: targets.clone(),
             },
-            Drop { ref location, target, unwind } => {
-                Drop { location: location.fold_with(folder), target, unwind }
+            Drop { ref place, target, unwind } => {
+                Drop { place: place.fold_with(folder), target, unwind }
             }
-            DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace {
-                location: location.fold_with(folder),
+            DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace {
+                place: place.fold_with(folder),
                 value: value.fold_with(folder),
                 target,
                 unwind,
@@ -58,15 +58,14 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
             Assert { ref cond, expected, ref msg, target, cleanup } => {
                 use AssertKind::*;
                 let msg = match msg {
-                    BoundsCheck { ref len, ref index } => {
+                    BoundsCheck { len, index } => {
                         BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
                     }
-                    Overflow(_)
-                    | OverflowNeg
-                    | DivisionByZero
-                    | RemainderByZero
-                    | ResumedAfterReturn(_)
-                    | ResumedAfterPanic(_) => msg.clone(),
+                    Overflow(op, l, r) => Overflow(*op, l.fold_with(folder), r.fold_with(folder)),
+                    OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
+                    DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
+                    RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
+                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg.clone(),
                 };
                 Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
             }
@@ -97,9 +96,9 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             SwitchInt { ref discr, switch_ty, .. } => {
                 discr.visit_with(visitor) || switch_ty.visit_with(visitor)
             }
-            Drop { ref location, .. } => location.visit_with(visitor),
-            DropAndReplace { ref location, ref value, .. } => {
-                location.visit_with(visitor) || value.visit_with(visitor)
+            Drop { ref place, .. } => place.visit_with(visitor),
+            DropAndReplace { ref place, ref value, .. } => {
+                place.visit_with(visitor) || value.visit_with(visitor)
             }
             Yield { ref value, .. } => value.visit_with(visitor),
             Call { ref func, ref args, ref destination, .. } => {
@@ -117,12 +116,11 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
                         BoundsCheck { ref len, ref index } => {
                             len.visit_with(visitor) || index.visit_with(visitor)
                         }
-                        Overflow(_)
-                        | OverflowNeg
-                        | DivisionByZero
-                        | RemainderByZero
-                        | ResumedAfterReturn(_)
-                        | ResumedAfterPanic(_) => false,
+                        Overflow(_, l, r) => l.visit_with(visitor) || r.visit_with(visitor),
+                        OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+                            op.visit_with(visitor)
+                        }
+                        ResumedAfterReturn(_) | ResumedAfterPanic(_) => false,
                     }
                 } else {
                     false
index 5f9fcdca516b1ae802515bbbbc656dfb226be0be..c6ace5bbf6685b393e0f24c9cc5301fcce0dc5a8 100644 (file)
@@ -108,12 +108,6 @@ fn visit_terminator(&mut self,
                 self.super_terminator(terminator, location);
             }
 
-            fn visit_terminator_kind(&mut self,
-                                     kind: & $($mutability)? TerminatorKind<'tcx>,
-                                     location: Location) {
-                self.super_terminator_kind(kind, location);
-            }
-
             fn visit_assert_message(&mut self,
                                     msg: & $($mutability)? AssertMessage<'tcx>,
                                     location: Location) {
@@ -417,12 +411,6 @@ fn super_terminator(&mut self,
                 let Terminator { source_info, kind } = terminator;
 
                 self.visit_source_info(source_info);
-                self.visit_terminator_kind(kind, location);
-            }
-
-            fn super_terminator_kind(&mut self,
-                                     kind: & $($mutability)? TerminatorKind<'tcx>,
-                                     source_location: Location) {
                 match kind {
                     TerminatorKind::Goto { .. } |
                     TerminatorKind::Resume |
@@ -440,7 +428,7 @@ fn super_terminator_kind(&mut self,
                         self.visit_local(
                             & $($mutability)? local,
                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
-                            source_location,
+                            location,
                         );
 
                         assert_eq!(
@@ -456,34 +444,34 @@ fn super_terminator_kind(&mut self,
                         values: _,
                         targets: _
                     } => {
-                        self.visit_operand(discr, source_location);
-                        self.visit_ty(switch_ty, TyContext::Location(source_location));
+                        self.visit_operand(discr, location);
+                        self.visit_ty(switch_ty, TyContext::Location(location));
                     }
 
                     TerminatorKind::Drop {
-                        location,
+                        place,
                         target: _,
                         unwind: _,
                     } => {
                         self.visit_place(
-                            location,
+                            place,
                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
-                            source_location
+                            location
                         );
                     }
 
                     TerminatorKind::DropAndReplace {
-                        location,
+                        place,
                         value,
                         target: _,
                         unwind: _,
                     } => {
                         self.visit_place(
-                            location,
+                            place,
                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
-                            source_location
+                            location
                         );
-                        self.visit_operand(value, source_location);
+                        self.visit_operand(value, location);
                     }
 
                     TerminatorKind::Call {
@@ -494,15 +482,15 @@ fn super_terminator_kind(&mut self,
                         from_hir_call: _,
                         fn_span: _
                     } => {
-                        self.visit_operand(func, source_location);
+                        self.visit_operand(func, location);
                         for arg in args {
-                            self.visit_operand(arg, source_location);
+                            self.visit_operand(arg, location);
                         }
                         if let Some((destination, _)) = destination {
                             self.visit_place(
                                 destination,
                                 PlaceContext::MutatingUse(MutatingUseContext::Call),
-                                source_location
+                                location
                             );
                         }
                     }
@@ -514,8 +502,8 @@ fn super_terminator_kind(&mut self,
                         target: _,
                         cleanup: _,
                     } => {
-                        self.visit_operand(cond, source_location);
-                        self.visit_assert_message(msg, source_location);
+                        self.visit_operand(cond, location);
+                        self.visit_assert_message(msg, location);
                     }
 
                     TerminatorKind::Yield {
@@ -524,11 +512,11 @@ fn super_terminator_kind(&mut self,
                         resume_arg,
                         drop: _,
                     } => {
-                        self.visit_operand(value, source_location);
+                        self.visit_operand(value, location);
                         self.visit_place(
                             resume_arg,
                             PlaceContext::MutatingUse(MutatingUseContext::Yield),
-                            source_location,
+                            location,
                         );
                     }
 
@@ -543,29 +531,29 @@ fn super_terminator_kind(&mut self,
                             match op {
                                 InlineAsmOperand::In { value, .. }
                                 | InlineAsmOperand::Const { value } => {
-                                    self.visit_operand(value, source_location);
+                                    self.visit_operand(value, location);
                                 }
                                 InlineAsmOperand::Out { place, .. } => {
                                     if let Some(place) = place {
                                         self.visit_place(
                                             place,
                                             PlaceContext::MutatingUse(MutatingUseContext::Store),
-                                            source_location,
+                                            location,
                                         );
                                     }
                                 }
                                 InlineAsmOperand::InOut { in_value, out_place, .. } => {
-                                    self.visit_operand(in_value, source_location);
+                                    self.visit_operand(in_value, location);
                                     if let Some(out_place) = out_place {
                                         self.visit_place(
                                             out_place,
                                             PlaceContext::MutatingUse(MutatingUseContext::Store),
-                                            source_location,
+                                            location,
                                         );
                                     }
                                 }
                                 InlineAsmOperand::SymFn { value } => {
-                                    self.visit_constant(value, source_location);
+                                    self.visit_constant(value, location);
                                 }
                                 InlineAsmOperand::SymStatic { def_id: _ } => {}
                             }
@@ -583,7 +571,13 @@ fn super_assert_message(&mut self,
                         self.visit_operand(len, location);
                         self.visit_operand(index, location);
                     }
-                    Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
+                    Overflow(_, l, r) => {
+                        self.visit_operand(l, location);
+                        self.visit_operand(r, location);
+                    }
+                    OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+                        self.visit_operand(op, location);
+                    }
                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
                         // Nothing to visit
                     }
index 3b6d54a1bc1eed958e35888c4f4517e339b1e732..ba5a8c3ec2052a22dc2fdaa2a68ef7e0d66acbe4 100644 (file)
 use rustc_span::symbol::Symbol;
 use std::borrow::Cow;
 
-fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     if def_id.is_top_level_module() {
         "top-level module".to_string()
     } else {
-        format!("module `{}`", tcx.def_path_str(def_id))
+        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
     }
 }
 
@@ -133,6 +133,23 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
             cache_on_disk_if { key.is_local() }
         }
 
+        /// Returns the list of predicates that can be used for
+        /// `SelectionCandidate::ProjectionCandidate` and
+        /// `ProjectionTyCandidate::TraitDef`.
+        /// Specifically this is the bounds (equivalent to) those
+        /// written on the trait's type definition, or those
+        /// after the `impl` keyword
+        ///
+        /// type X: Bound + 'lt
+        ///         ^^^^^^^^^^^
+        /// impl Debug + Display
+        ///      ^^^^^^^^^^^^^^^
+        ///
+        /// `key` is the `DefId` of the associated type or opaque type.
+        query projection_predicates(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+            desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) }
+        }
+
         query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
             desc { "looking up the native libraries of a linked crate" }
         }
@@ -214,6 +231,12 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
             cache_on_disk_if { key.is_local() }
         }
 
+        query coverage_data(key: DefId) -> mir::CoverageData {
+            desc { |tcx| "retrieving coverage data from MIR for `{}`", tcx.def_path_str(key) }
+            storage(ArenaCacheSelector<'tcx>)
+            cache_on_disk_if { key.is_local() }
+        }
+
         query promoted_mir(key: DefId) -> IndexVec<mir::Promoted, mir::Body<'tcx>> {
             desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
             storage(ArenaCacheSelector<'tcx>)
@@ -450,49 +473,49 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
 
     Other {
         query lint_mod(key: LocalDefId) -> () {
-            desc { |tcx| "linting {}", describe_as_module(key.to_def_id(), tcx) }
+            desc { |tcx| "linting {}", describe_as_module(key, tcx) }
         }
 
         /// Checks the attributes in the module.
-        query check_mod_attrs(key: DefId) -> () {
+        query check_mod_attrs(key: LocalDefId) -> () {
             desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_unstable_api_usage(key: DefId) -> () {
+        query check_mod_unstable_api_usage(key: LocalDefId) -> () {
             desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
         }
 
         /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`).
-        query check_mod_const_bodies(key: DefId) -> () {
+        query check_mod_const_bodies(key: LocalDefId) -> () {
             desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) }
         }
 
         /// Checks the loops in the module.
-        query check_mod_loops(key: DefId) -> () {
+        query check_mod_loops(key: LocalDefId) -> () {
             desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_item_types(key: DefId) -> () {
+        query check_mod_item_types(key: LocalDefId) -> () {
             desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) }
         }
 
         query check_mod_privacy(key: LocalDefId) -> () {
-            desc { |tcx| "checking privacy in {}", describe_as_module(key.to_def_id(), tcx) }
+            desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_intrinsics(key: DefId) -> () {
+        query check_mod_intrinsics(key: LocalDefId) -> () {
             desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_liveness(key: DefId) -> () {
+        query check_mod_liveness(key: LocalDefId) -> () {
             desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
         }
 
-        query check_mod_impl_wf(key: DefId) -> () {
+        query check_mod_impl_wf(key: LocalDefId) -> () {
             desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
         }
 
-        query collect_mod_item_types(key: DefId) -> () {
+        query collect_mod_item_types(key: LocalDefId) -> () {
             desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) }
         }
 
@@ -526,7 +549,7 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
     }
 
     Other {
-        query used_trait_imports(key: LocalDefId) -> &'tcx DefIdSet {
+        query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
             desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
             cache_on_disk_if { true }
         }
index b963af96f5027cd5b96207353c02e1f8f386908e..405af8cb2406c12891fbafa3730a70e7d3bc4458 100644 (file)
@@ -5,13 +5,12 @@
 //! its name suggest, is to provide an abstraction boundary for creating
 //! interned Chalk types.
 
-use chalk_ir::{GoalData, Parameter};
-
-use rustc_middle::mir::Mutability;
+use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 
 use rustc_hir::def_id::DefId;
+use rustc_target::spec::abi::Abi;
 
 use smallvec::SmallVec;
 
 use std::fmt;
 use std::hash::{Hash, Hasher};
 
-/// Since Chalk doesn't have full support for all Rust builtin types yet, we
-/// need to use an enum here, rather than just `DefId`.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub enum RustDefId {
-    Adt(DefId),
-    Str,
-    Never,
-    Slice,
-    Array,
-    Ref(Mutability),
-    RawPtr,
-
-    Trait(DefId),
-
-    Impl(DefId),
-
-    FnDef(DefId),
-
-    AssocTy(DefId),
-}
-
 #[derive(Copy, Clone)]
 pub struct RustInterner<'tcx> {
     pub tcx: TyCtxt<'tcx>,
@@ -86,17 +64,21 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
     type InternedType = Box<chalk_ir::TyData<Self>>;
     type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>;
-    type InternedParameter = Box<chalk_ir::ParameterData<Self>>;
+    type InternedConst = Box<chalk_ir::ConstData<Self>>;
+    type InternedConcreteConst = ConstValue<'tcx>;
+    type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>;
     type InternedGoal = Box<chalk_ir::GoalData<Self>>;
     type InternedGoals = Vec<chalk_ir::Goal<Self>>;
-    type InternedSubstitution = Vec<chalk_ir::Parameter<Self>>;
+    type InternedSubstitution = Vec<chalk_ir::GenericArg<Self>>;
     type InternedProgramClause = Box<chalk_ir::ProgramClauseData<Self>>;
     type InternedProgramClauses = Vec<chalk_ir::ProgramClause<Self>>;
     type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
-    type InternedParameterKinds = Vec<chalk_ir::ParameterKind<()>>;
-    type InternedCanonicalVarKinds = Vec<chalk_ir::ParameterKind<chalk_ir::UniverseIndex>>;
-    type DefId = RustDefId;
+    type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
+    type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
+    type DefId = DefId;
+    type InternedAdtId = &'tcx AdtDef;
     type Identifier = ();
+    type FnAbi = Abi;
 
     fn debug_program_clause_implication(
         pci: &chalk_ir::ProgramClauseImplication<Self>,
@@ -209,25 +191,39 @@ fn lifetime_data<'a>(
         &lifetime
     }
 
-    fn intern_parameter(
+    fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst {
+        Box::new(constant)
+    }
+
+    fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData<Self> {
+        &constant
+    }
+
+    fn const_eq(
         &self,
-        parameter: chalk_ir::ParameterData<Self>,
-    ) -> Self::InternedParameter {
-        Box::new(parameter)
+        _ty: &Self::InternedType,
+        c1: &Self::InternedConcreteConst,
+        c2: &Self::InternedConcreteConst,
+    ) -> bool {
+        c1 == c2
+    }
+
+    fn intern_generic_arg(&self, data: chalk_ir::GenericArgData<Self>) -> Self::InternedGenericArg {
+        Box::new(data)
     }
 
-    fn parameter_data<'a>(
+    fn generic_arg_data<'a>(
         &self,
-        parameter: &'a Self::InternedParameter,
-    ) -> &'a chalk_ir::ParameterData<Self> {
-        &parameter
+        data: &'a Self::InternedGenericArg,
+    ) -> &'a chalk_ir::GenericArgData<Self> {
+        &data
     }
 
-    fn intern_goal(&self, goal: GoalData<Self>) -> Self::InternedGoal {
+    fn intern_goal(&self, goal: chalk_ir::GoalData<Self>) -> Self::InternedGoal {
         Box::new(goal)
     }
 
-    fn goal_data<'a>(&self, goal: &'a Self::InternedGoal) -> &'a GoalData<Self> {
+    fn goal_data<'a>(&self, goal: &'a Self::InternedGoal) -> &'a chalk_ir::GoalData<Self> {
         &goal
     }
 
@@ -244,7 +240,7 @@ fn goals_data<'a>(&self, goals: &'a Self::InternedGoals) -> &'a [chalk_ir::Goal<
 
     fn intern_substitution<E>(
         &self,
-        data: impl IntoIterator<Item = Result<chalk_ir::Parameter<Self>, E>>,
+        data: impl IntoIterator<Item = Result<chalk_ir::GenericArg<Self>, E>>,
     ) -> Result<Self::InternedSubstitution, E> {
         data.into_iter().collect::<Result<Vec<_>, _>>()
     }
@@ -252,7 +248,7 @@ fn intern_substitution<E>(
     fn substitution_data<'a>(
         &self,
         substitution: &'a Self::InternedSubstitution,
-    ) -> &'a [Parameter<Self>] {
+    ) -> &'a [chalk_ir::GenericArg<Self>] {
         substitution
     }
 
@@ -298,23 +294,23 @@ fn quantified_where_clauses_data<'a>(
         clauses
     }
 
-    fn intern_parameter_kinds<E>(
+    fn intern_generic_arg_kinds<E>(
         &self,
-        data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<()>, E>>,
-    ) -> Result<Self::InternedParameterKinds, E> {
+        data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>,
+    ) -> Result<Self::InternedVariableKinds, E> {
         data.into_iter().collect::<Result<Vec<_>, _>>()
     }
 
-    fn parameter_kinds_data<'a>(
+    fn variable_kinds_data<'a>(
         &self,
-        parameter_kinds: &'a Self::InternedParameterKinds,
-    ) -> &'a [chalk_ir::ParameterKind<()>] {
+        parameter_kinds: &'a Self::InternedVariableKinds,
+    ) -> &'a [chalk_ir::VariableKind<Self>] {
         parameter_kinds
     }
 
     fn intern_canonical_var_kinds<E>(
         &self,
-        data: impl IntoIterator<Item = Result<chalk_ir::ParameterKind<chalk_ir::UniverseIndex>, E>>,
+        data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>,
     ) -> Result<Self::InternedCanonicalVarKinds, E> {
         data.into_iter().collect::<Result<Vec<_>, _>>()
     }
@@ -322,7 +318,7 @@ fn intern_canonical_var_kinds<E>(
     fn canonical_var_kinds_data<'a>(
         &self,
         canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
-    ) -> &'a [chalk_ir::ParameterKind<chalk_ir::UniverseIndex>] {
+    ) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
         canonical_var_kinds
     }
 }
index 17ea84836bf0adda03fb96886e3a2f369b4900d8..fc37cb2504daaceff8bb7539ff2fb27239a754cf 100644 (file)
@@ -33,8 +33,7 @@
 pub use self::SelectionError::*;
 
 pub use self::chalk::{
-    ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustDefId as ChalkRustDefId,
-    RustInterner as ChalkRustInterner,
+    ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustInterner as ChalkRustInterner,
 };
 
 /// Depending on the stage of compilation, we want projection to be
@@ -393,23 +392,25 @@ pub enum SelectionError<'tcx> {
 /// ```
 /// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
 /// impl<T:Clone> Clone<T> for Box<T> { ... }    // Impl_2
-/// impl Clone for int { ... }             // Impl_3
+/// impl Clone for i32 { ... }                   // Impl_3
 ///
-/// fn foo<T:Clone>(concrete: Option<Box<int>>,
-///                 param: T,
-///                 mixed: Option<T>) {
+/// fn foo<T: Clone>(concrete: Option<Box<i32>>, param: T, mixed: Option<T>) {
+///     // Case A: Vtable points at a specific impl. Only possible when
+///     // type is concretely known. If the impl itself has bounded
+///     // type parameters, Vtable will carry resolutions for those as well:
+///     concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
 ///
-///    // Case A: ImplSource points at a specific impl. Only possible when
-///    // type is concretely known. If the impl itself has bounded
-///    // type parameters, ImplSource will carry resolutions for those as well:
-///    concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
+///     // Case A: ImplSource points at a specific impl. Only possible when
+///     // type is concretely known. If the impl itself has bounded
+///     // type parameters, ImplSource will carry resolutions for those as well:
+///     concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])])
 ///
-///    // Case B: ImplSource must be provided by caller. This applies when
-///    // type is a type parameter.
-///    param.clone();    // ImplSourceParam
+///     // Case B: ImplSource must be provided by caller. This applies when
+///     // type is a type parameter.
+///     param.clone();    // ImplSourceParam
 ///
-///    // Case C: A mix of cases A and B.
-///    mixed.clone();    // ImplSource(Impl_1, [ImplSourceParam])
+///     // Case C: A mix of cases A and B.
+///     mixed.clone();    // ImplSource(Impl_1, [ImplSourceParam])
 /// }
 /// ```
 ///
index e030125b5b15c3adbb27d46f4bf6a80d1e717046..69696ac9e93c062dbd36636b7394b39d149e3541 100644 (file)
@@ -221,7 +221,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Ref(..)
         | ty::Str
         | ty::Foreign(..)
-        | ty::Error => true,
+        | ty::Error(_) => true,
 
         // [T; N] and [T] have same properties as T.
         ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
index 02abe868f3943b7234561d259d3ff875e15e9114..db9229ae3d214b8a49b410908a22acac4e5df86a 100644 (file)
@@ -79,7 +79,7 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 Err(TypeError::Sorts(relate::expected_found(self, &a, &b)))
             }
 
-            (&ty::Error, _) | (_, &ty::Error) => Ok(self.tcx().types.err),
+            (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()),
 
             _ => relate::super_relate_tys(self, a, b),
         }
index 1a8e5c45dd2f7f6a16a0a946c49f236005f26414..67ceaca103e9f172333b2f34a74bad96d067d64d 100644 (file)
@@ -10,7 +10,7 @@
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use crate::mir::{self, interpret::Allocation};
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, List, ToPredicate, Ty, TyCtxt};
+use crate::ty::{self, List, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
@@ -95,23 +95,6 @@ pub fn encode_with_shorthand<E, T, M>(encoder: &mut E, value: &T, cache: M) -> R
     Ok(())
 }
 
-pub fn encode_spanned_predicates<'tcx, E, C>(
-    encoder: &mut E,
-    predicates: &[(ty::Predicate<'tcx>, Span)],
-    cache: C,
-) -> Result<(), E::Error>
-where
-    E: TyEncoder,
-    C: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<ty::Predicate<'tcx>, usize>,
-{
-    predicates.len().encode(encoder)?;
-    for (predicate, span) in predicates {
-        encode_with_shorthand(encoder, predicate, &cache)?;
-        span.encode(encoder)?;
-    }
-    Ok(())
-}
-
 pub trait TyDecoder<'tcx>: Decoder {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
@@ -127,6 +110,14 @@ fn cached_ty_for_shorthand<F>(
     where
         F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>;
 
+    fn cached_predicate_for_shorthand<F>(
+        &mut self,
+        shorthand: usize,
+        or_insert_with: F,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error>
+    where
+        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>;
+
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R;
@@ -188,6 +179,26 @@ pub fn decode_ty<D>(decoder: &mut D) -> Result<Ty<'tcx>, D::Error>
     }
 }
 
+#[inline]
+pub fn decode_predicate<D>(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error>
+where
+    D: TyDecoder<'tcx>,
+{
+    // Handle shorthands first, if we have an usize > 0x80.
+    if decoder.positioned_at_shorthand() {
+        let pos = decoder.read_usize()?;
+        assert!(pos >= SHORTHAND_OFFSET);
+        let shorthand = pos - SHORTHAND_OFFSET;
+
+        decoder.cached_predicate_for_shorthand(shorthand, |decoder| {
+            decoder.with_position(shorthand, ty::Predicate::decode)
+        })
+    } else {
+        let tcx = decoder.tcx();
+        Ok(tcx.mk_predicate(ty::PredicateKind::decode(decoder)?))
+    }
+}
+
 #[inline]
 pub fn decode_spanned_predicates<D>(
     decoder: &mut D,
@@ -198,20 +209,7 @@ pub fn decode_spanned_predicates<D>(
     let tcx = decoder.tcx();
     Ok(tcx.arena.alloc_from_iter(
         (0..decoder.read_usize()?)
-            .map(|_| {
-                // Handle shorthands first, if we have an usize > 0x80.
-                let predicate_kind = if decoder.positioned_at_shorthand() {
-                    let pos = decoder.read_usize()?;
-                    assert!(pos >= SHORTHAND_OFFSET);
-                    let shorthand = pos - SHORTHAND_OFFSET;
-
-                    decoder.with_position(shorthand, ty::PredicateKind::decode)
-                } else {
-                    ty::PredicateKind::decode(decoder)
-                }?;
-                let predicate = predicate_kind.to_predicate(tcx);
-                Ok((predicate, Decodable::decode(decoder)?))
-            })
+            .map(|_| Decodable::decode(decoder))
             .collect::<Result<Vec<_>, _>>()?,
     ))
 }
@@ -421,7 +419,6 @@ fn error(&mut self, err: &str) -> Self::Error {
             // FIXME(#36588): These impls are horribly unsound as they allow
             // the caller to pick any lifetime for `'tcx`, including `'static`.
 
-            rustc_hir::arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx);
             arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx);
 
             impl<$($typaram),*> SpecializedDecoder<CrateNum>
@@ -436,7 +433,24 @@ impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x ty::TyS<'_y>>
             where &'_x ty::TyS<'_y>: UseSpecializedDecodable
             {
                 fn specialized_decode(&mut self) -> Result<&'_x ty::TyS<'_y>, Self::Error> {
-                    unsafe { transmute::<Result<ty::Ty<'tcx>, Self::Error>, Result<&'_x ty::TyS<'_y>, Self::Error>>(decode_ty(self)) }
+                    unsafe {
+                        transmute::<
+                            Result<ty::Ty<'tcx>, Self::Error>,
+                            Result<&'_x ty::TyS<'_y>, Self::Error>,
+                        >(decode_ty(self))
+                    }
+                }
+            }
+
+            impl<'_x, $($typaram),*> SpecializedDecoder<ty::Predicate<'_x>>
+            for $DecoderName<$($typaram),*> {
+                fn specialized_decode(&mut self) -> Result<ty::Predicate<'_x>, Self::Error> {
+                    unsafe {
+                        transmute::<
+                            Result<ty::Predicate<'tcx>, Self::Error>,
+                            Result<ty::Predicate<'_x>, Self::Error>,
+                        >(decode_predicate(self))
+                    }
                 }
             }
 
diff --git a/src/librustc_middle/ty/consts.rs b/src/librustc_middle/ty/consts.rs
new file mode 100644 (file)
index 0000000..ced0429
--- /dev/null
@@ -0,0 +1,111 @@
+use crate::mir::interpret::truncate;
+use rustc_target::abi::Size;
+
+#[derive(Copy, Clone)]
+/// A type for representing any integer. Only used for printing.
+// FIXME: Use this for the integer-tree representation needed for type level ints and
+// const generics?
+pub struct ConstInt {
+    /// Number of bytes of the integer. Only 1, 2, 4, 8, 16 are legal values.
+    size: u8,
+    /// Whether the value is of a signed integer type.
+    signed: bool,
+    /// Whether the value is a `usize` or `isize` type.
+    is_ptr_sized_integral: bool,
+    /// Raw memory of the integer. All bytes beyond the `size` are unused and must be zero.
+    raw: u128,
+}
+
+impl ConstInt {
+    pub fn new(raw: u128, size: Size, signed: bool, is_ptr_sized_integral: bool) -> Self {
+        assert!(raw <= truncate(u128::MAX, size));
+        Self { raw, size: size.bytes() as u8, signed, is_ptr_sized_integral }
+    }
+}
+
+impl std::fmt::Debug for ConstInt {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let Self { size, signed, raw, is_ptr_sized_integral } = *self;
+        if signed {
+            let bit_size = size * 8;
+            let min = 1u128 << (bit_size - 1);
+            let max = min - 1;
+            if raw == min {
+                match (size, is_ptr_sized_integral) {
+                    (_, true) => write!(fmt, "isize::MIN"),
+                    (1, _) => write!(fmt, "i8::MIN"),
+                    (2, _) => write!(fmt, "i16::MIN"),
+                    (4, _) => write!(fmt, "i32::MIN"),
+                    (8, _) => write!(fmt, "i64::MIN"),
+                    (16, _) => write!(fmt, "i128::MIN"),
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+            } else if raw == max {
+                match (size, is_ptr_sized_integral) {
+                    (_, true) => write!(fmt, "isize::MAX"),
+                    (1, _) => write!(fmt, "i8::MAX"),
+                    (2, _) => write!(fmt, "i16::MAX"),
+                    (4, _) => write!(fmt, "i32::MAX"),
+                    (8, _) => write!(fmt, "i64::MAX"),
+                    (16, _) => write!(fmt, "i128::MAX"),
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+            } else {
+                match size {
+                    1 => write!(fmt, "{}", raw as i8)?,
+                    2 => write!(fmt, "{}", raw as i16)?,
+                    4 => write!(fmt, "{}", raw as i32)?,
+                    8 => write!(fmt, "{}", raw as i64)?,
+                    16 => write!(fmt, "{}", raw as i128)?,
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+                if fmt.alternate() {
+                    match (size, is_ptr_sized_integral) {
+                        (_, true) => write!(fmt, "_isize")?,
+                        (1, _) => write!(fmt, "_i8")?,
+                        (2, _) => write!(fmt, "_i16")?,
+                        (4, _) => write!(fmt, "_i32")?,
+                        (8, _) => write!(fmt, "_i64")?,
+                        (16, _) => write!(fmt, "_i128")?,
+                        _ => bug!(),
+                    }
+                }
+                Ok(())
+            }
+        } else {
+            let max = truncate(u128::MAX, Size::from_bytes(size));
+            if raw == max {
+                match (size, is_ptr_sized_integral) {
+                    (_, true) => write!(fmt, "usize::MAX"),
+                    (1, _) => write!(fmt, "u8::MAX"),
+                    (2, _) => write!(fmt, "u16::MAX"),
+                    (4, _) => write!(fmt, "u32::MAX"),
+                    (8, _) => write!(fmt, "u64::MAX"),
+                    (16, _) => write!(fmt, "u128::MAX"),
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+            } else {
+                match size {
+                    1 => write!(fmt, "{}", raw as u8)?,
+                    2 => write!(fmt, "{}", raw as u16)?,
+                    4 => write!(fmt, "{}", raw as u32)?,
+                    8 => write!(fmt, "{}", raw as u64)?,
+                    16 => write!(fmt, "{}", raw as u128)?,
+                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
+                }
+                if fmt.alternate() {
+                    match (size, is_ptr_sized_integral) {
+                        (_, true) => write!(fmt, "_usize")?,
+                        (1, _) => write!(fmt, "_u8")?,
+                        (2, _) => write!(fmt, "_u16")?,
+                        (4, _) => write!(fmt, "_u32")?,
+                        (8, _) => write!(fmt, "_u64")?,
+                        (16, _) => write!(fmt, "_u128")?,
+                        _ => bug!(),
+                    }
+                }
+                Ok(())
+            }
+        }
+    }
+}
index de2e1046f1cbbb60ea245fbe5655ed737ca21325..e2f601371b1eeab9a07941bab20fe4ea72ffe076 100644 (file)
@@ -19,8 +19,9 @@
 use crate::ty::{
     self, query, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
     DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy,
-    IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy,
-    Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut,
+    IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
+    ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
+    TyVid, TypeAndMut,
 };
 use rustc_ast::ast;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -35,8 +36,9 @@
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefPathHash, Definitions};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::{self, PanicLocationLangItem};
 use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
@@ -46,7 +48,7 @@
 use rustc_session::Session;
 use rustc_span::source_map::MultiSpan;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
 
@@ -76,7 +78,7 @@ pub struct CtxtInterners<'tcx> {
     canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo>>,
     region: InternedSet<'tcx, RegionKind>,
     existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>,
-    predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>,
+    predicate: InternedSet<'tcx, PredicateInner<'tcx>>,
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
@@ -95,7 +97,7 @@ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
             region: Default::default(),
             existential_predicates: Default::default(),
             canonical_var_infos: Default::default(),
-            predicate_kind: Default::default(),
+            predicate: Default::default(),
             predicates: Default::default(),
             projs: Default::default(),
             place_elems: Default::default(),
@@ -123,6 +125,23 @@ fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> {
             })
             .0
     }
+
+    #[inline(never)]
+    fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> {
+        self.predicate
+            .intern(kind, |kind| {
+                let flags = super::flags::FlagComputation::for_predicate(&kind);
+
+                let predicate_struct = PredicateInner {
+                    kind,
+                    flags: flags.flags,
+                    outer_exclusive_binder: flags.outer_exclusive_binder,
+                };
+
+                Interned(self.arena.alloc(predicate_struct))
+            })
+            .0
+    }
 }
 
 pub struct CommonTypes<'tcx> {
@@ -143,9 +162,9 @@ pub struct CommonTypes<'tcx> {
     pub u128: Ty<'tcx>,
     pub f32: Ty<'tcx>,
     pub f64: Ty<'tcx>,
+    pub str_: Ty<'tcx>,
     pub never: Ty<'tcx>,
     pub self_param: Ty<'tcx>,
-    pub err: Ty<'tcx>,
 
     /// Dummy type used for the `Self` of a `TraitRef` created for converting
     /// a trait object, and which gets removed in `ExistentialTraitRef`.
@@ -391,7 +410,7 @@ pub struct TypeckTables<'tcx> {
     /// This is used for warning unused imports. During type
     /// checking, this `Lrc` should not be cloned: it must have a ref-count
     /// of 1 so that we can insert things into the set mutably.
-    pub used_trait_imports: Lrc<DefIdSet>,
+    pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>,
 
     /// If any errors occurred while type-checking this body,
     /// this field will be set to `Some(ErrorReported)`.
@@ -803,7 +822,6 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
             bool: mk(Bool),
             char: mk(Char),
             never: mk(Never),
-            err: mk(Error),
             isize: mk(Int(ast::IntTy::Isize)),
             i8: mk(Int(ast::IntTy::I8)),
             i16: mk(Int(ast::IntTy::I16)),
@@ -818,6 +836,7 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
             u128: mk(Uint(ast::UintTy::U128)),
             f32: mk(Float(ast::FloatTy::F32)),
             f64: mk(Float(ast::FloatTy::F64)),
+            str_: mk(Str),
             self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })),
 
             trait_object_dummy_self: mk(Infer(ty::FreshTy(0))),
@@ -854,8 +873,8 @@ fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonCons
 // conflict.
 #[derive(Debug)]
 pub struct FreeRegionInfo {
-    // def id corresponding to FreeRegion
-    pub def_id: DefId,
+    // `LocalDefId` corresponding to FreeRegion
+    pub def_id: LocalDefId,
     // the bound region corresponding to FreeRegion
     pub boundregion: ty::BoundRegion,
     // checks if bound region is in Impl Item
@@ -938,8 +957,9 @@ pub struct GlobalCtxt<'tcx> {
     /// via `extern crate` item and not `--extern` option or compiler built-in.
     pub extern_prelude: FxHashMap<Symbol, bool>,
 
-    // Internal cache for metadata decoding. No need to track deps on this.
-    pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+    // Internal caches for metadata decoding. No need to track deps on this.
+    pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
+    pub pred_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Predicate<'tcx>>>,
 
     /// Caches the results of trait selection. This cache is used
     /// for things that do not have to do with the parameters in scope.
@@ -1101,9 +1121,9 @@ pub fn create_global_ctxt(
         };
 
         let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
-        for (hir_id, v) in resolutions.trait_map.into_iter() {
+        for (hir_id, v) in krate.trait_map.iter() {
             let map = trait_map.entry(hir_id.owner).or_default();
-            map.insert(hir_id.local_id, StableVec::new(v));
+            map.insert(hir_id.local_id, StableVec::new(v.to_vec()));
         }
 
         GlobalCtxt {
@@ -1128,7 +1148,8 @@ pub fn create_global_ctxt(
             definitions,
             def_path_hash_to_def_id,
             queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache),
-            rcache: Default::default(),
+            ty_rcache: Default::default(),
+            pred_rcache: Default::default(),
             selection_cache: Default::default(),
             evaluation_cache: Default::default(),
             crate_name: Symbol::intern(crate_name),
@@ -1142,6 +1163,31 @@ pub fn create_global_ctxt(
         }
     }
 
+    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
+    #[track_caller]
+    pub fn ty_error(self) -> Ty<'tcx> {
+        self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported")
+    }
+
+    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to
+    /// ensure it gets used.
+    #[track_caller]
+    pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
+        self.sess.delay_span_bug(span, msg);
+        self.mk_ty(Error(super::sty::DelaySpanBugEmitted(())))
+    }
+
+    /// Like `err` but for constants.
+    #[track_caller]
+    pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
+        self.sess
+            .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported.");
+        self.mk_const(ty::Const {
+            val: ty::ConstKind::Error(super::sty::DelaySpanBugEmitted(())),
+            ty,
+        })
+    }
+
     pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
         let cname = self.crate_name(LOCAL_CRATE).as_str();
         self.sess.consider_optimizing(&cname, msg)
@@ -1261,6 +1307,13 @@ pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
         StableHashingContext::new(self.sess, krate, self.definitions, &*self.cstore)
     }
 
+    #[inline(always)]
+    pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
+        let krate = self.gcx.untracked_crate;
+
+        StableHashingContext::ignore_spans(self.sess, krate, self.definitions, &*self.cstore)
+    }
+
     // This method makes sure that we have a DepNode and a Fingerprint for
     // every upstream crate. It needs to be called once right after the tcx is
     // created.
@@ -1359,14 +1412,17 @@ pub fn local_crate_exports_generics(self) -> bool {
     // Returns the `DefId` and the `BoundRegion` corresponding to the given region.
     pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
         let (suitable_region_binding_scope, bound_region) = match *region {
-            ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
-            ty::ReEarlyBound(ref ebr) => {
-                (self.parent(ebr.def_id).unwrap(), ty::BoundRegion::BrNamed(ebr.def_id, ebr.name))
+            ty::ReFree(ref free_region) => {
+                (free_region.scope.expect_local(), free_region.bound_region)
             }
+            ty::ReEarlyBound(ref ebr) => (
+                self.parent(ebr.def_id).unwrap().expect_local(),
+                ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
+            ),
             _ => return None, // not a free region
         };
 
-        let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope.expect_local());
+        let hir_id = self.hir().as_local_hir_id(suitable_region_binding_scope);
         let is_impl_item = match self.hir().find(hir_id) {
             Some(Node::Item(..) | Node::TraitItem(..)) => false,
             Some(Node::ImplItem(..)) => {
@@ -1382,8 +1438,12 @@ pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo>
         })
     }
 
-    pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> {
-        let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
+    /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type.
+    pub fn return_type_impl_or_dyn_traits(
+        &self,
+        scope_def_id: LocalDefId,
+    ) -> Vec<&'tcx hir::Ty<'tcx>> {
+        let hir_id = self.hir().as_local_hir_id(scope_def_id);
         let hir_output = match self.hir().get(hir_id) {
             Node::Item(hir::Item {
                 kind:
@@ -1418,33 +1478,17 @@ pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span
                     ),
                 ..
             }) => ty,
-            _ => return None,
+            _ => return vec![],
         };
 
-        let ret_ty = self.type_of(scope_def_id);
-        match ret_ty.kind {
-            ty::FnDef(_, _) => {
-                let sig = ret_ty.fn_sig(*self);
-                let output = self.erase_late_bound_regions(&sig.output());
-                if output.is_impl_trait() {
-                    let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
-                    Some((fn_decl.output.span(), false))
-                } else {
-                    let mut v = TraitObjectVisitor(vec![]);
-                    rustc_hir::intravisit::walk_ty(&mut v, hir_output);
-                    if v.0.len() == 1 {
-                        return Some((v.0[0], true));
-                    }
-                    None
-                }
-            }
-            _ => None,
-        }
+        let mut v = TraitObjectVisitor(vec![], self.hir());
+        v.visit_ty(hir_output);
+        v.0
     }
 
-    pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> {
+    pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> {
         // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`.
-        let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local());
+        let hir_id = self.hir().as_local_hir_id(scope_def_id);
         match self.hir().get(hir_id) {
             Node::Item(item) => {
                 match item.kind {
@@ -1474,8 +1518,9 @@ pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, S
     }
 
     // Checks if the bound region is in Impl Item.
-    pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: DefId) -> bool {
-        let container_id = self.associated_item(suitable_region_binding_scope).container.id();
+    pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool {
+        let container_id =
+            self.associated_item(suitable_region_binding_scope.to_def_id()).container.id();
         if self.impl_trait_ref(container_id).is_some() {
             // For now, we do not try to target impls of traits. This is
             // because this message is going to suggest that the user
@@ -1515,28 +1560,6 @@ pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static
     }
 }
 
-impl<'tcx> GlobalCtxt<'tcx> {
-    /// Calls the closure with a local `TyCtxt` using the given arena.
-    /// `interners` is a slot passed so we can create a CtxtInterners
-    /// with the same lifetime as `arena`.
-    pub fn enter_local<F, R>(&'tcx self, f: F) -> R
-    where
-        F: FnOnce(TyCtxt<'tcx>) -> R,
-    {
-        let tcx = TyCtxt { gcx: self };
-        ty::tls::with_related_context(tcx, |icx| {
-            let new_icx = ty::tls::ImplicitCtxt {
-                tcx,
-                query: icx.query,
-                diagnostics: icx.diagnostics,
-                layout_depth: icx.layout_depth,
-                task_deps: icx.task_deps,
-            };
-            ty::tls::enter_context(&new_icx, |_| f(tcx))
-        })
-    }
-}
-
 /// A trait implemented for all `X<'a>` types that can be safely and
 /// efficiently converted to `X<'tcx>` as long as they are part of the
 /// provided `TyCtxt<'tcx>`.
@@ -1595,7 +1618,7 @@ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
-nop_lift! {predicate_kind; &'a PredicateKind<'a> => &'tcx PredicateKind<'tcx>}
+nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
 
 nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
 nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>}
@@ -1773,11 +1796,11 @@ pub fn with_context<F, R>(f: F) -> R
         with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
     }
 
-    /// Allows access to the current `ImplicitCtxt` whose tcx field has the same global
-    /// interner as the tcx argument passed in. This means the closure is given an `ImplicitCtxt`
-    /// with the same `'tcx` lifetime as the `TyCtxt` passed in.
-    /// This will panic if you pass it a `TyCtxt` which has a different global interner from
-    /// the current `ImplicitCtxt`'s `tcx` field.
+    /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
+    /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
+    /// as the `TyCtxt` passed in.
+    /// This will panic if you pass it a `TyCtxt` which is different from the current
+    /// `ImplicitCtxt`'s `tcx` field.
     #[inline]
     pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
     where
@@ -1845,7 +1868,7 @@ pub fn go(tcx: TyCtxt<'_>) {
                     let variant = match t.kind {
                         ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
                             ty::Float(..) | ty::Str | ty::Never => continue,
-                        ty::Error => /* unimportant */ continue,
+                        ty::Error(_) => /* unimportant */ continue,
                         $(ty::$variant(..) => &mut $variant,)*
                     };
                     let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
@@ -1954,6 +1977,26 @@ fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
         &self.0.kind
     }
 }
+// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
+impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
+    fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+        self.0.kind == other.0.kind
+    }
+}
+
+impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
+
+impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        self.0.kind.hash(s)
+    }
+}
+
+impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateInner<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
+        &self.0.kind
+    }
+}
 
 // N.B., an `Interned<List<T>>` compares and hashes as its elements.
 impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
@@ -2020,11 +2063,10 @@ pub fn $method(self, v: $ty) -> &'tcx $ty {
     }
 }
 
-direct_interners!(
+direct_interners! {
     region: mk_region(RegionKind),
     const_: mk_const(Const<'tcx>),
-    predicate_kind: intern_predicate_kind(PredicateKind<'tcx>),
-);
+}
 
 macro_rules! slice_interners {
     ($($field:ident: $method:ident($ty:ty)),+) => (
@@ -2080,6 +2122,13 @@ pub fn signature_unclosure(
         })
     }
 
+    /// Same a `self.mk_region(kind)`, but avoids accessing the interners if
+    /// `*r == kind`.
+    #[inline]
+    pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind) -> Region<'tcx> {
+        if *r == kind { r } else { self.mk_region(kind) }
+    }
+
     #[allow(rustc::usage_of_ty_tykind)]
     #[inline]
     pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> {
@@ -2088,8 +2137,8 @@ pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> {
 
     #[inline]
     pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> {
-        let kind = self.intern_predicate_kind(kind);
-        Predicate { kind }
+        let inner = self.interners.intern_predicate(kind);
+        Predicate { inner }
     }
 
     pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
@@ -2121,14 +2170,9 @@ pub fn mk_mach_float(self, tm: ast::FloatTy) -> Ty<'tcx> {
         }
     }
 
-    #[inline]
-    pub fn mk_str(self) -> Ty<'tcx> {
-        self.mk_ty(Str)
-    }
-
     #[inline]
     pub fn mk_static_str(self) -> Ty<'tcx> {
-        self.mk_imm_ref(self.lifetimes.re_static, self.mk_str())
+        self.mk_imm_ref(self.lifetimes.re_static, self.types.str_)
     }
 
     #[inline]
index 2e9aa724ac5af744fde06c944550ff3f760777fb..b22727bdd7587b71848ce692971577f2cf1cdc3c 100644 (file)
@@ -236,21 +236,35 @@ pub fn suggest_constraining_type_param(
     }
 }
 
-pub struct TraitObjectVisitor(pub Vec<rustc_span::Span>);
-impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor {
+/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
+pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
+
+impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
     type Map = rustc_hir::intravisit::ErasedMap<'v>;
 
     fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
         hir::intravisit::NestedVisitorMap::None
     }
 
-    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
-        if let hir::TyKind::TraitObject(
-            _,
-            hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. },
-        ) = ty.kind
-        {
-            self.0.push(ty.span);
+    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+        match ty.kind {
+            hir::TyKind::TraitObject(
+                _,
+                hir::Lifetime {
+                    name:
+                        hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
+                    ..
+                },
+            ) => {
+                self.0.push(ty);
+            }
+            hir::TyKind::OpaqueDef(item_id, _) => {
+                self.0.push(ty);
+                let item = self.1.expect_item(item_id.id);
+                hir::intravisit::walk_item(self, item);
+            }
+            _ => {}
         }
+        hir::intravisit::walk_ty(self, ty);
     }
 }
index be3bf748225b9885097f4c6e07379e49a9782079..6113359ca93a72787597bd7ce95eb02757779d6c 100644 (file)
@@ -286,14 +286,14 @@ pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
             ty::Projection(_) => "associated type".into(),
             ty::Param(p) => format!("type parameter `{}`", p).into(),
             ty::Opaque(..) => "opaque type".into(),
-            ty::Error => "type error".into(),
+            ty::Error(_) => "type error".into(),
         }
     }
 
     pub fn prefix_string(&self) -> Cow<'static, str> {
         match self.kind {
             ty::Infer(_)
-            | ty::Error
+            | ty::Error(_)
             | ty::Bool
             | ty::Char
             | ty::Int(_)
index 16d8e37940763646d83655fae5b3d63da737319e..b0fb179b18bdfbaecc242c11802e45c46843b99f 100644 (file)
@@ -104,7 +104,7 @@ pub fn simplify_type(
         }
         ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
         ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
-        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error => None,
+        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
     }
 }
 
index edcb69c5e8cbdf3fc3b01cbdf3d0e4883fee1f08..c782eee938721aca7f3c2c0c7bf47fd4dbb60dcf 100644 (file)
@@ -1,5 +1,6 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::{self, InferConst, Ty, TypeFlags};
+use std::slice;
 
 #[derive(Debug)]
 pub struct FlagComputation {
@@ -21,6 +22,12 @@ pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation {
         result
     }
 
+    pub fn for_predicate(kind: &ty::PredicateKind<'_>) -> FlagComputation {
+        let mut result = FlagComputation::new();
+        result.add_predicate_kind(kind);
+        result
+    }
+
     pub fn for_const(c: &ty::Const<'_>) -> TypeFlags {
         let mut result = FlagComputation::new();
         result.add_const(c);
@@ -32,7 +39,7 @@ fn add_flags(&mut self, flags: TypeFlags) {
     }
 
     /// indicates that `self` refers to something at binding level `binder`
-    fn add_binder(&mut self, binder: ty::DebruijnIndex) {
+    fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
         let exclusive_binder = binder.shifted_in(1);
         self.add_exclusive_binder(exclusive_binder);
     }
@@ -46,7 +53,7 @@ fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
 
     /// Adds the flags/depth from a set of types that appear within the current type, but within a
     /// region binder.
-    fn add_bound_computation(&mut self, computation: &FlagComputation) {
+    fn add_bound_computation(&mut self, computation: FlagComputation) {
         self.add_flags(computation.flags);
 
         // The types that contributed to `computation` occurred within
@@ -70,7 +77,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             | &ty::Str
             | &ty::Foreign(..) => {}
 
-            &ty::Error => self.add_flags(TypeFlags::HAS_ERROR),
+            &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
 
             &ty::Param(_) => {
                 self.add_flags(TypeFlags::HAS_TY_PARAM);
@@ -84,7 +91,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             &ty::GeneratorWitness(ref ts) => {
                 let mut computation = FlagComputation::new();
                 computation.add_tys(&ts.skip_binder()[..]);
-                self.add_bound_computation(&computation);
+                self.add_bound_computation(computation);
             }
 
             &ty::Closure(_, ref substs) => {
@@ -92,8 +99,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             }
 
             &ty::Bound(debruijn, _) => {
-                self.add_binder(debruijn);
-                self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+                self.add_bound_var(debruijn);
             }
 
             &ty::Placeholder(..) => {
@@ -134,12 +140,12 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
                         ty::ExistentialPredicate::Projection(p) => {
                             let mut proj_computation = FlagComputation::new();
                             proj_computation.add_existential_projection(&p);
-                            self.add_bound_computation(&proj_computation);
+                            self.add_bound_computation(proj_computation);
                         }
                         ty::ExistentialPredicate::AutoTrait(_) => {}
                     }
                 }
-                self.add_bound_computation(&computation);
+                self.add_bound_computation(computation);
                 self.add_region(r);
             }
 
@@ -173,6 +179,63 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
         }
     }
 
+    fn add_predicate_kind(&mut self, kind: &ty::PredicateKind<'_>) {
+        match kind {
+            ty::PredicateKind::Trait(trait_pred, _constness) => {
+                let mut computation = FlagComputation::new();
+                computation.add_substs(trait_pred.skip_binder().trait_ref.substs);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::RegionOutlives(poly_outlives) => {
+                let mut computation = FlagComputation::new();
+                let ty::OutlivesPredicate(a, b) = poly_outlives.skip_binder();
+                computation.add_region(a);
+                computation.add_region(b);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::TypeOutlives(poly_outlives) => {
+                let mut computation = FlagComputation::new();
+                let ty::OutlivesPredicate(ty, region) = poly_outlives.skip_binder();
+                computation.add_ty(ty);
+                computation.add_region(region);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::Subtype(poly_subtype) => {
+                let mut computation = FlagComputation::new();
+                let ty::SubtypePredicate { a_is_expected: _, a, b } = poly_subtype.skip_binder();
+                computation.add_ty(a);
+                computation.add_ty(b);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::Projection(projection) => {
+                let mut computation = FlagComputation::new();
+                let ty::ProjectionPredicate { projection_ty, ty } = projection.skip_binder();
+                computation.add_projection_ty(projection_ty);
+                computation.add_ty(ty);
+
+                self.add_bound_computation(computation);
+            }
+            ty::PredicateKind::WellFormed(arg) => {
+                self.add_substs(slice::from_ref(arg));
+            }
+            ty::PredicateKind::ObjectSafe(_def_id) => {}
+            ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
+                self.add_substs(substs);
+            }
+            ty::PredicateKind::ConstEvaluatable(_def_id, substs) => {
+                self.add_substs(substs);
+            }
+            ty::PredicateKind::ConstEquate(expected, found) => {
+                self.add_const(expected);
+                self.add_const(found);
+            }
+        }
+    }
+
     fn add_ty(&mut self, ty: Ty<'_>) {
         self.add_flags(ty.flags);
         self.add_exclusive_binder(ty.outer_exclusive_binder);
@@ -190,13 +253,13 @@ fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig<'_>) {
         computation.add_tys(fn_sig.skip_binder().inputs());
         computation.add_ty(fn_sig.skip_binder().output());
 
-        self.add_bound_computation(&computation);
+        self.add_bound_computation(computation);
     }
 
     fn add_region(&mut self, r: ty::Region<'_>) {
         self.add_flags(r.type_flags());
         if let ty::ReLateBound(debruijn, _) = *r {
-            self.add_binder(debruijn);
+            self.add_bound_var(debruijn);
         }
     }
 
@@ -215,8 +278,7 @@ fn add_const(&mut self, c: &ty::Const<'_>) {
                 }
             }
             ty::ConstKind::Bound(debruijn, _) => {
-                self.add_binder(debruijn);
-                self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+                self.add_bound_var(debruijn);
             }
             ty::ConstKind::Param(_) => {
                 self.add_flags(TypeFlags::HAS_CT_PARAM);
@@ -227,7 +289,7 @@ fn add_const(&mut self, c: &ty::Const<'_>) {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
             ty::ConstKind::Value(_) => {}
-            ty::ConstKind::Error => self.add_flags(TypeFlags::HAS_ERROR),
+            ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
         }
     }
 
index 248dd00ef47be562095414b57508811038a03433..2d25c7c6ac983546a87cfb4f954f235f3b88ef97 100644 (file)
@@ -31,6 +31,7 @@
 //! These methods return true to indicate that the visitor has found what it is
 //! looking for, and does not need to visit anything else.
 
+use crate::ty::structural_impls::PredicateVisitor;
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -87,6 +88,9 @@ fn references_error(&self) -> bool {
     fn has_param_types_or_consts(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
     }
+    fn has_infer_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_INFER)
+    }
     fn has_infer_types(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_TY_INFER)
     }
@@ -905,6 +909,12 @@ fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool {
     }
 }
 
+impl<'tcx> PredicateVisitor<'tcx> for HasEscapingVarsVisitor {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+        predicate.inner.outer_exclusive_binder > self.outer_index
+    }
+}
+
 // FIXME: Optimize for checking for infer flags
 struct HasTypeFlagsVisitor {
     flags: ty::TypeFlags,
@@ -929,6 +939,15 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
     }
 }
 
+impl<'tcx> PredicateVisitor<'tcx> for HasTypeFlagsVisitor {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+        debug!(
+            "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
+            predicate, predicate.inner.flags, self.flags
+        );
+        predicate.inner.flags.intersects(self.flags)
+    }
+}
 /// Collects all the late-bound regions at the innermost binding level
 /// into a hash set.
 struct LateBoundRegionsCollector {
index 1ce079821a22e52665609836777f986e2654a681..d628d6783d5b0d71f12ed4c9aaf900660dec040f 100644 (file)
@@ -9,6 +9,11 @@
 
 use std::fmt;
 
+/// A monomorphized `InstanceDef`.
+///
+/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
+/// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval
+/// will do all required substitution as they run.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 #[derive(HashStable, Lift)]
 pub struct Instance<'tcx> {
@@ -18,10 +23,26 @@ pub struct Instance<'tcx> {
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub enum InstanceDef<'tcx> {
+    /// A user-defined callable item.
+    ///
+    /// This includes:
+    /// - `fn` items
+    /// - closures
+    /// - generators
     Item(DefId),
+
+    /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI).
+    ///
+    /// Alongside `Virtual`, this is the only `InstanceDef` that does not have its own callable MIR.
+    /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the
+    /// caller.
     Intrinsic(DefId),
 
-    /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
+    /// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the
+    /// `unsized_locals` feature).
+    ///
+    /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` -
+    /// and dereference the argument to call the original function.
     VtableShim(DefId),
 
     /// `fn()` pointer where the function itself cannot be turned into a pointer.
@@ -37,7 +58,8 @@ pub enum InstanceDef<'tcx> {
     /// (the definition of the function itself).
     ReifyShim(DefId),
 
-    /// `<fn() as FnTrait>::call_*`
+    /// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
+    ///
     /// `DefId` is `FnTrait::call_*`.
     ///
     /// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution
@@ -45,19 +67,22 @@ pub enum InstanceDef<'tcx> {
     // FIXME(#69925) support polymorphic MIR shim bodies properly instead.
     FnPtrShim(DefId, Ty<'tcx>),
 
-    /// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
-    /// codegen'd as virtual calls.
+    /// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
     ///
-    /// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used
-    /// (see `ReifyShim` above for more details on that).
+    /// This `InstanceDef` does not have callable MIR. Calls to `Virtual` instances must be
+    /// codegen'd as virtual calls through the vtable.
+    ///
+    /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more
+    /// details on that).
     Virtual(DefId, usize),
 
-    /// `<[mut closure] as FnOnce>::call_once`
-    ClosureOnceShim {
-        call_once: DefId,
-    },
+    /// `<[FnMut closure] as FnOnce>::call_once`.
+    ///
+    /// The `DefId` is the ID of the `call_once` method in `FnOnce`.
+    ClosureOnceShim { call_once: DefId },
 
     /// `core::ptr::drop_in_place::<T>`.
+    ///
     /// The `DefId` is for `core::ptr::drop_in_place`.
     /// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
     /// glue.
@@ -67,7 +92,12 @@ pub enum InstanceDef<'tcx> {
     // FIXME(#69925) support polymorphic MIR shim bodies properly instead.
     DropGlue(DefId, Option<Ty<'tcx>>),
 
-    ///`<T as Clone>::clone` shim.
+    /// Compiler-generated `<T as Clone>::clone` implementation.
+    ///
+    /// For all types that automatically implement `Copy`, a trivial `Clone` impl is provided too.
+    /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`.
+    ///
+    /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl.
     ///
     /// NB: the type must currently be monomorphic to avoid double substitution
     /// problems with the MIR shim bodies. `Instance::resolve` enforces this.
index f5bca90c2bd523d7075ff4eaeb0307b90480d1ca..e4cc96dd83bfbd751cd4b29b9e1b9bcd1e892b32 100644 (file)
@@ -974,13 +974,13 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
 
                             return Ok(tcx.intern_layout(Layout {
                                 variants: Variants::Multiple {
-                                    discr: niche_scalar,
-                                    discr_kind: DiscriminantKind::Niche {
+                                    tag: niche_scalar,
+                                    tag_encoding: TagEncoding::Niche {
                                         dataful_variant: i,
                                         niche_variants,
                                         niche_start,
                                     },
-                                    discr_index: 0,
+                                    tag_field: 0,
                                     variants: st,
                                 },
                                 fields: FieldsShape::Arbitrary {
@@ -1216,9 +1216,9 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
 
                 tcx.intern_layout(Layout {
                     variants: Variants::Multiple {
-                        discr: tag,
-                        discr_kind: DiscriminantKind::Tag,
-                        discr_index: 0,
+                        tag,
+                        tag_encoding: TagEncoding::Direct,
+                        tag_field: 0,
                         variants: layout_variants,
                     },
                     fields: FieldsShape::Arbitrary {
@@ -1245,7 +1245,7 @@ fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<
                 bug!("Layout::compute: unexpected type `{}`", ty)
             }
 
-            ty::Param(_) | ty::Error => {
+            ty::Param(_) | ty::Error(_) => {
                 return Err(LayoutError::Unknown(ty));
             }
         })
@@ -1399,15 +1399,15 @@ fn generator_layout(
         // Build a prefix layout, including "promoting" all ineligible
         // locals as part of the prefix. We compute the layout of all of
         // these fields at once to get optimal packing.
-        let discr_index = substs.as_generator().prefix_tys().count();
+        let tag_index = substs.as_generator().prefix_tys().count();
 
         // `info.variant_fields` already accounts for the reserved variants, so no need to add them.
         let max_discr = (info.variant_fields.len() - 1) as u128;
         let discr_int = Integer::fit_unsigned(max_discr);
         let discr_int_ty = discr_int.to_ty(tcx, false);
-        let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
-        let discr_layout = self.tcx.intern_layout(Layout::scalar(self, discr.clone()));
-        let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout };
+        let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
+        let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
+        let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
 
         let promoted_layouts = ineligible_locals
             .iter()
@@ -1418,7 +1418,7 @@ fn generator_layout(
             .as_generator()
             .prefix_tys()
             .map(|ty| self.layout_of(ty))
-            .chain(iter::once(Ok(discr_layout)))
+            .chain(iter::once(Ok(tag_layout)))
             .chain(promoted_layouts)
             .collect::<Result<Vec<_>, _>>()?;
         let prefix = self.univariant_uninterned(
@@ -1441,7 +1441,7 @@ fn generator_layout(
 
                 // "a" (`0..b_start`) and "b" (`b_start..`) correspond to
                 // "outer" and "promoted" fields respectively.
-                let b_start = (discr_index + 1) as u32;
+                let b_start = (tag_index + 1) as u32;
                 let offsets_b = offsets.split_off(b_start as usize);
                 let offsets_a = offsets;
 
@@ -1558,9 +1558,9 @@ fn generator_layout(
 
         let layout = tcx.intern_layout(Layout {
             variants: Variants::Multiple {
-                discr,
-                discr_kind: DiscriminantKind::Tag,
-                discr_index,
+                tag: tag,
+                tag_encoding: TagEncoding::Direct,
+                tag_field: tag_index,
                 variants,
             },
             fields: outer_fields,
@@ -1680,7 +1680,7 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
                 }
             }
 
-            Variants::Multiple { ref discr, ref discr_kind, .. } => {
+            Variants::Multiple { ref tag, ref tag_encoding, .. } => {
                 debug!(
                     "print-type-size `{:#?}` adt general variants def {}",
                     layout.ty,
@@ -1702,8 +1702,8 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
                 record(
                     adt_kind.into(),
                     adt_packed,
-                    match discr_kind {
-                        DiscriminantKind::Tag => Some(discr.value.size(self)),
+                    match tag_encoding {
+                        TagEncoding::Direct => Some(tag.value.size(self)),
                         _ => None,
                     },
                     variant_infos,
@@ -2001,6 +2001,8 @@ fn for_variant(
                 }
 
                 let fields = match this.ty.kind {
+                    ty::Adt(def, _) if def.variants.is_empty() =>
+                        bug!("for_variant called on zero-variant enum"),
                     ty::Adt(def, _) => def.variants[variant_index].fields.len(),
                     _ => bug!(),
                 };
@@ -2028,11 +2030,11 @@ fn for_variant(
 
     fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
         let tcx = cx.tcx();
-        let discr_layout = |discr: &Scalar| -> C::TyAndLayout {
-            let layout = Layout::scalar(cx, discr.clone());
+        let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
+            let layout = Layout::scalar(cx, tag.clone());
             MaybeResult::from(Ok(TyAndLayout {
                 layout: tcx.intern_layout(layout),
-                ty: discr.value.to_ty(tcx),
+                ty: tag.value.to_ty(tcx),
             }))
         };
 
@@ -2109,9 +2111,9 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
                     .unwrap()
                     .nth(i)
                     .unwrap(),
-                Variants::Multiple { ref discr, discr_index, .. } => {
-                    if i == discr_index {
-                        return discr_layout(discr);
+                Variants::Multiple { ref tag, tag_field, .. } => {
+                    if i == tag_field {
+                        return tag_layout(tag);
                     }
                     substs.as_generator().prefix_tys().nth(i).unwrap()
                 }
@@ -2128,9 +2130,9 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
                     Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
 
                     // Discriminant field for enums (where applicable).
-                    Variants::Multiple { ref discr, .. } => {
+                    Variants::Multiple { ref tag, .. } => {
                         assert_eq!(i, 0);
-                        return discr_layout(discr);
+                        return tag_layout(tag);
                     }
                 }
             }
@@ -2141,7 +2143,7 @@ fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
             | ty::Opaque(..)
             | ty::Param(_)
             | ty::Infer(_)
-            | ty::Error => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
+            | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
         })
     }
 
@@ -2157,7 +2159,7 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin
 
             ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
                 let tcx = cx.tcx();
-                let is_freeze = ty.is_freeze(tcx, cx.param_env(), DUMMY_SP);
+                let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env());
                 let kind = match mt {
                     hir::Mutability::Not => {
                         if is_freeze {
@@ -2207,10 +2209,10 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin
                     // using more niches than just null (e.g., the first page of
                     // the address space, or unaligned pointers).
                     Variants::Multiple {
-                        discr_kind: DiscriminantKind::Niche { dataful_variant, .. },
-                        discr_index,
+                        tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+                        tag_field,
                         ..
-                    } if this.fields.offset(discr_index) == offset => {
+                    } if this.fields.offset(tag_field) == offset => {
                         Some(this.for_variant(cx, dataful_variant))
                     }
                     _ => Some(this),
index 76c72e4c2603d53f7d8673b4fe9e73c548351ed9..92d6dbb5f90f557fb59ab4d2959a193a0112572c 100644 (file)
@@ -2,7 +2,8 @@
 
 use rustc_serialize::{Encodable, Encoder};
 
-use std::cmp::{self, Ordering};
+use std::alloc::Layout;
+use std::cmp::Ordering;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter;
@@ -43,17 +44,9 @@ pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx L
         assert!(mem::size_of::<T>() != 0);
         assert!(!slice.is_empty());
 
-        // Align up the size of the len (usize) field
-        let align = mem::align_of::<T>();
-        let align_mask = align - 1;
-        let offset = mem::size_of::<usize>();
-        let offset = (offset + align_mask) & !align_mask;
-
-        let size = offset + slice.len() * mem::size_of::<T>();
-
-        let mem = arena
-            .dropless
-            .alloc_raw(size, cmp::max(mem::align_of::<T>(), mem::align_of::<usize>()));
+        let (layout, _offset) =
+            Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap();
+        let mem = arena.dropless.alloc_raw(layout);
         unsafe {
             let result = &mut *(mem as *mut List<T>);
             // Write the length
index 93ef73171993c0522fd161cda065e54c821fdf7d..03aab2c0f9f2cb11d0ff46b4282c940455ff6961 100644 (file)
@@ -84,6 +84,8 @@
 
 pub use self::query::queries;
 
+pub use self::consts::ConstInt;
+
 pub mod adjustment;
 pub mod binding;
 pub mod cast;
 pub mod util;
 pub mod walk;
 
+mod consts;
 mod context;
 mod diagnostics;
 mod instance;
@@ -121,7 +124,6 @@ pub struct ResolverOutputs {
     pub definitions: rustc_hir::definitions::Definitions,
     pub cstore: Box<CrateStoreDyn>,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
-    pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate<hir::HirId>>>,
     pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
     pub export_map: ExportMap<LocalDefId>,
@@ -628,7 +630,7 @@ fn hash<H: Hasher>(&self, s: &mut H) {
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::TyS<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         let ty::TyS {
             ref kind,
@@ -1002,16 +1004,35 @@ pub fn instantiate_supertrait(
     }
 }
 
-#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable, Lift)]
-#[derive(HashStable)]
+#[derive(Debug)]
+crate struct PredicateInner<'tcx> {
+    kind: PredicateKind<'tcx>,
+    flags: TypeFlags,
+    /// See the comment for the corresponding field of [TyS].
+    outer_exclusive_binder: ty::DebruijnIndex,
+}
+
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PredicateInner<'_>, 40);
+
+#[derive(Clone, Copy, Lift)]
 pub struct Predicate<'tcx> {
-    kind: &'tcx PredicateKind<'tcx>,
+    inner: &'tcx PredicateInner<'tcx>,
 }
 
+impl rustc_serialize::UseSpecializedEncodable for Predicate<'_> {}
+impl rustc_serialize::UseSpecializedDecodable for Predicate<'_> {}
+
 impl<'tcx> PartialEq for Predicate<'tcx> {
     fn eq(&self, other: &Self) -> bool {
         // `self.kind` is always interned.
-        ptr::eq(self.kind, other.kind)
+        ptr::eq(self.inner, other.inner)
+    }
+}
+
+impl Hash for Predicate<'_> {
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        (self.inner as *const PredicateInner<'_>).hash(s)
     }
 }
 
@@ -1020,7 +1041,22 @@ impl<'tcx> Eq for Predicate<'tcx> {}
 impl<'tcx> Predicate<'tcx> {
     #[inline(always)]
     pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
-        self.kind
+        &self.inner.kind
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        let PredicateInner {
+            ref kind,
+
+            // The other fields just provide fast access to information that is
+            // also contained in `kind`, so no need to hash them.
+            flags: _,
+            outer_exclusive_binder: _,
+        } = self.inner;
+
+        kind.hash_stable(hcx, hasher);
     }
 }
 
@@ -1807,6 +1843,19 @@ pub fn new(
     pub fn is_field_list_non_exhaustive(&self) -> bool {
         self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
     }
+
+    /// `repr(transparent)` structs can have a single non-ZST field, this function returns that
+    /// field.
+    pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> {
+        for field in &self.fields {
+            let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id));
+            if !field_ty.is_zst(tcx, self.def_id) {
+                return Some(field);
+            }
+        }
+
+        None
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
@@ -2339,6 +2388,7 @@ pub fn discriminant_for_variant(
     /// Alternatively, if there is no explicit discriminant, returns the
     /// inferred discriminant directly.
     pub fn discriminant_def_for_variant(&self, variant_index: VariantIdx) -> (Option<DefId>, u32) {
+        assert!(!self.variants.is_empty());
         let mut explicit_index = variant_index.as_u32();
         let expr_did;
         loop {
@@ -2376,29 +2426,6 @@ pub fn destructor(&self, tcx: TyCtxt<'tcx>) -> Option<Destructor> {
     pub fn sized_constraint(&self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
         tcx.adt_sized_constraint(self.did).0
     }
-
-    /// `repr(transparent)` structs can have a single non-ZST field, this function returns that
-    /// field.
-    pub fn transparent_newtype_field(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Option<&FieldDef> {
-        assert!(self.is_struct() && self.repr.transparent());
-
-        for field in &self.non_enum_variant().fields {
-            let field_ty = tcx.normalize_erasing_regions(
-                param_env,
-                field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.did)),
-            );
-
-            if !field_ty.is_zst(tcx, self.did) {
-                return Some(field);
-            }
-        }
-
-        None
-    }
 }
 
 impl<'tcx> FieldDef {
index 1da042e161737ec6f7ebe730d06aa1bf0172bd76..1a8693b8df711fa0f7e69513604607813260b4ea 100644 (file)
@@ -171,7 +171,7 @@ impl<'tcx> TyCtxt<'tcx> {
             ty::Dynamic(..) |     // OutlivesObject, OutlivesFragment (*)
             ty::Placeholder(..) |
             ty::Bound(..) |
-            ty::Error => {
+            ty::Error(_) => {
                 // (*) Function pointers and trait objects are both binders.
                 // In the RFC, this means we would add the bound regions to
                 // the "bound regions list".  In our representation, no such
index 69b36980bd73cee0f711682982bd12385fdd0fd4..6c8f23c139f6ecf6b6ca579d06c41dceb86c18dc 100644 (file)
@@ -298,7 +298,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
         | ty::Opaque(..)
         | ty::Infer(_)
         | ty::Bound(..)
-        | ty::Error
+        | ty::Error(_)
         | ty::GeneratorWitness(..)
         | ty::Never
         | ty::Float(_) => None,
index 7d9943ab07902986478494a6a2e58041d901a5e4..67b6433b6114327e31737dd164bc38d72d1253a5 100644 (file)
@@ -144,7 +144,7 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
                 let substs = substs.truncate_to(self.tcx, generics);
                 self.push_generic_params(substs, iter::empty(), output, debug);
             }
-            ty::Error
+            ty::Error(_)
             | ty::Bound(..)
             | ty::Infer(_)
             | ty::Placeholder(..)
index d782dd07a65889c4dbc4548e1d99a34b0e50ef00..061214249713d689f2d7f1e1c6eb9e0ab6f677df 100644 (file)
@@ -1,10 +1,8 @@
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
-use crate::mir::interpret::{
-    sign_extend, truncate, AllocId, ConstValue, GlobalAlloc, Pointer, Scalar,
-};
+use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar};
 use crate::ty::layout::IntegerExt;
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ConstInt, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::Float;
 use rustc_ast::ast;
@@ -518,7 +516,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     p!(write("{}", infer_ty))
                 }
             }
-            ty::Error => p!(write("[type error]")),
+            ty::Error(_) => p!(write("[type error]")),
             ty::Param(ref param_ty) => p!(write("{}", param_ty)),
             ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
                 ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
@@ -919,7 +917,7 @@ macro_rules! print_underscore {
                 self.pretty_print_bound_var(debruijn, bound_var)?
             }
             ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
-            ty::ConstKind::Error => p!(write("[const error]")),
+            ty::ConstKind::Error(_) => p!(write("[const error]")),
         };
         Ok(self)
     }
@@ -981,35 +979,14 @@ fn pretty_print_const_scalar(
             }
             // Int
             (Scalar::Raw { data, .. }, ty::Uint(ui)) => {
-                let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
-                let max = truncate(u128::MAX, bit_size);
-
-                let ui_str = ui.name_str();
-                if data == max {
-                    p!(write("{}::MAX", ui_str))
-                } else {
-                    if print_ty { p!(write("{}{}", data, ui_str)) } else { p!(write("{}", data)) }
-                };
+                let size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
+                let int = ConstInt::new(data, size, false, ty.is_ptr_sized_integral());
+                if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
             }
             (Scalar::Raw { data, .. }, ty::Int(i)) => {
                 let size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size();
-                let bit_size = size.bits() as u128;
-                let min = 1u128 << (bit_size - 1);
-                let max = min - 1;
-
-                let i_str = i.name_str();
-                match data {
-                    d if d == min => p!(write("{}::MIN", i_str)),
-                    d if d == max => p!(write("{}::MAX", i_str)),
-                    _ => {
-                        let data = sign_extend(data, size) as i128;
-                        if print_ty {
-                            p!(write("{}{}", data, i_str))
-                        } else {
-                            p!(write("{}", data))
-                        }
-                    }
-                }
+                let int = ConstInt::new(data, size, true, ty.is_ptr_sized_integral());
+                if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
             }
             // Char
             (Scalar::Raw { data, .. }, ty::Char) if char::from_u32(data as u32).is_some() => {
@@ -1177,8 +1154,13 @@ fn pretty_print_const_value(
                         }
                         p!(write(")"));
                     }
+                    ty::Adt(def, substs) if def.variants.is_empty() => {
+                        p!(print_value_path(def.did, substs));
+                    }
                     ty::Adt(def, substs) => {
-                        let variant_def = &def.variants[contents.variant];
+                        let variant_id =
+                            contents.variant.expect("destructed const of adt without variant id");
+                        let variant_def = &def.variants[variant_id];
                         p!(print_value_path(variant_def.def_id, substs));
 
                         match variant_def.ctor_kind {
index 5374dff422425e938e066c8628616d68a59cb9f4..c84a7c38d0a0e70f5417b0a7ff986f78ba9a73c1 100644 (file)
@@ -524,16 +524,39 @@ fn cached_ty_for_shorthand<F>(
         let cache_key =
             ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
 
-        if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) {
+        if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
             return Ok(ty);
         }
 
         let ty = or_insert_with(self)?;
         // This may overwrite the entry, but it should overwrite with the same value.
-        tcx.rcache.borrow_mut().insert_same(cache_key, ty);
+        tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
         Ok(ty)
     }
 
+    fn cached_predicate_for_shorthand<F>(
+        &mut self,
+        shorthand: usize,
+        or_insert_with: F,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error>
+    where
+        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
+    {
+        let tcx = self.tcx();
+
+        let cache_key =
+            ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
+
+        if let Some(&pred) = tcx.pred_rcache.borrow().get(&cache_key) {
+            return Ok(pred);
+        }
+
+        let pred = or_insert_with(self)?;
+        // This may overwrite the entry, but it should overwrite with the same value.
+        tcx.pred_rcache.borrow_mut().insert_same(cache_key, pred);
+        Ok(pred)
+    }
+
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
@@ -820,24 +843,16 @@ fn specialized_encode(&mut self, ty: &&'b ty::TyS<'c>) -> Result<(), Self::Error
     }
 }
 
-impl<'a, 'b, 'c, 'tcx, E> SpecializedEncoder<&'b [(ty::Predicate<'c>, Span)]>
-    for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'b, 'tcx, E> SpecializedEncoder<ty::Predicate<'b>> for CacheEncoder<'a, 'tcx, E>
 where
     E: 'a + TyEncoder,
 {
     #[inline]
-    fn specialized_encode(
-        &mut self,
-        predicates: &&'b [(ty::Predicate<'c>, Span)],
-    ) -> Result<(), Self::Error> {
-        debug_assert!(self.tcx.lift(*predicates).is_some());
-        let predicates = unsafe {
-            std::mem::transmute::<
-                &&'b [(ty::Predicate<'c>, Span)],
-                &&'tcx [(ty::Predicate<'tcx>, Span)],
-            >(predicates)
-        };
-        ty_codec::encode_spanned_predicates(self, predicates, |encoder| {
+    fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> {
+        debug_assert!(self.tcx.lift(predicate).is_some());
+        let predicate =
+            unsafe { std::mem::transmute::<&ty::Predicate<'b>, &ty::Predicate<'tcx>>(predicate) };
+        ty_codec::encode_with_shorthand(self, predicate, |encoder| {
             &mut encoder.predicate_shorthands
         })
     }
index b1f76ff6a03bd2ad6a26f526e24c1e005a7fc6fd..0a0ff101b52032fcf2066e08b35800b1c600aaf8 100644 (file)
@@ -17,7 +17,7 @@ impl<'tcx> Value<'tcx> for &'_ TyS<'_> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
-        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.types.err) }
+        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
     }
 }
 
@@ -33,7 +33,7 @@ fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe {
             std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>(
-                AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])),
+                AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])),
             )
         }
     }
index cddd7081ca375fc05f020d42717cf5075dc1d063..e9a8b9095bf72d2845da10d211fef979bdf61e73 100644 (file)
@@ -354,7 +354,7 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
             bug!("bound types encountered in super_relate_tys")
         }
 
-        (&ty::Error, _) | (_, &ty::Error) => Ok(tcx.types.err),
+        (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(tcx.ty_error()),
 
         (&ty::Never, _)
         | (&ty::Char, _)
@@ -524,7 +524,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
             bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
         }
 
-        (ty::ConstKind::Error, _) | (_, ty::ConstKind::Error) => Ok(ty::ConstKind::Error),
+        (ty::ConstKind::Error(d), _) | (_, ty::ConstKind::Error(d)) => Ok(ty::ConstKind::Error(d)),
 
         (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => {
             return Ok(a);
@@ -617,12 +617,22 @@ fn relate<R: TypeRelation<'tcx>>(
         a: &Self,
         b: &Self,
     ) -> RelateResult<'tcx, Self> {
-        if a.len() != b.len() {
+        let tcx = relation.tcx();
+
+        // FIXME: this is wasteful, but want to do a perf run to see how slow it is.
+        // We need to perform this deduplication as we sometimes generate duplicate projections
+        // in `a`.
+        let mut a_v: Vec<_> = a.into_iter().collect();
+        let mut b_v: Vec<_> = b.into_iter().collect();
+        a_v.sort_by(|a, b| a.stable_cmp(tcx, b));
+        a_v.dedup();
+        b_v.sort_by(|a, b| a.stable_cmp(tcx, b));
+        b_v.dedup();
+        if a_v.len() != b_v.len() {
             return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
         }
 
-        let tcx = relation.tcx();
-        let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| {
+        let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| {
             use crate::ty::ExistentialPredicate::*;
             match (ep_a, ep_b) {
                 (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)),
index f6f5dfd651612dbbc5e3376558218a2191f31bc9..f736037b5c15a598eccd5ccb8b093e73b72e307e 100644 (file)
@@ -911,7 +911,7 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
             | ty::Int(_)
             | ty::Uint(_)
             | ty::Float(_)
-            | ty::Error
+            | ty::Error(_)
             | ty::Infer(_)
             | ty::Param(..)
             | ty::Bound(..)
@@ -952,7 +952,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             | ty::Int(_)
             | ty::Uint(_)
             | ty::Float(_)
-            | ty::Error
+            | ty::Error(_)
             | ty::Infer(_)
             | ty::Bound(..)
             | ty::Placeholder(..)
@@ -987,12 +987,34 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let new = ty::PredicateKind::super_fold_with(self.kind, folder);
-        if new != *self.kind { folder.tcx().mk_predicate(new) } else { *self }
+        let new = ty::PredicateKind::super_fold_with(&self.inner.kind, folder);
+        if new != self.inner.kind { folder.tcx().mk_predicate(new) } else { *self }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        ty::PredicateKind::super_visit_with(self.kind, visitor)
+        ty::PredicateKind::super_visit_with(&self.inner.kind, visitor)
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.visit_predicate(*self)
+    }
+
+    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.inner.outer_exclusive_binder > binder
+    }
+
+    fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
+        self.inner.flags.intersects(flags)
+    }
+}
+
+pub(super) trait PredicateVisitor<'tcx>: TypeVisitor<'tcx> {
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool;
+}
+
+impl<T: TypeVisitor<'tcx>> PredicateVisitor<'tcx> for T {
+    default fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
+        predicate.super_visit_with(self)
     }
 }
 
@@ -1051,7 +1073,7 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
             ty::ConstKind::Value(_)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Placeholder(..)
-            | ty::ConstKind::Error => *self,
+            | ty::ConstKind::Error(_) => *self,
         }
     }
 
@@ -1063,7 +1085,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
             ty::ConstKind::Value(_)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Placeholder(_)
-            | ty::ConstKind::Error => false,
+            | ty::ConstKind::Error(_) => false,
         }
     }
 }
index fad96aa86cc0afc27eaac0dc629fe0f04ed1f0a9..8f86d2ef522d33a82b4fed5511578e03799a289a 100644 (file)
@@ -203,9 +203,15 @@ pub enum TyKind<'tcx> {
 
     /// A placeholder for a type which could not be computed; this is
     /// propagated to avoid useless error messages.
-    Error,
+    Error(DelaySpanBugEmitted),
 }
 
+/// A type that is not publicly constructable. This prevents people from making `TyKind::Error`
+/// except through `tcx.err*()`.
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[derive(RustcEncodable, RustcDecodable, HashStable)]
+pub struct DelaySpanBugEmitted(pub(super) ());
+
 // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(TyKind<'_>, 24);
@@ -516,8 +522,7 @@ pub fn discriminants(
 
     /// Calls `f` with a reference to the name of the enumerator for the given
     /// variant `v`.
-    #[inline]
-    pub fn variant_name(self, v: VariantIdx) -> Cow<'static, str> {
+    pub fn variant_name(v: VariantIdx) -> Cow<'static, str> {
         match v.as_usize() {
             Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME),
             Self::RETURNED => Cow::from(Self::RETURNED_NAME),
@@ -1583,19 +1588,16 @@ pub fn type_flags(&self) -> TypeFlags {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_INFER;
-                flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
             }
             ty::RePlaceholder(..) => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
-                flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
             }
             ty::ReEarlyBound(..) => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_PARAM;
-                flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
             }
             ty::ReFree { .. } => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
@@ -1984,7 +1986,7 @@ pub fn is_machine(&self) -> bool {
     #[inline]
     pub fn has_concrete_skeleton(&self) -> bool {
         match self.kind {
-            Param(_) | Infer(_) | Error => false,
+            Param(_) | Infer(_) | Error(_) => false,
             _ => true,
         }
     }
@@ -2016,7 +2018,7 @@ pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
         match self.kind {
             FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs),
             FnPtr(f) => f,
-            Error => {
+            Error(_) => {
                 // ignore errors (#54954)
                 ty::Binder::dummy(FnSig::fake())
             }
@@ -2093,6 +2095,9 @@ pub fn discriminant_for_variant(
         variant_index: VariantIdx,
     ) -> Option<Discr<'tcx>> {
         match self.kind {
+            TyKind::Adt(adt, _) if adt.variants.is_empty() => {
+                bug!("discriminant_for_variant called on zero variant enum");
+            }
             TyKind::Adt(adt, _) if adt.is_enum() => {
                 Some(adt.discriminant_for_variant(tcx, variant_index))
             }
@@ -2140,7 +2145,7 @@ pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
             // closure type is not yet known
             Bound(..) | Infer(_) => None,
 
-            Error => Some(ty::ClosureKind::Fn),
+            Error(_) => Some(ty::ClosureKind::Fn),
 
             _ => bug!("cannot convert type `{:?}` to a closure kind", self),
         }
@@ -2167,7 +2172,7 @@ pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
             | ty::Array(..)
             | ty::Closure(..)
             | ty::Never
-            | ty::Error => true,
+            | ty::Error(_) => true,
 
             ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false,
 
@@ -2372,9 +2377,7 @@ pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx>
                 // can leak through `val` into the const we return.
                 Ok(val) => Const::from_value(tcx, val, self.ty),
                 Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
-                Err(ErrorHandled::Reported(ErrorReported)) => {
-                    tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: self.ty })
-                }
+                Err(ErrorHandled::Reported(ErrorReported)) => tcx.const_error(self.ty),
             }
         } else {
             self
@@ -2434,7 +2437,7 @@ pub enum ConstKind<'tcx> {
 
     /// A placeholder for a const which could not be computed; this is
     /// propagated to avoid useless error messages.
-    Error,
+    Error(DelaySpanBugEmitted),
 }
 
 #[cfg(target_arch = "x86_64")]
index 1529f1173b391caea5df017e76d86b1e957eb646..e9fd67a748c857835b2a8602d2f40f11966a2216 100644 (file)
@@ -333,6 +333,19 @@ pub fn type_for_def(&self, def: &ty::GenericParamDef) -> GenericArg<'tcx> {
     /// in a different item, with `target_substs` as the base for
     /// the target impl/trait, with the source child-specific
     /// parameters (e.g., method parameters) on top of that base.
+    ///
+    /// For example given:
+    ///
+    /// ```no_run
+    /// trait X<S> { fn f<T>(); }
+    /// impl<U> X<U> for U { fn f<V>() {} }
+    /// ```
+    ///
+    /// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait.
+    /// * If `source_ancestor` is the def_id of the trait.
+    /// * If `target_substs` is `[U]`, the substs for the impl.
+    /// * Then we will return `[U, T]`, the subst for `f` in the impl that
+    ///   are needed for it to match the trait.
     pub fn rebase_onto(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -599,12 +612,12 @@ fn const_for_param(
     ///
     /// ```
     /// type Func<A> = fn(A);
-    /// type MetaFunc = for<'a> fn(Func<&'a int>)
+    /// type MetaFunc = for<'a> fn(Func<&'a i32>)
     /// ```
     ///
     /// The type `MetaFunc`, when fully expanded, will be
     ///
-    ///     for<'a> fn(fn(&'a int))
+    ///     for<'a> fn(fn(&'a i32))
     ///             ^~ ^~ ^~~
     ///             |  |  |
     ///             |  |  DebruijnIndex of 2
@@ -613,7 +626,7 @@ fn const_for_param(
     /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
     /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
     /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the
-    /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a
+    /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a
     /// De Bruijn index of 1. It's only during the substitution that we can see we must increase the
     /// depth by 1 to account for the binder that we passed through.
     ///
@@ -621,18 +634,18 @@ fn const_for_param(
     ///
     /// ```
     /// type FuncTuple<A> = (A,fn(A));
-    /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
+    /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>)
     /// ```
     ///
     /// Here the final type will be:
     ///
-    ///     for<'a> fn((&'a int, fn(&'a int)))
+    ///     for<'a> fn((&'a i32, fn(&'a i32)))
     ///                 ^~~         ^~~
     ///                 |           |
     ///          DebruijnIndex of 1 |
     ///                      DebruijnIndex of 2
     ///
-    /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
+    /// As indicated in the diagram, here the same type `&'a i32` is substituted once, but in the
     /// first case we do not increase the De Bruijn index and in the second case we do. The reason
     /// is that only in the second case have we passed through a fn binder.
     fn shift_vars_through_binders<T: TypeFoldable<'tcx>>(&self, val: T) -> T {
index ff284b709c2cfeee5c3170353719f1e9962c26b5..67ad7ee708267968560c9b5b1b97106d5b041ff2 100644 (file)
@@ -176,7 +176,7 @@ pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
         if let ty::Adt(def, substs) = ty.kind {
             for field in def.all_fields() {
                 let field_ty = field.ty(self, substs);
-                if let Error = field_ty.kind {
+                if let Error(_) = field_ty.kind {
                     return true;
                 }
             }
@@ -681,11 +681,10 @@ pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<
     /// winds up being reported as an error during NLL borrow check.
     pub fn is_copy_modulo_regions(
         &'tcx self,
-        tcx: TyCtxt<'tcx>,
+        tcx_at: TyCtxtAt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        span: Span,
     ) -> bool {
-        tcx.at(span).is_copy_raw(param_env.and(self))
+        tcx_at.is_copy_raw(param_env.and(self))
     }
 
     /// Checks whether values of this type `T` have a size known at
@@ -706,13 +705,8 @@ pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx
     /// that the `Freeze` trait is not exposed to end users and is
     /// effectively an implementation detail.
     // FIXME: use `TyCtxtAt` instead of separate `Span`.
-    pub fn is_freeze(
-        &'tcx self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        span: Span,
-    ) -> bool {
-        self.is_trivially_freeze() || tcx.at(span).is_freeze_raw(param_env.and(self))
+    pub fn is_freeze(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+        self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self))
     }
 
     /// Fast path helper for testing if a type is `Freeze`.
@@ -731,7 +725,7 @@ fn is_trivially_freeze(&self) -> bool {
             | ty::Ref(..)
             | ty::RawPtr(_)
             | ty::FnDef(..)
-            | ty::Error
+            | ty::Error(_)
             | ty::FnPtr(_) => true,
             ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze),
             ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
@@ -826,7 +820,7 @@ pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool {
             // called for known, fully-monomorphized types.
             Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false,
 
-            Foreign(_) | GeneratorWitness(..) | Error => false,
+            Foreign(_) | GeneratorWitness(..) | Error(_) => false,
         }
     }
 
@@ -1109,7 +1103,7 @@ pub fn needs_drop_components(
         // Foreign types can never have destructors.
         ty::Foreign(..) => Ok(SmallVec::new()),
 
-        ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop),
+        ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
 
         ty::Slice(ty) => needs_drop_components(ty, target_layout),
         ty::Array(elem_ty, size) => {
index bf988a430263303e9687dae8e9d2ef91d26c56b2..633d4fda8a46d9691711df2633ab97daeb730c63 100644 (file)
@@ -22,13 +22,13 @@ pub fn new(root: GenericArg<'tcx>) -> TypeWalker<'tcx> {
     /// Skips the subtree corresponding to the last type
     /// returned by `next()`.
     ///
-    /// Example: Imagine you are walking `Foo<Bar<int>, usize>`.
+    /// Example: Imagine you are walking `Foo<Bar<i32>, usize>`.
     ///
     /// ```
     /// let mut iter: TypeWalker = ...;
     /// iter.next(); // yields Foo
-    /// iter.next(); // yields Bar<int>
-    /// iter.skip_current_subtree(); // skips int
+    /// iter.next(); // yields Bar<i32>
+    /// iter.skip_current_subtree(); // skips i32
     /// iter.next(); // yields usize
     /// ```
     pub fn skip_current_subtree(&mut self) {
@@ -108,7 +108,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             | ty::Infer(_)
             | ty::Param(_)
             | ty::Never
-            | ty::Error
+            | ty::Error(_)
             | ty::Placeholder(..)
             | ty::Bound(..)
             | ty::Foreign(..) => {}
@@ -171,7 +171,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                 | ty::ConstKind::Placeholder(_)
                 | ty::ConstKind::Bound(..)
                 | ty::ConstKind::Value(_)
-                | ty::ConstKind::Error => {}
+                | ty::ConstKind::Error(_) => {}
 
                 ty::ConstKind::Unevaluated(_, substs, _) => {
                     stack.extend(substs.iter().rev());
index 2e897647a3beb18a32ca9638d881142cc5c0ca80..e85f69554d0c831cf3ba0bf18180ff8c3bb7af89 100644 (file)
@@ -139,7 +139,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
 
                 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
 
-                if span == move_span {
+                if location == move_out.source {
                     err.span_label(
                         span,
                         format!("value moved{} here, in previous iteration of loop", move_msg),
@@ -214,6 +214,20 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                         );
                     }
                 }
+                if let UseSpans::PatUse(span) = move_spans {
+                    err.span_suggestion_verbose(
+                        span.shrink_to_lo(),
+                        &format!(
+                            "borrow this field in the pattern to avoid moving {}",
+                            self.describe_place(moved_place.as_ref())
+                                .map(|n| format!("`{}`", n))
+                                .unwrap_or_else(|| "the value".to_string())
+                        ),
+                        "ref ".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+
                 if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
                     let sess = self.infcx.tcx.sess;
                     if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
@@ -256,11 +270,28 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                 _ => true,
             };
 
-            if needs_note {
-                let mpi = self.move_data.moves[move_out_indices[0]].path;
-                let place = &self.move_data.move_paths[mpi].place;
+            let mpi = self.move_data.moves[move_out_indices[0]].path;
+            let place = &self.move_data.move_paths[mpi].place;
+            let ty = place.ty(self.body, self.infcx.tcx).ty;
+
+            if is_loop_move {
+                if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind {
+                    // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
+                    err.span_suggestion_verbose(
+                        span.shrink_to_lo(),
+                        &format!(
+                            "consider creating a fresh reborrow of {} here",
+                            self.describe_place(moved_place)
+                                .map(|n| format!("`{}`", n))
+                                .unwrap_or_else(|| "the mutable reference".to_string()),
+                        ),
+                        "&mut *".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
 
-                let ty = place.ty(self.body, self.infcx.tcx).ty;
+            if needs_note {
                 let opt_name =
                     self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
                 let note_msg = match opt_name {
index d04059ff0fc7ffc405a82505b7fe26462b338102..b591b938b5ac32efb41f8f391decc77879cff34d 100644 (file)
@@ -509,7 +509,9 @@ fn later_use_kind(
                 // Used in a closure.
                 (LaterUseKind::ClosureCapture, var_span)
             }
-            UseSpans::OtherUse(span) | UseSpans::FnSelfUse { var_span: span, .. } => {
+            UseSpans::PatUse(span)
+            | UseSpans::OtherUse(span)
+            | UseSpans::FnSelfUse { var_span: span, .. } => {
                 let block = &self.body.basic_blocks()[location.block];
 
                 let kind = if let Some(&Statement {
index 04f48cd65823054613daa1804218756a462b30bc..e94952e1c543cd6ee92ee7b7cdfb189bbdc3aa06 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItemGroup;
 use rustc_hir::GeneratorKind;
 use rustc_middle::mir::{
     AggregateKind, Constant, Field, Local, LocalInfo, LocalKind, Location, Operand, Place,
@@ -558,7 +559,9 @@ pub(super) enum UseSpans {
         fn_span: Span,
         kind: FnSelfUseKind,
     },
-    // This access has a single span associated to it: common case.
+    /// This access is caused by a `match` or `if let` pattern.
+    PatUse(Span),
+    /// This access has a single span associated to it: common case.
     OtherUse(Span),
 }
 
@@ -576,6 +579,7 @@ impl UseSpans {
     pub(super) fn args_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { args_span: span, .. }
+            | UseSpans::PatUse(span)
             | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
         }
@@ -584,6 +588,7 @@ pub(super) fn args_or_use(self) -> Span {
     pub(super) fn var_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { var_span: span, .. }
+            | UseSpans::PatUse(span)
             | UseSpans::FnSelfUse { var_span: span, .. }
             | UseSpans::OtherUse(span) => span,
         }
@@ -654,8 +659,8 @@ pub(super) fn or_else<F>(self, if_other: F) -> Self
     {
         match self {
             closure @ UseSpans::ClosureUse { .. } => closure,
+            UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
             fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
-            UseSpans::OtherUse(_) => if_other(),
         }
     }
 }
@@ -772,7 +777,12 @@ pub(super) fn move_spans(
             }
         }
 
-        let normal_ret = OtherUse(stmt.source_info.span);
+        let normal_ret =
+            if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
+                PatUse(stmt.source_info.span)
+            } else {
+                OtherUse(stmt.source_info.span)
+            };
 
         // We are trying to find MIR of the form:
         // ```
@@ -794,8 +804,10 @@ pub(super) fn move_spans(
 
         debug!("move_spans: target_temp = {:?}", target_temp);
 
-        if let Some(Terminator { kind: TerminatorKind::Call { func, args, fn_span, .. }, .. }) =
-            &self.body[location.block].terminator
+        if let Some(Terminator {
+            kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. },
+            ..
+        }) = &self.body[location.block].terminator
         {
             let mut method_did = None;
             if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
@@ -816,14 +828,19 @@ pub(super) fn move_spans(
 
             if let [Operand::Move(self_place), ..] = **args {
                 if self_place.as_local() == Some(target_temp) {
-                    let is_fn_once = tcx.parent(method_did) == tcx.lang_items().fn_once_trait();
+                    let parent = tcx.parent(method_did);
+                    let is_fn_once = parent == tcx.lang_items().fn_once_trait();
+                    let is_operator = !from_hir_call
+                        && parent.map_or(false, |p| {
+                            tcx.lang_items().group(LangItemGroup::Op).contains(&p)
+                        });
                     let fn_call_span = *fn_span;
 
                     let self_arg = tcx.fn_arg_names(method_did)[0];
 
                     let kind = if is_fn_once {
                         FnSelfUseKind::FnOnceCall
-                    } else if fn_call_span.is_desugaring(DesugaringKind::Operator) {
+                    } else if is_operator {
                         FnSelfUseKind::Operator { self_arg }
                     } else {
                         debug!(
index f1923b9e81c66ab23f591e80d3ea07a7d402b051..99b9788c20b053b549c6b5eb918e2fc60ab27076 100644 (file)
@@ -579,7 +579,7 @@ fn add_static_impl_trait_suggestion(
         if let (Some(f), Some(ty::RegionKind::ReStatic)) =
             (self.to_error_region(fr), self.to_error_region(outlived_fr))
         {
-            if let Some((ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self
+            if let Some((&ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self
                 .infcx
                 .tcx
                 .is_suitable_region(f)
@@ -592,7 +592,7 @@ fn add_static_impl_trait_suggestion(
                 //
                 // eg. check for `impl Trait + 'static` instead of `impl Trait`.
                 let has_static_predicate = {
-                    let predicates_of = self.infcx.tcx.predicates_of(*did);
+                    let predicates_of = self.infcx.tcx.predicates_of(did);
                     let bounds = predicates_of.instantiate(self.infcx.tcx, substs);
 
                     let mut found = false;
@@ -625,7 +625,7 @@ fn add_static_impl_trait_suggestion(
                     diag.help(&format!("consider replacing `{}` with `{}`", fr_name, static_str));
                 } else {
                     // Otherwise, we should suggest adding a constraint on the return type.
-                    let span = self.infcx.tcx.def_span(*did);
+                    let span = self.infcx.tcx.def_span(did);
                     if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
                         let suggestable_fr_name = if fr_name.was_named() {
                             fr_name.to_string()
index 17fa641ae6c17d1c6edd2ee56e348d677d1454ca..fd8f17718e795b48f5bacc0e569eb8e8932bf9e2 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
 use rustc_middle::mir::{BorrowKind, Mutability, Operand};
-use rustc_middle::mir::{InlineAsmOperand, TerminatorKind};
+use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::mir::{Statement, StatementKind};
 use rustc_middle::ty::TyCtxt;
 
@@ -112,14 +112,14 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         self.super_statement(statement, location);
     }
 
-    fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) {
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         self.check_activations(location);
 
-        match kind {
+        match &terminator.kind {
             TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
                 self.consume_operand(location, discr);
             }
-            TerminatorKind::Drop { location: drop_place, target: _, unwind: _ } => {
+            TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
                 self.access_place(
                     location,
                     *drop_place,
@@ -128,7 +128,7 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
                 );
             }
             TerminatorKind::DropAndReplace {
-                location: drop_place,
+                place: drop_place,
                 value: ref new_value,
                 target: _,
                 unwind: _,
@@ -222,7 +222,7 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
             }
         }
 
-        self.super_terminator_kind(kind, location);
+        self.super_terminator(terminator, location);
     }
 }
 
index d099f48adc5c6312534cacd1b74001c90d9eb326..83691d439eb81c983dc1af5da94f01eb310ce4c2 100644 (file)
@@ -663,7 +663,7 @@ fn visit_terminator_before_primary_effect(
             TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
                 self.consume_operand(loc, (discr, span), flow_state);
             }
-            TerminatorKind::Drop { location: ref drop_place, target: _, unwind: _ } => {
+            TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => {
                 let tcx = self.infcx.tcx;
 
                 // Compute the type with accurate region information.
@@ -692,7 +692,7 @@ fn visit_terminator_before_primary_effect(
                 );
             }
             TerminatorKind::DropAndReplace {
-                location: drop_place,
+                place: drop_place,
                 value: ref new_value,
                 target: _,
                 unwind: _,
index 5707127340d87fa92bec7359fc80fcb08cf0635b..beee31812563ed4d536ea5abd4b58fb81222a767 100644 (file)
@@ -264,7 +264,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
                             .tcx
                             .sess
                             .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
-                        (self.infcx.tcx.types.err, None)
+                        (self.infcx.tcx.ty_error(), None)
                     });
                 let constraints2 = self.add_implied_bounds(ty);
                 normalized_inputs_and_output.push(ty);
index 7cf4fdfcf3c5b05d16539023286f104e26a137fe..0e35cafb9f3e928a7a29dd39a2c76161a24345cc 100644 (file)
@@ -498,7 +498,7 @@ fn sanitize_place(
             if place_ty.variant_index.is_none() {
                 if place_ty.ty.references_error() {
                     assert!(self.errors_reported);
-                    return PlaceTy::from_ty(self.tcx().types.err);
+                    return PlaceTy::from_ty(self.tcx().ty_error());
                 }
             }
             place_ty = self.sanitize_projection(place_ty, elem, place, location)
@@ -725,7 +725,7 @@ fn sanitize_projection(
 
     fn error(&mut self) -> Ty<'tcx> {
         self.errors_reported = true;
-        self.tcx().types.err
+        self.tcx().ty_error()
     }
 
     fn field_ty(
@@ -1558,8 +1558,8 @@ fn check_terminator(
                 // no checks needed for these
             }
 
-            TerminatorKind::DropAndReplace { ref location, ref value, target: _, unwind: _ } => {
-                let place_ty = location.ty(body, tcx).ty;
+            TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => {
+                let place_ty = place.ty(body, tcx).ty;
                 let rv_ty = value.ty(body, tcx);
 
                 let locations = term_location.to_locations();
index 7ff12820db8151858fbf33b6e89221ecaac237bc..285d9ed64691a555e190f134a375f2fbf9059bcf 100644 (file)
@@ -25,7 +25,7 @@ pub(super) fn relate_types<'tcx>(
     category: ConstraintCategory,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
 ) -> Fallible<()> {
-    debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
+    debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
     TypeRelating::new(
         infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
index 3003f4639d9fa3806d48b2d32f319f9ee6350e07..7b292ee71f99d22f49dbef2ad6e5f4256b0473e2 100644 (file)
@@ -232,8 +232,7 @@ pub fn new(
     ) -> Self {
         let tcx = infcx.tcx;
         let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id);
-        UniversalRegionsBuilder { infcx, mir_def_id: mir_def_id.to_def_id(), mir_hir_id, param_env }
-            .build()
+        UniversalRegionsBuilder { infcx, mir_def_id, mir_hir_id, param_env }.build()
     }
 
     /// Given a reference to a closure type, extracts all the values
@@ -389,7 +388,7 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
 
 struct UniversalRegionsBuilder<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
-    mir_def_id: DefId,
+    mir_def_id: LocalDefId,
     mir_hir_id: HirId,
     param_env: ty::ParamEnv<'tcx>,
 }
@@ -418,7 +417,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id.to_def_id());
 
         // If this is a closure or generator, then the late-bound regions from the enclosing
         // function are actually external regions to us. For example, here, 'a is not local
@@ -426,7 +425,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         // fn foo<'a>() {
         //     let c = || { let x: &'a u32 = ...; }
         // }
-        if self.mir_def_id != closure_base_def_id {
+        if self.mir_def_id.to_def_id() != closure_base_def_id {
             self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
         }
 
@@ -443,7 +442,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def_id == closure_base_def_id {
+        if self.mir_def_id.to_def_id() == closure_base_def_id {
             self.infcx
                 .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
         }
@@ -508,14 +507,14 @@ fn build(self) -> UniversalRegions<'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def_id == closure_base_def_id {
+                let defining_ty = if self.mir_def_id.to_def_id() == closure_base_def_id {
                     tcx.type_of(closure_base_def_id)
                 } else {
-                    let tables = tcx.typeck_tables_of(self.mir_def_id.expect_local());
+                    let tables = tcx.typeck_tables_of(self.mir_def_id);
                     tables.node_type(self.mir_hir_id)
                 };
 
@@ -540,11 +539,11 @@ fn defining_ty(&self) -> DefiningTy<'tcx> {
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(closure_base_def_id, self.mir_def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), closure_base_def_id);
                 let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
                 let substs =
                     self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
-                DefiningTy::Const(self.mir_def_id, substs)
+                DefiningTy::Const(self.mir_def_id.to_def_id(), substs)
             }
         }
     }
@@ -559,7 +558,7 @@ fn compute_indices(
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
         let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
         let fr_substs = match defining_ty {
             DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
@@ -593,7 +592,7 @@ fn compute_inputs_and_output(
         let tcx = self.infcx.tcx;
         match defining_ty {
             DefiningTy::Closure(def_id, substs) => {
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), def_id);
                 let closure_sig = substs.as_closure().sig();
                 let inputs_and_output = closure_sig.inputs_and_output();
                 let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
@@ -617,7 +616,7 @@ fn compute_inputs_and_output(
             }
 
             DefiningTy::Generator(def_id, substs, movability) => {
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), def_id);
                 let resume_ty = substs.as_generator().resume_ty();
                 let output = substs.as_generator().return_ty();
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
@@ -635,7 +634,7 @@ fn compute_inputs_and_output(
             DefiningTy::Const(def_id, _) => {
                 // For a constant body, there are no inputs, and one
                 // "output" (the type of the constant).
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def_id.to_def_id(), def_id);
                 let ty = tcx.type_of(def_id);
                 let ty = indices.fold_to_region_vids(tcx, &ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
@@ -656,7 +655,7 @@ fn replace_free_regions_with_nll_infer_vars<T>(
     fn replace_bound_regions_with_nll_infer_vars<T>(
         &self,
         origin: NLLRegionVariableOrigin,
-        all_outlive_scope: DefId,
+        all_outlive_scope: LocalDefId,
         value: &ty::Binder<T>,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) -> T
@@ -665,7 +664,7 @@ fn replace_bound_regions_with_nll_infer_vars<T>(
 
     fn replace_late_bound_regions_with_nll_infer_vars(
         &self,
-        mir_def_id: DefId,
+        mir_def_id: LocalDefId,
         indices: &mut UniversalRegionIndices<'tcx>,
     );
 }
@@ -685,7 +684,7 @@ fn replace_free_regions_with_nll_infer_vars<T>(
     fn replace_bound_regions_with_nll_infer_vars<T>(
         &self,
         origin: NLLRegionVariableOrigin,
-        all_outlive_scope: DefId,
+        all_outlive_scope: LocalDefId,
         value: &ty::Binder<T>,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) -> T
@@ -699,7 +698,7 @@ fn replace_bound_regions_with_nll_infer_vars<T>(
         let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
             debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
             let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                scope: all_outlive_scope,
+                scope: all_outlive_scope.to_def_id(),
                 bound_region: br,
             }));
             let region_vid = self.next_nll_region_var(origin);
@@ -724,11 +723,11 @@ fn replace_bound_regions_with_nll_infer_vars<T>(
     /// inputs vector.
     fn replace_late_bound_regions_with_nll_infer_vars(
         &self,
-        mir_def_id: DefId,
+        mir_def_id: LocalDefId,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) {
         debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
-        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id);
+        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
         for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
             debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
             if !indices.indices.contains_key(&r) {
index 2da72f3bcc517451239ca8ffed3a0134e6593983..e027056842db97d20cf69c0109df7def59377a78 100644 (file)
@@ -1,5 +1,7 @@
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
-use rustc_middle::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind};
+use rustc_middle::mir::{
+    Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
+};
 
 use rustc_data_structures::fx::FxHashSet;
 
@@ -62,20 +64,22 @@ fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) {
 }
 
 impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
-    fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, _location: Location) {
-        debug!("visit_terminator_kind: kind={:?}", kind);
-        match &kind {
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        debug!("visit_terminator: terminator={:?}", terminator);
+        match &terminator.kind {
             TerminatorKind::Call { destination: Some((into, _)), .. } => {
                 self.remove_never_initialized_mut_locals(*into);
             }
-            TerminatorKind::DropAndReplace { location, .. } => {
-                self.remove_never_initialized_mut_locals(*location);
+            TerminatorKind::DropAndReplace { place, .. } => {
+                self.remove_never_initialized_mut_locals(*place);
             }
             _ => {}
         }
+
+        self.super_terminator(terminator, location);
     }
 
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) {
+    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         if let StatementKind::Assign(box (into, _)) = &statement.kind {
             debug!(
                 "visit_statement: statement={:?} local={:?} \
@@ -84,6 +88,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location)
             );
             self.remove_never_initialized_mut_locals(*into);
         }
+
+        self.super_statement(statement, location);
     }
 
     fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
index 5deae94fe0c8e785086b005f72b626051e1e9d43..8a72be33b8429ce34d90131492e1f193a9217453 100644 (file)
@@ -2,6 +2,7 @@
 use std::fmt;
 
 use rustc_middle::mir::AssertKind;
+use rustc_middle::ty::ConstInt;
 use rustc_span::{Span, Symbol};
 
 use super::InterpCx;
@@ -13,7 +14,7 @@ pub enum ConstEvalErrKind {
     NeedsRfc(String),
     ConstAccessesStatic,
     ModifiedGlobal,
-    AssertFailure(AssertKind<u64>),
+    AssertFailure(AssertKind<ConstInt>),
     Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
 }
 
index dc13126df0e4cdd5b006c0601be2db3d5551eff0..8be0ab9019fe228d064b49dc921be8839bb31da4 100644 (file)
@@ -248,25 +248,19 @@ fn assert_panic(
         _unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
         use rustc_middle::mir::AssertKind::*;
-        // Convert `AssertKind<Operand>` to `AssertKind<u64>`.
+        // Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.
+        let eval_to_int =
+            |op| ecx.read_immediate(ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
         let err = match msg {
             BoundsCheck { ref len, ref index } => {
-                let len = ecx
-                    .read_immediate(ecx.eval_operand(len, None)?)
-                    .expect("can't eval len")
-                    .to_scalar()?
-                    .to_machine_usize(&*ecx)?;
-                let index = ecx
-                    .read_immediate(ecx.eval_operand(index, None)?)
-                    .expect("can't eval index")
-                    .to_scalar()?
-                    .to_machine_usize(&*ecx)?;
+                let len = eval_to_int(len)?;
+                let index = eval_to_int(index)?;
                 BoundsCheck { len, index }
             }
-            Overflow(op) => Overflow(*op),
-            OverflowNeg => OverflowNeg,
-            DivisionByZero => DivisionByZero,
-            RemainderByZero => RemainderByZero,
+            Overflow(op, l, r) => Overflow(*op, eval_to_int(l)?, eval_to_int(r)?),
+            OverflowNeg(op) => OverflowNeg(eval_to_int(op)?),
+            DivisionByZero(op) => DivisionByZero(eval_to_int(op)?),
+            RemainderByZero(op) => RemainderByZero(eval_to_int(op)?),
             ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind),
             ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind),
         };
index 3539ccf5de038299aa83a349ec41de59265b50b7..ed992a59839547b802664c8bd9161c213e0234ca 100644 (file)
@@ -30,8 +30,10 @@ pub(crate) fn const_caller_location(
     ConstValue::Scalar(loc_place.ptr)
 }
 
-// this function uses `unwrap` copiously, because an already validated constant
-// must have valid fields and can thus never fail outside of compiler bugs
+/// This function uses `unwrap` copiously, because an already validated constant
+/// must have valid fields and can thus never fail outside of compiler bugs. However, it is
+/// invoked from the pretty printer, where it can receive enums with no variants and e.g.
+/// `read_discriminant` needs to be able to handle that.
 pub(crate) fn destructure_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -41,17 +43,21 @@ pub(crate) fn destructure_const<'tcx>(
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
     let op = ecx.eval_const_to_op(val, None).unwrap();
 
-    let variant = ecx.read_discriminant(op).unwrap().1;
-
     // We go to `usize` as we cannot allocate anything bigger anyway.
-    let field_count = match val.ty.kind {
-        ty::Array(_, len) => usize::try_from(len.eval_usize(tcx, param_env)).unwrap(),
-        ty::Adt(def, _) => def.variants[variant].fields.len(),
-        ty::Tuple(substs) => substs.len(),
+    let (field_count, variant, down) = match val.ty.kind {
+        ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
+        ty::Adt(def, _) if def.variants.is_empty() => {
+            return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) };
+        }
+        ty::Adt(def, _) => {
+            let variant = ecx.read_discriminant(op).unwrap().1;
+            let down = ecx.operand_downcast(op, variant).unwrap();
+            (def.variants[variant].fields.len(), Some(variant), down)
+        }
+        ty::Tuple(substs) => (substs.len(), None, op),
         _ => 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();
         let val = op_to_const(&ecx, field_op);
index 6c9cb529dc2f3bdc8b817d89139b0dc8d28839de..4512ae96c0833f24d7af72180987e40b10d58fe0 100644 (file)
@@ -441,8 +441,8 @@ fn join_state_into_successors_of<A>(
             Goto { target } => propagate(target, exit_state),
 
             Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
-            | Drop { target, unwind, location: _ }
-            | DropAndReplace { target, unwind, value: _, location: _ }
+            | Drop { target, unwind, place: _ }
+            | DropAndReplace { target, unwind, value: _, place: _ }
             | FalseUnwind { real_target: target, unwind } => {
                 if let Some(unwind) = unwind {
                     if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
index 1d49a32e19645d61f8a57fa42cc6e813e1f146f4..a3fc51cad656b0c9f2721f2d53b3b68d21dd527f 100644 (file)
@@ -189,8 +189,8 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
         self.super_terminator(terminator, location);
 
         match terminator.kind {
-            mir::TerminatorKind::Drop { location: dropped_place, .. }
-            | mir::TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
+            mir::TerminatorKind::Drop { place: dropped_place, .. }
+            | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
                 // See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
                 if !self.ignore_borrow_on_drop {
                     self.trans.gen(dropped_place.local);
@@ -233,7 +233,7 @@ impl MutBorrow<'mir, 'tcx> {
     ///
     /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
     fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
-        !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx, self.param_env, DUMMY_SP)
+        !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
     }
 }
 
index d24faacd3779e5423ceeb684cb1a5e1c4565e8af..784b0bd9293e25f8b65072d726059ce503fa9f99 100644 (file)
@@ -92,7 +92,27 @@ impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
 where
     T: GenKill<Local>,
 {
+    fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
+        let mir::Place { projection, local } = *place;
+
+        // We purposefully do not call `super_place` here to avoid calling `visit_local` for this
+        // place with one of the `Projection` variants of `PlaceContext`.
+        self.visit_projection(local, projection, context, location);
+
+        match DefUse::for_place(context) {
+            // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
+            Some(_) if place.is_indirect() => self.0.gen(local),
+
+            Some(DefUse::Def) if projection.is_empty() => self.0.kill(local),
+            Some(DefUse::Use) => self.0.gen(local),
+            _ => {}
+        }
+    }
+
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+        // Because we do not call `super_place` above, `visit_local` is only called for locals that
+        // do not appear as part of  a `Place` in the MIR. This handles cases like the implicit use
+        // of the return place in a `Return` terminator or the index in an `Index` projection.
         match DefUse::for_place(context) {
             Some(DefUse::Def) => self.0.kill(local),
             Some(DefUse::Use) => self.0.gen(local),
@@ -126,7 +146,6 @@ fn for_place(context: PlaceContext) -> Option<DefUse> {
                 | MutatingUseContext::AsmOutput
                 | MutatingUseContext::Borrow
                 | MutatingUseContext::Drop
-                | MutatingUseContext::Projection
                 | MutatingUseContext::Retag,
             )
             | PlaceContext::NonMutatingUse(
@@ -134,11 +153,15 @@ fn for_place(context: PlaceContext) -> Option<DefUse> {
                 | NonMutatingUseContext::Copy
                 | NonMutatingUseContext::Inspect
                 | NonMutatingUseContext::Move
-                | NonMutatingUseContext::Projection
                 | NonMutatingUseContext::ShallowBorrow
                 | NonMutatingUseContext::SharedBorrow
                 | NonMutatingUseContext::UniqueBorrow,
             ) => Some(DefUse::Use),
+
+            PlaceContext::MutatingUse(MutatingUseContext::Projection)
+            | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
+                unreachable!("A projection could be a def or a use and must be handled separately")
+            }
         }
     }
 }
index 41c7bd95a96cc1e877fe7e63362e76f3bdef3e84..7c8aa1db71ff873f56ff15d916a1ff14e138b87b 100644 (file)
@@ -387,13 +387,13 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
                 self.gather_init(place.as_ref(), InitKind::Deep);
             }
 
-            TerminatorKind::Drop { location, target: _, unwind: _ } => {
-                self.gather_move(location);
+            TerminatorKind::Drop { place, target: _, unwind: _ } => {
+                self.gather_move(place);
             }
-            TerminatorKind::DropAndReplace { location, ref value, .. } => {
-                self.create_move_path(location);
+            TerminatorKind::DropAndReplace { place, ref value, .. } => {
+                self.create_move_path(place);
                 self.gather_operand(value);
-                self.gather_init(location.as_ref(), InitKind::Deep);
+                self.gather_init(place.as_ref(), InitKind::Deep);
             }
             TerminatorKind::Call {
                 ref func,
index cfe856abe36dda2ca6c6c073417d1c864c711138..60cf21552e9e91102bbd368bd6aa3511dd5bf95f 100644 (file)
@@ -52,7 +52,10 @@ pub fn cast(
                         }
 
                         if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
-                            bug!("reifying a fn ptr that requires const arguments");
+                            span_bug!(
+                                self.cur_span(),
+                                "reifying a fn ptr that requires const arguments"
+                            );
                         }
 
                         let instance = ty::Instance::resolve_for_fn_ptr(
@@ -66,7 +69,7 @@ pub fn cast(
                         let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                         self.write_scalar(fn_ptr, dest)?;
                     }
-                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
+                    _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty),
                 }
             }
 
@@ -77,7 +80,7 @@ pub fn cast(
                         // No change to value
                         self.write_immediate(*src, dest)?;
                     }
-                    _ => bug!("fn to unsafe fn cast on {:?}", cast_ty),
+                    _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty),
                 }
             }
 
@@ -99,7 +102,7 @@ pub fn cast(
                         let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                         self.write_scalar(fn_ptr, dest)?;
                     }
-                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
+                    _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
                 }
             }
         }
@@ -162,7 +165,8 @@ fn misc_cast(
                 assert!(src.layout.ty.is_unsafe_ptr());
                 return match *src {
                     Immediate::ScalarPair(data, _) => Ok(data.into()),
-                    Immediate::Scalar(..) => bug!(
+                    Immediate::Scalar(..) => span_bug!(
+                        self.cur_span(),
                         "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
                         *src,
                         src.layout.ty,
@@ -216,7 +220,7 @@ pub(super) fn cast_from_scalar(
             }
 
             // Casts to bool are not permitted by rustc, no need to handle them here.
-            _ => bug!("invalid int to {:?} cast", cast_ty),
+            _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty),
         }
     }
 
@@ -248,7 +252,7 @@ fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
             // float -> f64
             Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
             // That's it.
-            _ => bug!("invalid float to {:?} cast", dest_ty),
+            _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty),
         }
     }
 
@@ -287,7 +291,9 @@ fn unsize_into_ptr(
                 self.write_immediate(val, dest)
             }
 
-            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty),
+            _ => {
+                span_bug!(self.cur_span(), "invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty)
+            }
         }
     }
 
@@ -307,7 +313,12 @@ fn unsize_into(
                 assert_eq!(def_a, def_b);
                 if def_a.is_box() || def_b.is_box() {
                     if !def_a.is_box() || !def_b.is_box() {
-                        bug!("invalid unsizing between {:?} -> {:?}", src.layout.ty, cast_ty.ty);
+                        span_bug!(
+                            self.cur_span(),
+                            "invalid unsizing between {:?} -> {:?}",
+                            src.layout.ty,
+                            cast_ty.ty
+                        );
                     }
                     return self.unsize_into_ptr(
                         src,
@@ -335,7 +346,12 @@ fn unsize_into(
                 }
                 Ok(())
             }
-            _ => bug!("unsize_into: invalid conversion: {:?} -> {:?}", src.layout, dest.layout),
+            _ => span_bug!(
+                self.cur_span(),
+                "unsize_into: invalid conversion: {:?} -> {:?}",
+                src.layout,
+                dest.layout
+            ),
         }
     }
 }
index 22f4691c22b3de81226fe406c8fafd6c427c04bd..602876e3de1686e97ce6bb1513e05ba6492c3a85 100644 (file)
@@ -15,7 +15,7 @@
 };
 use rustc_middle::ty::layout::{self, TyAndLayout};
 use rustc_middle::ty::{
-    self, fold::BottomUpFolder, query::TyCtxtAt, subst::SubstsRef, Ty, TyCtxt, TypeFoldable,
+    self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_span::{source_map::DUMMY_SP, Span};
 use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
@@ -24,6 +24,7 @@
     Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy,
     ScalarMaybeUninit, StackPopJump,
 };
+use crate::transform::validate::equal_up_to_regions;
 use crate::util::storage::AlwaysLiveLocals;
 
 pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
@@ -131,6 +132,10 @@ pub enum LocalValue<Tag = ()> {
 }
 
 impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> {
+    /// Read the local's value or error if the local is not yet live or not live anymore.
+    ///
+    /// Note: This may only be invoked from the `Machine::access_local` hook and not from
+    /// anywhere else. You may be invalidating machine invariants if you do!
     pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
         match self.value {
             LocalValue::Dead => throw_ub!(DeadLocal),
@@ -143,6 +148,9 @@ pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
 
     /// Overwrite the local.  If the local can be overwritten in place, return a reference
     /// to do so; otherwise return the `MemPlace` to consult instead.
+    ///
+    /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from
+    /// anywhere else. You may be invalidating machine invariants if you do!
     pub fn access_mut(
         &mut self,
     ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
@@ -220,42 +228,27 @@ fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
 /// This test should be symmetric, as it is primarily about layout compatibility.
 pub(super) fn mir_assign_valid_types<'tcx>(
     tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     src: TyAndLayout<'tcx>,
     dest: TyAndLayout<'tcx>,
 ) -> bool {
-    if src.ty == dest.ty {
-        // Equal types, all is good.
-        return true;
-    }
-    if src.layout != dest.layout {
-        // Layout differs, definitely not equal.
-        // We do this here because Miri would *do the wrong thing* if we allowed layout-changing
-        // assignments.
-        return false;
-    }
-
-    // Type-changing assignments can happen for (at least) two reasons:
-    // 1. `&mut T` -> `&T` gets optimized from a reborrow to a mere assignment.
-    // 2. Subtyping is used. While all normal lifetimes are erased, higher-ranked types
-    //    with their late-bound lifetimes are still around and can lead to type differences.
-    // Normalize both of them away.
-    let normalize = |ty: Ty<'tcx>| {
-        ty.fold_with(&mut BottomUpFolder {
-            tcx,
-            // Normalize all references to immutable.
-            ty_op: |ty| match ty.kind {
-                ty::Ref(_, pointee, _) => tcx.mk_imm_ref(tcx.lifetimes.re_erased, pointee),
-                _ => ty,
-            },
-            // We just erase all late-bound lifetimes, but this is not fully correct (FIXME):
-            // lifetimes in invariant positions could matter (e.g. through associated types).
-            // We rely on the fact that layout was confirmed to be equal above.
-            lt_op: |_| tcx.lifetimes.re_erased,
-            // Leave consts unchanged.
-            ct_op: |ct| ct,
-        })
-    };
-    normalize(src.ty) == normalize(dest.ty)
+    // Type-changing assignments can happen when subtyping is used. While
+    // all normal lifetimes are erased, higher-ranked types with their
+    // late-bound lifetimes are still around and can lead to type
+    // differences. So we compare ignoring lifetimes.
+    if equal_up_to_regions(tcx, param_env, src.ty, dest.ty) {
+        // Make sure the layout is equal, too -- just to be safe. Miri really
+        // needs layout equality. For performance reason we skip this check when
+        // the types are equal. Equal types *can* have different layouts when
+        // enum downcast is involved (as enum variants carry the type of the
+        // enum), but those should never occur in assignments.
+        if cfg!(debug_assertions) || src.ty != dest.ty {
+            assert_eq!(src.layout, dest.layout);
+        }
+        true
+    } else {
+        false
+    }
 }
 
 /// Use the already known layout if given (but sanity check in debug mode),
@@ -263,6 +256,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
 #[cfg_attr(not(debug_assertions), inline(always))]
 pub(super) fn from_known_layout<'tcx>(
     tcx: TyCtxtAt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     known_layout: Option<TyAndLayout<'tcx>>,
     compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
 ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
@@ -271,7 +265,7 @@ pub(super) fn from_known_layout<'tcx>(
         Some(known_layout) => {
             if cfg!(debug_assertions) {
                 let check_layout = compute()?;
-                if !mir_assign_valid_types(tcx.tcx, check_layout, known_layout) {
+                if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
                     span_bug!(
                         tcx.span,
                         "expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
@@ -391,7 +385,7 @@ pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
 
     #[inline]
     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(*self.tcx, self.param_env, self.tcx.span)
+        ty.is_freeze(self.tcx, self.param_env)
     }
 
     pub fn load_mir(
@@ -475,7 +469,7 @@ pub fn layout_of_local(
         // have to support that case (mostly by skipping all caching).
         match frame.locals.get(local).and_then(|state| state.layout.get()) {
             None => {
-                let layout = from_known_layout(self.tcx, layout, || {
+                let layout = from_known_layout(self.tcx, self.param_env, layout, || {
                     let local_ty = frame.body.local_decls[local].ty;
                     let local_ty =
                         self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
@@ -536,7 +530,10 @@ pub(super) fn size_and_align_of(
                         if sized_size == Size::ZERO {
                             return Ok(None);
                         } else {
-                            bug!("Fields cannot be extern types, unless they are at offset 0")
+                            span_bug!(
+                                self.cur_span(),
+                                "Fields cannot be extern types, unless they are at offset 0"
+                            )
                         }
                     }
                 };
@@ -584,7 +581,7 @@ pub(super) fn size_and_align_of(
 
             ty::Foreign(_) => Ok(None),
 
-            _ => bug!("size_and_align_of::<{:?}> not supported", layout.ty),
+            _ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty),
         }
     }
     #[inline]
index 3c724c79b4082448860d9fc256c272537a8342e6..dffbc969c21b8c645158e7ba7850e59d29df5bb6 100644 (file)
@@ -111,7 +111,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
     if let InternMode::Static(mutability) = mode {
         // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
         // no interior mutability.
-        let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env, ecx.tcx.span));
+        let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env));
         // For statics, allocation mutability is the combination of the place mutability and
         // the type mutability.
         // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
@@ -293,7 +293,6 @@ pub enum InternKind {
     Static(hir::Mutability),
     Constant,
     Promoted,
-    ConstProp,
 }
 
 /// Intern `ret` and everything it references.
@@ -314,9 +313,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
     let base_intern_mode = match intern_kind {
         InternKind::Static(mutbl) => InternMode::Static(mutbl),
         // FIXME: what about array lengths, array initializers?
-        InternKind::Constant | InternKind::ConstProp | InternKind::Promoted => {
-            InternMode::ConstBase
-        }
+        InternKind::Constant | InternKind::Promoted => InternMode::ConstBase,
     };
 
     // Type based interning.
@@ -358,7 +355,10 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
             Err(error) => {
                 ecx.tcx.sess.delay_span_bug(
                     ecx.tcx.span,
-                    "error during interning should later cause validation failure",
+                    &format!(
+                        "error during interning should later cause validation failure: {}",
+                        error
+                    ),
                 );
                 // Some errors shouldn't come up because creating them causes
                 // an allocation, which we should avoid. When that happens,
@@ -399,7 +399,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
                     // immutability is so important.
                     alloc.mutability = Mutability::Not;
                 }
-                InternKind::Constant | InternKind::ConstProp => {
+                InternKind::Constant => {
                     // If it's a constant, we should not have any "leftovers" as everything
                     // is tracked by const-checking.
                     // FIXME: downgrade this to a warning? It rejects some legitimate consts,
index 47e5b8b4fcec453a7be7951569878d52c76fa863..88ba28dab82e18081ea8ce1756a62b212081916b 100644 (file)
@@ -69,6 +69,13 @@ fn numeric_intrinsic<'tcx, Tag>(
             ConstValue::from_machine_usize(n, &tcx)
         }
         sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)),
+        sym::variant_count => {
+            if let ty::Adt(ref adt, _) = tp_ty.kind {
+                ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
+            } else {
+                ConstValue::from_machine_usize(0u64, &tcx)
+            }
+        }
         other => bug!("`{}` is not a zero arg intrinsic", other),
     })
 }
@@ -109,10 +116,13 @@ pub fn emulate_intrinsic(
             | sym::needs_drop
             | sym::size_of
             | sym::type_id
-            | sym::type_name => {
+            | sym::type_name
+            | sym::variant_count => {
                 let gid = GlobalId { instance, promoted: None };
                 let ty = match intrinsic_name {
-                    sym::min_align_of | sym::pref_align_of | sym::size_of => self.tcx.types.usize,
+                    sym::min_align_of | sym::pref_align_of | sym::size_of | sym::variant_count => {
+                        self.tcx.types.usize
+                    }
                     sym::needs_drop => self.tcx.types.bool,
                     sym::type_id => self.tcx.types.u64,
                     sym::type_name => self.tcx.mk_static_str(),
@@ -135,7 +145,12 @@ pub fn emulate_intrinsic(
                 let bits = self.force_bits(val, layout_of.size)?;
                 let kind = match layout_of.abi {
                     Abi::Scalar(ref scalar) => scalar.value,
-                    _ => bug!("{} called on invalid type {:?}", intrinsic_name, ty),
+                    _ => span_bug!(
+                        self.cur_span(),
+                        "{} called on invalid type {:?}",
+                        intrinsic_name,
+                        ty
+                    ),
                 };
                 let (nonzero, intrinsic_name) = match intrinsic_name {
                     sym::cttz_nonzero => (true, sym::cttz),
@@ -291,6 +306,11 @@ pub fn emulate_intrinsic(
                 let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self);
                 self.write_scalar(offset_ptr, dest)?;
             }
+            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
+                // FIXME: return `true` for at least some comparisons where we can reliably
+                // determine the result of runtime (in)equality tests at compile-time.
+                self.write_scalar(Scalar::from_bool(false), dest)?;
+            }
             sym::ptr_offset_from => {
                 let a = self.read_immediate(args[0])?.to_scalar()?;
                 let b = self.read_immediate(args[1])?.to_scalar()?;
@@ -389,6 +409,8 @@ pub fn emulate_intrinsic(
                 );
                 self.copy_op(self.operand_index(args[0], index)?, dest)?;
             }
+            // FIXME(#73156): Handle source code coverage in const eval
+            sym::count_code_region => (),
             _ => return Ok(false),
         }
 
index 71cca725982f5bdd4ec16e6e4ca085c089a403f8..379117f3b846a26135307518fd57b5e90267f7f8 100644 (file)
@@ -50,7 +50,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             | ty::Dynamic(_, _) => self.pretty_print_type(ty),
 
             // Placeholders (all printed as `_` to uniformize them).
-            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => {
+            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
                 write!(self, "_")?;
                 Ok(self)
             }
index b5dc40d95519195eb9149b7f600f7b828c44a360..ec1c93c81657ee2e733c7306239d072f580be88d 100644 (file)
@@ -11,7 +11,7 @@
 
 use super::{
     AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult,
-    Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
+    LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
 };
 
 /// Data returned by Machine::stack_pop,
@@ -192,6 +192,8 @@ fn box_alloc(
     ) -> InterpResult<'tcx>;
 
     /// Called to read the specified `local` from the `frame`.
+    /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
+    /// for ZST reads.
     #[inline]
     fn access_local(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
@@ -201,6 +203,21 @@ fn access_local(
         frame.locals[local].access()
     }
 
+    /// Called to write the specified `local` from the `frame`.
+    /// Since writing a ZST is not actually accessing memory or locals, this is never invoked
+    /// for ZST reads.
+    #[inline]
+    fn access_local_mut<'a>(
+        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
+        frame: usize,
+        local: mir::Local,
+    ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
+    where
+        'tcx: 'mir,
+    {
+        ecx.stack_mut()[frame].locals[local].access_mut()
+    }
+
     /// Called before a basic block terminator is executed.
     /// You can use this to detect endlessly running programs.
     #[inline]
index 38f5988d0eb3fd82eb27768994647d9c219f1d72..b02b5219ba1a4f95c718983d27f127e942b26a42 100644 (file)
@@ -9,9 +9,9 @@
 use rustc_macros::HashStable;
 use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{ConstInt, Ty};
 use rustc_middle::{mir, ty};
-use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size};
+use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
 use super::{
@@ -207,6 +207,19 @@ pub fn try_from_int(i: impl Into<i128>, layout: TyAndLayout<'tcx>) -> Option<Sel
     pub fn from_int(i: impl Into<i128>, layout: TyAndLayout<'tcx>) -> Self {
         Self::from_scalar(Scalar::from_int(i, layout.size), layout)
     }
+
+    #[inline]
+    pub fn to_const_int(self) -> ConstInt {
+        assert!(self.layout.ty.is_integral());
+        ConstInt::new(
+            self.to_scalar()
+                .expect("to_const_int doesn't work on scalar pairs")
+                .assert_bits(self.layout.size),
+            self.layout.size,
+            self.layout.ty.is_signed(),
+            self.layout.ty.is_ptr_sized_integral(),
+        )
+    }
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
@@ -311,7 +324,7 @@ pub fn read_immediate(
         if let Ok(imm) = self.try_read_immediate(op)? {
             Ok(imm)
         } else {
-            bug!("primitive read failed for type: {:?}", op.layout.ty);
+            span_bug!(self.cur_span(), "primitive read failed for type: {:?}", op.layout.ty);
         }
     }
 
@@ -360,9 +373,12 @@ pub fn operand_field(
                 let val = if offset.bytes() == 0 { a } else { b };
                 Immediate::from(val)
             }
-            Immediate::Scalar(val) => {
-                bug!("field access on non aggregate {:#?}, {:#?}", val, op.layout)
-            }
+            Immediate::Scalar(val) => span_bug!(
+                self.cur_span(),
+                "field access on non aggregate {:#?}, {:#?}",
+                val,
+                op.layout
+            ),
         };
         Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout })
     }
@@ -416,7 +432,11 @@ pub fn operand_projection(
         })
     }
 
-    /// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local
+    /// Read from a local. Will not actually access the local if reading from a ZST.
+    /// Will not access memory, instead an indirect `Operand` is returned.
+    ///
+    /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
+    /// OpTy from a local
     pub fn access_local(
         &self,
         frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
@@ -472,6 +492,7 @@ pub fn eval_place_to_op(
         // Sanity-check the type we ended up with.
         debug_assert!(mir_assign_valid_types(
             *self.tcx,
+            self.param_env,
             self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
                 place.ty(&self.frame().body.local_decls, *self.tcx).ty
             ))?,
@@ -527,7 +548,7 @@ pub(super) fn eval_operands(
         // Early-return cases.
         let val_val = match val.val {
             ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
-            ty::ConstKind::Error => throw_inval!(TypeckError(ErrorReported)),
+            ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
             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.
@@ -545,7 +566,7 @@ pub(super) fn eval_operands(
             ty::ConstKind::Infer(..)
             | ty::ConstKind::Bound(..)
             | ty::ConstKind::Placeholder(..) => {
-                bug!("eval_const_to_op: Unexpected ConstKind {:?}", val)
+                span_bug!(self.cur_span(), "eval_const_to_op: Unexpected ConstKind {:?}", val)
             }
             ty::ConstKind::Value(val_val) => val_val,
         };
@@ -554,7 +575,8 @@ pub(super) fn eval_operands(
         // documentation).
         let val_val = M::adjust_global_const(self, val_val)?;
         // Other cases need layout.
-        let layout = from_known_layout(self.tcx, layout, || self.layout_of(val.ty))?;
+        let layout =
+            from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(val.ty))?;
         let op = match val_val {
             ConstValue::ByRef { alloc, offset } => {
                 let id = self.tcx.create_memory_alloc(alloc);
@@ -587,7 +609,6 @@ pub fn read_discriminant(
         op: OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
         trace!("read_discriminant_value {:#?}", op.layout);
-
         // Get type and layout of the discriminant.
         let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?;
         trace!("discriminant type: {:?}", discr_layout.ty);
@@ -596,10 +617,8 @@ pub fn read_discriminant(
         // This is not to be confused with its "variant index", which is just determining its position in the
         // declared list of variants -- they can differ with explicitly assigned discriminants.
         // We use "tag" to refer to how the discriminant is encoded in memory, which can be either
-        // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`).
-        // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things
-        // rather confusing.
-        let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants {
+        // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
+        let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants {
             Variants::Single { index } => {
                 let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) {
                     Some(discr) => {
@@ -615,8 +634,8 @@ pub fn read_discriminant(
                 };
                 return Ok((discr, index));
             }
-            Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => {
-                (discr, discr_kind, discr_index)
+            Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+                (tag, tag_encoding, tag_field)
             }
         };
 
@@ -633,21 +652,21 @@ pub fn read_discriminant(
         let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
 
         // Read tag and sanity-check `tag_layout`.
-        let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?;
+        let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
         assert_eq!(tag_layout.size, tag_val.layout.size);
         assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
         let tag_val = tag_val.to_scalar()?;
         trace!("tag value: {:?}", tag_val);
 
         // Figure out which discriminant and variant this corresponds to.
-        Ok(match *tag_kind {
-            DiscriminantKind::Tag => {
+        Ok(match *tag_encoding {
+            TagEncoding::Direct => {
                 let tag_bits = self
                     .force_bits(tag_val, tag_layout.size)
-                    .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+                    .map_err(|_| err_ub!(InvalidTag(tag_val.erase_tag())))?;
                 // Cast bits from tag layout to discriminant layout.
-                let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
-                let discr_bits = discr_val_cast.assert_bits(discr_layout.size);
+                let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
+                let discr_bits = discr_val.assert_bits(discr_layout.size);
                 // Convert discriminant to variant index, and catch invalid discriminants.
                 let index = match op.layout.ty.kind {
                     ty::Adt(adt, _) => {
@@ -659,13 +678,13 @@ pub fn read_discriminant(
                             .discriminants(def_id, *self.tcx)
                             .find(|(_, var)| var.val == discr_bits)
                     }
-                    _ => bug!("tagged layout for non-adt non-generator"),
+                    _ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
                 }
-                .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?;
+                .ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_tag())))?;
                 // Return the cast value, and the index.
-                (discr_val_cast, index.0)
+                (discr_val, index.0)
             }
-            DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => {
+            TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
                 // Compute the variant this niche value/"tag" corresponds to. With niche layout,
                 // discriminant (encoded in niche/tag) and variant index are the same.
                 let variants_start = niche_variants.start().as_u32();
@@ -677,7 +696,7 @@ pub fn read_discriminant(
                             && variants_start == variants_end
                             && !self.memory.ptr_may_be_null(ptr);
                         if !ptr_valid {
-                            throw_ub!(InvalidDiscriminant(tag_val.erase_tag()))
+                            throw_ub!(InvalidTag(tag_val.erase_tag()))
                         }
                         dataful_variant
                     }
index d651267f82b7943e38e43189186592267a75c5f9..607122935347e127537b59185385f0d7c44513cd 100644 (file)
@@ -61,7 +61,7 @@ fn binary_char_op(
             Le => l <= r,
             Gt => l > r,
             Ge => l >= r,
-            _ => bug!("Invalid operation on char: {:?}", bin_op),
+            _ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op),
         };
         (Scalar::from_bool(res), false, self.tcx.types.bool)
     }
@@ -84,7 +84,7 @@ fn binary_bool_op(
             BitAnd => l & r,
             BitOr => l | r,
             BitXor => l ^ r,
-            _ => bug!("Invalid operation on bool: {:?}", bin_op),
+            _ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op),
         };
         (Scalar::from_bool(res), false, self.tcx.types.bool)
     }
@@ -110,7 +110,7 @@ fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
             Mul => ((l * r).value.into(), ty),
             Div => ((l / r).value.into(), ty),
             Rem => ((l % r).value.into(), ty),
-            _ => bug!("invalid float op: `{:?}`", bin_op),
+            _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
         };
         (val, false, ty)
     }
@@ -154,7 +154,8 @@ fn binary_int_op(
 
         // For the remaining ops, the types must be the same on both sides
         if left_layout.ty != right_layout.ty {
-            bug!(
+            span_bug!(
+                self.cur_span(),
                 "invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
                 bin_op,
                 l,
@@ -251,7 +252,8 @@ fn binary_int_op(
                 ));
             }
 
-            _ => bug!(
+            _ => span_bug!(
+                self.cur_span(),
                 "invalid binary op {:?}: {:?}, {:?} (both {:?})",
                 bin_op,
                 l,
@@ -333,7 +335,11 @@ pub fn overflowing_binary_op(
 
                 M::binary_ptr_op(self, bin_op, left, right)
             }
-            _ => bug!("Invalid MIR: bad LHS type for binop: {:?}", left.layout.ty),
+            _ => span_bug!(
+                self.cur_span(),
+                "Invalid MIR: bad LHS type for binop: {:?}",
+                left.layout.ty
+            ),
         }
     }
 
@@ -367,7 +373,7 @@ pub fn overflowing_unary_op(
                 let val = val.to_bool()?;
                 let res = match un_op {
                     Not => !val,
-                    _ => bug!("Invalid bool op {:?}", un_op),
+                    _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
                 };
                 Ok((Scalar::from_bool(res), false, self.tcx.types.bool))
             }
@@ -375,7 +381,7 @@ pub fn overflowing_unary_op(
                 let res = match (un_op, fty) {
                     (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
                     (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
-                    _ => bug!("Invalid float op {:?}", un_op),
+                    _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op),
                 };
                 Ok((res, false, layout.ty))
             }
index 24b191e9b535ab6c2daf9f56db6813b69186dc5b..3868150c6bd288f71cb2f076b60a0f356c4de628 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::mir;
 use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape};
+use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
 use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
 
 use super::{
@@ -652,6 +652,7 @@ pub fn eval_place(
         // Sanity-check the type we ended up with.
         debug_assert!(mir_assign_valid_types(
             *self.tcx,
+            self.param_env,
             self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
                 place.ty(&self.frame().body.local_decls, *self.tcx).ty
             ))?,
@@ -740,7 +741,7 @@ fn write_immediate_no_validate(
         // but not factored as a separate function.
         let mplace = match dest.place {
             Place::Local { frame, local } => {
-                match self.stack_mut()[frame].locals[local].access_mut()? {
+                match M::access_local_mut(self, frame, local)? {
                     Ok(local) => {
                         // Local can be updated in-place.
                         *local = LocalValue::Live(Operand::Immediate(src));
@@ -855,7 +856,7 @@ fn copy_op_no_validate(
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
-        if !mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
+        if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
             span_bug!(
                 self.cur_span(),
                 "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
@@ -912,7 +913,7 @@ pub fn copy_op_transmute(
         src: OpTy<'tcx, M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
-        if mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
+        if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
             // Fast path: Just use normal `copy_op`
             return self.copy_op(src, dest);
         }
@@ -973,7 +974,7 @@ pub fn force_allocation_maybe_sized(
     ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
         let (mplace, size) = match place.place {
             Place::Local { frame, local } => {
-                match self.stack_mut()[frame].locals[local].access_mut()? {
+                match M::access_local_mut(self, frame, local)? {
                     Ok(&mut local_val) => {
                         // We need to make an allocation.
 
@@ -997,7 +998,7 @@ pub fn force_allocation_maybe_sized(
                         }
                         // Now we can call `access_mut` again, asserting it goes well,
                         // and actually overwrite things.
-                        *self.stack_mut()[frame].locals[local].access_mut().unwrap().unwrap() =
+                        *M::access_local_mut(self, frame, local).unwrap().unwrap() =
                             LocalValue::Live(Operand::Indirect(mplace));
                         (mplace, Some(size))
                     }
@@ -1045,7 +1046,8 @@ pub fn allocate_str(
         MPlaceTy { mplace, layout }
     }
 
-    pub fn write_discriminant_index(
+    /// Writes the discriminant of the given variant.
+    pub fn write_discriminant(
         &mut self,
         variant_index: VariantIdx,
         dest: PlaceTy<'tcx, M::PointerTag>,
@@ -1061,9 +1063,9 @@ pub fn write_discriminant_index(
                 assert_eq!(index, variant_index);
             }
             Variants::Multiple {
-                discr_kind: DiscriminantKind::Tag,
-                discr: ref discr_layout,
-                discr_index,
+                tag_encoding: TagEncoding::Direct,
+                tag: ref tag_layout,
+                tag_field,
                 ..
             } => {
                 // No need to validate that the discriminant here because the
@@ -1075,17 +1077,17 @@ pub fn write_discriminant_index(
                 // raw discriminants for enums are isize or bigger during
                 // their computation, but the in-memory tag is the smallest possible
                 // representation
-                let size = discr_layout.value.size(self);
-                let discr_val = truncate(discr_val, size);
+                let size = tag_layout.value.size(self);
+                let tag_val = truncate(discr_val, size);
 
-                let discr_dest = self.place_field(dest, discr_index)?;
-                self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
+                let tag_dest = self.place_field(dest, tag_field)?;
+                self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
             }
             Variants::Multiple {
-                discr_kind:
-                    DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start },
-                discr: ref discr_layout,
-                discr_index,
+                tag_encoding:
+                    TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+                tag: ref tag_layout,
+                tag_field,
                 ..
             } => {
                 // No need to validate that the discriminant here because the
@@ -1098,19 +1100,19 @@ pub fn write_discriminant_index(
                         .checked_sub(variants_start)
                         .expect("overflow computing relative variant idx");
                     // We need to use machine arithmetic when taking into account `niche_start`:
-                    // discr_val = variant_index_relative + niche_start_val
-                    let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?;
-                    let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
+                    // tag_val = variant_index_relative + niche_start_val
+                    let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?;
+                    let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
                     let variant_index_relative_val =
-                        ImmTy::from_uint(variant_index_relative, discr_layout);
-                    let discr_val = self.binary_op(
+                        ImmTy::from_uint(variant_index_relative, tag_layout);
+                    let tag_val = self.binary_op(
                         mir::BinOp::Add,
                         variant_index_relative_val,
                         niche_start_val,
                     )?;
                     // Write result.
-                    let niche_dest = self.place_field(dest, discr_index)?;
-                    self.write_immediate(*discr_val, niche_dest)?;
+                    let niche_dest = self.place_field(dest, tag_field)?;
+                    self.write_immediate(*tag_val, niche_dest)?;
                 }
             }
         }
index 16c6396799e634eedbb067b7409966875ccb2208..18f9bbd2e315086bdb978d3eb11da7811a47e537 100644 (file)
@@ -88,7 +88,7 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
 
             SetDiscriminant { place, variant_index } => {
                 let dest = self.eval_place(**place)?;
-                self.write_discriminant_index(*variant_index, dest)?;
+                self.write_discriminant(*variant_index, dest)?;
             }
 
             // Mark locals as alive
@@ -179,7 +179,7 @@ pub fn eval_rvalue_into_place(
             Aggregate(ref kind, ref operands) => {
                 let (dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
-                        self.write_discriminant_index(variant_index, dest)?;
+                        self.write_discriminant(variant_index, dest)?;
                         if adt_def.is_enum() {
                             (self.place_downcast(dest, variant_index)?, active_field_index)
                         } else {
index cd7621ea9752b4ebc51a0d40394b060bb7a74346..4681079a22ddf4f3ef7abca68251054098c2ed30 100644 (file)
@@ -24,9 +24,10 @@ pub(super) fn eval_terminator(
 
             Goto { target } => self.go_to_block(target),
 
-            SwitchInt { ref discr, ref values, ref targets, .. } => {
+            SwitchInt { ref discr, ref values, ref targets, switch_ty } => {
                 let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
                 trace!("SwitchInt({:?})", *discr);
+                assert_eq!(discr.layout.ty, switch_ty);
 
                 // Branch to the `otherwise` case by default, if no match is found.
                 assert!(!targets.is_empty());
@@ -50,14 +51,7 @@ pub(super) fn eval_terminator(
                 self.go_to_block(target_block);
             }
 
-            Call {
-                ref func,
-                ref args,
-                destination,
-                ref cleanup,
-                from_hir_call: _from_hir_call,
-                fn_span: _,
-            } => {
+            Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => {
                 let old_stack = self.frame_idx();
                 let old_loc = self.frame().loc;
                 let func = self.eval_operand(func, None)?;
@@ -91,10 +85,10 @@ pub(super) fn eval_terminator(
                 }
             }
 
-            Drop { location, target, unwind } => {
-                let place = self.eval_place(location)?;
+            Drop { place, target, unwind } => {
+                let place = self.eval_place(place)?;
                 let ty = place.layout.ty;
-                trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
+                trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
 
                 let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
                 self.drop_in_place(place, instance, target, unwind)?;
@@ -232,7 +226,7 @@ fn eval_fn_call(
                     ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(),
                     ty::Closure(..) => Abi::RustCall,
                     ty::Generator(..) => Abi::Rust,
-                    _ => bug!("unexpected callee ty: {:?}", instance_ty),
+                    _ => span_bug!(self.cur_span(), "unexpected callee ty: {:?}", instance_ty),
                 }
             };
             let normalize_abi = |abi| match abi {
index 7e3b6c08e08f40a4abcff3e66456bd8e645117bb..3bb9ba37120582fda0f770298e2daa4ba3c84c98 100644 (file)
@@ -208,8 +208,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
     fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
         // First, check if we are projecting to a variant.
         match layout.variants {
-            Variants::Multiple { discr_index, .. } => {
-                if discr_index == field {
+            Variants::Multiple { tag_field, .. } => {
+                if tag_field == field {
                     return match layout.ty.kind {
                         ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
                         ty::Generator(..) => PathElem::GeneratorTag,
@@ -561,7 +561,7 @@ fn try_visit_primitive(
             | ty::Generator(..) => Ok(false),
             // Some types only occur during typechecking, they have no layout.
             // We should not see them here and we could not check them anyway.
-            ty::Error
+            ty::Error(_)
             | ty::Infer(..)
             | ty::Placeholder(..)
             | ty::Bound(..)
@@ -697,8 +697,8 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         try_validation!(
             self.walk_value(op),
             self.path,
-            err_ub!(InvalidDiscriminant(val)) =>
-                { "{}", val } expected { "a valid enum discriminant" },
+            err_ub!(InvalidTag(val)) =>
+                { "{}", val } expected { "a valid enum tag" },
             err_unsup!(ReadPointerAsBytes) =>
                 { "a pointer" } expected { "plain (non-pointer) bytes" },
         );
index 928d5bf88f2fcbaa44880d4de197830647e7a522..cb6893166fd79a9094b208d7f39e2ddfc04a852a 100644 (file)
@@ -10,8 +10,8 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(const_fn)]
-#![feature(const_if_match)]
-#![feature(const_loop)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
+#![cfg_attr(bootstrap, feature(const_loop))]
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
index 994d1e69f2e3e709cefadfa34f4205121b151bf7..f9b3c319c1f66654463ee89ff3c6386007f9325c 100644 (file)
@@ -1,7 +1,7 @@
 //! Mono Item Collection
 //! ====================
 //!
-//! This module is responsible for discovering all items that will contribute to
+//! This module is responsible for discovering all items that will contribute
 //! to code generation of the crate. The important part here is that it not only
 //! needs to find syntax-level items (functions, structs, etc) but also all
 //! their monomorphized instantiations. Every non-generic, non-const function
@@ -79,7 +79,7 @@
 //! function or method call (represented by a CALL terminator in MIR). But
 //! calls are not the only thing that might introduce a reference between two
 //! function mono items, and as we will see below, they are just a
-//! specialized of the form described next, and consequently will don't get any
+//! specialization of the form described next, and consequently will not get any
 //! special treatment in the algorithm.
 //!
 //! #### Taking a reference to a function or method
 //! - Eager mode is meant to be used in conjunction with incremental compilation
 //!   where a stable set of mono items is more important than a minimal
 //!   one. Thus, eager mode will instantiate drop-glue for every drop-able type
-//!   in the crate, even of no drop call for that type exists (yet). It will
+//!   in the crate, even if no drop call for that type exists (yet). It will
 //!   also instantiate default implementations of trait methods, something that
 //!   otherwise is only done on demand.
 //!
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
-use rustc_errors::ErrorReported;
+use rustc_errors::{ErrorReported, FatalError};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_session::config::EntryFnType;
+use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
 use smallvec::SmallVec;
 use std::iter;
 
@@ -294,7 +295,13 @@ pub fn collect_crate_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);
+                collect_items_rec(
+                    tcx,
+                    dummy_spanned(root),
+                    visited,
+                    &mut recursion_depths,
+                    inlining_map,
+                );
             });
         });
     }
@@ -323,29 +330,30 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
     // We can only codegen items that are instantiable - items all of
     // whose predicates hold. Luckily, items that aren't instantiable
     // can't actually be used, so we can just skip codegenning them.
-    roots.retain(|root| root.is_instantiable(tcx));
-
     roots
+        .into_iter()
+        .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node))
+        .collect()
 }
 
 // Collect all monomorphized items reachable from `starting_point`
 fn collect_items_rec<'tcx>(
     tcx: TyCtxt<'tcx>,
-    starting_point: MonoItem<'tcx>,
+    starting_point: Spanned<MonoItem<'tcx>>,
     visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
     recursion_depths: &mut DefIdMap<usize>,
     inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
 ) {
-    if !visited.lock_mut().insert(starting_point) {
+    if !visited.lock_mut().insert(starting_point.node) {
         // We've been here already, no need to search again.
         return;
     }
-    debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx, true));
+    debug!("BEGIN collect_items_rec({})", starting_point.node.to_string(tcx, true));
 
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
 
-    match starting_point {
+    match starting_point.node {
         MonoItem::Static(def_id) => {
             let instance = Instance::mono(tcx, def_id);
 
@@ -353,7 +361,7 @@ fn collect_items_rec<'tcx>(
             debug_assert!(should_monomorphize_locally(tcx, &instance));
 
             let ty = instance.monomorphic_ty(tcx);
-            visit_drop_use(tcx, ty, true, &mut neighbors);
+            visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors);
 
             recursion_depth_reset = None;
 
@@ -366,7 +374,8 @@ fn collect_items_rec<'tcx>(
             debug_assert!(should_monomorphize_locally(tcx, &instance));
 
             // Keep track of the monomorphization recursion depth
-            recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths));
+            recursion_depth_reset =
+                Some(check_recursion_limit(tcx, instance, starting_point.span, recursion_depths));
             check_type_length_limit(tcx, instance);
 
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
@@ -378,7 +387,7 @@ fn collect_items_rec<'tcx>(
         }
     }
 
-    record_accesses(tcx, starting_point, &neighbors[..], inlining_map);
+    record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
 
     for neighbour in neighbors {
         collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map);
@@ -388,13 +397,13 @@ fn collect_items_rec<'tcx>(
         recursion_depths.insert(def_id, depth);
     }
 
-    debug!("END collect_items_rec({})", starting_point.to_string(tcx, true));
+    debug!("END collect_items_rec({})", starting_point.node.to_string(tcx, true));
 }
 
-fn record_accesses<'tcx>(
+fn record_accesses<'a, 'tcx: 'a>(
     tcx: TyCtxt<'tcx>,
     caller: MonoItem<'tcx>,
-    callees: &[MonoItem<'tcx>],
+    callees: impl Iterator<Item = &'a MonoItem<'tcx>>,
     inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
 ) {
     let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| {
@@ -405,7 +414,7 @@ fn record_accesses<'tcx>(
     // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec`
     // instead to avoid creating this `SmallVec`.
     let accesses: SmallVec<[_; 128]> =
-        callees.iter().map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
+        callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
 
     inlining_map.lock_mut().record_accesses(caller, &accesses);
 }
@@ -413,6 +422,7 @@ fn record_accesses<'tcx>(
 fn check_recursion_limit<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
+    span: Span,
     recursion_depths: &mut DefIdMap<usize>,
 ) -> (DefId, usize) {
     let def_id = instance.def_id();
@@ -432,12 +442,13 @@ fn check_recursion_limit<'tcx>(
     // infinite expansion.
     if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) {
         let error = format!("reached the recursion limit while instantiating `{}`", instance);
-        if let Some(def_id) = def_id.as_local() {
-            let hir_id = tcx.hir().as_local_hir_id(def_id);
-            tcx.sess.span_fatal(tcx.hir().span(hir_id), &error);
-        } else {
-            tcx.sess.fatal(&error);
-        }
+        let mut err = tcx.sess.struct_span_fatal(span, &error);
+        err.span_note(
+            tcx.def_span(def_id),
+            &format!("`{}` defined here", tcx.def_path_str(def_id)),
+        );
+        err.emit();
+        FatalError.raise();
     }
 
     recursion_depths.insert(def_id, recursion_depth + 1);
@@ -498,7 +509,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
 struct MirNeighborCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
-    output: &'a mut Vec<MonoItem<'tcx>>,
+    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
     instance: Instance<'tcx>,
 }
 
@@ -520,6 +531,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
         debug!("visiting rvalue {:?}", *rvalue);
 
+        let span = self.body.source_info(location).span;
+
         match *rvalue {
             // When doing an cast from a regular pointer to a fat pointer, we
             // have to instantiate all methods of the trait being cast to, so we
@@ -542,6 +555,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                         self.tcx,
                         target_ty,
                         source_ty,
+                        span,
                         self.output,
                     );
                 }
@@ -553,7 +567,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
             ) => {
                 let fn_ty = operand.ty(self.body, self.tcx);
                 let fn_ty = self.monomorphize(fn_ty);
-                visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+                visit_fn_use(self.tcx, fn_ty, false, span, &mut self.output);
             }
             mir::Rvalue::Cast(
                 mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)),
@@ -571,7 +585,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                             ty::ClosureKind::FnOnce,
                         );
                         if should_monomorphize_locally(self.tcx, &instance) {
-                            self.output.push(create_fn_mono_item(instance));
+                            self.output.push(create_fn_mono_item(instance, span));
                         }
                     }
                     _ => bug!(),
@@ -583,7 +597,15 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                     tcx.require_lang_item(ExchangeMallocFnLangItem, None);
                 let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
                 if should_monomorphize_locally(tcx, &instance) {
-                    self.output.push(create_fn_mono_item(instance));
+                    self.output.push(create_fn_mono_item(instance, span));
+                }
+            }
+            mir::Rvalue::ThreadLocalRef(def_id) => {
+                assert!(self.tcx.is_thread_local_static(def_id));
+                let instance = Instance::mono(self.tcx, def_id);
+                if should_monomorphize_locally(self.tcx, &instance) {
+                    trace!("collecting thread-local static {:?}", def_id);
+                    self.output.push(respan(span, MonoItem::Static(def_id)));
                 }
             }
             _ => { /* not interesting */ }
@@ -616,34 +638,35 @@ fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location)
         self.super_const(constant);
     }
 
-    fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
-        debug!("visiting terminator {:?} @ {:?}", kind, location);
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
+        debug!("visiting terminator {:?} @ {:?}", terminator, location);
+        let source = self.body.source_info(location).span;
 
         let tcx = self.tcx;
-        match *kind {
+        match terminator.kind {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.body, tcx);
                 let callee_ty = self.monomorphize(callee_ty);
-                visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
+                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output);
             }
-            mir::TerminatorKind::Drop { ref location, .. }
-            | mir::TerminatorKind::DropAndReplace { ref location, .. } => {
-                let ty = location.ty(self.body, self.tcx).ty;
+            mir::TerminatorKind::Drop { ref place, .. }
+            | mir::TerminatorKind::DropAndReplace { ref place, .. } => {
+                let ty = place.ty(self.body, self.tcx).ty;
                 let ty = self.monomorphize(ty);
-                visit_drop_use(self.tcx, ty, true, self.output);
+                visit_drop_use(self.tcx, ty, true, source, self.output);
             }
             mir::TerminatorKind::InlineAsm { ref operands, .. } => {
                 for op in operands {
                     match *op {
                         mir::InlineAsmOperand::SymFn { ref value } => {
                             let fn_ty = self.monomorphize(value.literal.ty);
-                            visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
+                            visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output);
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
                             if should_monomorphize_locally(self.tcx, &instance) {
                                 trace!("collecting asm sym static {:?}", def_id);
-                                self.output.push(MonoItem::Static(def_id));
+                                self.output.push(respan(source, MonoItem::Static(def_id)));
                             }
                         }
                         _ => {}
@@ -663,7 +686,7 @@ fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location:
             | mir::TerminatorKind::FalseUnwind { .. } => bug!(),
         }
 
-        self.super_terminator_kind(kind, location);
+        self.super_terminator(terminator, location);
     }
 
     fn visit_local(
@@ -679,17 +702,19 @@ fn visit_drop_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     let instance = Instance::resolve_drop_in_place(tcx, ty);
-    visit_instance_use(tcx, instance, is_direct_call, output);
+    visit_instance_use(tcx, instance, is_direct_call, source, output);
 }
 
 fn visit_fn_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     if let ty::FnDef(def_id, substs) = ty.kind {
         let instance = if is_direct_call {
@@ -698,7 +723,7 @@ fn visit_fn_use<'tcx>(
             ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, substs)
                 .unwrap()
         };
-        visit_instance_use(tcx, instance, is_direct_call, output);
+        visit_instance_use(tcx, instance, is_direct_call, source, output);
     }
 }
 
@@ -706,7 +731,8 @@ fn visit_instance_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::Instance<'tcx>,
     is_direct_call: bool,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
     if !should_monomorphize_locally(tcx, &instance) {
@@ -722,7 +748,7 @@ fn visit_instance_use<'tcx>(
         ty::InstanceDef::DropGlue(_, None) => {
             // Don't need to emit noop drop glue if we are calling directly.
             if !is_direct_call {
-                output.push(create_fn_mono_item(instance));
+                output.push(create_fn_mono_item(instance, source));
             }
         }
         ty::InstanceDef::DropGlue(_, Some(_))
@@ -732,7 +758,7 @@ fn visit_instance_use<'tcx>(
         | ty::InstanceDef::Item(..)
         | ty::InstanceDef::FnPtrShim(..)
         | ty::InstanceDef::CloneShim(..) => {
-            output.push(create_fn_mono_item(instance));
+            output.push(create_fn_mono_item(instance, source));
         }
     }
 }
@@ -824,7 +850,6 @@ fn find_vtable_types_for_unsizing<'tcx>(
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
         let param_env = ty::ParamEnv::reveal_all();
         let type_has_metadata = |ty: Ty<'tcx>| -> bool {
-            use rustc_span::DUMMY_SP;
             if ty.is_sized(tcx.at(DUMMY_SP), param_env) {
                 return false;
             }
@@ -878,9 +903,9 @@ fn find_vtable_types_for_unsizing<'tcx>(
     }
 }
 
-fn create_fn_mono_item(instance: Instance<'_>) -> MonoItem<'_> {
+fn create_fn_mono_item(instance: Instance<'_>, source: Span) -> Spanned<MonoItem<'_>> {
     debug!("create_fn_mono_item(instance={})", instance);
-    MonoItem::Fn(instance)
+    respan(source, MonoItem::Fn(instance))
 }
 
 /// Creates a `MonoItem` for each method that is referenced by the vtable for
@@ -889,7 +914,8 @@ fn create_mono_items_for_vtable_methods<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ty: Ty<'tcx>,
     impl_ty: Ty<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    source: Span,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     assert!(
         !trait_ty.needs_subst()
@@ -919,12 +945,12 @@ fn create_mono_items_for_vtable_methods<'tcx>(
                     .unwrap()
                 })
                 .filter(|&instance| should_monomorphize_locally(tcx, &instance))
-                .map(create_fn_mono_item);
+                .map(|item| create_fn_mono_item(item, source));
             output.extend(methods);
         }
 
         // Also add the destructor.
-        visit_drop_use(tcx, impl_ty, false, output);
+        visit_drop_use(tcx, impl_ty, false, source, output);
     }
 }
 
@@ -935,7 +961,7 @@ fn create_mono_items_for_vtable_methods<'tcx>(
 struct RootCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     mode: MonoItemCollectionMode,
-    output: &'a mut Vec<MonoItem<'tcx>>,
+    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
     entry_fn: Option<(LocalDefId, EntryFnType)>,
 }
 
@@ -972,7 +998,7 @@ fn visit_item(&mut self, item: &'v hir::Item<'v>) {
 
                         let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty())
                             .monomorphic_ty(self.tcx);
-                        visit_drop_use(self.tcx, ty, true, self.output);
+                        visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
                     }
                 }
             }
@@ -981,12 +1007,12 @@ fn visit_item(&mut self, item: &'v hir::Item<'v>) {
                     "RootCollector: ItemKind::GlobalAsm({})",
                     def_id_to_string(self.tcx, self.tcx.hir().local_def_id(item.hir_id))
                 );
-                self.output.push(MonoItem::GlobalAsm(item.hir_id));
+                self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id)));
             }
             hir::ItemKind::Static(..) => {
                 let def_id = self.tcx.hir().local_def_id(item.hir_id);
                 debug!("RootCollector: ItemKind::Static({})", def_id_to_string(self.tcx, def_id));
-                self.output.push(MonoItem::Static(def_id.to_def_id()));
+                self.output.push(dummy_spanned(MonoItem::Static(def_id.to_def_id())));
             }
             hir::ItemKind::Const(..) => {
                 // const items only generate mono items if they are
@@ -1043,7 +1069,7 @@ fn push_if_root(&mut self, def_id: LocalDefId) {
             debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
 
             let instance = Instance::mono(self.tcx, def_id.to_def_id());
-            self.output.push(create_fn_mono_item(instance));
+            self.output.push(create_fn_mono_item(instance, DUMMY_SP));
         }
     }
 
@@ -1080,7 +1106,7 @@ fn push_extra_entry_roots(&mut self) {
         .unwrap()
         .unwrap();
 
-        self.output.push(create_fn_mono_item(start_instance));
+        self.output.push(create_fn_mono_item(start_instance, DUMMY_SP));
     }
 }
 
@@ -1092,7 +1118,7 @@ fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
 fn create_mono_items_for_default_impls<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &'tcx hir::Item<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     match item.kind {
         hir::ItemKind::Impl { ref generics, ref items, .. } => {
@@ -1137,8 +1163,9 @@ fn create_mono_items_for_default_impls<'tcx>(
                         .unwrap()
                         .unwrap();
 
-                    let mono_item = create_fn_mono_item(instance);
-                    if mono_item.is_instantiable(tcx) && should_monomorphize_locally(tcx, &instance)
+                    let mono_item = create_fn_mono_item(instance, DUMMY_SP);
+                    if mono_item.node.is_instantiable(tcx)
+                        && should_monomorphize_locally(tcx, &instance)
                     {
                         output.push(mono_item);
                     }
@@ -1150,14 +1177,18 @@ fn create_mono_items_for_default_impls<'tcx>(
 }
 
 /// Scans the miri alloc in order to find function calls, closures, and drop-glue.
-fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<MonoItem<'tcx>>) {
+fn collect_miri<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    alloc_id: AllocId,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+) {
     match tcx.global_alloc(alloc_id) {
         GlobalAlloc::Static(def_id) => {
             assert!(!tcx.is_thread_local_static(def_id));
             let instance = Instance::mono(tcx, def_id);
             if should_monomorphize_locally(tcx, &instance) {
                 trace!("collecting static {:?}", def_id);
-                output.push(MonoItem::Static(def_id));
+                output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
         }
         GlobalAlloc::Memory(alloc) => {
@@ -1171,7 +1202,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon
         GlobalAlloc::Function(fn_instance) => {
             if should_monomorphize_locally(tcx, &fn_instance) {
                 trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
-                output.push(create_fn_mono_item(fn_instance));
+                output.push(create_fn_mono_item(fn_instance, DUMMY_SP));
             }
         }
     }
@@ -1181,7 +1212,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon
 fn collect_neighbours<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     debug!("collect_neighbours: {:?}", instance.def_id());
     let body = tcx.instance_mir(instance.def);
@@ -1199,7 +1230,7 @@ fn def_id_to_string(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
 fn collect_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     value: ConstValue<'tcx>,
-    output: &mut Vec<MonoItem<'tcx>>,
+    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
 ) {
     match value {
         ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output),
index db1ea72c0a53101af30755e93ef5934c80d82947..a945c1d626a9a63849c17386ac2c1dd656781e59 100644 (file)
@@ -454,18 +454,11 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
 fn merge_codegen_units<'tcx>(
     tcx: TyCtxt<'tcx>,
     initial_partitioning: &mut PreInliningPartitioning<'tcx>,
-    mut target_cgu_count: usize,
+    target_cgu_count: usize,
 ) {
     assert!(target_cgu_count >= 1);
     let codegen_units = &mut initial_partitioning.codegen_units;
 
-    if tcx.is_compiler_builtins(LOCAL_CRATE) {
-        // Compiler builtins require some degree of control over how mono items
-        // are partitioned into compilation units. Provide it by keeping the
-        // original partitioning when compiling the compiler builtins crate.
-        target_cgu_count = codegen_units.len();
-    }
-
     // Note that at this point in time the `codegen_units` here may not be in a
     // deterministic order (but we know they're deterministically the same set).
     // We want this merging to produce a deterministic ordering of codegen units
index f95fd9b9e90c562f51b31024f7795957268934f9..5671b5b4f04c1d37fbc62d50bc917293a6b7ac1b 100644 (file)
@@ -32,13 +32,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
 
     let mut result = match instance {
         ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
-        ty::InstanceDef::VtableShim(def_id) => build_call_shim(
-            tcx,
-            instance,
-            Some(Adjustment::DerefMove),
-            CallKind::Direct(def_id),
-            None,
-        ),
+        ty::InstanceDef::VtableShim(def_id) => {
+            build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None)
+        }
         ty::InstanceDef::FnPtrShim(def_id, ty) => {
             // FIXME(eddyb) support generating shims for a "shallow type",
             // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
@@ -60,7 +56,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
             let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
             let arg_tys = sig.inputs();
 
-            build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys))
+            build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys))
         }
         // We are generating a call back to our def-id, which the
         // codegen backend knows to turn to an actual call, be it
@@ -134,15 +130,28 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 enum Adjustment {
+    /// Pass the receiver as-is.
     Identity,
+
+    /// We get passed `&[mut] self` and call the target with `*self`.
+    ///
+    /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
+    /// (for `VtableShim`, which effectively is passed `&own Self`).
     Deref,
-    DerefMove,
+
+    /// We get passed `self: Self` and call the target with `&mut self`.
+    ///
+    /// In this case we need to ensure that the `Self` is dropped after the call, as the callee
+    /// won't do it for us.
     RefMut,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
-enum CallKind {
-    Indirect,
+enum CallKind<'tcx> {
+    /// Call the `FnPtr` that was passed as the receiver.
+    Indirect(Ty<'tcx>),
+
+    /// Call a known `FnDef`.
     Direct(DefId),
 }
 
@@ -242,7 +251,6 @@ fn new_body<'tcx>(
         arg_count,
         vec![],
         span,
-        vec![],
         None,
     )
 }
@@ -318,7 +326,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
     let param_env = tcx.param_env(def_id);
 
     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
-    let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
+    let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env);
 
     let dest = Place::return_place();
     let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
@@ -582,7 +590,7 @@ fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len:
         self.block(
             vec![],
             TerminatorKind::Drop {
-                location: self.tcx.mk_place_index(dest, beg),
+                place: self.tcx.mk_place_index(dest, beg),
                 target: BasicBlock::new(8),
                 unwind: None,
             },
@@ -634,7 +642,7 @@ fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
                 self.block(
                     vec![],
                     TerminatorKind::Drop {
-                        location: previous_field,
+                        place: previous_field,
                         target: previous_cleanup,
                         unwind: None,
                     },
@@ -662,7 +670,7 @@ fn build_call_shim<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::InstanceDef<'tcx>,
     rcvr_adjustment: Option<Adjustment>,
-    call_kind: CallKind,
+    call_kind: CallKind<'tcx>,
     untuple_args: Option<&[Ty<'tcx>]>,
 ) -> Body<'tcx> {
     debug!(
@@ -675,6 +683,29 @@ fn build_call_shim<'tcx>(
     let sig = tcx.fn_sig(def_id);
     let mut sig = tcx.erase_late_bound_regions(&sig);
 
+    if let CallKind::Indirect(fnty) = call_kind {
+        // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
+        // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
+        // the implemented `FnX` trait.
+
+        // Apply the opposite adjustment to the MIR input.
+        let mut inputs_and_output = sig.inputs_and_output.to_vec();
+
+        // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
+        // fn arguments. `Self` may be passed via (im)mutable reference or by-value.
+        assert_eq!(inputs_and_output.len(), 3);
+
+        // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
+        // `FnDef` and `FnPtr` callees, not the `Self` type param.
+        let self_arg = &mut inputs_and_output[0];
+        *self_arg = match rcvr_adjustment.unwrap() {
+            Adjustment::Identity => fnty,
+            Adjustment::Deref => tcx.mk_imm_ptr(fnty),
+            Adjustment::RefMut => tcx.mk_mut_ptr(fnty),
+        };
+        sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
+    }
+
     // FIXME(eddyb) avoid having this snippet both here and in
     // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
     if let ty::InstanceDef::VtableShim(..) = instance {
@@ -701,8 +732,7 @@ fn build_call_shim<'tcx>(
 
     let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
         Adjustment::Identity => Operand::Move(rcvr_place()),
-        Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), // Can't copy `&mut`
-        Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
+        Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())),
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
             let ref_rcvr = local_decls.push(
@@ -728,7 +758,10 @@ fn build_call_shim<'tcx>(
     });
 
     let (callee, mut args) = match call_kind {
-        CallKind::Indirect => (rcvr.unwrap(), vec![]),
+        // `FnPtr` call has no receiver. Args are untupled below.
+        CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
+
+        // `FnDef` call with optional receiver.
         CallKind::Direct(def_id) => {
             let ty = tcx.type_of(def_id);
             (
@@ -799,11 +832,7 @@ fn build_call_shim<'tcx>(
         block(
             &mut blocks,
             vec![],
-            TerminatorKind::Drop {
-                location: rcvr_place(),
-                target: BasicBlock::new(2),
-                unwind: None,
-            },
+            TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None },
             false,
         );
     }
@@ -814,11 +843,7 @@ fn build_call_shim<'tcx>(
         block(
             &mut blocks,
             vec![],
-            TerminatorKind::Drop {
-                location: rcvr_place(),
-                target: BasicBlock::new(4),
-                unwind: None,
-            },
+            TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None },
             true,
         );
 
index 39ce2340aed2198a67a46754a440dd01f15c023c..a02d0f655600d9db337171f54348b88e702083dd 100644 (file)
@@ -64,8 +64,8 @@ fn add_moves_for_packed_drops_patch<'tcx>(
         let terminator = data.terminator();
 
         match terminator.kind {
-            TerminatorKind::Drop { location, .. }
-                if util::is_disaligned(tcx, body, param_env, location) =>
+            TerminatorKind::Drop { place, .. }
+                if util::is_disaligned(tcx, body, param_env, place) =>
             {
                 add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
             }
@@ -88,13 +88,13 @@ fn add_move_for_packed_drop<'tcx>(
     is_cleanup: bool,
 ) {
     debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
-    let (location, target, unwind) = match terminator.kind {
-        TerminatorKind::Drop { ref location, target, unwind } => (location, target, unwind),
+    let (place, target, unwind) = match terminator.kind {
+        TerminatorKind::Drop { ref place, target, unwind } => (place, target, unwind),
         _ => unreachable!(),
     };
 
     let source_info = terminator.source_info;
-    let ty = location.ty(body, tcx).ty;
+    let ty = place.ty(body, tcx).ty;
     let temp = patch.new_temp(ty, terminator.source_info.span);
 
     let storage_dead_block = patch.new_block(BasicBlockData {
@@ -104,9 +104,9 @@ fn add_move_for_packed_drop<'tcx>(
     });
 
     patch.add_statement(loc, StatementKind::StorageLive(temp));
-    patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*location)));
+    patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
     patch.patch_terminator(
         loc.block,
-        TerminatorKind::Drop { location: Place::from(temp), target: storage_dead_block, unwind },
+        TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind },
     );
 }
index d5059c98c9511053c4c14f9eb44f19ae421a3d7d..ea025f208e49d733a25a3be51bf856cdcfb0a101 100644 (file)
@@ -142,48 +142,25 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
     }
 }
 
-#[derive(Debug)]
-pub struct IfOrMatch;
-impl NonConstOp for IfOrMatch {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_if_match)
-    }
-
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        // This should be caught by the HIR const-checker.
-        ccx.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
-    }
-}
-
 #[derive(Debug)]
 pub struct InlineAsm;
 impl NonConstOp for InlineAsm {}
 
 #[derive(Debug)]
-pub struct LiveDrop;
+pub struct LiveDrop(pub Option<Span>);
 impl NonConstOp for LiveDrop {
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        struct_span_err!(
+        let mut diagnostic = struct_span_err!(
             ccx.tcx.sess,
             span,
             E0493,
             "destructors cannot be evaluated at compile-time"
-        )
-        .span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()))
-        .emit();
-    }
-}
-
-#[derive(Debug)]
-pub struct Loop;
-impl NonConstOp for Loop {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_loop)
-    }
-
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        // This should be caught by the HIR const-checker.
-        ccx.tcx.sess.delay_span_bug(span, "complex control flow is forbidden in a const context");
+        );
+        diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
+        if let Some(span) = self.0 {
+            diagnostic.span_label(span, "value is dropped here");
+        }
+        diagnostic.emit();
     }
 }
 
@@ -205,22 +182,34 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct MutBorrow;
 impl NonConstOp for MutBorrow {
+    fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
+        // Forbid everywhere except in const fn
+        ccx.const_kind() == hir::ConstContext::ConstFn
+            && ccx.tcx.features().enabled(Self::feature_gate().unwrap())
+    }
+
     fn feature_gate() -> Option<Symbol> {
         Some(sym::const_mut_refs)
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        let mut err = feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_mut_refs,
-            span,
-            &format!(
-                "references in {}s may only refer \
-                      to immutable values",
-                ccx.const_kind()
-            ),
-        );
-        err.span_label(span, format!("{}s require immutable values", ccx.const_kind()));
+        let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
+            feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_mut_refs,
+                span,
+                &format!("mutable references are not allowed in {}s", ccx.const_kind()),
+            )
+        } else {
+            struct_span_err!(
+                ccx.tcx.sess,
+                span,
+                E0764,
+                "mutable references are not allowed in {}s",
+                ccx.const_kind(),
+            )
+        };
+        err.span_label(span, "`&mut` is only allowed in `const fn`".to_string());
         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "References in statics and constants may only refer \
@@ -284,18 +273,16 @@ fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
 #[derive(Debug)]
 pub struct RawPtrComparison;
 impl NonConstOp for RawPtrComparison {
-    fn feature_gate() -> Option<Symbol> {
-        Some(sym::const_compare_raw_pointers)
-    }
-
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_compare_raw_pointers,
-            span,
-            &format!("comparing raw pointers inside {}", ccx.const_kind()),
-        )
-        .emit();
+        let mut err = ccx
+            .tcx
+            .sess
+            .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
+        err.note(
+            "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
+            for more information",
+        );
+        err.emit();
     }
 }
 
index 226e0e2049ebd62a47818d324586309529c68650..1fd907f89fe1819ef77e4ea1fab1368d48f17d0b 100644 (file)
@@ -58,7 +58,7 @@ fn deref(&self) -> &Self::Target {
 
 impl CheckLiveDrops<'mir, 'tcx> {
     fn check_live_drop(&self, span: Span) {
-        ops::non_const(self.ccx, ops::LiveDrop, span);
+        ops::non_const(self.ccx, ops::LiveDrop(None), span);
     }
 }
 
@@ -78,7 +78,7 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
         trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
 
         match &terminator.kind {
-            mir::TerminatorKind::Drop { location: dropped_place, .. } => {
+            mir::TerminatorKind::Drop { place: dropped_place, .. } => {
                 let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
                 if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
                     return;
index 936c1a84e142eb9a595c042c016dfe695eac7303..e2893e81a2ce63dc8a0cebdce21ac276ce145957 100644 (file)
@@ -77,7 +77,7 @@ fn in_qualifs(qualifs: &ConstQualifs) -> bool {
     }
 
     fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        !ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP)
+        !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
     }
 
     fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
index a81d7a23be2fb640c0a60a58396770aa81e437fb..b8104292aab23cf47c8d76181b352ce8abb08c29 100644 (file)
@@ -121,25 +121,25 @@ fn visit_assign(
         self.super_assign(place, rvalue, location);
     }
 
-    fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
         // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
         // here; that occurs in `apply_call_return_effect`.
 
-        if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind {
+        if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
             let qualif = qualifs::in_operand::<Q, _>(
                 self.ccx,
                 &mut |l| self.qualifs_per_local.contains(l),
                 value,
             );
 
-            if !dest.is_indirect() {
-                self.assign_qualif_direct(dest, qualif);
+            if !place.is_indirect() {
+                self.assign_qualif_direct(place, qualif);
             }
         }
 
         // We need to assign qualifs to the dropped location before visiting the operand that
         // replaces it since qualifs can be cleared on move.
-        self.super_terminator_kind(kind, location);
+        self.super_terminator(terminator, location);
     }
 }
 
index 428a74bcdcbfba54599dbdf49723e40906ad5160..ca1f0aecd048a9d4adac6c72b59a2dc46bdafd41 100644 (file)
@@ -207,14 +207,6 @@ pub fn check_body(&mut self) {
             }
         }
 
-        check_short_circuiting_in_const_local(self.ccx);
-
-        if body.is_cfg_cyclic() {
-            // We can't provide a good span for the error here, but this should be caught by the
-            // HIR const-checker anyways.
-            self.check_op_spanned(ops::Loop, body.span);
-        }
-
         self.visit_body(&body);
 
         // Ensure that the end result is `Sync` in a non-thread local `static`.
@@ -483,21 +475,12 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 self.super_statement(statement, location);
             }
 
-            StatementKind::FakeRead(
-                FakeReadCause::ForMatchedPlace
-                | FakeReadCause::ForMatchGuard
-                | FakeReadCause::ForGuardBinding,
-                _,
-            ) => {
-                self.super_statement(statement, location);
-                self.check_op(ops::IfOrMatch);
-            }
             StatementKind::LlvmInlineAsm { .. } => {
                 self.super_statement(statement, location);
                 self.check_op(ops::InlineAsm);
             }
 
-            StatementKind::FakeRead(FakeReadCause::ForLet | FakeReadCause::ForIndex, _)
+            StatementKind::FakeRead(..)
             | StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
             | StatementKind::Retag { .. }
@@ -560,8 +543,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
 
             // Forbid all `Drop` terminators unless the place being dropped is a local with no
             // projections that cannot be `NeedsDrop`.
-            TerminatorKind::Drop { location: dropped_place, .. }
-            | TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
+            TerminatorKind::Drop { place: dropped_place, .. }
+            | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
                 // If we are checking live drops after drop-elaboration, don't emit duplicate
                 // errors here.
                 if super::post_drop_elaboration::checking_enabled(self.tcx) {
@@ -588,7 +571,10 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 };
 
                 if needs_drop {
-                    self.check_op_spanned(ops::LiveDrop, err_span);
+                    self.check_op_spanned(
+                        ops::LiveDrop(Some(terminator.source_info.span)),
+                        err_span,
+                    );
                 }
             }
 
@@ -623,44 +609,6 @@ fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>)
         .emit();
 }
 
-fn check_short_circuiting_in_const_local(ccx: &ConstCx<'_, 'tcx>) {
-    let body = ccx.body;
-
-    if body.control_flow_destroyed.is_empty() {
-        return;
-    }
-
-    let mut locals = body.vars_iter();
-    if let Some(local) = locals.next() {
-        let span = body.local_decls[local].source_info.span;
-        let mut error = ccx.tcx.sess.struct_span_err(
-            span,
-            &format!(
-                "new features like let bindings are not permitted in {}s \
-                which also use short circuiting operators",
-                ccx.const_kind(),
-            ),
-        );
-        for (span, kind) in body.control_flow_destroyed.iter() {
-            error.span_note(
-                *span,
-                &format!(
-                    "use of {} here does not actually short circuit due to \
-                     the const evaluator presently not being able to do control flow. \
-                     See issue #49146 <https://github.com/rust-lang/rust/issues/49146> \
-                     for more information.",
-                    kind
-                ),
-            );
-        }
-        for local in locals {
-            let span = body.local_decls[local].source_info.span;
-            error.span_note(span, "more locals are defined here");
-        }
-        error.emit();
-    }
-}
-
 fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
     let ty = body.return_ty();
     tcx.infer_ctxt().enter(|infcx| {
index 7dbb2ebad8b996b0c43b28978368fe60c1b93fa8..b8f725e967ddb4239af9fed9fbda64129ce13be8 100644 (file)
@@ -171,21 +171,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     _ => {}
                 }
             }
-            // raw pointer and fn pointer operations are unsafe as it is not clear whether one
-            // pointer would be "less" or "equal" to another, because we cannot know where llvm
-            // or the linker will place various statics in memory. Without this information the
-            // result of a comparison of addresses would differ between runtime and compile-time.
-            Rvalue::BinaryOp(_, ref lhs, _)
-                if self.const_context && self.tcx.features().const_compare_raw_pointers =>
-            {
-                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
-                    self.require_unsafe(
-                        "pointer operation",
-                        "operations on pointers in constants",
-                        UnsafetyViolationKind::General,
-                    );
-                }
-            }
             _ => {}
         }
         self.super_rvalue(rvalue, location);
@@ -282,9 +267,8 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                                 ),
                             };
                             if !elem_ty.is_copy_modulo_regions(
-                                self.tcx,
+                                self.tcx.at(self.source_info.span),
                                 self.param_env,
-                                self.source_info.span,
                             ) {
                                 self.require_unsafe(
                                     "assignment to non-`Copy` union field",
@@ -459,11 +443,11 @@ fn check_mut_borrowing_layout_constrained_field(
 
                             // Check `is_freeze` as late as possible to avoid cycle errors
                             // with opaque types.
-                            } else if !place.ty(self.body, self.tcx).ty.is_freeze(
-                                self.tcx,
-                                self.param_env,
-                                self.source_info.span,
-                            {
+                            } else if !place
+                                .ty(self.body, self.tcx)
+                                .ty
+                                .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
+                            {
                                 (
                                     "borrow of layout constrained field with interior \
                                         mutability",
index 83ed2fc2d439bf8a838a57ed1c58b33f9a48f37e..2c1565b54261c264adf0efcf221d6b29ce90bbdd 100644 (file)
@@ -4,6 +4,7 @@
 use std::cell::Cell;
 
 use rustc_ast::ast::Mutability;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
 use rustc_index::bit_set::BitSet;
@@ -19,7 +20,7 @@
 };
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ConstInt, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
@@ -27,9 +28,9 @@
 
 use crate::const_eval::error_to_const_error;
 use crate::interpret::{
-    self, compile_time_machine, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy,
-    Immediate, InternKind, InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy,
-    Operand as InterpOperand, PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup,
+    self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState,
+    LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
+    ScalarMaybeUninit, StackPopCleanup,
 };
 use crate::transform::{MirPass, MirSource};
 
@@ -133,7 +134,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
             body.arg_count,
             Default::default(),
             tcx.def_span(source.def_id()),
-            Default::default(),
             body.generator_kind,
         );
 
@@ -151,11 +151,19 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
 struct ConstPropMachine<'mir, 'tcx> {
     /// The virtual call stack.
     stack: Vec<Frame<'mir, 'tcx, (), ()>>,
+    /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
+    written_only_inside_own_block_locals: FxHashSet<Local>,
+    /// Locals that need to be cleared after every block terminates.
+    only_propagate_inside_block_locals: BitSet<Local>,
 }
 
 impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
-    fn new() -> Self {
-        Self { stack: Vec::new() }
+    fn new(only_propagate_inside_block_locals: BitSet<Local>) -> Self {
+        Self {
+            stack: Vec::new(),
+            written_only_inside_own_block_locals: Default::default(),
+            only_propagate_inside_block_locals,
+        }
     }
 }
 
@@ -227,6 +235,18 @@ fn access_local(
         l.access()
     }
 
+    fn access_local_mut<'a>(
+        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
+        frame: usize,
+        local: Local,
+    ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
+    {
+        if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
+            ecx.machine.written_only_inside_own_block_locals.insert(local);
+        }
+        ecx.machine.stack[frame].locals[local].access_mut()
+    }
+
     fn before_access_global(
         _memory_extra: &(),
         _alloc_id: AllocId,
@@ -274,8 +294,6 @@ struct ConstPropagator<'mir, 'tcx> {
     // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
     // the last known `SourceInfo` here and just keep revisiting it.
     source_info: Option<SourceInfo>,
-    // Locals we need to forget at the end of the current block
-    locals_of_current_block: BitSet<Local>,
 }
 
 impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
@@ -313,8 +331,20 @@ fn new(
         let param_env = tcx.param_env(def_id).with_reveal_all();
 
         let span = tcx.def_span(def_id);
-        let mut ecx = InterpCx::new(tcx, span, param_env, ConstPropMachine::new(), ());
         let can_const_prop = CanConstProp::check(body);
+        let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
+        for (l, mode) in can_const_prop.iter_enumerated() {
+            if *mode == ConstPropMode::OnlyInsideOwnBlock {
+                only_propagate_inside_block_locals.insert(l);
+            }
+        }
+        let mut ecx = InterpCx::new(
+            tcx,
+            span,
+            param_env,
+            ConstPropMachine::new(only_propagate_inside_block_locals),
+            (),
+        );
 
         let ret = ecx
             .layout_of(body.return_ty().subst(tcx, substs))
@@ -345,19 +375,24 @@ fn new(
             //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
             local_decls: body.local_decls.clone(),
             source_info: None,
-            locals_of_current_block: BitSet::new_empty(body.local_decls.len()),
         }
     }
 
     fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
-        let op = self.ecx.eval_place_to_op(place, None).ok();
+        let op = match self.ecx.eval_place_to_op(place, None) {
+            Ok(op) => op,
+            Err(e) => {
+                trace!("get_const failed: {}", e);
+                return None;
+            }
+        };
 
         // Try to read the local as an immediate so that if it is representable as a scalar, we can
         // handle it as such, but otherwise, just return the value as is.
-        match op.map(|ret| self.ecx.try_read_immediate(ret)) {
-            Some(Ok(Ok(imm))) => Some(imm.into()),
+        Some(match self.ecx.try_read_immediate(op) {
+            Ok(Ok(imm)) => imm.into(),
             _ => op,
-        }
+        })
     }
 
     /// Remove `local` from the pool of `Locals`. Allows writing to them,
@@ -449,7 +484,7 @@ fn report_assert_as_lint(
         lint: &'static lint::Lint,
         source_info: SourceInfo,
         message: &'static str,
-        panic: AssertKind<u64>,
+        panic: AssertKind<ConstInt>,
     ) -> Option<()> {
         let lint_root = self.lint_root(source_info)?;
         self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
@@ -466,10 +501,10 @@ fn check_unary_op(
         arg: &Operand<'tcx>,
         source_info: SourceInfo,
     ) -> Option<()> {
-        if self.use_ecx(|this| {
+        if let (val, true) = self.use_ecx(|this| {
             let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
             let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
-            Ok(overflow)
+            Ok((val, overflow))
         })? {
             // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
             // appropriate to use.
@@ -478,7 +513,7 @@ fn check_unary_op(
                 lint::builtin::ARITHMETIC_OVERFLOW,
                 source_info,
                 "this arithmetic operation will overflow",
-                AssertKind::OverflowNeg,
+                AssertKind::OverflowNeg(val.to_const_int()),
             )?;
         }
 
@@ -494,30 +529,45 @@ fn check_binary_op(
     ) -> Option<()> {
         let r =
             self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?;
+        let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
         // Check for exceeding shifts *even if* we cannot evaluate the LHS.
         if op == BinOp::Shr || op == BinOp::Shl {
             // We need the type of the LHS. We cannot use `place_layout` as that is the type
             // of the result, which for checked binops is not the same!
             let left_ty = left.ty(&self.local_decls, self.tcx);
-            let left_size_bits = self.ecx.layout_of(left_ty).ok()?.size.bits();
+            let left_size = self.ecx.layout_of(left_ty).ok()?.size;
             let right_size = r.layout.size;
             let r_bits = r.to_scalar().ok();
             // This is basically `force_bits`.
             let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok());
-            if r_bits.map_or(false, |b| b >= left_size_bits as u128) {
+            if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
                 debug!("check_binary_op: reporting assert for {:?}", source_info);
                 self.report_assert_as_lint(
                     lint::builtin::ARITHMETIC_OVERFLOW,
                     source_info,
                     "this arithmetic operation will overflow",
-                    AssertKind::Overflow(op),
+                    AssertKind::Overflow(
+                        op,
+                        match l {
+                            Some(l) => l.to_const_int(),
+                            // Invent a dummy value, the diagnostic ignores it anyway
+                            None => ConstInt::new(
+                                1,
+                                left_size,
+                                left_ty.is_signed(),
+                                left_ty.is_ptr_sized_integral(),
+                            ),
+                        },
+                        r.to_const_int(),
+                    ),
                 )?;
             }
         }
 
+        let l = l?;
+
         // The remaining operators are handled through `overflowing_binary_op`.
         if self.use_ecx(|this| {
-            let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
             let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
             Ok(overflow)
         })? {
@@ -525,7 +575,7 @@ fn check_binary_op(
                 lint::builtin::ARITHMETIC_OVERFLOW,
                 source_info,
                 "this arithmetic operation will overflow",
-                AssertKind::Overflow(op),
+                AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
             )?;
         }
 
@@ -575,8 +625,16 @@ fn const_prop(
             }
 
             // Do not try creating references (#67862)
-            Rvalue::Ref(_, _, place_ref) => {
-                trace!("skipping Ref({:?})", place_ref);
+            Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
+                trace!("skipping AddressOf | Ref for {:?}", place);
+
+                // This may be creating mutable references or immutable references to cells.
+                // If that happens, the pointed to value could be mutated via that reference.
+                // Since we aren't tracking references, the const propagator loses track of what
+                // value the local has right now.
+                // Thus, all locals that have their reference taken
+                // must not take part in propagation.
+                Self::remove_const(&mut self.ecx, place.local);
 
                 return None;
             }
@@ -702,11 +760,6 @@ fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
                 ScalarMaybeUninit::Scalar(l),
                 ScalarMaybeUninit::Scalar(r),
             )) => l.is_bits() && r.is_bits(),
-            interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
-                let mplace = op.assert_mem_place(&self.ecx);
-                intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false);
-                true
-            }
             _ => false,
         }
     }
@@ -721,7 +774,8 @@ enum ConstPropMode {
     OnlyInsideOwnBlock,
     /// The `Local` can be propagated into but reads cannot be propagated.
     OnlyPropagateInto,
-    /// No propagation is allowed at all.
+    /// The `Local` cannot be part of propagation at all. Any statement
+    /// referencing it either for reading or writing will not get propagated.
     NoPropagation,
 }
 
@@ -788,12 +842,14 @@ fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
                         // end of the block anyway, and inside the block we overwrite previous
                         // states as applicable.
                         ConstPropMode::OnlyInsideOwnBlock => {}
-                        other => {
+                        ConstPropMode::NoPropagation => {}
+                        ConstPropMode::OnlyPropagateInto => {}
+                        other @ ConstPropMode::FullConstProp => {
                             trace!(
                                 "local {:?} can't be propagated because of multiple assignments",
                                 local,
                             );
-                            *other = ConstPropMode::NoPropagation;
+                            *other = ConstPropMode::OnlyPropagateInto;
                         }
                     }
                 }
@@ -852,35 +908,35 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
             if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
                 let can_const_prop = self.can_const_prop[place.local];
                 if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
-                    if can_const_prop != ConstPropMode::NoPropagation {
-                        // This will return None for variables that are from other blocks,
-                        // so it should be okay to propagate from here on down.
-                        if let Some(value) = self.get_const(place) {
-                            if self.should_const_prop(value) {
-                                trace!("replacing {:?} with {:?}", rval, value);
-                                self.replace_with_const(rval, value, source_info);
-                                if can_const_prop == ConstPropMode::FullConstProp
-                                    || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
-                                {
-                                    trace!("propagated into {:?}", place);
-                                }
-                            }
-                            if can_const_prop == ConstPropMode::OnlyInsideOwnBlock {
-                                trace!(
-                                    "found local restricted to its block. Will remove it from const-prop after block is finished. Local: {:?}",
-                                    place.local
-                                );
-                                self.locals_of_current_block.insert(place.local);
+                    // This will return None if the above `const_prop` invocation only "wrote" a
+                    // type whose creation requires no write. E.g. a generator whose initial state
+                    // consists solely of uninitialized memory (so it doesn't capture any locals).
+                    if let Some(value) = self.get_const(place) {
+                        if self.should_const_prop(value) {
+                            trace!("replacing {:?} with {:?}", rval, value);
+                            self.replace_with_const(rval, value, source_info);
+                            if can_const_prop == ConstPropMode::FullConstProp
+                                || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+                            {
+                                trace!("propagated into {:?}", place);
                             }
                         }
                     }
-                    if can_const_prop == ConstPropMode::OnlyPropagateInto
-                        || can_const_prop == ConstPropMode::NoPropagation
-                    {
-                        trace!("can't propagate into {:?}", place);
-                        if place.local != RETURN_PLACE {
-                            Self::remove_const(&mut self.ecx, place.local);
+                    match can_const_prop {
+                        ConstPropMode::OnlyInsideOwnBlock => {
+                            trace!(
+                                "found local restricted to its block. \
+                                Will remove it from const-prop after block is finished. Local: {:?}",
+                                place.local
+                            );
                         }
+                        ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
+                            trace!("can't propagate into {:?}", place);
+                            if place.local != RETURN_PLACE {
+                                Self::remove_const(&mut self.ecx, place.local);
+                            }
+                        }
+                        ConstPropMode::FullConstProp => {}
                     }
                 } else {
                     // Const prop failed, so erase the destination, ensuring that whatever happens
@@ -900,6 +956,12 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
                     );
                     Self::remove_const(&mut self.ecx, place.local);
                 }
+            } else {
+                trace!(
+                    "cannot propagate into {:?}, because the type of the local is generic.",
+                    place,
+                );
+                Self::remove_const(&mut self.ecx, place.local);
             }
         } else {
             match statement.kind {
@@ -938,31 +1000,26 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
                             }
                             Operand::Constant(_) => {}
                         }
+                        let mut eval_to_int = |op| {
+                            let op = self
+                                .eval_operand(op, source_info)
+                                .expect("if we got here, it must be const");
+                            self.ecx.read_immediate(op).unwrap().to_const_int()
+                        };
                         let msg = match msg {
-                            AssertKind::DivisionByZero => AssertKind::DivisionByZero,
-                            AssertKind::RemainderByZero => AssertKind::RemainderByZero,
+                            AssertKind::DivisionByZero(op) => {
+                                AssertKind::DivisionByZero(eval_to_int(op))
+                            }
+                            AssertKind::RemainderByZero(op) => {
+                                AssertKind::RemainderByZero(eval_to_int(op))
+                            }
                             AssertKind::BoundsCheck { ref len, ref index } => {
-                                let len =
-                                    self.eval_operand(len, source_info).expect("len must be const");
-                                let len = self
-                                    .ecx
-                                    .read_scalar(len)
-                                    .unwrap()
-                                    .to_machine_usize(&self.tcx)
-                                    .unwrap();
-                                let index = self
-                                    .eval_operand(index, source_info)
-                                    .expect("index must be const");
-                                let index = self
-                                    .ecx
-                                    .read_scalar(index)
-                                    .unwrap()
-                                    .to_machine_usize(&self.tcx)
-                                    .unwrap();
+                                let len = eval_to_int(len);
+                                let index = eval_to_int(index);
                                 AssertKind::BoundsCheck { len, index }
                             }
                             // Overflow is are already covered by checks on the binary operators.
-                            AssertKind::Overflow(_) | AssertKind::OverflowNeg => return,
+                            AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => return,
                             // Need proper const propagator for these.
                             _ => return,
                         };
@@ -1060,10 +1117,27 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
                 }
             }
         }
-        // We remove all Locals which are restricted in propagation to their containing blocks.
-        for local in self.locals_of_current_block.iter() {
+
+        // We remove all Locals which are restricted in propagation to their containing blocks and
+        // which were modified in the current block.
+        // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`
+        let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
+        for &local in locals.iter() {
             Self::remove_const(&mut self.ecx, local);
         }
-        self.locals_of_current_block.clear();
+        locals.clear();
+        // Put it back so we reuse the heap of the storage
+        self.ecx.machine.written_only_inside_own_block_locals = locals;
+        if cfg!(debug_assertions) {
+            // Ensure we are correctly erasing locals with the non-debug-assert logic.
+            for local in self.ecx.machine.only_propagate_inside_block_locals.iter() {
+                assert!(
+                    self.get_const(local.into()).is_none()
+                        || self
+                            .layout_of(self.local_decls[local].ty)
+                            .map_or(true, |layout| layout.is_zst())
+                )
+            }
+        }
     }
 }
index e4129f447d532532b17355d4139b6355fc414041..1704d8baabdc8c24a617498e5e7c938be844fbca 100644 (file)
@@ -85,15 +85,15 @@ fn find_dead_unwinds<'tcx>(
         .iterate_to_fixpoint()
         .into_results_cursor(body);
     for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
-        let location = match bb_data.terminator().kind {
-            TerminatorKind::Drop { ref location, unwind: Some(_), .. }
-            | TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location,
+        let place = match bb_data.terminator().kind {
+            TerminatorKind::Drop { ref place, unwind: Some(_), .. }
+            | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place,
             _ => continue,
         };
 
         debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data);
 
-        let path = match env.move_data.rev_lookup.find(location.as_ref()) {
+        let path = match env.move_data.rev_lookup.find(place.as_ref()) {
             LookupResult::Exact(e) => e,
             LookupResult::Parent(..) => {
                 debug!("find_dead_unwinds: has parent; skipping");
@@ -105,7 +105,7 @@ fn find_dead_unwinds<'tcx>(
         debug!(
             "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}",
             bb,
-            location,
+            place,
             path,
             flow_inits.get()
         );
@@ -294,16 +294,16 @@ fn elaborate(mut self) -> MirPatch<'tcx> {
     fn collect_drop_flags(&mut self) {
         for (bb, data) in self.body.basic_blocks().iter_enumerated() {
             let terminator = data.terminator();
-            let location = match terminator.kind {
-                TerminatorKind::Drop { ref location, .. }
-                | TerminatorKind::DropAndReplace { ref location, .. } => location,
+            let place = match terminator.kind {
+                TerminatorKind::Drop { ref place, .. }
+                | TerminatorKind::DropAndReplace { ref place, .. } => place,
                 _ => continue,
             };
 
             self.init_data.seek_before(self.body.terminator_loc(bb));
 
-            let path = self.move_data().rev_lookup.find(location.as_ref());
-            debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, location, path);
+            let path = self.move_data().rev_lookup.find(place.as_ref());
+            debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, place, path);
 
             let path = match path {
                 LookupResult::Exact(e) => e,
@@ -315,7 +315,7 @@ fn collect_drop_flags(&mut self) {
                             terminator.source_info.span,
                             "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
                             bb,
-                            location,
+                            place,
                             path
                         );
                     }
@@ -328,7 +328,7 @@ fn collect_drop_flags(&mut self) {
                 debug!(
                     "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
                     child,
-                    location,
+                    place,
                     path,
                     (maybe_live, maybe_dead)
                 );
@@ -346,13 +346,13 @@ fn elaborate_drops(&mut self) {
 
             let resume_block = self.patch.resume_block();
             match terminator.kind {
-                TerminatorKind::Drop { location, target, unwind } => {
+                TerminatorKind::Drop { place, target, unwind } => {
                     self.init_data.seek_before(loc);
-                    match self.move_data().rev_lookup.find(location.as_ref()) {
+                    match self.move_data().rev_lookup.find(place.as_ref()) {
                         LookupResult::Exact(path) => elaborate_drop(
                             &mut Elaborator { ctxt: self },
                             terminator.source_info,
-                            location,
+                            place,
                             path,
                             target,
                             if data.is_cleanup {
@@ -371,10 +371,10 @@ fn elaborate_drops(&mut self) {
                         }
                     }
                 }
-                TerminatorKind::DropAndReplace { location, ref value, target, unwind } => {
+                TerminatorKind::DropAndReplace { place, ref value, target, unwind } => {
                     assert!(!data.is_cleanup);
 
-                    self.elaborate_replace(loc, location, value, target, unwind);
+                    self.elaborate_replace(loc, place, value, target, unwind);
                 }
                 _ => continue,
             }
@@ -396,7 +396,7 @@ fn elaborate_drops(&mut self) {
     fn elaborate_replace(
         &mut self,
         loc: Location,
-        location: Place<'tcx>,
+        place: Place<'tcx>,
         value: &Operand<'tcx>,
         target: BasicBlock,
         unwind: Option<BasicBlock>,
@@ -407,7 +407,7 @@ fn elaborate_replace(
         assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
 
         let assign = Statement {
-            kind: StatementKind::Assign(box (location, Rvalue::Use(value.clone()))),
+            kind: StatementKind::Assign(box (place, Rvalue::Use(value.clone()))),
             source_info: terminator.source_info,
         };
 
@@ -427,14 +427,14 @@ fn elaborate_replace(
             is_cleanup: false,
         });
 
-        match self.move_data().rev_lookup.find(location.as_ref()) {
+        match self.move_data().rev_lookup.find(place.as_ref()) {
             LookupResult::Exact(path) => {
                 debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
                 self.init_data.seek_before(loc);
                 elaborate_drop(
                     &mut Elaborator { ctxt: self },
                     terminator.source_info,
-                    location,
+                    place,
                     path,
                     target,
                     Unwind::To(unwind),
@@ -459,7 +459,7 @@ fn elaborate_replace(
                 debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
                 self.patch.patch_terminator(
                     bb,
-                    TerminatorKind::Drop { location, target, unwind: Some(unwind) },
+                    TerminatorKind::Drop { place, target, unwind: Some(unwind) },
                 );
             }
         }
index acadb5385c9cfa402b5473a2faa05eba5e2cb73f..523d3c9af3f68c0dfde4f15e4272545618479c9d 100644 (file)
@@ -64,7 +64,7 @@
 use rustc_hir::lang_items::{GeneratorStateLangItem, PinTypeLangItem};
 use rustc_index::bit_set::{BitMatrix, BitSet};
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::GeneratorSubsts;
@@ -72,7 +72,7 @@
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::PanicStrategy;
 use std::borrow::Cow;
-use std::iter;
+use std::{iter, ops};
 
 pub struct StateTransform;
 
@@ -93,13 +93,13 @@ fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
         }
     }
 
-    fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) {
-        match kind {
+    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
+        match terminator.kind {
             TerminatorKind::Return => {
                 // Do not replace the implicit `_0` access here, as that's not possible. The
                 // transform already handles `return` correctly.
             }
-            _ => self.super_terminator_kind(kind, location),
+            _ => self.super_terminator(terminator, location),
         }
     }
 }
@@ -417,15 +417,14 @@ fn replace_local<'tcx>(
 
 struct LivenessInfo {
     /// Which locals are live across any suspension point.
-    ///
-    /// GeneratorSavedLocal is indexed in terms of the elements in this set;
-    /// i.e. GeneratorSavedLocal::new(1) corresponds to the second local
-    /// included in this set.
-    live_locals: BitSet<Local>,
+    saved_locals: GeneratorSavedLocals,
 
     /// The set of saved locals live at each suspension point.
     live_locals_at_suspension_points: Vec<BitSet<GeneratorSavedLocal>>,
 
+    /// Parallel vec to the above with SourceInfo for each yield terminator.
+    source_info_at_suspension_points: Vec<SourceInfo>,
+
     /// For every saved local, the set of other saved locals that are
     /// storage-live at the same time as this local. We cannot overlap locals in
     /// the layout which have conflicting storage.
@@ -477,6 +476,7 @@ fn locals_live_across_suspend_points(
 
     let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks());
     let mut live_locals_at_suspension_points = Vec::new();
+    let mut source_info_at_suspension_points = Vec::new();
     let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
 
     for (block, data) in body.basic_blocks().iter_enumerated() {
@@ -522,51 +522,79 @@ fn locals_live_across_suspend_points(
             live_locals_at_any_suspension_point.union(&live_locals);
 
             live_locals_at_suspension_points.push(live_locals);
+            source_info_at_suspension_points.push(data.terminator().source_info);
         }
     }
+
     debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point);
+    let saved_locals = GeneratorSavedLocals(live_locals_at_any_suspension_point);
 
     // Renumber our liveness_map bitsets to include only the locals we are
     // saving.
     let live_locals_at_suspension_points = live_locals_at_suspension_points
         .iter()
-        .map(|live_here| renumber_bitset(&live_here, &live_locals_at_any_suspension_point))
+        .map(|live_here| saved_locals.renumber_bitset(&live_here))
         .collect();
 
     let storage_conflicts = compute_storage_conflicts(
         body_ref,
-        &live_locals_at_any_suspension_point,
+        &saved_locals,
         always_live_locals.clone(),
         requires_storage_results,
     );
 
     LivenessInfo {
-        live_locals: live_locals_at_any_suspension_point,
+        saved_locals,
         live_locals_at_suspension_points,
+        source_info_at_suspension_points,
         storage_conflicts,
         storage_liveness: storage_liveness_map,
     }
 }
 
-/// Renumbers the items present in `stored_locals` and applies the renumbering
-/// to 'input`.
+/// The set of `Local`s that must be saved across yield points.
 ///
-/// For example, if `stored_locals = [1, 3, 5]`, this would be renumbered to
-/// `[0, 1, 2]`. Thus, if `input = [3, 5]` we would return `[1, 2]`.
-fn renumber_bitset(
-    input: &BitSet<Local>,
-    stored_locals: &BitSet<Local>,
-) -> BitSet<GeneratorSavedLocal> {
-    assert!(stored_locals.superset(&input), "{:?} not a superset of {:?}", stored_locals, input);
-    let mut out = BitSet::new_empty(stored_locals.count());
-    for (idx, local) in stored_locals.iter().enumerate() {
-        let saved_local = GeneratorSavedLocal::from(idx);
-        if input.contains(local) {
-            out.insert(saved_local);
+/// `GeneratorSavedLocal` is indexed in terms of the elements in this set;
+/// i.e. `GeneratorSavedLocal::new(1)` corresponds to the second local
+/// included in this set.
+struct GeneratorSavedLocals(BitSet<Local>);
+
+impl GeneratorSavedLocals {
+    /// Returns an iterator over each `GeneratorSavedLocal` along with the `Local` it corresponds
+    /// to.
+    fn iter_enumerated(&self) -> impl '_ + Iterator<Item = (GeneratorSavedLocal, Local)> {
+        self.iter().enumerate().map(|(i, l)| (GeneratorSavedLocal::from(i), l))
+    }
+
+    /// Transforms a `BitSet<Local>` that contains only locals saved across yield points to the
+    /// equivalent `BitSet<GeneratorSavedLocal>`.
+    fn renumber_bitset(&self, input: &BitSet<Local>) -> BitSet<GeneratorSavedLocal> {
+        assert!(self.superset(&input), "{:?} not a superset of {:?}", self.0, input);
+        let mut out = BitSet::new_empty(self.count());
+        for (saved_local, local) in self.iter_enumerated() {
+            if input.contains(local) {
+                out.insert(saved_local);
+            }
         }
+        out
+    }
+
+    fn get(&self, local: Local) -> Option<GeneratorSavedLocal> {
+        if !self.contains(local) {
+            return None;
+        }
+
+        let idx = self.iter().take_while(|&l| l < local).count();
+        Some(GeneratorSavedLocal::new(idx))
+    }
+}
+
+impl ops::Deref for GeneratorSavedLocals {
+    type Target = BitSet<Local>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
     }
-    debug!("renumber_bitset({:?}, {:?}) => {:?}", input, stored_locals, out);
-    out
 }
 
 /// For every saved local, looks for which locals are StorageLive at the same
@@ -575,11 +603,11 @@ fn renumber_bitset(
 /// computation; see `GeneratorLayout` for more.
 fn compute_storage_conflicts(
     body: &'mir Body<'tcx>,
-    stored_locals: &BitSet<Local>,
+    saved_locals: &GeneratorSavedLocals,
     always_live_locals: storage::AlwaysLiveLocals,
     requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
-    assert_eq!(body.local_decls.len(), stored_locals.domain_size());
+    assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
     debug!("compute_storage_conflicts({:?})", body.span);
     debug!("always_live = {:?}", always_live_locals);
@@ -587,12 +615,12 @@ fn compute_storage_conflicts(
     // Locals that are always live or ones that need to be stored across
     // suspension points are not eligible for overlap.
     let mut ineligible_locals = always_live_locals.into_inner();
-    ineligible_locals.intersect(stored_locals);
+    ineligible_locals.intersect(saved_locals);
 
     // Compute the storage conflicts for all eligible locals.
     let mut visitor = StorageConflictVisitor {
         body,
-        stored_locals: &stored_locals,
+        saved_locals: &saved_locals,
         local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
     };
 
@@ -609,16 +637,14 @@ fn compute_storage_conflicts(
     // However, in practice these bitsets are not usually large. The layout code
     // also needs to keep track of how many conflicts each local has, so it's
     // simpler to keep it this way for now.
-    let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count());
-    for (idx_a, local_a) in stored_locals.iter().enumerate() {
-        let saved_local_a = GeneratorSavedLocal::new(idx_a);
+    let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count());
+    for (saved_local_a, local_a) in saved_locals.iter_enumerated() {
         if ineligible_locals.contains(local_a) {
             // Conflicts with everything.
             storage_conflicts.insert_all_into_row(saved_local_a);
         } else {
             // Keep overlap information only for stored locals.
-            for (idx_b, local_b) in stored_locals.iter().enumerate() {
-                let saved_local_b = GeneratorSavedLocal::new(idx_b);
+            for (saved_local_b, local_b) in saved_locals.iter_enumerated() {
                 if local_conflicts.contains(local_a, local_b) {
                     storage_conflicts.insert(saved_local_a, saved_local_b);
                 }
@@ -630,7 +656,7 @@ fn compute_storage_conflicts(
 
 struct StorageConflictVisitor<'mir, 'tcx, 's> {
     body: &'mir Body<'tcx>,
-    stored_locals: &'s BitSet<Local>,
+    saved_locals: &'s GeneratorSavedLocals,
     // FIXME(tmandry): Consider using sparse bitsets here once we have good
     // benchmarks for generators.
     local_conflicts: BitMatrix<Local, Local>,
@@ -666,7 +692,7 @@ fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
         }
 
         let mut eligible_storage_live = flow_state.clone();
-        eligible_storage_live.intersect(&self.stored_locals);
+        eligible_storage_live.intersect(&self.saved_locals);
 
         for local in eligible_storage_live.iter() {
             self.local_conflicts.union_row_with(&eligible_storage_live, local);
@@ -678,7 +704,7 @@ fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
     }
 }
 
-/// Validates the typeck view of the generator against the actual set of types retained between
+/// Validates the typeck view of the generator against the actual set of types saved between
 /// yield points.
 fn sanitize_witness<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -686,7 +712,7 @@ fn sanitize_witness<'tcx>(
     did: DefId,
     witness: Ty<'tcx>,
     upvars: &Vec<Ty<'tcx>>,
-    retained: &BitSet<Local>,
+    saved_locals: &GeneratorSavedLocals,
 ) {
     let allowed_upvars = tcx.erase_regions(upvars);
     let allowed = match witness.kind {
@@ -703,8 +729,8 @@ fn sanitize_witness<'tcx>(
     let param_env = tcx.param_env(did);
 
     for (local, decl) in body.local_decls.iter_enumerated() {
-        // Ignore locals which are internal or not retained between yields.
-        if !retained.contains(local) || decl.internal {
+        // Ignore locals which are internal or not saved between yields.
+        if !saved_locals.contains(local) || decl.internal {
             continue;
         }
         let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty);
@@ -724,39 +750,43 @@ fn sanitize_witness<'tcx>(
 }
 
 fn compute_layout<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    source: MirSource<'tcx>,
-    upvars: &Vec<Ty<'tcx>>,
-    interior: Ty<'tcx>,
-    always_live_locals: &storage::AlwaysLiveLocals,
-    movable: bool,
+    liveness: LivenessInfo,
     body: &mut Body<'tcx>,
 ) -> (
     FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
     GeneratorLayout<'tcx>,
     IndexVec<BasicBlock, Option<BitSet<Local>>>,
 ) {
-    // Use a liveness analysis to compute locals which are live across a suspension point
     let LivenessInfo {
-        live_locals,
+        saved_locals,
         live_locals_at_suspension_points,
+        source_info_at_suspension_points,
         storage_conflicts,
         storage_liveness,
-    } = locals_live_across_suspend_points(tcx, body, source, always_live_locals, movable);
-
-    sanitize_witness(tcx, body, source.def_id(), interior, upvars, &live_locals);
+    } = liveness;
 
     // Gather live local types and their indices.
     let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
     let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
-    for (idx, local) in live_locals.iter().enumerate() {
+    for (saved_local, local) in saved_locals.iter_enumerated() {
         locals.push(local);
         tys.push(body.local_decls[local].ty);
-        debug!("generator saved local {:?} => {:?}", GeneratorSavedLocal::from(idx), local);
+        debug!("generator saved local {:?} => {:?}", saved_local, local);
     }
 
     // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
+    // In debuginfo, these will correspond to the beginning (UNRESUMED) or end
+    // (RETURNED, POISONED) of the function.
     const RESERVED_VARIANTS: usize = 3;
+    let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span;
+    let mut variant_source_info: IndexVec<VariantIdx, SourceInfo> = [
+        SourceInfo::outermost(body_span.shrink_to_lo()),
+        SourceInfo::outermost(body_span.shrink_to_hi()),
+        SourceInfo::outermost(body_span.shrink_to_hi()),
+    ]
+    .iter()
+    .copied()
+    .collect();
 
     // Build the generator variant field list.
     // Create a map from local indices to generator struct indices.
@@ -775,11 +805,13 @@ fn compute_layout<'tcx>(
             remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx));
         }
         variant_fields.push(fields);
+        variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]);
     }
     debug!("generator variant_fields = {:?}", variant_fields);
     debug!("generator storage_conflicts = {:#?}", storage_conflicts);
 
-    let layout = GeneratorLayout { field_tys: tys, variant_fields, storage_conflicts };
+    let layout =
+        GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts };
 
     (remap, layout, storage_liveness)
 }
@@ -835,8 +867,8 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut
 
     for (block, block_data) in body.basic_blocks().iter_enumerated() {
         let (target, unwind, source_info) = match block_data.terminator() {
-            Terminator { source_info, kind: TerminatorKind::Drop { location, target, unwind } } => {
-                if let Some(local) = location.as_local() {
+            Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
+                if let Some(local) = place.as_local() {
                     if local == SELF_ARG {
                         (target, unwind, source_info)
                     } else {
@@ -1102,11 +1134,8 @@ fn create_generator_resume_function<'tcx>(
 fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
     let return_block = insert_term_block(body, TerminatorKind::Return);
 
-    let term = TerminatorKind::Drop {
-        location: Place::from(SELF_ARG),
-        target: return_block,
-        unwind: None,
-    };
+    let term =
+        TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None };
     let source_info = SourceInfo::outermost(body.span);
 
     // Create a block to destroy an unresumed generators. This can only destroy upvars.
@@ -1263,11 +1292,25 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
 
         let always_live_locals = storage::AlwaysLiveLocals::new(&body);
 
+        let liveness_info =
+            locals_live_across_suspend_points(tcx, body, source, &always_live_locals, movable);
+
+        sanitize_witness(tcx, body, def_id, interior, &upvars, &liveness_info.saved_locals);
+
+        if tcx.sess.opts.debugging_opts.validate_mir {
+            let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
+                assigned_local: None,
+                saved_locals: &liveness_info.saved_locals,
+                storage_conflicts: &liveness_info.storage_conflicts,
+            };
+
+            vis.visit_body(body);
+        }
+
         // Extract locals which are live across suspension point into `layout`
         // `remap` gives a mapping from local indices onto generator struct indices
         // `storage_liveness` tells us which locals have live storage at suspension points
-        let (remap, layout, storage_liveness) =
-            compute_layout(tcx, source, &upvars, interior, &always_live_locals, movable, body);
+        let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
 
         let can_return = can_return(tcx, body);
 
@@ -1318,3 +1361,134 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'
         create_generator_resume_function(tcx, transform, source, body, can_return);
     }
 }
+
+/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
+/// in the generator state machine but whose storage is not marked as conflicting
+///
+/// Validation needs to happen immediately *before* `TransformVisitor` is invoked, not after.
+///
+/// This condition would arise when the assignment is the last use of `_5` but the initial
+/// definition of `_4` if we weren't extra careful to mark all locals used inside a statement as
+/// conflicting. Non-conflicting generator saved locals may be stored at the same location within
+/// the generator state machine, which would result in ill-formed MIR: the left-hand and right-hand
+/// sides of an assignment may not alias. This caused a miscompilation in [#73137].
+///
+/// [#73137]: https://github.com/rust-lang/rust/issues/73137
+struct EnsureGeneratorFieldAssignmentsNeverAlias<'a> {
+    saved_locals: &'a GeneratorSavedLocals,
+    storage_conflicts: &'a BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
+    assigned_local: Option<GeneratorSavedLocal>,
+}
+
+impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
+    fn saved_local_for_direct_place(&self, place: Place<'_>) -> Option<GeneratorSavedLocal> {
+        if place.is_indirect() {
+            return None;
+        }
+
+        self.saved_locals.get(place.local)
+    }
+
+    fn check_assigned_place(&mut self, place: Place<'tcx>, f: impl FnOnce(&mut Self)) {
+        if let Some(assigned_local) = self.saved_local_for_direct_place(place) {
+            assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse");
+
+            self.assigned_local = Some(assigned_local);
+            f(self);
+            self.assigned_local = None;
+        }
+    }
+}
+
+impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
+    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
+        let lhs = match self.assigned_local {
+            Some(l) => l,
+            None => {
+                // This visitor only invokes `visit_place` for the right-hand side of an assignment
+                // and only after setting `self.assigned_local`. However, the default impl of
+                // `Visitor::super_body` may call `visit_place` with a `NonUseContext` for places
+                // with debuginfo. Ignore them here.
+                assert!(!context.is_use());
+                return;
+            }
+        };
+
+        let rhs = match self.saved_local_for_direct_place(*place) {
+            Some(l) => l,
+            None => return,
+        };
+
+        if !self.storage_conflicts.contains(lhs, rhs) {
+            bug!(
+                "Assignment between generator saved locals whose storage is not \
+                    marked as conflicting: {:?}: {:?} = {:?}",
+                location,
+                lhs,
+                rhs,
+            );
+        }
+    }
+
+    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+        match &statement.kind {
+            StatementKind::Assign(box (lhs, rhs)) => {
+                self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
+            }
+
+            // FIXME: Does `llvm_asm!` have any aliasing requirements?
+            StatementKind::LlvmInlineAsm(_) => {}
+
+            StatementKind::FakeRead(..)
+            | StatementKind::SetDiscriminant { .. }
+            | StatementKind::StorageLive(_)
+            | StatementKind::StorageDead(_)
+            | StatementKind::Retag(..)
+            | StatementKind::AscribeUserType(..)
+            | StatementKind::Nop => {}
+        }
+    }
+
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        // Checking for aliasing in terminators is probably overkill, but until we have actual
+        // semantics, we should be conservative here.
+        match &terminator.kind {
+            TerminatorKind::Call {
+                func,
+                args,
+                destination: Some((dest, _)),
+                cleanup: _,
+                from_hir_call: _,
+                fn_span: _,
+            } => {
+                self.check_assigned_place(*dest, |this| {
+                    this.visit_operand(func, location);
+                    for arg in args {
+                        this.visit_operand(arg, location);
+                    }
+                });
+            }
+
+            TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
+                self.check_assigned_place(*resume_arg, |this| this.visit_operand(value, location));
+            }
+
+            // FIXME: Does `asm!` have any aliasing requirements?
+            TerminatorKind::InlineAsm { .. } => {}
+
+            TerminatorKind::Call { .. }
+            | TerminatorKind::Goto { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Abort
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::Drop { .. }
+            | TerminatorKind::DropAndReplace { .. }
+            | TerminatorKind::Assert { .. }
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::FalseUnwind { .. } => {}
+        }
+    }
+}
index 47aa4fbf60c034cefff77cc49963c4b4803b8df2..068d055fa78f83311e3d5fdaf329824afb7048bf 100644 (file)
@@ -9,7 +9,6 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
-use rustc_session::config::Sanitizer;
 use rustc_target::spec::abi::Abi;
 
 use super::simplify::{remove_dead_blocks, CfgSimplifier};
@@ -232,24 +231,8 @@ fn should_inline(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> b
 
         // Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
         // since instrumentation might be enabled and performed on the caller.
-        match self.tcx.sess.opts.debugging_opts.sanitizer {
-            Some(Sanitizer::Address) => {
-                if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
-                    return false;
-                }
-            }
-            Some(Sanitizer::Memory) => {
-                if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
-                    return false;
-                }
-            }
-            Some(Sanitizer::Thread) => {
-                if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
-                    return false;
-                }
-            }
-            Some(Sanitizer::Leak) => {}
-            None => {}
+        if self.tcx.sess.opts.debugging_opts.sanitizer.intersects(codegen_fn_attrs.no_sanitize) {
+            return false;
         }
 
         let hinted = match codegen_fn_attrs.inline {
@@ -319,13 +302,13 @@ fn should_inline(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> b
             let term = blk.terminator();
             let mut is_drop = false;
             match term.kind {
-                TerminatorKind::Drop { ref location, target, unwind }
-                | TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => {
+                TerminatorKind::Drop { ref place, target, unwind }
+                | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } => {
                     is_drop = true;
                     work_list.push(target);
-                    // If the location doesn't actually need dropping, treat it like
+                    // If the place doesn't actually need dropping, treat it like
                     // a regular goto.
-                    let ty = location.ty(callee_body, tcx).subst(tcx, callsite.substs).ty;
+                    let ty = place.ty(callee_body, tcx).subst(tcx, callsite.substs).ty;
                     if ty.needs_drop(tcx, param_env) {
                         cost += CALL_PENALTY;
                         if let Some(unwind) = unwind {
@@ -731,14 +714,14 @@ fn visit_retag(&mut self, kind: &mut RetagKind, place: &mut Place<'tcx>, loc: Lo
         }
     }
 
-    fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, loc: Location) {
+    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) {
         // Don't try to modify the implicit `_0` access on return (`return` terminators are
         // replaced down below anyways).
-        if !matches!(kind, TerminatorKind::Return) {
-            self.super_terminator_kind(kind, loc);
+        if !matches!(terminator.kind, TerminatorKind::Return) {
+            self.super_terminator(terminator, loc);
         }
 
-        match *kind {
+        match terminator.kind {
             TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => bug!(),
             TerminatorKind::Goto { ref mut target } => {
                 *target = self.update_target(*target);
@@ -782,11 +765,11 @@ fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, loc: Locati
                 }
             }
             TerminatorKind::Return => {
-                *kind = TerminatorKind::Goto { target: self.return_block };
+                terminator.kind = TerminatorKind::Goto { target: self.return_block };
             }
             TerminatorKind::Resume => {
                 if let Some(tgt) = self.cleanup_block {
-                    *kind = TerminatorKind::Goto { target: tgt }
+                    terminator.kind = TerminatorKind::Goto { target: tgt }
                 }
             }
             TerminatorKind::Abort => {}
diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs
new file mode 100644 (file)
index 0000000..06b648a
--- /dev/null
@@ -0,0 +1,193 @@
+use crate::transform::{MirPass, MirSource};
+use crate::util::patch::MirPatch;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::lang_items;
+use rustc_middle::hir;
+use rustc_middle::ich::StableHashingContext;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::mir::{
+    self, traversal, BasicBlock, BasicBlockData, CoverageData, Operand, Place, SourceInfo,
+    StatementKind, Terminator, TerminatorKind, START_BLOCK,
+};
+use rustc_middle::ty;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ConstKind, FnDef};
+use rustc_span::def_id::DefId;
+use rustc_span::Span;
+
+/// Inserts call to count_code_region() as a placeholder to be replaced during code generation with
+/// the intrinsic llvm.instrprof.increment.
+pub struct InstrumentCoverage;
+
+/// The `query` provider for `CoverageData`, requested by `codegen_intrinsic_call()` when
+/// constructing the arguments for `llvm.instrprof.increment`.
+pub(crate) fn provide(providers: &mut Providers<'_>) {
+    providers.coverage_data = |tcx, def_id| {
+        let mir_body = tcx.optimized_mir(def_id);
+        // FIXME(richkadel): The current implementation assumes the MIR for the given DefId
+        // represents a single function. Validate and/or correct if inlining and/or monomorphization
+        // invalidates these assumptions.
+        let count_code_region_fn =
+            tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None);
+        let mut num_counters: u32 = 0;
+        // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected
+        // counters, with each counter having an index from `0..num_counters-1`. MIR optimization
+        // may split and duplicate some BasicBlock sequences. Simply counting the calls may not
+        // not work; but computing the num_counters by adding `1` to the highest index (for a given
+        // instrumented function) is valid.
+        for (_, data) in traversal::preorder(mir_body) {
+            if let Some(terminator) = &data.terminator {
+                if let TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
+                    &terminator.kind
+                {
+                    if let FnDef(called_fn_def_id, _) = func.literal.ty.kind {
+                        if called_fn_def_id == count_code_region_fn {
+                            if let Operand::Constant(constant) =
+                                args.get(0).expect("count_code_region has at least one arg")
+                            {
+                                if let ConstKind::Value(ConstValue::Scalar(value)) =
+                                    constant.literal.val
+                                {
+                                    let index = value
+                                        .to_u32()
+                                        .expect("count_code_region index at arg0 is u32");
+                                    num_counters = std::cmp::max(num_counters, index + 1);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        let hash = if num_counters > 0 { hash_mir_source(tcx, def_id) } else { 0 };
+        CoverageData { num_counters, hash }
+    };
+}
+
+struct Instrumentor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    num_counters: u32,
+}
+
+impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &mut mir::Body<'tcx>) {
+        if tcx.sess.opts.debugging_opts.instrument_coverage {
+            // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
+            // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
+            if src.promoted.is_none() {
+                debug!(
+                    "instrumenting {:?}, span: {}",
+                    src.def_id(),
+                    tcx.sess.source_map().span_to_string(mir_body.span)
+                );
+                Instrumentor::new(tcx).inject_counters(mir_body);
+            }
+        }
+    }
+}
+
+impl<'tcx> Instrumentor<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx, num_counters: 0 }
+    }
+
+    fn next_counter(&mut self) -> u32 {
+        let next = self.num_counters;
+        self.num_counters += 1;
+        next
+    }
+
+    fn inject_counters(&mut self, mir_body: &mut mir::Body<'tcx>) {
+        // FIXME(richkadel): As a first step, counters are only injected at the top of each
+        // function. The complete solution will inject counters at each conditional code branch.
+        let top_of_function = START_BLOCK;
+        let entire_function = mir_body.span;
+
+        self.inject_counter(mir_body, top_of_function, entire_function);
+    }
+
+    fn inject_counter(
+        &mut self,
+        mir_body: &mut mir::Body<'tcx>,
+        next_block: BasicBlock,
+        code_region: Span,
+    ) {
+        let injection_point = code_region.shrink_to_lo();
+
+        let count_code_region_fn = function_handle(
+            self.tcx,
+            self.tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None),
+            injection_point,
+        );
+        let counter_index = Operand::const_from_scalar(
+            self.tcx,
+            self.tcx.types.u32,
+            Scalar::from_u32(self.next_counter()),
+            injection_point,
+        );
+
+        let mut patch = MirPatch::new(mir_body);
+
+        let temp = patch.new_temp(self.tcx.mk_unit(), code_region);
+        let new_block = patch.new_block(placeholder_block(code_region));
+        patch.patch_terminator(
+            new_block,
+            TerminatorKind::Call {
+                func: count_code_region_fn,
+                args: vec![counter_index],
+                // new_block will swapped with the next_block, after applying patch
+                destination: Some((Place::from(temp), new_block)),
+                cleanup: None,
+                from_hir_call: false,
+                fn_span: injection_point,
+            },
+        );
+
+        patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp));
+        patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp));
+
+        patch.apply(mir_body);
+
+        // To insert the `new_block` in front of the first block in the counted branch (the
+        // `next_block`), just swap the indexes, leaving the rest of the graph unchanged.
+        mir_body.basic_blocks_mut().swap(next_block, new_block);
+    }
+}
+
+fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Operand<'tcx> {
+    let ret_ty = tcx.fn_sig(fn_def_id).output();
+    let ret_ty = ret_ty.no_bound_vars().unwrap();
+    let substs = tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(ret_ty)));
+    Operand::function_handle(tcx, fn_def_id, substs, span)
+}
+
+fn placeholder_block(span: Span) -> BasicBlockData<'tcx> {
+    BasicBlockData {
+        statements: vec![],
+        terminator: Some(Terminator {
+            source_info: SourceInfo::outermost(span),
+            // this gets overwritten by the counter Call
+            kind: TerminatorKind::Unreachable,
+        }),
+        is_cleanup: false,
+    }
+}
+
+fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> u64 {
+    let hir_node = tcx.hir().get_if_local(def_id).expect("DefId is local");
+    let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
+    let hir_body = tcx.hir().body(fn_body_id);
+    let mut hcx = tcx.create_no_span_stable_hashing_context();
+    hash(&mut hcx, &hir_body.value).to_smaller_hash()
+}
+
+fn hash(
+    hcx: &mut StableHashingContext<'tcx>,
+    node: &impl HashStable<StableHashingContext<'tcx>>,
+) -> Fingerprint {
+    let mut stable_hasher = StableHasher::new();
+    node.hash_stable(hcx, &mut stable_hasher);
+    stable_hasher.finish()
+}
index 4240b528a6124c2be08d34ddcbb8ad0b55466b19..8ca240d2c7da77eeffcc15137d77304ed3ba7706 100644 (file)
@@ -28,6 +28,7 @@
 pub mod generator;
 pub mod inline;
 pub mod instcombine;
+pub mod instrument_coverage;
 pub mod no_landing_pads;
 pub mod nrvo;
 pub mod promote_consts;
@@ -55,6 +56,7 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
         promoted_mir,
         ..*providers
     };
+    instrument_coverage::provide(providers);
 }
 
 fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
@@ -288,6 +290,10 @@ fn mir_validated(
             // What we need to run borrowck etc.
             &promote_pass,
             &simplify::SimplifyCfg::new("qualify-consts"),
+            // If the `instrument-coverage` option is enabled, analyze the CFG, identify each
+            // conditional branch, construct a coverage map to be passed to LLVM, and inject counters
+            // where needed.
+            &instrument_coverage::InstrumentCoverage,
         ]],
     );
 
index 3bffafa1b2f9ce27bc9ff50b652d7029936291f4..1d83733e4cd306bc88868a32f6195286df53327d 100644 (file)
@@ -34,10 +34,10 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
-    fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) {
-        if let Some(unwind) = kind.unwind_mut() {
+    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
+        if let Some(unwind) = terminator.kind.unwind_mut() {
             unwind.take();
         }
-        self.super_terminator_kind(kind, location);
+        self.super_terminator(terminator, location);
     }
 }
index e1311ccd3746fbb1b346c482ed1a7e9c17b01ab7..bd7ebaa01f81b236593e9dd9afcf27913cfef034 100644 (file)
@@ -147,7 +147,6 @@ struct Collector<'a, 'tcx> {
     ccx: &'a ConstCx<'a, 'tcx>,
     temps: IndexVec<Local, TempState>,
     candidates: Vec<Candidate>,
-    span: Span,
 }
 
 impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
@@ -216,10 +215,10 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         }
     }
 
-    fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) {
-        self.super_terminator_kind(kind, location);
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        self.super_terminator(terminator, location);
 
-        match *kind {
+        match terminator.kind {
             TerminatorKind::Call { ref func, .. } => {
                 if let ty::FnDef(def_id, _) = func.ty(self.ccx.body, self.ccx.tcx).kind {
                     let fn_sig = self.ccx.tcx.fn_sig(def_id);
@@ -254,10 +253,6 @@ fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Locat
             _ => {}
         }
     }
-
-    fn visit_source_info(&mut self, source_info: &SourceInfo) {
-        self.span = source_info.span;
-    }
 }
 
 pub fn collect_temps_and_candidates(
@@ -267,7 +262,6 @@ pub fn collect_temps_and_candidates(
     let mut collector = Collector {
         temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls),
         candidates: vec![],
-        span: ccx.body.span,
         ccx,
     };
     for (bb, data) in rpo {
@@ -347,7 +341,7 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
                                     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) {
+                                if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
                                     has_mut_interior = false;
                                     break;
                                 }
@@ -684,7 +678,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                         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) {
+                        if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
                             has_mut_interior = false;
                             break;
                         }
@@ -1148,7 +1142,6 @@ pub fn promote_candidates<'tcx>(
             0,
             vec![],
             body.span,
-            vec![],
             body.generator_kind,
         );
         promoted.ignore_interior_mut_in_const_validation = true;
@@ -1192,7 +1185,7 @@ pub fn promote_candidates<'tcx>(
             _ => true,
         });
         let terminator = block.terminator_mut();
-        if let TerminatorKind::Drop { location: place, target, .. } = &terminator.kind {
+        if let TerminatorKind::Drop { place, target, .. } = &terminator.kind {
             if let Some(index) = place.as_local() {
                 if promoted(index) {
                     terminator.kind = TerminatorKind::Goto { target: *target };
index 4c8fc49099b2af109b4e5b9278f2d59df278b9e7..5a3663384fb872f3424c7f146998a82d66aadedc 100644 (file)
@@ -239,12 +239,6 @@ fn check_statement(
             check_rvalue(tcx, body, def_id, rval, span)
         }
 
-        StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
-            if !feature_allowed(tcx, def_id, sym::const_if_match) =>
-        {
-            Err((span, "loops and conditional expressions are not stable in const fn".into()))
-        }
-
         StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, def_id, body),
 
         // just an assignment
@@ -349,16 +343,12 @@ fn check_terminator(
         | TerminatorKind::Resume
         | TerminatorKind::Unreachable => Ok(()),
 
-        TerminatorKind::Drop { location, .. } => check_place(tcx, *location, span, def_id, body),
-        TerminatorKind::DropAndReplace { location, value, .. } => {
-            check_place(tcx, *location, span, def_id, body)?;
+        TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, def_id, body),
+        TerminatorKind::DropAndReplace { place, value, .. } => {
+            check_place(tcx, *place, span, def_id, body)?;
             check_operand(tcx, value, span, def_id, body)
         }
 
-        TerminatorKind::SwitchInt { .. } if !feature_allowed(tcx, def_id, sym::const_if_match) => {
-            Err((span, "loops and conditional expressions are not stable in const fn".into()))
-        }
-
         TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
             check_operand(tcx, discr, span, def_id, body)
         }
index 8150c328316cbb3d9faceeb47064f5bb288d1f52..d3f486c815e6c438869442042f71d109d4b31de7 100644 (file)
@@ -7,9 +7,12 @@
         BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
         TerminatorKind,
     },
-    ty::{self, ParamEnv, TyCtxt},
+    ty::{
+        self,
+        relate::{Relate, RelateResult, TypeRelation},
+        ParamEnv, Ty, TyCtxt,
+    },
 };
-use rustc_span::def_id::DefId;
 
 #[derive(Copy, Clone, Debug)]
 enum EdgeKind {
@@ -24,15 +27,106 @@ pub struct Validator {
 
 impl<'tcx> MirPass<'tcx> for Validator {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let def_id = source.def_id();
-        let param_env = tcx.param_env(def_id);
-        TypeChecker { when: &self.when, def_id, body, tcx, param_env }.visit_body(body);
+        let param_env = tcx.param_env(source.def_id());
+        TypeChecker { when: &self.when, source, body, tcx, param_env }.visit_body(body);
     }
 }
 
+/// Returns whether the two types are equal up to lifetimes.
+/// All lifetimes, including higher-ranked ones, get ignored for this comparison.
+/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.)
+///
+/// The point of this function is to approximate "equal up to subtyping".  However,
+/// the approximation is incorrect as variance is ignored.
+pub fn equal_up_to_regions(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    src: Ty<'tcx>,
+    dest: Ty<'tcx>,
+) -> bool {
+    // Fast path.
+    if src == dest {
+        return true;
+    }
+
+    struct LifetimeIgnoreRelation<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    }
+
+    impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> {
+        fn tcx(&self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn param_env(&self) -> ty::ParamEnv<'tcx> {
+            self.param_env
+        }
+
+        fn tag(&self) -> &'static str {
+            "librustc_mir::transform::validate"
+        }
+
+        fn a_is_expected(&self) -> bool {
+            true
+        }
+
+        fn relate_with_variance<T: Relate<'tcx>>(
+            &mut self,
+            _: ty::Variance,
+            a: &T,
+            b: &T,
+        ) -> RelateResult<'tcx, T> {
+            // Ignore variance, require types to be exactly the same.
+            self.relate(a, b)
+        }
+
+        fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+            if a == b {
+                // Short-circuit.
+                return Ok(a);
+            }
+            ty::relate::super_relate_tys(self, a, b)
+        }
+
+        fn regions(
+            &mut self,
+            a: ty::Region<'tcx>,
+            _b: ty::Region<'tcx>,
+        ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+            // Ignore regions.
+            Ok(a)
+        }
+
+        fn consts(
+            &mut self,
+            a: &'tcx ty::Const<'tcx>,
+            b: &'tcx ty::Const<'tcx>,
+        ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+            ty::relate::super_relate_consts(self, a, b)
+        }
+
+        fn binders<T>(
+            &mut self,
+            a: &ty::Binder<T>,
+            b: &ty::Binder<T>,
+        ) -> RelateResult<'tcx, ty::Binder<T>>
+        where
+            T: Relate<'tcx>,
+        {
+            self.relate(a.skip_binder(), b.skip_binder())?;
+            Ok(a.clone())
+        }
+    }
+
+    // Instantiate and run relation.
+    let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env };
+    relator.relate(&src, &dest).is_ok()
+}
+
 struct TypeChecker<'a, 'tcx> {
     when: &'a str,
-    def_id: DefId,
+    source: MirSource<'tcx>,
     body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
@@ -47,7 +141,7 @@ fn fail(&self, location: Location, msg: impl AsRef<str>) {
             span,
             &format!(
                 "broken MIR in {:?} ({}) at {:?}:\n{}",
-                self.def_id,
+                self.source.instance,
                 self.when,
                 location,
                 msg.as_ref()
@@ -83,6 +177,28 @@ fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
             self.fail(location, format!("encountered jump to invalid basic block {:?}", bb))
         }
     }
+
+    /// Check if src can be assigned into dest.
+    /// This is not precise, it will accept some incorrect assignments.
+    fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
+        // Fast path before we normalize.
+        if src == dest {
+            // Equal types, all is good.
+            return true;
+        }
+        // Normalize projections and things like that.
+        // FIXME: We need to reveal_all, as some optimizations change types in ways
+        // that require unfolding opaque types.
+        let param_env = self.param_env.with_reveal_all();
+        let src = self.tcx.normalize_erasing_regions(param_env, src);
+        let dest = self.tcx.normalize_erasing_regions(param_env, dest);
+
+        // Type-changing assignments can happen when subtyping is used. While
+        // all normal lifetimes are erased, higher-ranked types with their
+        // late-bound lifetimes are still around and can lead to type
+        // differences. So we compare ignoring lifetimes.
+        equal_up_to_regions(self.tcx, param_env, src, dest)
+    }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
@@ -92,7 +208,7 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
             let ty = place.ty(&self.body.local_decls, self.tcx).ty;
             let span = self.body.source_info(location).span;
 
-            if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) {
+            if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) {
                 self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty));
             }
         }
@@ -101,20 +217,37 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
     }
 
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        // The sides of an assignment must not alias. Currently this just checks whether the places
-        // are identical.
-        if let StatementKind::Assign(box (dest, rvalue)) = &statement.kind {
-            match rvalue {
-                Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
-                    if dest == src {
-                        self.fail(
-                            location,
-                            "encountered `Assign` statement with overlapping memory",
-                        );
+        match &statement.kind {
+            StatementKind::Assign(box (dest, rvalue)) => {
+                // LHS and RHS of the assignment must have the same type.
+                let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
+                let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
+                if !self.mir_assign_valid_types(right_ty, left_ty) {
+                    self.fail(
+                        location,
+                        format!(
+                            "encountered `Assign` statement with incompatible types:\n\
+                            left-hand side has type: {}\n\
+                            right-hand side has type: {}",
+                            left_ty, right_ty,
+                        ),
+                    );
+                }
+                // The sides of an assignment must not alias. Currently this just checks whether the places
+                // are identical.
+                match rvalue {
+                    Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
+                        if dest == src {
+                            self.fail(
+                                location,
+                                "encountered `Assign` statement with overlapping memory",
+                            );
+                        }
                     }
+                    _ => {}
                 }
-                _ => {}
             }
+            _ => {}
         }
     }
 
@@ -123,7 +256,17 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             TerminatorKind::Goto { target } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
             }
-            TerminatorKind::SwitchInt { targets, values, .. } => {
+            TerminatorKind::SwitchInt { targets, values, switch_ty, discr } => {
+                let ty = discr.ty(&self.body.local_decls, self.tcx);
+                if ty != *switch_ty {
+                    self.fail(
+                        location,
+                        format!(
+                            "encountered `SwitchInt` terminator with type mismatch: {:?} != {:?}",
+                            ty, switch_ty,
+                        ),
+                    );
+                }
                 if targets.len() != values.len() + 1 {
                     self.fail(
                         location,
index a1345452ca9793e63de8a4e905f45e26de7feb04..5f55a812a4e0dc2cdfbc63c0022b17ff1627dd17 100644 (file)
@@ -238,7 +238,7 @@ pub fn elaborate_drop(&mut self, bb: BasicBlock) {
                 self.elaborator.patch().patch_terminator(
                     bb,
                     TerminatorKind::Drop {
-                        location: self.place,
+                        place: self.place,
                         target: self.succ,
                         unwind: self.unwind.into_option(),
                     },
@@ -723,7 +723,7 @@ fn drop_loop(
         self.elaborator.patch().patch_terminator(
             drop_block,
             TerminatorKind::Drop {
-                location: tcx.mk_place_deref(ptr),
+                place: tcx.mk_place_deref(ptr),
                 target: loop_block,
                 unwind: unwind.into_option(),
             },
@@ -1000,7 +1000,7 @@ fn unelaborated_free_block(
 
     fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
         let block =
-            TerminatorKind::Drop { location: self.place, target, unwind: unwind.into_option() };
+            TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() };
         self.new_block(unwind, block)
     }
 
index 02614044063fce04a66dac26add05396ba11b64c..db45481e4fd259acbd6114f6fb9768aba7727d7f 100644 (file)
@@ -131,7 +131,7 @@ fn dump_matched_mir_node<'tcx, F>(
         }
         writeln!(file, " {} {}", disambiguator, pass_name)?;
         if let Some(ref layout) = body.generator_layout {
-            writeln!(file, "// generator_layout = {:?}", layout)?;
+            writeln!(file, "/* generator_layout = {:#?} */", layout)?;
         }
         writeln!(file)?;
         extra_data(PassWhere::BeforeCFG, &mut file)?;
index 9a75f3afe8f082bccffe7e60cc0d895c4400f37d..5949fd1e22ce88dbc3effbb1487311d48e738e7f 100644 (file)
@@ -172,7 +172,7 @@ fn expr_as_call_operand(
 
             if !ty.is_sized(tcx.at(span), param_env) {
                 // !sized means !copy, so this is an unsized move
-                assert!(!ty.is_copy_modulo_regions(tcx, param_env, span));
+                assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
 
                 // As described above, detect the case where we are passing a value of unsized
                 // type, and that value is coming from the deref of a box.
index 9531ff0a9071fd29d289c49c14934a915880b621..e2217fdfac036becda935869bc0ff7c53cfba4d6 100644 (file)
@@ -87,7 +87,7 @@ fn expr_as_rvalue(
                         block,
                         Operand::Move(is_min),
                         false,
-                        AssertKind::OverflowNeg,
+                        AssertKind::OverflowNeg(arg.to_copy()),
                         expr_span,
                     );
                 }
@@ -288,7 +288,7 @@ fn expr_as_rvalue(
                 block,
                 source_info,
                 result_value,
-                Rvalue::CheckedBinaryOp(op, lhs, rhs),
+                Rvalue::CheckedBinaryOp(op, lhs.to_copy(), rhs.to_copy()),
             );
             let val_fld = Field::new(0);
             let of_fld = Field::new(1);
@@ -297,7 +297,7 @@ fn expr_as_rvalue(
             let val = tcx.mk_place_field(result_value, val_fld, ty);
             let of = tcx.mk_place_field(result_value, of_fld, bool_ty);
 
-            let err = AssertKind::Overflow(op);
+            let err = AssertKind::Overflow(op, lhs, rhs);
 
             block = self.assert(block, Operand::Move(of), false, err, span);
 
@@ -308,11 +308,11 @@ fn expr_as_rvalue(
                 // and 2. there are two possible failure cases, divide-by-zero and overflow.
 
                 let zero_err = if op == BinOp::Div {
-                    AssertKind::DivisionByZero
+                    AssertKind::DivisionByZero(lhs.to_copy())
                 } else {
-                    AssertKind::RemainderByZero
+                    AssertKind::RemainderByZero(lhs.to_copy())
                 };
-                let overflow_err = AssertKind::Overflow(op);
+                let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy());
 
                 // Check for / 0
                 let is_zero = self.temp(bool_ty, span);
index 2efe93d057b9be509b878ccd4ae640e27ca77971..e69f6b30abd5cb89c27c87597a1640bb98484300 100644 (file)
@@ -687,7 +687,7 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t
     let tcx = hir.tcx();
     let owner_id = tcx.hir().body_owner(body_id);
     let span = tcx.hir().span(owner_id);
-    let ty = tcx.types.err;
+    let ty = tcx.ty_error();
     let num_params = match hir.body_owner_kind {
         hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(),
         hir::BodyOwnerKind::Closure => {
@@ -778,7 +778,6 @@ fn finish(self) -> Body<'tcx> {
             self.arg_count,
             self.var_debug_info,
             self.fn_span,
-            self.hir.control_flow_destroyed(),
             self.generator_kind,
         )
     }
@@ -909,7 +908,9 @@ fn args_and_body(
                         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 {
-                            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind))))
+                            Some(box LocalInfo::User(ClearCrossCrate::Set(
+                                BindingForm::ImplicitSelf(*kind),
+                            )))
                         } else {
                             let binding_mode = ty::BindingMode::BindByValue(mutability);
                             Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
index 4daf567d7d451497682ce5618fa9e840bff8747b..b8df27094471ffcc87b4aa02cc39c026d8e5e400 100644 (file)
@@ -1037,7 +1037,7 @@ fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
         &mut self,
         block: BasicBlock,
         span: Span,
-        location: Place<'tcx>,
+        place: Place<'tcx>,
         value: Operand<'tcx>,
     ) -> BlockAnd<()> {
         let source_info = self.source_info(span);
@@ -1047,7 +1047,7 @@ fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
             block,
             source_info,
             TerminatorKind::DropAndReplace {
-                location,
+                place,
                 value,
                 target: next_target,
                 unwind: Some(diverge_target),
@@ -1158,7 +1158,7 @@ fn build_scope_drops<'tcx>(
                     block,
                     source_info,
                     TerminatorKind::Drop {
-                        location: local.into(),
+                        place: local.into(),
                         target: next,
                         unwind: Some(unwind_to),
                     },
@@ -1272,7 +1272,7 @@ fn build_diverge_scope<'tcx>(
                         block,
                         source_info(drop_data.span),
                         TerminatorKind::Drop {
-                            location: drop_data.local.into(),
+                            place: drop_data.local.into(),
                             target,
                             unwind: None,
                         },
index 703f6ef8dc41e91fcc74c4e3ff8256f477d37dc1..d36990684e03b46ae2c0a1907322609c32e7fce1 100644 (file)
@@ -255,20 +255,6 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             } 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(),
@@ -478,7 +464,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                                     );
 
                                     // Not a real fn, but we're not reaching codegen anyways...
-                                    ty = cx.tcx.types.err;
+                                    ty = cx.tcx.ty_error();
                                     InlineAsmOperand::SymFn {
                                         expr: Expr {
                                             ty,
index 46607fd07cdd731f69e4d4d0b96ef52fc207fcda..d8b3ac79e6b9c81c32db548e40ad53197898ca80 100644 (file)
@@ -47,9 +47,6 @@
 
     /// 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> {
@@ -89,13 +86,8 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
             body_owner: src_def_id.to_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> {
index 4a4de6c420bd80d86b472f26dcb40af7ef533e13..6ac5d41ec6135ee371554cf130f902a9389fe525 100644 (file)
@@ -800,7 +800,11 @@ fn variant_index_for_adt<'a>(
                 assert!(!adt.is_enum());
                 VariantIdx::new(0)
             }
-            ConstantValue(c) => cx.tcx.destructure_const(cx.param_env.and(c)).variant,
+            ConstantValue(c) => cx
+                .tcx
+                .destructure_const(cx.param_env.and(c))
+                .variant
+                .expect("destructed const of adt without variant id"),
             _ => bug!("bad constructor {:?} for adt {:?}", self, adt),
         }
     }
index 4d97a19f4086bdff11222171efcc635fe3874f4d..6fc447a87f57a7892bfe694846bc568495941f89 100644 (file)
@@ -579,7 +579,7 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec<Span>
 
 /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
 fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> bool {
-    !cx.tables.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env, span)
+    !cx.tables.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
 }
 
 /// Check the legality of legality of by-move bindings.
index 087c2c064cfaf3c57f4de92a1911f85905ff2b4b..6dd7e0871b45ef8bb9b319dd805fa873d3fdb951 100644 (file)
@@ -107,8 +107,15 @@ fn to_pat(
                 cv.ty, structural
             );
 
+            // This can occur because const qualification treats all associated constants as
+            // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them
+            // before it runs.
+            //
+            // FIXME(#73448): Find a way to bring const qualification into parity with
+            // `search_for_structural_match_violation`.
             if structural.is_none() && mir_structural_match_violation {
-                bug!("MIR const-checker found novel structural match violation");
+                warn!("MIR const-checker found novel structural match violation. See #73448.");
+                return inlined_const_as_pat;
             }
 
             if let Some(non_sm_ty) = structural {
@@ -268,7 +275,9 @@ fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
                 PatKind::Variant {
                     adt_def,
                     substs,
-                    variant_index: destructured.variant,
+                    variant_index: destructured
+                        .variant
+                        .expect("destructed const of adt without variant id"),
                     subpatterns: field_pats(destructured.fields),
                 }
             }
index e9aa7f597beb62cd03162d31046962a9572be237..5c30b2a448c6d3a6b6d86f6c161df8870355f1ef 100644 (file)
@@ -509,7 +509,7 @@ fn normalize_range_pattern_ends(
     fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
         let mut ty = self.tables.node_type(pat.hir_id);
 
-        if let ty::Error = ty.kind {
+        if let ty::Error(_) = ty.kind {
             // Avoid ICEs (e.g., #50577 and #50585).
             return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
         }
@@ -708,7 +708,7 @@ fn lower_variant_or_leaf(
                 if adt_def.is_enum() {
                     let substs = match ty.kind {
                         ty::Adt(_, substs) | ty::FnDef(_, substs) => substs,
-                        ty::Error => {
+                        ty::Error(_) => {
                             // Avoid ICE (#50585)
                             return PatKind::Wild;
                         }
@@ -1051,7 +1051,7 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
     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;
+        use rustc_apfloat::Float;
         return match ty.kind {
             ty::Float(ast::FloatTy::F32) => {
                 let l = ::rustc_apfloat::ieee::Single::from_bits(a);
index c6d65d56c93f0c85e91fe238c57e18ea8f6b6c28..b44d8eee462f09dfd5ba77974b13ec21f6b33f5d 100644 (file)
@@ -4,7 +4,7 @@
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
index 84b3335a0f628d7f865ed736c60de8ca06814369..5050f03bea9b2244a4224571e8e024b16b3109f1 100644 (file)
@@ -339,26 +339,43 @@ fn cook_lexer_literal(
             }
             rustc_lexer::LiteralKind::Byte { terminated } => {
                 if !terminated {
-                    self.fatal_span_(start + BytePos(1), suffix_start, "unterminated byte constant")
-                        .raise()
+                    self.sess
+                        .span_diagnostic
+                        .struct_span_fatal_with_code(
+                            self.mk_sp(start + BytePos(1), suffix_start),
+                            "unterminated byte constant",
+                            error_code!(E0763),
+                        )
+                        .emit();
+                    FatalError.raise();
                 }
                 (token::Byte, Mode::Byte, 2, 1) // b' '
             }
             rustc_lexer::LiteralKind::Str { terminated } => {
                 if !terminated {
-                    self.fatal_span_(start, suffix_start, "unterminated double quote string")
-                        .raise()
+                    self.sess
+                        .span_diagnostic
+                        .struct_span_fatal_with_code(
+                            self.mk_sp(start, suffix_start),
+                            "unterminated double quote string",
+                            error_code!(E0765),
+                        )
+                        .emit();
+                    FatalError.raise();
                 }
                 (token::Str, Mode::Str, 1, 1) // " "
             }
             rustc_lexer::LiteralKind::ByteStr { terminated } => {
                 if !terminated {
-                    self.fatal_span_(
-                        start + BytePos(1),
-                        suffix_start,
-                        "unterminated double quote byte string",
-                    )
-                    .raise()
+                    self.sess
+                        .span_diagnostic
+                        .struct_span_fatal_with_code(
+                            self.mk_sp(start + BytePos(1), suffix_start),
+                            "unterminated double quote byte string",
+                            error_code!(E0766),
+                        )
+                        .emit();
+                    FatalError.raise();
                 }
                 (token::ByteStr, Mode::ByteStr, 2, 1) // b" "
             }
index 803f14a2a228a6789915694fe27ee9ec38541dbb..b8cb146145b98c7771c8f1987e34ab3db3ca1213 100644 (file)
@@ -155,7 +155,7 @@ pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerA
     /// The delimiters or `=` are still put into the resulting token stream.
     pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
         let item = match self.token.kind {
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt, _) => match **nt {
                 Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()),
                 _ => None,
             },
@@ -254,7 +254,7 @@ pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrIt
     ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
         let nt_meta = match self.token.kind {
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt, _) => match **nt {
                 token::NtMeta(ref e) => Some(e.clone()),
                 _ => None,
             },
index 8792605c08d38a4092f15fdffe5c258f282af0b6..fc9ffc3092447e7941668e671f6f6702ffd2abc3 100644 (file)
@@ -961,7 +961,7 @@ pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
             self.bump();
             let sp = self.prev_token.span;
             self.struct_span_err(sp, &msg)
-                .span_suggestion(sp, "change this to `;`", ";".to_string(), appl)
+                .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
                 .emit();
             return Ok(());
         } else if self.look_ahead(0, |t| {
index 49a5c8801766c5521de580d6d8d170bbd52a81a2..2745b18a8cd51e44b13ced0f8f797653523bd3b1 100644 (file)
@@ -26,7 +26,7 @@
 /// `token::Interpolated` tokens.
 macro_rules! maybe_whole_expr {
     ($p:expr) => {
-        if let token::Interpolated(nt) = &$p.token.kind {
+        if let token::Interpolated(nt, _) = &$p.token.kind {
             match &**nt {
                 token::NtExpr(e) | token::NtLiteral(e) => {
                     let e = e.clone();
index 04b64d93c70dd2b2a4ff4ff5d79d0cf5da25eeb5..47794746126daa02579ccc7fc822c80d03d3110b 100644 (file)
@@ -47,21 +47,21 @@ fn parse_ty_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, Gen
     }
 
     fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
-        let lo = self.token.span;
+        let const_span = self.token.span;
 
         self.expect_keyword(kw::Const)?;
         let ident = self.parse_ident()?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
-        self.sess.gated_spans.gate(sym::const_generics, lo.to(self.prev_token.span));
+        self.sess.gated_spans.gate(sym::const_generics, const_span.to(self.prev_token.span));
 
         Ok(GenericParam {
             ident,
             id: ast::DUMMY_NODE_ID,
             attrs: preceding_attrs.into(),
             bounds: Vec::new(),
-            kind: GenericParamKind::Const { ty },
+            kind: GenericParamKind::Const { ty, kw_span: const_span },
             is_placeholder: false,
         })
     }
index 6f13d7994d17d257ec0fecb132f5d8baad5253cd..10df16964da084d32d6c64f590ed1406d08fd603 100644 (file)
@@ -1780,7 +1780,7 @@ fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
 
     fn is_named_param(&self) -> bool {
         let offset = match self.token.kind {
-            token::Interpolated(ref nt) => match **nt {
+            token::Interpolated(ref nt, _) => match **nt {
                 token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
                 _ => 0,
             },
index 47ae92c48bd88dce1277adb8d348326d69646aba..04074479a21a4e22c333b1339a96246f4c792312 100644 (file)
@@ -54,7 +54,7 @@ enum BlockMode {
 #[macro_export]
 macro_rules! maybe_whole {
     ($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
-        if let token::Interpolated(nt) = &$p.token.kind {
+        if let token::Interpolated(nt, _) = &$p.token.kind {
             if let token::$constructor(x) = &**nt {
                 let $x = x.clone();
                 $p.bump();
@@ -69,7 +69,7 @@ macro_rules! maybe_whole {
 macro_rules! maybe_recover_from_interpolated_ty_qpath {
     ($self: expr, $allow_qpath_recovery: expr) => {
         if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) {
-            if let token::Interpolated(nt) = &$self.token.kind {
+            if let token::Interpolated(nt, _) = &$self.token.kind {
                 if let token::NtTy(ty) = &**nt {
                     let ty = ty.clone();
                     $self.bump();
@@ -922,7 +922,7 @@ fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs
                 if self.eat(&token::Eq) {
                     let eq_span = self.prev_token.span;
                     let mut is_interpolated_expr = false;
-                    if let token::Interpolated(nt) = &self.token.kind {
+                    if let token::Interpolated(nt, _) = &self.token.kind {
                         if let token::NtExpr(..) = **nt {
                             is_interpolated_expr = true;
                         }
@@ -1151,7 +1151,7 @@ fn parse_abi(&mut self) -> Option<StrLit> {
     /// This restriction shouldn't be an issue in practice,
     /// since this function is used to record the tokens for
     /// a parsed AST item, which always has matching delimiters.
-    fn collect_tokens<R>(
+    pub fn collect_tokens<R>(
         &mut self,
         f: impl FnOnce(&mut Self) -> PResult<'a, R>,
     ) -> PResult<'a, (R, TokenStream)> {
index 6603d0afc0248d6cf52ad3d147c3cf8a05d95d7d..742183d36973562b4d082a33b20239325a9f5bb7 100644 (file)
@@ -515,7 +515,7 @@ fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
         self.recover_additional_muts();
 
         // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
-        if let token::Interpolated(ref nt) = self.token.kind {
+        if let token::Interpolated(ref nt, _) = self.token.kind {
             if let token::NtPat(_) = **nt {
                 self.expected_ident_found().emit();
             }
index 849193151c33567dbd15eef31b8b80fbd5a3495a..53f32b7c800bdaf74af35dfcba588571e1be4f16 100644 (file)
@@ -216,8 +216,28 @@ fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
     }
 
     /// Parses the RHS of a local variable declaration (e.g., '= 14;').
-    fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> {
-        if self.eat(&token::Eq) || skip_eq { Ok(Some(self.parse_expr()?)) } else { Ok(None) }
+    fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> {
+        let eq_consumed = match self.token.kind {
+            token::BinOpEq(..) => {
+                // Recover `let x <op>= 1` as `let x = 1`
+                self.struct_span_err(
+                    self.token.span,
+                    "can't reassign to an uninitialized variable",
+                )
+                .span_suggestion_short(
+                    self.token.span,
+                    "initialize the variable",
+                    "=".to_string(),
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+                self.bump();
+                true
+            }
+            _ => self.eat(&token::Eq),
+        };
+
+        Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None })
     }
 
     /// Parses a block. No inner attributes are allowed.
index 23bf7b35419db9767d20d7340bd20320dc124ca1..a5b5a1090cbfd5052e0d6beb64b0b79581a87698 100644 (file)
@@ -178,7 +178,7 @@ pub struct Parser<'a> {
     /// Error messages accumulated during parsing
     pub errors: Vec<ParseError>,
     /// Current position of implicit positional argument pointer
-    curarg: usize,
+    pub curarg: usize,
     /// `Some(raw count)` when the string is "raw", used to position spans correctly
     style: Option<usize>,
     /// Start and end byte offset of every successfully parsed argument
@@ -243,11 +243,13 @@ fn next(&mut self) -> Option<Piece<'a>> {
                 _ => Some(String(self.string(pos))),
             }
         } else {
-            if self.is_literal && self.cur_line_start != self.input.len() {
+            if self.is_literal {
                 let start = self.to_span_index(self.cur_line_start);
                 let end = self.to_span_index(self.input.len());
-                self.line_spans.push(start.to(end));
-                self.cur_line_start = self.input.len();
+                let span = start.to(end);
+                if self.line_spans.last() != Some(&span) {
+                    self.line_spans.push(span);
+                }
             }
             None
         }
index 80681c143750fc7e8fe091158cfc49a891aa7c35..ef84f251390e6045efcf82bfa15ec9935feca066 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_ast::attr;
 use rustc_errors::struct_span_err;
 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_hir::{self, HirId, Item, ItemKind, TraitItem};
 use rustc_hir::{MethodKind, Target};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
-fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
+pub(crate) fn target_from_impl_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_item: &hir::ImplItem<'_>,
+) -> Target {
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
@@ -461,7 +464,7 @@ fn is_c_like_enum(item: &Item<'_>) -> bool {
     }
 }
 
-fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir()
         .visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
 }
index 94f9c619a3a26493a5ad649406a1a723bb4b4861..738754557d84cfba8aaf5bc6154864e861d70754 100644 (file)
@@ -7,9 +7,10 @@
 //! 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_attr as attr;
 use rustc_errors::struct_span_err;
 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_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
@@ -23,7 +24,6 @@
 enum NonConstExpr {
     Loop(hir::LoopSource),
     Match(hir::MatchSource),
-    OrPattern,
 }
 
 impl NonConstExpr {
@@ -31,7 +31,6 @@ fn name(self) -> String {
         match self {
             Self::Loop(src) => format!("`{}`", src.name()),
             Self::Match(src) => format!("`{}`", src.name()),
-            Self::OrPattern => "or-pattern".to_string(),
         }
     }
 
@@ -40,29 +39,25 @@ fn required_feature_gates(self) -> Option<&'static [Symbol]> {
         use hir::MatchSource::*;
 
         let gates: &[_] = match self {
-            Self::Match(Normal)
-            | Self::Match(IfDesugar { .. })
-            | Self::Match(IfLetDesugar { .. })
-            | Self::OrPattern => &[sym::const_if_match],
-
-            Self::Loop(Loop) => &[sym::const_loop],
-
-            Self::Loop(While)
-            | Self::Loop(WhileLet)
-            | Self::Match(WhileDesugar | WhileLetDesugar) => {
-                &[sym::const_loop, sym::const_if_match]
+            // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
+            // so they are not yet allowed.
+            // Likewise, `?` desugars to a call to `Try::into_result`.
+            Self::Loop(ForLoop) | Self::Match(ForLoopDesugar | TryDesugar | AwaitDesugar) => {
+                return None;
             }
 
-            // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
-            // so they are not yet allowed with `#![feature(const_loop)]`.
-            _ => return None,
+            // All other expressions are allowed.
+            Self::Loop(Loop | While | WhileLet)
+            | Self::Match(
+                WhileDesugar | WhileLetDesugar | Normal | IfDesugar { .. } | IfLetDesugar { .. },
+            ) => &[],
         };
 
         Some(gates)
     }
 }
 
-fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let mut vis = CheckConstVisitor::new(tcx);
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
 }
@@ -75,35 +70,63 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
 struct CheckConstVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     const_kind: Option<hir::ConstContext>,
+    def_id: Option<LocalDefId>,
 }
 
 impl<'tcx> CheckConstVisitor<'tcx> {
     fn new(tcx: TyCtxt<'tcx>) -> Self {
-        CheckConstVisitor { tcx, const_kind: None }
+        CheckConstVisitor { tcx, const_kind: None, def_id: None }
     }
 
     /// Emits an error when an unsupported expression is found in a const context.
     fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
-        let features = self.tcx.features();
+        let Self { tcx, def_id, const_kind } = *self;
+
+        let features = tcx.features();
         let required_gates = expr.required_feature_gates();
+
+        let is_feature_allowed = |feature_gate| {
+            // 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 `def_id` is `None`, we don't need to consider stability attributes.
+            let def_id = match def_id {
+                Some(x) => x.to_def_id(),
+                None => return true,
+            };
+
+            // 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))
+        };
+
         match required_gates {
             // Don't emit an error if the user has enabled the requisite feature gates.
-            Some(gates) if gates.iter().all(|&g| features.enabled(g)) => return,
+            Some(gates) if gates.iter().copied().all(is_feature_allowed) => return,
 
             // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
             // corresponding feature gate. This encourages nightly users to use feature gates when
             // possible.
-            None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
-                self.tcx.sess.span_warn(span, "skipping const checks");
+            None if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
+                tcx.sess.span_warn(span, "skipping const checks");
                 return;
             }
 
             _ => {}
         }
 
-        let const_kind = self
-            .const_kind
-            .expect("`const_check_violated` may only be called inside a const context");
+        let const_kind =
+            const_kind.expect("`const_check_violated` may only be called inside a const context");
 
         let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
 
@@ -112,21 +135,10 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
             required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
 
         match missing_gates.as_slice() {
-            &[] => 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.
-            &[gate @ sym::const_if_match] if required_gates.contains(&sym::const_loop) => {
-                feature_err(&self.tcx.sess.parse_sess, gate, span, &msg)
-                    .note(
-                        "`#![feature(const_loop)]` alone is not sufficient, \
-                           since this loop expression contains an implicit conditional",
-                    )
-                    .emit();
-            }
+            &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
 
             &[missing_primary, ref missing_secondary @ ..] => {
-                let mut err = feature_err(&self.tcx.sess.parse_sess, missing_primary, span, &msg);
+                let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg);
 
                 // If multiple feature gates would be required to enable this expression, include
                 // them as help messages. Don't emit a separate error for each missing feature gate.
@@ -149,10 +161,18 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
     }
 
     /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
-    fn recurse_into(&mut self, kind: Option<hir::ConstContext>, f: impl FnOnce(&mut Self)) {
+    fn recurse_into(
+        &mut self,
+        kind: Option<hir::ConstContext>,
+        def_id: Option<LocalDefId>,
+        f: impl FnOnce(&mut Self),
+    ) {
+        let parent_def_id = self.def_id;
         let parent_kind = self.const_kind;
+        self.def_id = def_id;
         self.const_kind = kind;
         f(self);
+        self.def_id = parent_def_id;
         self.const_kind = parent_kind;
     }
 }
@@ -166,22 +186,13 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
         let kind = Some(hir::ConstContext::Const);
-        self.recurse_into(kind, |this| intravisit::walk_anon_const(this, anon));
+        self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
     }
 
     fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
         let owner = self.tcx.hir().body_owner_def_id(body.id());
         let kind = self.tcx.hir().body_const_context(owner);
-        self.recurse_into(kind, |this| intravisit::walk_body(this, body));
-    }
-
-    fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
-        if self.const_kind.is_some() {
-            if let hir::PatKind::Or { .. } = p.kind {
-                self.const_check_violated(NonConstExpr::OrPattern, p.span);
-            }
-        }
-        intravisit::walk_pat(self, p)
+        self.recurse_into(kind, Some(owner), |this| intravisit::walk_body(this, body));
     }
 
     fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
index 80dfcd9c2417aa708a09d3e77e1310e03b51fed9..2edbc29b7efb6fcb92936d694547a39ece519ca0 100644 (file)
@@ -17,7 +17,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
         let local_def_id = hir_map.local_def_id(*module_id);
         hir_map.visit_item_likes_in_module(
-            local_def_id.to_def_id(),
+            local_def_id,
             &mut OuterVisitor { hir_map, errors: &errors },
         );
     });
index e2bfcf18edb1731fe219a58b2d22bac0f7c12f48..683039df15ac6d0de0f47898f577befc37df68ea 100644 (file)
@@ -2,7 +2,7 @@
 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::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
@@ -14,7 +14,7 @@
 use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
 use rustc_target::spec::abi::Abi::RustIntrinsic;
 
-fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
 }
 
@@ -150,7 +150,7 @@ fn check_asm_operand_type(
             _ => unreachable!(),
         };
         let asm_ty = match ty.kind {
-            ty::Never | ty::Error => return None,
+            ty::Never | ty::Error(_) => return None,
             ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
             ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
             ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
@@ -167,7 +167,7 @@ fn check_asm_operand_type(
                 let fields = &adt.non_enum_variant().fields;
                 let elem_ty = fields[0].ty(self.tcx, substs);
                 match elem_ty.kind {
-                    ty::Never | ty::Error => return None,
+                    ty::Never | ty::Error(_) => return None,
                     ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => {
                         Some(InlineAsmType::VecI8(fields.len() as u64))
                     }
@@ -214,7 +214,7 @@ fn check_asm_operand_type(
 
         // Check that the type implements Copy. The only case where this can
         // possibly fail is for SIMD types which don't #[derive(Copy)].
-        if !ty.is_copy_modulo_regions(self.tcx, self.param_env, DUMMY_SP) {
+        if !ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), self.param_env) {
             let msg = "arguments for inline assembly must be copyable";
             let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
             err.note(&format!("`{}` does not implement the Copy trait", ty));
index 779fb8039d15713b08bc38b06f285c29500c7f5a..0be37cb096038a7ddb6a6db6cc9c3b8c72fec94c 100644 (file)
@@ -7,17 +7,19 @@
 //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
 //! * Functions called by the compiler itself.
 
+use crate::check_attr::target_from_impl_item;
 use crate::weak_lang_items;
 
 use rustc_middle::middle::cstore::ExternCrate;
 use rustc_middle::ty::TyCtxt;
 
+use rustc_ast::ast::Attribute;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items::{extract, ITEM_REFS};
-use rustc_hir::{LangItem, LanguageItems, Target};
+use rustc_hir::{HirId, LangItem, LanguageItems, Target};
 
 use rustc_middle::ty::query::Providers;
 
@@ -28,12 +30,37 @@ struct LanguageItemCollector<'tcx> {
 
 impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        if let Some((value, span)) = extract(&item.attrs) {
-            let actual_target = Target::from_item(item);
+        self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs)
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
+        self.check_for_lang(
+            Target::from_trait_item(trait_item),
+            trait_item.hir_id,
+            trait_item.attrs,
+        )
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
+        self.check_for_lang(
+            target_from_impl_item(self.tcx, impl_item),
+            impl_item.hir_id,
+            impl_item.attrs,
+        )
+    }
+}
+
+impl LanguageItemCollector<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
+        LanguageItemCollector { tcx, items: LanguageItems::new() }
+    }
+
+    fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
+        if let Some((value, span)) = extract(&attrs) {
             match ITEM_REFS.get(&*value.as_str()).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
-                    let def_id = self.tcx.hir().local_def_id(item.hir_id);
+                    let def_id = self.tcx.hir().local_def_id(hir_id);
                     self.collect_item(item_index, def_id.to_def_id());
                 }
                 // Known lang item with attribute on incorrect target.
@@ -71,25 +98,12 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
         }
     }
 
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {
-        // At present, lang items are always items, not trait items.
-    }
-
-    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
-        // At present, lang items are always items, not impl items.
-    }
-}
-
-impl LanguageItemCollector<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
-        LanguageItemCollector { tcx, items: LanguageItems::new() }
-    }
-
     fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
         // Check for duplicates.
         if let Some(original_def_id) = self.items.items[item_index] {
             if original_def_id != item_def_id {
-                let name = LangItem::from_u32(item_index as u32).unwrap().name();
+                let lang_item = LangItem::from_u32(item_index as u32).unwrap();
+                let name = lang_item.name();
                 let mut err = match self.tcx.hir().span_if_local(item_def_id) {
                     Some(span) => struct_span_err!(
                         self.tcx.sess,
@@ -139,6 +153,9 @@ fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
 
         // Matched.
         self.items.items[item_index] = Some(item_def_id);
+        if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
+            self.items.groups[group as usize].push(item_def_id);
+        }
     }
 }
 
index ff5dabd5418c9187d99bed46609d97eb8e95e983..798c6b8925bbf6d03c992507d955c3633a8d9a06 100644 (file)
@@ -89,7 +89,7 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::*;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node};
 use rustc_middle::hir::map::Map;
@@ -172,7 +172,7 @@ fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
     }
 }
 
-fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
         &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
@@ -248,7 +248,7 @@ enum VarKind {
 
 struct IrMaps<'tcx> {
     tcx: TyCtxt<'tcx>,
-    body_owner: DefId,
+    body_owner: LocalDefId,
     num_live_nodes: usize,
     num_vars: usize,
     live_node_map: HirIdMap<LiveNode>,
@@ -259,7 +259,7 @@ struct IrMaps<'tcx> {
 }
 
 impl IrMaps<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, body_owner: DefId) -> IrMaps<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, body_owner: LocalDefId) -> IrMaps<'tcx> {
         IrMaps {
             tcx,
             body_owner,
@@ -349,7 +349,7 @@ fn visit_fn<'tcx>(
 
     // swap in a new set of IR maps for this function body:
     let def_id = ir.tcx.hir().local_def_id(id);
-    let mut fn_maps = IrMaps::new(ir.tcx, def_id.to_def_id());
+    let mut fn_maps = IrMaps::new(ir.tcx, def_id);
 
     // Don't run unused pass for #[derive()]
     if let FnKind::Method(..) = fk {
@@ -484,7 +484,7 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
             }
             ir.set_captures(expr.hir_id, call_caps);
             let old_body_owner = ir.body_owner;
-            ir.body_owner = closure_def_id.to_def_id();
+            ir.body_owner = closure_def_id;
             intravisit::walk_expr(ir, expr);
             ir.body_owner = old_body_owner;
         }
@@ -937,7 +937,7 @@ fn compute(
             for (&var_hir_id, upvar) in upvars.iter().rev() {
                 let upvar_id = ty::UpvarId {
                     var_path: ty::UpvarPath { hir_id: var_hir_id },
-                    closure_expr_id: self.ir.body_owner.expect_local(),
+                    closure_expr_id: self.ir.body_owner,
                 };
                 match self.tables.upvar_capture(upvar_id) {
                     ty::UpvarCapture::ByRef(_) => {
@@ -1614,7 +1614,7 @@ fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
             let var = self.variable(var_hir_id, upvar.span);
             let upvar_id = ty::UpvarId {
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
-                closure_expr_id: self.ir.body_owner.expect_local(),
+                closure_expr_id: self.ir.body_owner,
             };
             match self.tables.upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue => {}
index 767a6909d31d44f26b53a5d54dc933ae5b660be5..d7012d4d711df89de5d8e08cd4fc7a96ddd78636 100644 (file)
@@ -2,7 +2,7 @@
 
 use rustc_errors::{struct_span_err, Applicability};
 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_hir::{Destination, Movability, Node};
 use rustc_middle::hir::map::Map;
@@ -29,7 +29,7 @@ struct CheckLoopVisitor<'a, 'hir> {
     cx: Context,
 }
 
-fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
         &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(),
index 054748c09fc44b4a90853932568f5aeef4d24dc1..ad512c63352f1a062c8bf0daeee2cb5a216754f2 100644 (file)
@@ -7,7 +7,7 @@
 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::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Generics, HirId, Item, StructField, Variant};
 use rustc_middle::hir::map::Map;
@@ -472,7 +472,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
 
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
-fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
 }
 
index 96ec23692df512dc799b0c5d700b102f91f17d26..f2f07b5d4fb26fba2d7a8acf877d2136f734b2ff 100644 (file)
@@ -5,10 +5,12 @@
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::lang_items;
+use rustc_hir::lang_items::ITEM_REFS;
 use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
 use rustc_middle::middle::lang_items::whitelisted;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
+use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
@@ -70,11 +72,21 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
 }
 
 impl<'a, 'tcx> Context<'a, 'tcx> {
-    fn register(&mut self, name: Symbol, span: Span) {
+    fn register(&mut self, name: Symbol, span: Span, hir_id: hir::HirId) {
         if let Some(&item) = WEAK_ITEMS_REFS.get(&name) {
             if self.items.require(item).is_err() {
                 self.items.missing.push(item);
             }
+        } else if name == sym::count_code_region {
+            // `core::intrinsics::code_count_region()` is (currently) the only `extern` lang item
+            // that is never actually linked. It is not a `weak_lang_item` that can be registered
+            // when used, and should be registered here instead.
+            if let Some((item_index, _)) = ITEM_REFS.get(&*name.as_str()).cloned() {
+                if self.items.items[item_index].is_none() {
+                    let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
+                    self.items.items[item_index] = Some(item_def_id);
+                }
+            }
         } else {
             struct_span_err!(self.tcx.sess, span, E0264, "unknown external lang item: `{}`", name)
                 .emit();
@@ -91,7 +103,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 
     fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
         if let Some((lang_item, _)) = hir::lang_items::extract(&i.attrs) {
-            self.register(lang_item, i.span);
+            self.register(lang_item, i.span, i.hir_id);
         }
         intravisit::walk_foreign_item(self, i)
     }
index 3c1b56a9ef40ae4986ee48881bf89cbf2813578b..9e6e7ea962bc378f21f3dc34aab3a50e22cdb68b 100644 (file)
@@ -220,7 +220,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
             | ty::Ref(..)
             | ty::FnPtr(..)
             | ty::Param(..)
-            | ty::Error
+            | ty::Error(_)
             | ty::GeneratorWitness(..) => {}
             ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
                 bug!("unexpected type: {:?}", ty)
index 12450a4ccd3ebc3937871f5b8cb3527644ece231..74a54176774ca65e29a8d060038a065e857dd727 100644 (file)
@@ -1,12 +1,11 @@
 #![feature(bool_to_option)]
 #![feature(const_fn)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_panic)]
 #![feature(core_intrinsics)]
 #![feature(hash_raw_entry)]
 #![feature(min_specialization)]
 #![feature(stmt_expr_attributes)]
-#![feature(vec_remove_item)]
 
 #[macro_use]
 extern crate log;
index 5150b278a77222549a9607970ba86625f39eb4ec..190312bb33001f9b673cf0abcace3b5db6cf4a96 100644 (file)
@@ -452,7 +452,9 @@ fn remove_cycle<CTX: QueryContext>(
 
         // Remove the queries in our cycle from the list of jobs to look at
         for r in &stack {
-            jobs.remove_item(&r.1);
+            if let Some(pos) = jobs.iter().position(|j| j == &r.1) {
+                jobs.remove(pos);
+            }
         }
 
         // Find the queries in the cycle which are
index fa5c557b5d9c647a94d6a6a267410c160d2f4b9d..6f6104c3d6932f5783edb6156444b713bc368a4f 100644 (file)
@@ -24,6 +24,7 @@ rustc_errors = { path = "../librustc_errors" }
 rustc_expand = { path = "../librustc_expand" }
 rustc_feature = { path = "../librustc_feature" }
 rustc_hir = { path = "../librustc_hir" }
+rustc_index = { path = "../librustc_index" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_session = { path = "../librustc_session" }
 rustc_span = { path = "../librustc_span" }
index e633bd1843e85d292411a45c65dbb0a5220d12f0..a92d451dfd006e2298c2a5e69a04f990ac44d6cc 100644 (file)
@@ -19,6 +19,7 @@
 use rustc_ast::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind};
 use rustc_ast::token::{self, Token};
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_attr as attr;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability};
@@ -171,7 +172,7 @@ impl<'a> Resolver<'a> {
         fragment: &AstFragment,
         parent_scope: ParentScope<'a>,
     ) -> MacroRulesScope<'a> {
-        collect_definitions(&mut self.definitions, fragment, parent_scope.expansion);
+        collect_definitions(self, fragment, parent_scope.expansion);
         let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
         fragment.visit_with(&mut visitor);
         visitor.parent_scope.macro_rules
@@ -485,6 +486,7 @@ fn build_reduced_graph_for_use_tree(
                             module_path.push(Segment {
                                 ident: Ident { name: kw::PathRoot, span: source.ident.span },
                                 id: Some(self.r.next_node_id()),
+                                has_generic_args: false,
                             });
                             source.ident.name = crate_name;
                         }
@@ -646,9 +648,9 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                 } else if orig_name == Some(kw::SelfLower) {
                     self.r.graph_root
                 } else {
-                    let def_id = self.r.definitions.local_def_id(item.id);
+                    let def_id = self.r.local_def_id(item.id);
                     let crate_id =
-                        self.r.crate_loader.process_extern_crate(item, &self.r.definitions);
+                        self.r.crate_loader.process_extern_crate(item, &self.r.definitions, def_id);
                     self.r.extern_crate_map.insert(def_id, crate_id);
                     self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
                 };
@@ -703,7 +705,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
 
             ItemKind::Mod(..) => {
-                let def_id = self.r.definitions.local_def_id(item.id);
+                let def_id = self.r.local_def_id(item.id);
                 let module_kind = ModuleKind::Def(DefKind::Mod, def_id.to_def_id(), ident.name);
                 let module = self.r.arenas.alloc_module(ModuleData {
                     no_implicit_prelude: parent.no_implicit_prelude || {
@@ -726,18 +728,15 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
 
             // These items live in the value namespace.
             ItemKind::Static(..) => {
-                let res =
-                    Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Const(..) => {
-                let res =
-                    Res::Def(DefKind::Const, self.r.definitions.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Const, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Fn(..) => {
-                let res =
-                    Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
 
                 // Functions introducing procedural macros reserve a slot
@@ -747,15 +746,12 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
 
             // These items live in the type namespace.
             ItemKind::TyAlias(..) => {
-                let res = Res::Def(
-                    DefKind::TyAlias,
-                    self.r.definitions.local_def_id(item.id).to_def_id(),
-                );
+                let res = Res::Def(DefKind::TyAlias, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             ItemKind::Enum(_, _) => {
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
                 self.r.variant_vis.insert(def_id, vis);
                 let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name);
                 let module = self.r.new_module(
@@ -770,17 +766,14 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             }
 
             ItemKind::TraitAlias(..) => {
-                let res = Res::Def(
-                    DefKind::TraitAlias,
-                    self.r.definitions.local_def_id(item.id).to_def_id(),
-                );
+                let res = Res::Def(DefKind::TraitAlias, self.r.local_def_id(item.id).to_def_id());
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             // These items live in both the type and value namespaces.
             ItemKind::Struct(ref vdata, _) => {
                 // Define a name in the type namespace.
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
                 let res = Res::Def(DefKind::Struct, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
@@ -813,7 +806,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                     }
                     let ctor_res = Res::Def(
                         DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
-                        self.r.definitions.local_def_id(ctor_node_id).to_def_id(),
+                        self.r.local_def_id(ctor_node_id).to_def_id(),
                     );
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis));
@@ -821,7 +814,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             }
 
             ItemKind::Union(ref vdata, _) => {
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
                 let res = Res::Def(DefKind::Union, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
@@ -830,7 +823,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
             }
 
             ItemKind::Trait(..) => {
-                let def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+                let def_id = self.r.local_def_id(item.id).to_def_id();
 
                 // Add all the items within to a new module.
                 let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
@@ -855,18 +848,15 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
     /// Constructs the reduced graph for one foreign item.
     fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
         let (res, ns) = match item.kind {
-            ForeignItemKind::Fn(..) => (
-                Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id).to_def_id()),
-                ValueNS,
-            ),
-            ForeignItemKind::Static(..) => (
-                Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id).to_def_id()),
-                ValueNS,
-            ),
-            ForeignItemKind::TyAlias(..) => (
-                Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id).to_def_id()),
-                TypeNS,
-            ),
+            ForeignItemKind::Fn(..) => {
+                (Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id()), ValueNS)
+            }
+            ForeignItemKind::Static(..) => {
+                (Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id()), ValueNS)
+            }
+            ForeignItemKind::TyAlias(..) => {
+                (Res::Def(DefKind::ForeignTy, self.r.local_def_id(item.id).to_def_id()), TypeNS)
+            }
             ForeignItemKind::MacCall(_) => unreachable!(),
         };
         let parent = self.parent_scope.module;
@@ -1169,7 +1159,7 @@ fn insert_unused_macro(
     fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> {
         let parent_scope = self.parent_scope;
         let expansion = parent_scope.expansion;
-        let def_id = self.r.definitions.local_def_id(item.id);
+        let def_id = self.r.local_def_id(item.id);
         let (ext, ident, span, macro_rules) = match &item.kind {
             ItemKind::MacroDef(def) => {
                 let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition()));
@@ -1314,7 +1304,7 @@ fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
         }
 
         // Add the item to the trait info.
-        let item_def_id = self.r.definitions.local_def_id(item.id).to_def_id();
+        let item_def_id = self.r.local_def_id(item.id).to_def_id();
         let (res, ns) = match item.kind {
             AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
             AssocItemKind::Fn(_, ref sig, _, _) => {
@@ -1335,7 +1325,7 @@ fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
     }
 
     fn visit_token(&mut self, t: Token) {
-        if let token::Interpolated(nt) = t.kind {
+        if let token::Interpolated(nt, _) = t.kind {
             if let token::NtExpr(ref expr) = *nt {
                 if let ast::ExprKind::MacCall(..) = expr.kind {
                     self.visit_invoc(expr.id);
@@ -1416,7 +1406,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         let ident = variant.ident;
 
         // Define a name in the type namespace.
-        let def_id = self.r.definitions.local_def_id(variant.id).to_def_id();
+        let def_id = self.r.local_def_id(variant.id).to_def_id();
         let res = Res::Def(DefKind::Variant, def_id);
         self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
 
@@ -1434,7 +1424,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         // It's ok to use the variant's id as a ctor id since an
         // error will be reported on any use of such resolution anyway.
         let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id);
-        let ctor_def_id = self.r.definitions.local_def_id(ctor_node_id).to_def_id();
+        let ctor_def_id = self.r.local_def_id(ctor_node_id).to_def_id();
         let ctor_kind = CtorKind::from_ast(&variant.data);
         let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
         self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
index cc0e97aeb14300ce1cf8fa8a47cb2ac1ea8d3766..1f36e1ed83de70b0abd11fbe70a399e4ad159a13 100644 (file)
@@ -29,6 +29,7 @@
 use rustc_ast::ast;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::visit::{self, Visitor};
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::pluralize;
 use rustc_middle::ty;
@@ -64,7 +65,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
     fn check_import(&mut self, id: ast::NodeId) {
         let mut used = false;
         self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
-        let def_id = self.r.definitions.local_def_id(id);
+        let def_id = self.r.local_def_id(id);
         if !used {
             if self.r.maybe_unused_trait_imports.contains(&def_id) {
                 // Check later.
@@ -246,7 +247,7 @@ impl Resolver<'_> {
                     }
                 }
                 ImportKind::ExternCrate { .. } => {
-                    let def_id = self.definitions.local_def_id(import.id);
+                    let def_id = self.local_def_id(import.id);
                     self.maybe_unused_extern_crates.push((def_id, import.span));
                 }
                 ImportKind::MacroUse => {
index 71cedb208fcf283edd49328fb6be8016c891bf54..c25a20210e0263a87d74fd5c75ffcb74969b4d37 100644 (file)
@@ -1,8 +1,10 @@
+use crate::Resolver;
 use log::debug;
 use rustc_ast::ast::*;
 use rustc_ast::token::{self, Token};
 use rustc_ast::visit::{self, FnKind};
 use rustc_ast::walk_list;
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::definitions::*;
 use rustc_span::Span;
 
 crate fn collect_definitions(
-    definitions: &mut Definitions,
+    resolver: &mut Resolver<'_>,
     fragment: &AstFragment,
     expansion: ExpnId,
 ) {
-    let parent_def = definitions.invocation_parent(expansion);
-    fragment.visit_with(&mut DefCollector { definitions, parent_def, expansion });
+    let parent_def = resolver.invocation_parents[&expansion];
+    fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion });
 }
 
 /// Creates `DefId`s for nodes in the AST.
-struct DefCollector<'a> {
-    definitions: &'a mut Definitions,
+struct DefCollector<'a, 'b> {
+    resolver: &'a mut Resolver<'b>,
     parent_def: LocalDefId,
     expansion: ExpnId,
 }
 
-impl<'a> DefCollector<'a> {
+impl<'a, 'b> DefCollector<'a, 'b> {
     fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
         let parent_def = self.parent_def;
         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
-        self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span)
+        self.resolver.create_def(parent_def, node_id, data, self.expansion, span)
     }
 
     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
@@ -43,12 +45,13 @@ fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
         let index = |this: &Self| {
             index.unwrap_or_else(|| {
                 let node_id = NodeId::placeholder_from_expn_id(this.expansion);
-                this.definitions.placeholder_field_index(node_id)
+                this.resolver.placeholder_field_indices[&node_id]
             })
         };
 
         if field.is_placeholder {
-            self.definitions.set_placeholder_field_index(field.id, index(self));
+            let old_index = self.resolver.placeholder_field_indices.insert(field.id, index(self));
+            assert!(old_index.is_none(), "placeholder field index is reset for a node ID");
             self.visit_macro_invoc(field.id);
         } else {
             let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
@@ -58,11 +61,13 @@ fn collect_field(&mut self, field: &'a StructField, index: Option<usize>) {
     }
 
     fn visit_macro_invoc(&mut self, id: NodeId) {
-        self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
+        let old_parent =
+            self.resolver.invocation_parents.insert(id.placeholder_to_expn_id(), self.parent_def);
+        assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
     }
 }
 
-impl<'a> visit::Visitor<'a> for DefCollector<'a> {
+impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
     fn visit_item(&mut self, i: &'a Item) {
         debug!("visit_item: {:?}", i);
 
@@ -251,7 +256,7 @@ fn visit_stmt(&mut self, stmt: &'a Stmt) {
     }
 
     fn visit_token(&mut self, t: Token) {
-        if let token::Interpolated(nt) = t.kind {
+        if let token::Interpolated(nt, _) = t.kind {
             if let token::NtExpr(ref expr) = *nt {
                 if let ExprKind::MacCall(..) = expr.kind {
                     self.visit_macro_invoc(expr.id);
index bd2ce5a72e8d924e1a1d320aa2d4da5c2a5f9a41..2854683b61bab30919de6906f8f421150d5f0dc4 100644 (file)
@@ -49,6 +49,7 @@ impl TypoSuggestion {
     pub did: Option<DefId>,
     pub descr: &'static str,
     pub path: Path,
+    pub accessible: bool,
 }
 
 /// Adjust the impl span so that just the `impl` keyword is taken by removing
@@ -107,7 +108,7 @@ impl<'a> Resolver<'a> {
                 match outer_res {
                     Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
                         if let Some(impl_span) =
-                            maybe_impl_defid.and_then(|def_id| self.definitions.opt_span(def_id))
+                            maybe_impl_defid.and_then(|def_id| self.opt_span(def_id))
                         {
                             err.span_label(
                                 reduce_impl_span_to_impl_keyword(sm, impl_span),
@@ -126,12 +127,12 @@ impl<'a> Resolver<'a> {
                         return err;
                     }
                     Res::Def(DefKind::TyParam, def_id) => {
-                        if let Some(span) = self.definitions.opt_span(def_id) {
+                        if let Some(span) = self.opt_span(def_id) {
                             err.span_label(span, "type parameter from outer function");
                         }
                     }
                     Res::Def(DefKind::ConstParam, def_id) => {
-                        if let Some(span) = self.definitions.opt_span(def_id) {
+                        if let Some(span) = self.opt_span(def_id) {
                             err.span_label(span, "const parameter from outer function");
                         }
                     }
@@ -640,18 +641,40 @@ fn lookup_import_candidates_from_module<FilterFn>(
         let mut candidates = Vec::new();
         let mut seen_modules = FxHashSet::default();
         let not_local_module = crate_name.name != kw::Crate;
-        let mut worklist = vec![(start_module, Vec::<ast::PathSegment>::new(), not_local_module)];
-
-        while let Some((in_module, path_segments, in_module_is_extern)) = worklist.pop() {
+        let mut worklist =
+            vec![(start_module, Vec::<ast::PathSegment>::new(), true, not_local_module)];
+        let mut worklist_via_import = vec![];
+
+        while let Some((in_module, path_segments, accessible, in_module_is_extern)) =
+            match worklist.pop() {
+                None => worklist_via_import.pop(),
+                Some(x) => Some(x),
+            }
+        {
             // We have to visit module children in deterministic order to avoid
             // instabilities in reported imports (#43552).
             in_module.for_each_child(self, |this, ident, ns, name_binding| {
-                // avoid imports entirely
-                if name_binding.is_import() && !name_binding.is_extern_crate() {
+                // avoid non-importable candidates
+                if !name_binding.is_importable() {
                     return;
                 }
-                // avoid non-importable candidates as well
-                if !name_binding.is_importable() {
+
+                let child_accessible =
+                    accessible && this.is_accessible_from(name_binding.vis, parent_scope.module);
+
+                // do not venture inside inaccessible items of other crates
+                if in_module_is_extern && !child_accessible {
+                    return;
+                }
+
+                let via_import = name_binding.is_import() && !name_binding.is_extern_crate();
+
+                // There is an assumption elsewhere that paths of variants are in the enum's
+                // declaration and not imported. With this assumption, the variant component is
+                // chopped and the rest of the path is assumed to be the enum's own path. For
+                // errors where a variant is used as the type instead of the enum, this causes
+                // funny looking invalid suggestions, i.e `foo` instead of `foo::MyEnum`.
+                if via_import && name_binding.is_possibly_imported_variant() {
                     return;
                 }
 
@@ -673,22 +696,29 @@ fn lookup_import_candidates_from_module<FilterFn>(
 
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path { span: name_binding.span, segments: segms };
-                        // the entity is accessible in the following cases:
-                        // 1. if it's defined in the same crate, it's always
-                        // accessible (since private entities can be made public)
-                        // 2. if it's defined in another crate, it's accessible
-                        // only if both the module is public and the entity is
-                        // declared as public (due to pruning, we don't explore
-                        // outside crate private modules => no need to check this)
-                        if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
-                            let did = match res {
-                                Res::Def(DefKind::Ctor(..), did) => this.parent(did),
-                                _ => res.opt_def_id(),
-                            };
-                            if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
-                                candidates.push(ImportSuggestion { did, descr: res.descr(), path });
+                        let did = match res {
+                            Res::Def(DefKind::Ctor(..), did) => this.parent(did),
+                            _ => res.opt_def_id(),
+                        };
+
+                        if child_accessible {
+                            // Remove invisible match if exists
+                            if let Some(idx) = candidates
+                                .iter()
+                                .position(|v: &ImportSuggestion| v.did == did && !v.accessible)
+                            {
+                                candidates.remove(idx);
                             }
                         }
+
+                        if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
+                            candidates.push(ImportSuggestion {
+                                did,
+                                descr: res.descr(),
+                                path,
+                                accessible: child_accessible,
+                            });
+                        }
                     }
                 }
 
@@ -701,20 +731,23 @@ fn lookup_import_candidates_from_module<FilterFn>(
                     let is_extern_crate_that_also_appears_in_prelude =
                         name_binding.is_extern_crate() && lookup_ident.span.rust_2018();
 
-                    let is_visible_to_user =
-                        !in_module_is_extern || name_binding.vis == ty::Visibility::Public;
-
-                    if !is_extern_crate_that_also_appears_in_prelude && is_visible_to_user {
-                        // add the module to the lookup
+                    if !is_extern_crate_that_also_appears_in_prelude {
                         let is_extern = in_module_is_extern || name_binding.is_extern_crate();
+                        // add the module to the lookup
                         if seen_modules.insert(module.def_id().unwrap()) {
-                            worklist.push((module, path_segments, is_extern));
+                            if via_import { &mut worklist_via_import } else { &mut worklist }
+                                .push((module, path_segments, child_accessible, is_extern));
                         }
                     }
                 }
             })
         }
 
+        // If only some candidates are accessible, take just them
+        if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) {
+            candidates = candidates.into_iter().filter(|x| x.accessible).collect();
+        }
+
         candidates
     }
 
@@ -825,7 +858,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
                 Applicability::MaybeIncorrect,
             );
             let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
-                LOCAL_CRATE => self.definitions.opt_span(def_id),
+                LOCAL_CRATE => self.opt_span(def_id),
                 _ => Some(
                     self.session
                         .source_map()
index 74a8b7e2f556d3c05310419d84cd5ffb32cb07c5..ded0ee8a9669963cef357414c8913b15855fc24d 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_ast::ast::NodeId;
 use rustc_ast::unwrap_or;
 use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
@@ -1393,7 +1394,7 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
             let is_good_import =
                 binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
             if is_good_import || binding.is_macro_def() {
-                let res = binding.res().map_id(|id| this.definitions.local_def_id(id));
+                let res = binding.res().map_id(|id| this.local_def_id(id));
                 if res != def::Res::Err {
                     reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
                 }
index 7166fef2d13952420262c0045bb8874730e06140..84ba9094ea16fedee6add5c9d39d4445fcc535ff 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{unwrap_or, walk_list};
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
@@ -24,6 +25,7 @@
 use rustc_hir::TraitCandidate;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use smallvec::{smallvec, SmallVec};
@@ -534,8 +536,8 @@ fn visit_generics(&mut self, generics: &'ast Generics) {
 
         for param in &generics.params {
             match param.kind {
-                GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
-                GenericParamKind::Type { ref default, .. } => {
+                GenericParamKind::Lifetime => self.visit_generic_param(param),
+                GenericParamKind::Type { ref default } => {
                     for bound in &param.bounds {
                         self.visit_param_bound(bound);
                     }
@@ -549,7 +551,7 @@ fn visit_generics(&mut self, generics: &'ast Generics) {
                     // Allow all following defaults to refer to this type parameter.
                     default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
                 }
-                GenericParamKind::Const { ref ty } => {
+                GenericParamKind::Const { ref ty, kw_span: _ } => {
                     for bound in &param.bounds {
                         self.visit_param_bound(bound);
                     }
@@ -706,7 +708,7 @@ fn with_rib<T>(
     }
 
     fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
-        let id = self.r.definitions.local_def_id(id);
+        let id = self.r.local_def_id(id);
         let module = self.r.module_map.get(&id).cloned(); // clones a reference
         if let Some(module) = module {
             // Move down in the graph.
@@ -758,7 +760,7 @@ fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         debug!("resolve_adt");
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                let item_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+                let item_def_id = this.r.local_def_id(item.id).to_def_id();
                 this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
                     visit::walk_item(this, item);
                 });
@@ -838,7 +840,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
             ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let local_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+                    let local_def_id = this.r.local_def_id(item.id).to_def_id();
                     this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
                         walk_list!(this, visit_param_bound, bounds);
@@ -879,7 +881,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
             ItemKind::TraitAlias(ref generics, ref bounds) => {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let local_def_id = this.r.definitions.local_def_id(item.id).to_def_id();
+                    let local_def_id = this.r.local_def_id(item.id).to_def_id();
                     this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
                         this.visit_generics(generics);
                         walk_list!(this, visit_param_bound, bounds);
@@ -960,7 +962,7 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib
             seen_bindings.entry(ident).or_insert(param.ident.span);
 
             // Plain insert (no renaming).
-            let res = Res::Def(def_kind, self.r.definitions.local_def_id(param.id).to_def_id());
+            let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
 
             match param.kind {
                 GenericParamKind::Type { .. } => {
@@ -1110,7 +1112,7 @@ fn resolve_implementation(
             this.with_self_rib(Res::SelfTy(None, None), |this| {
                 // Resolve the trait reference, if necessary.
                 this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
-                    let item_def_id = this.r.definitions.local_def_id(item_id).to_def_id();
+                    let item_def_id = this.r.local_def_id(item_id).to_def_id();
                     this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
                         if let Some(trait_ref) = opt_trait_reference.as_ref() {
                             // Resolve type arguments in the trait path.
@@ -2001,7 +2003,7 @@ fn resolve_block(&mut self, block: &'ast Block) {
             if let StmtKind::Item(ref item) = stmt.kind {
                 if let ItemKind::MacroDef(..) = item.kind {
                     num_macro_definition_ribs += 1;
-                    let res = self.r.definitions.local_def_id(item.id).to_def_id();
+                    let res = self.r.local_def_id(item.id).to_def_id();
                     self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
                     self.label_ribs.push(Rib::new(MacroDefinition(res)));
                 }
@@ -2188,7 +2190,7 @@ fn get_traits_containing_item(
         &mut self,
         mut ident: Ident,
         ns: Namespace,
-    ) -> Vec<TraitCandidate<NodeId>> {
+    ) -> Vec<TraitCandidate> {
         debug!("(getting traits containing item) looking for '{}'", ident.name);
 
         let mut found_traits = Vec::new();
@@ -2233,7 +2235,7 @@ fn get_traits_in_module_containing_item(
         ident: Ident,
         ns: Namespace,
         module: Module<'a>,
-        found_traits: &mut Vec<TraitCandidate<NodeId>>,
+        found_traits: &mut Vec<TraitCandidate>,
     ) {
         assert!(ns == TypeNS || ns == ValueNS);
         let mut traits = module.traits.borrow_mut();
@@ -2292,13 +2294,13 @@ fn find_transitive_imports(
         &mut self,
         mut kind: &NameBindingKind<'_>,
         trait_name: Ident,
-    ) -> SmallVec<[NodeId; 1]> {
+    ) -> SmallVec<[LocalDefId; 1]> {
         let mut import_ids = smallvec![];
         while let NameBindingKind::Import { import, binding, .. } = kind {
-            let id = self.r.definitions.local_def_id(import.id);
+            let id = self.r.local_def_id(import.id);
             self.r.maybe_unused_trait_imports.insert(id);
             self.r.add_to_glob_map(&import, trait_name);
-            import_ids.push(import.id);
+            import_ids.push(id);
             kind = &binding.kind;
         }
         import_ids
index ed7adefcb8c9e0a56985054fe9f0e92f0a44603e..1bce160acb6100ebbb2d23edd8c6a2d49f484ab1 100644 (file)
@@ -512,7 +512,7 @@ fn smart_resolve_context_dependent_help(
                 _ => {}
             }
             if !suggested {
-                if let Some(span) = self.r.definitions.opt_span(def_id) {
+                if let Some(span) = self.r.opt_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
                 }
                 err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str));
@@ -536,7 +536,7 @@ fn smart_resolve_context_dependent_help(
                 if nightly_options::is_nightly_build() {
                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
                                `type` alias";
-                    if let Some(span) = self.r.definitions.opt_span(def_id) {
+                    if let Some(span) = self.r.opt_span(def_id) {
                         err.span_help(span, msg);
                     } else {
                         err.help(msg);
@@ -593,7 +593,7 @@ fn smart_resolve_context_dependent_help(
                 bad_struct_syntax_suggestion(def_id);
             }
             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
-                if let Some(span) = self.r.definitions.opt_span(def_id) {
+                if let Some(span) = self.r.opt_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
                 }
                 err.span_label(span, format!("did you mean `{}( /* fields */ )`?", path_str));
@@ -887,7 +887,12 @@ fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion
                         let path = Path { span: name_binding.span, segments: path_segments };
                         result = Some((
                             module,
-                            ImportSuggestion { did: Some(def_id), descr: "module", path },
+                            ImportSuggestion {
+                                did: Some(def_id),
+                                descr: "module",
+                                path,
+                                accessible: true,
+                            },
                         ));
                     } else {
                         // add the module to the lookup
@@ -920,20 +925,47 @@ fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
         &self,
         path: &[Segment],
     ) -> Option<(Span, &'static str, String, Applicability)> {
-        let ident = match path {
-            [segment] => segment.ident,
+        let (ident, span) = match path {
+            [segment] if !segment.has_generic_args => {
+                (segment.ident.to_string(), segment.ident.span)
+            }
             _ => return None,
         };
-        match (
-            self.diagnostic_metadata.current_item,
-            self.diagnostic_metadata.currently_processing_generics,
-        ) {
-            (Some(Item { kind: ItemKind::Fn(..), ident, .. }), true) if ident.name == sym::main => {
+        let mut iter = ident.chars().map(|c| c.is_uppercase());
+        let single_uppercase_char =
+            matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
+        if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
+            return None;
+        }
+        match (self.diagnostic_metadata.current_item, single_uppercase_char) {
+            (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _) if ident.name == sym::main => {
                 // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
             }
-            (Some(Item { kind, .. }), true) => {
+            (
+                Some(Item {
+                    kind:
+                        kind @ ItemKind::Fn(..)
+                        | kind @ ItemKind::Enum(..)
+                        | kind @ ItemKind::Struct(..)
+                        | kind @ ItemKind::Union(..),
+                    ..
+                }),
+                true,
+            )
+            | (Some(Item { kind, .. }), false) => {
                 // Likely missing type parameter.
                 if let Some(generics) = kind.generics() {
+                    if span.overlaps(generics.span) {
+                        // Avoid the following:
+                        // error[E0405]: cannot find trait `A` in this scope
+                        //  --> $DIR/typo-suggestion-named-underscore.rs:CC:LL
+                        //   |
+                        // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore
+                        //   |           ^- help: you might be missing a type parameter: `, A`
+                        //   |           |
+                        //   |           not found in this scope
+                        return None;
+                    }
                     let msg = "you might be missing a type parameter";
                     let (span, sugg) = if let [.., param] = &generics.params[..] {
                         let span = if let [.., bound] = &param.bounds[..] {
index 5bbf8703f0b60d1b7ec8b6a9cc1492a0c61e7b7a..903eee672cf1fbbc2cfe9760a7a16303249081a9 100644 (file)
@@ -883,7 +883,6 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                         })
                         .collect();
                     if !lifetimes.is_empty() {
-                        self.trait_ref_hack = true;
                         let next_early_index = self.next_early_index();
                         let scope = Scope::Binder {
                             lifetimes,
@@ -895,9 +894,10 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                         let result = self.with(scope, |old_scope, this| {
                             this.check_lifetime_params(old_scope, &bound_generic_params);
                             this.visit_ty(&bounded_ty);
+                            this.trait_ref_hack = true;
                             walk_list!(this, visit_param_bound, bounds);
+                            this.trait_ref_hack = false;
                         });
-                        self.trait_ref_hack = false;
                         result
                     } else {
                         self.visit_ty(&bounded_ty);
@@ -932,13 +932,15 @@ fn visit_poly_trait_ref(
         debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
 
         let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
-        if !self.trait_ref_hack
+
+        let trait_ref_hack = take(&mut self.trait_ref_hack);
+        if !trait_ref_hack
             || trait_ref.bound_generic_params.iter().any(|param| match param.kind {
                 GenericParamKind::Lifetime { .. } => true,
                 _ => false,
             })
         {
-            if self.trait_ref_hack {
+            if trait_ref_hack {
                 struct_span_err!(
                     self.tcx.sess,
                     trait_ref.span,
@@ -968,10 +970,11 @@ fn visit_poly_trait_ref(
                 this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
                 walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
                 this.visit_trait_ref(&trait_ref.trait_ref);
-            })
+            });
         } else {
             self.visit_trait_ref(&trait_ref.trait_ref);
         }
+        self.trait_ref_hack = trait_ref_hack;
         if should_pop_missing_lt {
             self.missing_named_lifetime_spots.pop();
         }
index 61792e039c76ead953f6a911c7ef292b822992a3..dccaf76723a58188bb68ae8c3da0087b4466b331 100644 (file)
@@ -27,6 +27,7 @@
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::unwrap_or;
 use rustc_ast::visit::{self, Visitor};
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
-use rustc_hir::definitions::{DefKey, Definitions};
+use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
-use rustc_hir::TraitMap;
+use rustc_hir::TraitCandidate;
+use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::hir::exports::ExportMap;
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
@@ -225,13 +227,15 @@ enum VisResolutionError<'a> {
     ModuleOnly(Span),
 }
 
-// A minimal representation of a path segment. We use this in resolve because
-// we synthesize 'path segments' which don't have the rest of an AST or HIR
-// `PathSegment`.
+/// A minimal representation of a path segment. We use this in resolve because we synthesize 'path
+/// segments' which don't have the rest of an AST or HIR `PathSegment`.
 #[derive(Clone, Copy, Debug)]
 pub struct Segment {
     ident: Ident,
     id: Option<NodeId>,
+    /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
+    /// nonsensical suggestions.
+    has_generic_args: bool,
 }
 
 impl Segment {
@@ -240,7 +244,7 @@ fn from_path(path: &Path) -> Vec<Segment> {
     }
 
     fn from_ident(ident: Ident) -> Segment {
-        Segment { ident, id: None }
+        Segment { ident, id: None, has_generic_args: false }
     }
 
     fn names_to_string(segments: &[Segment]) -> String {
@@ -250,35 +254,25 @@ fn names_to_string(segments: &[Segment]) -> String {
 
 impl<'a> From<&'a ast::PathSegment> for Segment {
     fn from(seg: &'a ast::PathSegment) -> Segment {
-        Segment { ident: seg.ident, id: Some(seg.id) }
+        Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() }
     }
 }
 
-struct UsePlacementFinder<'d> {
-    definitions: &'d Definitions,
-    target_module: LocalDefId,
+struct UsePlacementFinder {
+    target_module: NodeId,
     span: Option<Span>,
     found_use: bool,
 }
 
-impl<'d> UsePlacementFinder<'d> {
-    fn check(
-        definitions: &'d Definitions,
-        krate: &Crate,
-        target_module: DefId,
-    ) -> (Option<Span>, bool) {
-        if let Some(target_module) = target_module.as_local() {
-            let mut finder =
-                UsePlacementFinder { definitions, target_module, span: None, found_use: false };
-            visit::walk_crate(&mut finder, krate);
-            (finder.span, finder.found_use)
-        } else {
-            (None, false)
-        }
+impl UsePlacementFinder {
+    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
+        let mut finder = UsePlacementFinder { target_module, span: None, found_use: false };
+        visit::walk_crate(&mut finder, krate);
+        (finder.span, finder.found_use)
     }
 }
 
-impl<'tcx, 'd> Visitor<'tcx> for UsePlacementFinder<'d> {
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
     fn visit_mod(
         &mut self,
         module: &'tcx ast::Mod,
@@ -289,7 +283,7 @@ fn visit_mod(
         if self.span.is_some() {
             return;
         }
-        if self.definitions.local_def_id(node_id) != self.target_module {
+        if node_id != self.target_module {
             visit::walk_mod(self, module);
             return;
         }
@@ -709,6 +703,13 @@ fn is_ambiguity(&self) -> bool {
             }
     }
 
+    fn is_possibly_imported_variant(&self) -> bool {
+        match self.kind {
+            NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
+            _ => self.is_variant(),
+        }
+    }
+
     // We sometimes need to treat variants as `pub` for backwards compatibility.
     fn pseudo_vis(&self) -> ty::Visibility {
         if self.is_variant() && self.res().def_id().is_local() {
@@ -879,7 +880,7 @@ pub struct Resolver<'a> {
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     export_map: ExportMap<LocalDefId>,
-    trait_map: TraitMap<NodeId>,
+    trait_map: NodeMap<Vec<TraitCandidate>>,
 
     /// A map from nodes to anonymous modules.
     /// Anonymous modules are pseudo-modules that are implicitly created around items
@@ -977,6 +978,19 @@ pub struct Resolver<'a> {
     lint_buffer: LintBuffer,
 
     next_node_id: NodeId,
+
+    def_id_to_span: IndexVec<LocalDefId, Span>,
+
+    node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
+    def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
+
+    /// Indices of unnamed struct or variant fields with unresolved attributes.
+    placeholder_field_indices: FxHashMap<NodeId, usize>,
+    /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId`
+    /// we know what parent node that fragment should be attached to thanks to this table.
+    invocation_parents: FxHashMap<ExpnId, LocalDefId>,
+
+    next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1040,7 +1054,7 @@ 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<'_> {
+impl ResolverAstLowering for Resolver<'_> {
     fn def_key(&mut self, id: DefId) -> DefKey {
         if let Some(id) = id.as_local() {
             self.definitions().def_key(id)
@@ -1107,6 +1121,60 @@ fn lint_buffer(&mut self) -> &mut LintBuffer {
     fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
     }
+
+    fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
+        &self.trait_map
+    }
+
+    fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
+        self.node_id_to_def_id.get(&node).copied()
+    }
+
+    fn local_def_id(&self, node: NodeId) -> LocalDefId {
+        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+    }
+
+    /// Adds a definition with a parent definition.
+    fn create_def(
+        &mut self,
+        parent: LocalDefId,
+        node_id: ast::NodeId,
+        data: DefPathData,
+        expn_id: ExpnId,
+        span: Span,
+    ) -> LocalDefId {
+        assert!(
+            !self.node_id_to_def_id.contains_key(&node_id),
+            "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
+            node_id,
+            data,
+            self.definitions.def_key(self.node_id_to_def_id[&node_id]),
+        );
+
+        // Find the next free disambiguator for this key.
+        let next_disambiguator = &mut self.next_disambiguator;
+        let next_disambiguator = |parent, data| {
+            let next_disamb = next_disambiguator.entry((parent, data)).or_insert(0);
+            let disambiguator = *next_disamb;
+            *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
+            disambiguator
+        };
+
+        let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator);
+
+        assert_eq!(self.def_id_to_span.push(span), def_id);
+
+        // Some things for which we allocate `LocalDefId`s don't correspond to
+        // anything in the AST, so they don't have a `NodeId`. For these cases
+        // we don't need a mapping from `NodeId` to `LocalDefId`.
+        if node_id != ast::DUMMY_NODE_ID {
+            debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
+            self.node_id_to_def_id.insert(node_id, def_id);
+        }
+        assert_eq!(self.def_id_to_node_id.push(node_id), def_id);
+
+        def_id
+    }
 }
 
 impl<'a> Resolver<'a> {
@@ -1137,8 +1205,18 @@ pub fn new(
         let mut module_map = FxHashMap::default();
         module_map.insert(LocalDefId { local_def_index: CRATE_DEF_INDEX }, graph_root);
 
-        let mut definitions = Definitions::default();
-        definitions.create_root_def(crate_name, session.local_crate_disambiguator());
+        let definitions = Definitions::new(crate_name, session.local_crate_disambiguator());
+        let root = definitions.get_root_def();
+
+        let mut def_id_to_span = IndexVec::default();
+        assert_eq!(def_id_to_span.push(rustc_span::DUMMY_SP), root);
+        let mut def_id_to_node_id = IndexVec::default();
+        assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
+        let mut node_id_to_def_id = FxHashMap::default();
+        node_id_to_def_id.insert(CRATE_NODE_ID, root);
+
+        let mut invocation_parents = FxHashMap::default();
+        invocation_parents.insert(ExpnId::root(), root);
 
         let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
             .opts
@@ -1257,6 +1335,12 @@ pub fn new(
             variant_vis: Default::default(),
             lint_buffer: LintBuffer::default(),
             next_node_id: NodeId::from_u32(1),
+            def_id_to_span,
+            node_id_to_def_id,
+            def_id_to_node_id,
+            placeholder_field_indices: Default::default(),
+            invocation_parents,
+            next_disambiguator: Default::default(),
         }
     }
 
@@ -1282,18 +1366,6 @@ pub fn into_outputs(self) -> ResolverOutputs {
         let definitions = self.definitions;
         let extern_crate_map = self.extern_crate_map;
         let export_map = self.export_map;
-        let trait_map = self
-            .trait_map
-            .into_iter()
-            .map(|(k, v)| {
-                (
-                    definitions.node_id_to_hir_id(k),
-                    v.into_iter()
-                        .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id)))
-                        .collect(),
-                )
-            })
-            .collect();
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
         let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
@@ -1302,7 +1374,6 @@ pub fn into_outputs(self) -> ResolverOutputs {
             cstore: Box::new(self.crate_loader.into_cstore()),
             extern_crate_map,
             export_map,
-            trait_map,
             glob_map,
             maybe_unused_trait_imports,
             maybe_unused_extern_crates,
@@ -1320,21 +1391,6 @@ pub fn clone_outputs(&self) -> ResolverOutputs {
             cstore: Box::new(self.cstore().clone()),
             extern_crate_map: self.extern_crate_map.clone(),
             export_map: self.export_map.clone(),
-            trait_map: self
-                .trait_map
-                .iter()
-                .map(|(&k, v)| {
-                    (
-                        self.definitions.node_id_to_hir_id(k),
-                        v.iter()
-                            .cloned()
-                            .map(|tc| {
-                                tc.map_import_ids(|id| self.definitions.node_id_to_hir_id(id))
-                            })
-                            .collect(),
-                    )
-                })
-                .collect(),
             glob_map: self.glob_map.clone(),
             maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(),
             maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(),
@@ -1479,7 +1535,7 @@ fn record_use(
     #[inline]
     fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) {
         if import.is_glob() {
-            let def_id = self.definitions.local_def_id(import.id);
+            let def_id = self.local_def_id(import.id);
             self.glob_map.entry(def_id).or_default().insert(ident.name);
         }
     }
@@ -2017,7 +2073,7 @@ fn resolve_path_with_ribs(
             path, opt_ns, record_used, path_span, crate_lint,
         );
 
-        for (i, &Segment { ident, id }) in path.iter().enumerate() {
+        for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
             let record_segment_res = |this: &mut Self, res| {
                 if record_used {
@@ -2560,7 +2616,11 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
         for UseError { mut err, candidates, def_id, instead, suggestion } in
             self.use_injections.drain(..)
         {
-            let (span, found_use) = UsePlacementFinder::check(&self.definitions, krate, def_id);
+            let (span, found_use) = if let Some(def_id) = def_id.as_local() {
+                UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
+            } else {
+                (None, false)
+            };
             if !candidates.is_empty() {
                 diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use);
             } else if let Some((span, msg, sugg, appl)) = suggestion {
@@ -2956,6 +3016,12 @@ pub fn graph_root(&self) -> Module<'a> {
     pub fn all_macros(&self) -> &FxHashMap<Symbol, Res> {
         &self.all_macros
     }
+
+    /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
+    #[inline]
+    pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
+        if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
+    }
 }
 
 fn names_to_string(names: &[Symbol]) -> String {
index 1b49722355e54133bf79c9a2cfc0fc732753a883..3976e501c169feb0f46574bf1b19c53f70d5f1df 100644 (file)
@@ -7,11 +7,11 @@
 use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
 use rustc_ast::ast::{self, NodeId};
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, StabilityLevel};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_expand::base::SyntaxExtension;
-use rustc_expand::base::{self, Indeterminate, InvocationRes};
+use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
 use rustc_feature::is_builtin_attr_name;
@@ -140,7 +140,7 @@ fn registered_idents(
     (registered_attrs, registered_tools)
 }
 
-impl<'a> base::Resolver for Resolver<'a> {
+impl<'a> ResolverExpand for Resolver<'a> {
     fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
     }
@@ -190,7 +190,7 @@ fn expansion_for_ast_pass(
         )));
 
         let parent_scope = if let Some(module_id) = parent_module_id {
-            let parent_def_id = self.definitions.local_def_id(module_id);
+            let parent_def_id = self.local_def_id(module_id);
             self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id.to_def_id());
             self.module_map[&parent_def_id]
         } else {
@@ -340,7 +340,9 @@ fn check_unused_macros(&mut self) {
     }
 
     fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
-        self.definitions.lint_node_id(expn_id)
+        self.invocation_parents
+            .get(&expn_id)
+            .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
     }
 
     fn has_derive_copy(&self, expn_id: ExpnId) -> bool {
index 12d2c8c7eb9a4c3be9db74681298a41b1bbab158..f5c3e84c624267788ac42e888ff06da83a631a0c 100644 (file)
@@ -518,24 +518,13 @@ pub fn get_trait_ref_data(&self, trait_ref: &hir::TraitRef<'_>) -> Option<Ref> {
     }
 
     pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
-        let hir_node = self.tcx.hir().expect_expr(expr.hir_id);
-        let ty = self.tables.expr_ty_adjusted_opt(&hir_node);
-        if ty.is_none() || ty.unwrap().kind == ty::Error {
+        let ty = self.tables.expr_ty_adjusted_opt(expr)?;
+        if matches!(ty.kind, ty::Error(_)) {
             return None;
         }
         match expr.kind {
             hir::ExprKind::Field(ref sub_ex, ident) => {
-                let hir_node = match self.tcx.hir().find(sub_ex.hir_id) {
-                    Some(Node::Expr(expr)) => expr,
-                    _ => {
-                        debug!(
-                            "Missing or weird node for sub-expression {} in {:?}",
-                            sub_ex.hir_id, expr
-                        );
-                        return None;
-                    }
-                };
-                match self.tables.expr_ty_adjusted(&hir_node).kind {
+                match self.tables.expr_ty_adjusted(&sub_ex).kind {
                     ty::Adt(def, _) if !def.is_enum() => {
                         let variant = &def.non_enum_variant();
                         filter!(self.span_utils, ident.span);
@@ -562,8 +551,8 @@ pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
                     hir::QPath::Resolved(_, path) => path.segments.last().unwrap(),
                     hir::QPath::TypeRelative(_, segment) => segment,
                 };
-                match self.tables.expr_ty_adjusted(&hir_node).kind {
-                    ty::Adt(def, _) if !def.is_enum() => {
+                match ty.kind {
+                    ty::Adt(def, _) => {
                         let sub_span = segment.ident.span;
                         filter!(self.span_utils, sub_span);
                         let span = self.span_from_span(sub_span);
@@ -574,9 +563,7 @@ pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
                         }))
                     }
                     _ => {
-                        // FIXME ty could legitimately be an enum, but then we will fail
-                        // later if we try to look up the fields.
-                        debug!("expected struct or union, found {:?}", ty);
+                        debug!("expected adt, found {:?}", ty);
                         None
                     }
                 }
index 4d57c6384ddbda9246326b8d5c48ecba43704f38..abce7359c0ed73be6b932470bf29ac83513483bd 100644 (file)
@@ -9,6 +9,7 @@ name = "rustc_session"
 path = "lib.rs"
 
 [dependencies]
+bitflags = "1.2.1"
 getopts = "0.2"
 log = "0.4"
 rustc_errors = { path = "../librustc_errors" }
index 411a6eecbba1584f3a49d45cbf861f694c99407b..c5a866817cb4a1930a5b085f22f32d11d50212c2 100644 (file)
@@ -10,6 +10,7 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::impl_stable_hash_via_hash;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
 use rustc_target::spec::{Target, TargetTriple};
 
@@ -37,35 +38,55 @@ pub struct Config {
     pub ptr_width: u32,
 }
 
-#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Sanitizer {
-    Address,
-    Leak,
-    Memory,
-    Thread,
+bitflags! {
+    #[derive(Default, RustcEncodable, RustcDecodable)]
+    pub struct SanitizerSet: u8 {
+        const ADDRESS = 1 << 0;
+        const LEAK    = 1 << 1;
+        const MEMORY  = 1 << 2;
+        const THREAD  = 1 << 3;
+    }
 }
 
-impl fmt::Display for Sanitizer {
+/// Formats a sanitizer set as a comma separated list of sanitizers' names.
+impl fmt::Display for SanitizerSet {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Sanitizer::Address => "address".fmt(f),
-            Sanitizer::Leak => "leak".fmt(f),
-            Sanitizer::Memory => "memory".fmt(f),
-            Sanitizer::Thread => "thread".fmt(f),
+        let mut first = true;
+        for s in *self {
+            let name = match s {
+                SanitizerSet::ADDRESS => "address",
+                SanitizerSet::LEAK => "leak",
+                SanitizerSet::MEMORY => "memory",
+                SanitizerSet::THREAD => "thread",
+                _ => panic!("unrecognized sanitizer {:?}", s),
+            };
+            if !first {
+                f.write_str(",")?;
+            }
+            f.write_str(name)?;
+            first = false;
         }
+        Ok(())
     }
 }
 
-impl FromStr for Sanitizer {
-    type Err = ();
-    fn from_str(s: &str) -> Result<Sanitizer, ()> {
-        match s {
-            "address" => Ok(Sanitizer::Address),
-            "leak" => Ok(Sanitizer::Leak),
-            "memory" => Ok(Sanitizer::Memory),
-            "thread" => Ok(Sanitizer::Thread),
-            _ => Err(()),
-        }
+impl IntoIterator for SanitizerSet {
+    type Item = SanitizerSet;
+    type IntoIter = std::vec::IntoIter<SanitizerSet>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
+            .iter()
+            .copied()
+            .filter(|&s| self.contains(s))
+            .collect::<Vec<_>>()
+            .into_iter()
+    }
+}
+
+impl<CTX> HashStable<CTX> for SanitizerSet {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.bits().hash_stable(ctx, hasher);
     }
 }
 
@@ -82,7 +103,7 @@ pub enum Strip {
     Symbols,
 }
 
-/// The different settings that the `-Z control_flow_guard` flag can have.
+/// The different settings that the `-Z control-flow-guard` flag can have.
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum CFGuard {
     /// Do not emit Control Flow Guard metadata or checks.
@@ -726,10 +747,12 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
             }
         }
     }
-    if let Some(s) = &sess.opts.debugging_opts.sanitizer {
+
+    for s in sess.opts.debugging_opts.sanitizer {
         let symbol = Symbol::intern(&s.to_string());
         ret.insert((sym::sanitize, Some(symbol)));
     }
+
     if sess.opts.debug_assertions {
         ret.insert((Symbol::intern("debug_assertions"), None));
     }
@@ -1826,6 +1849,7 @@ fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMo
                 }
             }
         };
+        log::debug!("got unpretty option: {:?}", first);
         first
     }
 }
@@ -1954,9 +1978,11 @@ pub fn needs_ast_map(&self) -> bool {
         use PpMode::*;
         use PpSourceMode::*;
         match *self {
-            PpmSource(PpmNormal | PpmEveryBodyLoops | PpmIdentified) => false,
+            PpmSource(PpmNormal | PpmIdentified) => false,
 
-            PpmSource(PpmExpanded | PpmExpandedIdentified | PpmExpandedHygiene)
+            PpmSource(
+                PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
+            )
             | PpmHir(_)
             | PpmHirTree(_)
             | PpmMir
@@ -1995,7 +2021,7 @@ pub fn needs_analysis(&self) -> bool {
 crate mod dep_tracking {
     use super::{
         CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
-        OutputTypes, Passes, Sanitizer, SourceFileHashAlgorithm, SwitchWithOptPath,
+        OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
         SymbolManglingVersion,
     };
     use crate::lint;
@@ -2069,8 +2095,7 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_via_hash!(UnstableFeatures);
     impl_dep_tracking_hash_via_hash!(OutputTypes);
     impl_dep_tracking_hash_via_hash!(NativeLibKind);
-    impl_dep_tracking_hash_via_hash!(Sanitizer);
-    impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
+    impl_dep_tracking_hash_via_hash!(SanitizerSet);
     impl_dep_tracking_hash_via_hash!(CFGuard);
     impl_dep_tracking_hash_via_hash!(TargetTriple);
     impl_dep_tracking_hash_via_hash!(Edition);
@@ -2085,7 +2110,6 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
     impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
-    impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
     where
index e98746231fb307e0510d2bb601dc243074df66b6..27396c524f4e6f4134dfeee763fd2f77a7cf283f 100644 (file)
@@ -41,6 +41,10 @@ pub fn get_lib_path(&self) -> PathBuf {
         make_target_lib_path(self.sysroot, self.triple)
     }
 
+    pub fn get_self_contained_lib_path(&self) -> PathBuf {
+        self.get_lib_path().join("self-contained")
+    }
+
     pub fn search<F>(&self, mut pick: F)
     where
         F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
@@ -88,13 +92,13 @@ pub fn search_path_dirs(&self) -> Vec<PathBuf> {
     }
 
     // Returns a list of directories where target-specific tool binaries are located.
-    pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
+    pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
         let mut p = PathBuf::from(self.sysroot);
         p.push(find_libdir(self.sysroot).as_ref());
         p.push(RUST_LIB_DIR);
         p.push(&self.triple);
         p.push("bin");
-        vec![p]
+        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p.clone()] }
     }
 }
 
index 80b693fe1ab60e542c40c4e90d388fd3e8d0617e..be9d2e7be27774ce5da48fb5ccf093ac74a58c18 100644 (file)
@@ -1,6 +1,9 @@
 #![feature(crate_visibility_modifier)]
 #![feature(or_patterns)]
 
+#[macro_use]
+extern crate bitflags;
+
 pub mod cgu_reuse_tracker;
 pub mod utils;
 #[macro_use]
index ffb45793090750926b7dc798751ca57e90675bd2..0dcbee08abea1f7d1d473fe832112573a09cb740 100644 (file)
@@ -88,6 +88,8 @@ pub struct Lint {
 
     /// `Some` if this lint is feature gated, otherwise `None`.
     pub feature_gate: Option<Symbol>,
+
+    pub crate_level_only: bool,
 }
 
 /// Extra information for a future incompatibility lint.
@@ -111,6 +113,7 @@ pub const fn default_fields_for_macro() -> Self {
             report_in_external_macro: false,
             future_incompatible: None,
             feature_gate: None,
+            crate_level_only: false,
         }
     }
 
@@ -336,6 +339,7 @@ macro_rules! declare_tool_lint {
             future_incompatible: None,
             is_plugin: true,
             feature_gate: None,
+            crate_level_only: false,
         };
     );
 }
index 58388bafbeddf27bbafbc3d21e0336c00603adcd..5deee6eb48e6acc0c8d6e3ed3977adcce800df66 100644 (file)
@@ -17,6 +17,7 @@
         reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
         edition: None,
     };
+    crate_level_only
 }
 
 declare_lint! {
@@ -75,7 +76,8 @@
 declare_lint! {
     pub UNUSED_CRATE_DEPENDENCIES,
     Allow,
-    "crate dependencies that are never used"
+    "crate dependencies that are never used",
+    crate_level_only
 }
 
 declare_lint! {
 declare_lint! {
     pub UNKNOWN_CRATE_TYPES,
     Deny,
-    "unknown crate type found in `#[crate_type]` directive"
+    "unknown crate type found in `#[crate_type]` directive",
+    crate_level_only
 }
 
 declare_lint! {
 declare_lint! {
     pub ELIDED_LIFETIMES_IN_PATHS,
     Allow,
-    "hidden lifetime parameters in types are deprecated"
+    "hidden lifetime parameters in types are deprecated",
+    crate_level_only
 }
 
 declare_lint! {
         reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
         edition: None,
     };
+    crate_level_only
 }
 
 declare_lint! {
     @feature_gate = sym::unsafe_block_in_unsafe_fn;
 }
 
+declare_lint! {
+    pub CENUM_IMPL_DROP_CAST,
+    Warn,
+    "a C-like enum implementing Drop is cast",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>",
+        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.
         ASM_SUB_REGISTER,
         UNSAFE_OP_IN_UNSAFE_FN,
         INCOMPLETE_INCLUDE,
+        CENUM_IMPL_DROP_CAST,
     ]
 }
 
index d22c6ec9d7d010930110db39125fedcee8fef86c..9337f241d7022fd322a2a708cba2fde5271ee716 100644 (file)
@@ -248,10 +248,10 @@ mod $mod_desc {
         pub const parse_passes: &str = "a space-separated list of passes, or `all`";
         pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
         pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-        pub const parse_sanitizer: &str = "one of: `address`, `leak`, `memory` or `thread`";
-        pub const parse_sanitizer_list: &str = "comma separated list of sanitizers";
+        pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
         pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
-        pub const parse_cfguard: &str = "either `disabled`, `nochecks`, or `checks`";
+        pub const parse_cfguard: &str =
+            "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
         pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
         pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
         pub const parse_optimization_fuel: &str = "crate=integer";
@@ -459,24 +459,15 @@ fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
             true
         }
 
-        fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
-            if let Some(Ok(s)) =  v.map(str::parse) {
-                *slot = Some(s);
-                true
-            } else {
-                false
-            }
-        }
-
-        fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
+        fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
             if let Some(v) = v {
-                for s in v.split(',').map(str::parse) {
-                    if let Ok(s) = s {
-                        if !slot.contains(&s) {
-                            slot.push(s);
-                        }
-                    } else {
-                        return false;
+                for s in v.split(',') {
+                    *slot |= match s {
+                        "address" => SanitizerSet::ADDRESS,
+                        "leak" => SanitizerSet::LEAK,
+                        "memory" => SanitizerSet::MEMORY,
+                        "thread" => SanitizerSet::THREAD,
+                        _ => return false,
                     }
                 }
                 true
@@ -505,12 +496,24 @@ fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
         }
 
         fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
-            match v {
-                Some("disabled") => *slot = CFGuard::Disabled,
-                Some("nochecks") => *slot = CFGuard::NoChecks,
-                Some("checks") => *slot = CFGuard::Checks,
-                _ => return false,
+            if v.is_some() {
+                let mut bool_arg = None;
+                if parse_opt_bool(&mut bool_arg, v) {
+                    *slot = if bool_arg.unwrap() {
+                        CFGuard::Checks
+                    } else {
+                        CFGuard::Disabled
+                    };
+                    return true
+                }
             }
+
+            *slot = match v {
+                None => CFGuard::Checks,
+                Some("checks") => CFGuard::Checks,
+                Some("nochecks") => CFGuard::NoChecks,
+                Some(_) => return false,
+            };
             true
         }
 
@@ -806,8 +809,8 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "enable the experimental Chalk-based trait solving engine"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
-    control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [UNTRACKED],
-        "use Windows Control Flow Guard (`disabled`, `nochecks` or `checks`)"),
+    control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
+        "use Windows Control Flow Guard (default: no)"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
         "inject the given attribute in the crate"),
     debug_macros: bool = (false, parse_bool, [TRACKED],
@@ -876,12 +879,19 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         "fix undefined behavior when a thread doesn't eventually make progress \
         (such as entering an empty infinite loop) by inserting llvm.sideeffect \
         (default: no)"),
+    instrument_coverage: bool = (false, parse_bool, [TRACKED],
+        "instrument the generated code with LLVM code region counters to (in the \
+        future) generate coverage reports (default: no; note, the compiler build \
+        config must include `profiler = true`)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
         "keep hygiene data after analysis (default: no)"),
     link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
         "link native libraries in the linker invocation (default: yes)"),
+    link_self_contained: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "control whether to link Rust provided C objects/libraries or rely
+         on C toolchain installed in the system"),
     link_only: bool = (false, parse_bool, [TRACKED],
         "link the `.rlink` file generated by `-Z no-link` (default: no)"),
     llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
@@ -971,11 +981,11 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
     // soon.
     run_dsymutil: bool = (true, parse_bool, [TRACKED],
         "if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"),
-    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
+    sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
         "use a sanitizer"),
     sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
         "enable origins tracking in MemorySanitizer"),
-    sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
+    sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
         "enable recovery for selected sanitizers"),
     saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
index ddbc95fb1b0b8ed61888b9b91a4829924aec1913..b428315b3cdf395c76ca03f1f8556b6e13775ab9 100644 (file)
@@ -13,6 +13,7 @@
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 use rustc_span::{MultiSpan, Span, Symbol};
 
+use std::collections::BTreeMap;
 use std::path::PathBuf;
 use std::str;
 
@@ -63,7 +64,7 @@ pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
 #[derive(Default)]
 pub struct SymbolGallery {
     /// All symbols occurred and their first occurrance span.
-    pub symbols: Lock<FxHashMap<Symbol, Span>>,
+    pub symbols: Lock<BTreeMap<Symbol, Span>>,
 }
 
 impl SymbolGallery {
@@ -135,6 +136,8 @@ pub struct ParseSess {
     pub symbol_gallery: SymbolGallery,
     /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors.
     pub reached_eof: Lock<bool>,
+    /// Environment variables accessed during the build and their values when they exist.
+    pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
 }
 
 impl ParseSess {
@@ -160,6 +163,7 @@ pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
             gated_spans: GatedSpans::default(),
             symbol_gallery: SymbolGallery::default(),
             reached_eof: Lock::new(false),
+            env_depinfo: Default::default(),
         }
     }
 
index 06d7d4f14d8f4407527a59f0a5a5ffd6867655e9..fcd5dab94a6c25efe39d6c0f0a2ea23dabe3665a 100644 (file)
@@ -1,7 +1,7 @@
 use crate::cgu_reuse_tracker::CguReuseTracker;
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
-use crate::config::{self, CrateType, OutputType, PrintRequest, Sanitizer, SwitchWithOptPath};
+use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath};
 use crate::filesearch;
 use crate::lint;
 use crate::parse::ParseSess;
@@ -650,14 +650,9 @@ pub fn panic_strategy(&self) -> PanicStrategy {
     }
     pub fn fewer_names(&self) -> bool {
         let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
-            || self.opts.output_types.contains_key(&OutputType::Bitcode);
-
-        // Address sanitizer and memory sanitizer use alloca name when reporting an issue.
-        let more_names = match self.opts.debugging_opts.sanitizer {
-            Some(Sanitizer::Address) => true,
-            Some(Sanitizer::Memory) => true,
-            _ => more_names,
-        };
+            || self.opts.output_types.contains_key(&OutputType::Bitcode)
+            // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
+            || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
 
         self.opts.debugging_opts.fewer_names || !more_names
     }
@@ -1020,12 +1015,10 @@ pub fn needs_plt(&self) -> bool {
 
     /// Checks if LLVM lifetime markers should be emitted.
     pub fn emit_lifetime_markers(&self) -> bool {
-        match self.opts.debugging_opts.sanitizer {
-            // AddressSanitizer uses lifetimes to detect use after scope bugs.
-            // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
-            Some(Sanitizer::Address | Sanitizer::Memory) => true,
-            _ => self.opts.optimize != config::OptLevel::No,
-        }
+        self.opts.optimize != config::OptLevel::No
+        // AddressSanitizer uses lifetimes to detect use after scope bugs.
+        // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
+        || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
     }
 }
 
@@ -1068,8 +1061,15 @@ fn default_emitter(
             }
         }
         (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
-            JsonEmitter::stderr(Some(registry), source_map, pretty, json_rendered, macro_backtrace)
-                .ui_testing(sopts.debugging_opts.ui_testing),
+            JsonEmitter::stderr(
+                Some(registry),
+                source_map,
+                pretty,
+                json_rendered,
+                sopts.debugging_opts.terminal_width,
+                macro_backtrace,
+            )
+            .ui_testing(sopts.debugging_opts.ui_testing),
         ),
         (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
             JsonEmitter::new(
@@ -1078,6 +1078,7 @@ fn default_emitter(
                 source_map,
                 pretty,
                 json_rendered,
+                sopts.debugging_opts.terminal_width,
                 macro_backtrace,
             )
             .ui_testing(sopts.debugging_opts.ui_testing),
@@ -1356,33 +1357,44 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         );
     }
 
+    const ASAN_SUPPORTED_TARGETS: &[&str] = &[
+        "aarch64-fuchsia",
+        "aarch64-unknown-linux-gnu",
+        "x86_64-apple-darwin",
+        "x86_64-fuchsia",
+        "x86_64-unknown-linux-gnu",
+    ];
+    const LSAN_SUPPORTED_TARGETS: &[&str] =
+        &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+    const MSAN_SUPPORTED_TARGETS: &[&str] =
+        &["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"];
+    const TSAN_SUPPORTED_TARGETS: &[&str] =
+        &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
     // 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",
-            "x86_64-fuchsia",
-            "aarch64-fuchsia",
-        ];
-        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,
+    for s in sess.opts.debugging_opts.sanitizer {
+        let supported_targets = match s {
+            SanitizerSet::ADDRESS => ASAN_SUPPORTED_TARGETS,
+            SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
+            SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
+            SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
+            _ => panic!("unrecognized sanitizer {}", s),
         };
-
         if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
             sess.err(&format!(
-                "{:?}Sanitizer only works with the `{}` target",
-                sanitizer,
-                supported_targets.join("` or `")
+                "`-Zsanitizer={}` only works with targets: {}",
+                s,
+                supported_targets.join(", ")
+            ));
+        }
+        let conflicting = sess.opts.debugging_opts.sanitizer - s;
+        if !conflicting.is_empty() {
+            sess.err(&format!(
+                "`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`",
+                s, conflicting,
             ));
+            // Don't report additional errors.
+            break;
         }
     }
 }
@@ -1412,7 +1424,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
             Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
         }
         config::ErrorOutputType::Json { pretty, json_rendered } => {
-            Box::new(JsonEmitter::basic(pretty, json_rendered, false))
+            Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
         }
     };
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
@@ -1427,7 +1439,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
             Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
         }
         config::ErrorOutputType::Json { pretty, json_rendered } => {
-            Box::new(JsonEmitter::basic(pretty, json_rendered, false))
+            Box::new(JsonEmitter::basic(pretty, json_rendered, None, false))
         }
     };
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
index f2c9f8055b9756d05a4435a9d61311a6ab0e3e3d..60bbdd0495cc4f9d0af6cbd745c38051ca5f9f06 100644 (file)
@@ -823,7 +823,6 @@ pub enum DesugaringKind {
     Async,
     Await,
     ForLoop(ForLoopLoc),
-    Operator,
 }
 
 /// A location in the desugaring of a `for` loop
@@ -844,7 +843,6 @@ fn descr(self) -> &'static str {
             DesugaringKind::TryBlock => "`try` block",
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop(_) => "`for` loop",
-            DesugaringKind::Operator => "operator",
         }
     }
 }
index af9b5a264e313d4bb689077aa285e46551901ec2..6dcb1430cdc17cf5b56017413cfe88d521c7a49d 100644 (file)
@@ -6,7 +6,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(crate_visibility_modifier)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(negative_impls)]
 pub mod edition;
 use edition::Edition;
 pub mod hygiene;
+pub use hygiene::SyntaxContext;
 use hygiene::Transparency;
-pub use hygiene::{
-    DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind, SyntaxContext,
-};
+pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
 pub mod def_id;
 use def_id::{CrateNum, DefId, LOCAL_CRATE};
 mod span_encoding;
index fdeb58b7b7a313608229ffa056b15e8caec96a81..857734037afe7c588dfa6b07d30be60234b94852 100644 (file)
         assume_init,
         async_await,
         async_closure,
+        atomics,
         attr,
         attributes,
         attr_literals,
         copy_closures,
         core,
         core_intrinsics,
+        count_code_region,
         crate_id,
         crate_in_paths,
         crate_local,
         from_method,
         from_ok,
         from_usize,
+        from_trait,
         fundamental,
         future,
         Future,
         proc_macro_mod,
         proc_macro_non_items,
         proc_macro_path_invoc,
+        profiler_builtins,
         profiler_runtime,
+        ptr_guaranteed_eq,
+        ptr_guaranteed_ne,
         ptr_offset_from,
         pub_restricted,
         pure,
         v1,
         val,
         var,
+        variant_count,
         vec,
         Vec,
         version,
index 1a536b6a4294feb96f7d28cb2ab9c9bca01e567e..7d117b77cf5e5ab95484cf54b8cdb8fdd5812fb9 100644 (file)
@@ -345,7 +345,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             ty::Never => "z",
 
             // Placeholders (should be demangled as `_`).
-            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => "p",
+            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => "p",
 
             _ => "",
         };
@@ -367,7 +367,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
             ty::Tuple(_) if ty.is_unit() => unreachable!(),
 
             // Placeholders, also handled as part of basic types.
-            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => {
+            ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
                 unreachable!()
             }
 
index dcf181cb59f4a22aa86c3e27b4e3ce3cb6a4374e..c79e9bb28900882ed0a41860f628a477d56b16a8 100644 (file)
@@ -809,25 +809,30 @@ pub enum Variants {
     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
     Single { index: VariantIdx },
 
-    /// Enum-likes with more than one inhabited variant: for each case there is
-    /// a struct, and they all have space reserved for the discriminant.
-    /// For enums this is the sole field of the layout.
+    /// Enum-likes with more than one inhabited variant: each variant comes with
+    /// a *discriminant* (usually the same as the variant index but the user can
+    /// assign explicit discriminant values).  That discriminant is encoded
+    /// as a *tag* on the machine.  The layout of each variant is
+    /// a struct, and they all have space reserved for the tag.
+    /// For enums, the tag is the sole field of the layout.
     Multiple {
-        discr: Scalar,
-        discr_kind: DiscriminantKind,
-        discr_index: usize,
+        tag: Scalar,
+        tag_encoding: TagEncoding,
+        tag_field: usize,
         variants: IndexVec<VariantIdx, Layout>,
     },
 }
 
 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum DiscriminantKind {
-    /// Integer tag holding the discriminant value itself.
-    Tag,
+pub enum TagEncoding {
+    /// The tag directly stores the discriminant, but possibly with a smaller layout
+    /// (so converting the tag to the discriminant can require sign extension).
+    Direct,
 
     /// Niche (values invalid for a type) encoding the discriminant:
-    /// the variant `dataful_variant` contains a niche at an arbitrary
-    /// offset (field `discr_index` of the enum), which for a variant with
+    /// Discriminant and variant index coincide.
+    /// The variant `dataful_variant` contains a niche at an arbitrary
+    /// offset (field `tag_field` of the enum), which for a variant with
     /// discriminant `d` is set to
     /// `(d - niche_variants.start).wrapping_add(niche_start)`.
     ///
index 1798b2a0949754125a40e92b2a43afc3c3780aba..85a136b94aa7998bad3523bdac5468ab718d7389 100644 (file)
@@ -1,4 +1,5 @@
 use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::Target;
 use rustc_macros::HashStable_Generic;
 use std::fmt;
 
@@ -58,6 +59,37 @@ pub fn supported_types(
     }
 }
 
+// This uses the same logic as useR7AsFramePointer in LLVM
+fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
+    target.options.is_like_osx || (!target.options.is_like_windows && has_feature("thumb-mode"))
+}
+
+fn frame_pointer_r11(
+    _arch: InlineAsmArch,
+    has_feature: impl FnMut(&str) -> bool,
+    target: &Target,
+    _allocating: bool,
+) -> Result<(), &'static str> {
+    if !frame_pointer_is_r7(has_feature, target) {
+        Err("the frame pointer (r11) cannot be used as an operand for inline asm")
+    } else {
+        Ok(())
+    }
+}
+
+fn frame_pointer_r7(
+    _arch: InlineAsmArch,
+    has_feature: impl FnMut(&str) -> bool,
+    target: &Target,
+    _allocating: bool,
+) -> Result<(), &'static str> {
+    if frame_pointer_is_r7(has_feature, target) {
+        Err("the frame pointer (r7) cannot be used as an operand for inline asm")
+    } else {
+        Ok(())
+    }
+}
+
 def_regs! {
     Arm ArmInlineAsmReg ArmInlineAsmRegClass {
         r0: reg, reg_thumb = ["r0", "a1"],
@@ -66,11 +98,11 @@ pub fn supported_types(
         r3: reg, reg_thumb = ["r3", "a4"],
         r4: reg, reg_thumb = ["r4", "v1"],
         r5: reg, reg_thumb = ["r5", "v2"],
-        r6: reg, reg_thumb = ["r6", "v3"],
-        r7: reg, reg_thumb = ["r7", "v4"],
+        r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
         r8: reg = ["r8", "v5"],
         r9: reg = ["r9", "v6", "rfp"],
         r10: reg = ["r10", "sl"],
+        r11: reg = ["r11", "fp"] % frame_pointer_r11,
         r12: reg = ["r12", "ip"],
         r14: reg = ["r14", "lr"],
         s0: sreg, sreg_low16 = ["s0"],
@@ -153,8 +185,8 @@ pub fn supported_types(
         q13: qreg = ["q13"],
         q14: qreg = ["q14"],
         q15: qreg = ["q15"],
-        #error = ["r11", "fp"] =>
-            "the frame pointer cannot be used as an operand for inline asm",
+        #error = ["r6", "v3"] =>
+            "r6 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r13", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["r15", "pc"] =>
diff --git a/src/librustc_target/asm/hexagon.rs b/src/librustc_target/asm/hexagon.rs
new file mode 100644 (file)
index 0000000..d41941d
--- /dev/null
@@ -0,0 +1,93 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use std::fmt;
+
+def_reg_class! {
+    Hexagon HexagonInlineAsmRegClass {
+        reg,
+    }
+}
+
+impl HexagonInlineAsmRegClass {
+    pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+        &[]
+    }
+
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
+    pub fn suggest_modifier(
+        self,
+        _arch: InlineAsmArch,
+        _ty: InlineAsmType,
+    ) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn supported_types(
+        self,
+        _arch: InlineAsmArch,
+    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+        match self {
+            Self::reg => types! { _: I8, I16, I32, F32; },
+        }
+    }
+}
+
+def_regs! {
+    Hexagon HexagonInlineAsmReg HexagonInlineAsmRegClass {
+        r0: reg = ["r0"],
+        r1: reg = ["r1"],
+        r2: reg = ["r2"],
+        r3: reg = ["r3"],
+        r4: reg = ["r4"],
+        r5: reg = ["r5"],
+        r6: reg = ["r6"],
+        r7: reg = ["r7"],
+        r8: reg = ["r8"],
+        r9: reg = ["r9"],
+        r10: reg = ["r10"],
+        r11: reg = ["r11"],
+        r12: reg = ["r12"],
+        r13: reg = ["r13"],
+        r14: reg = ["r14"],
+        r15: reg = ["r15"],
+        r16: reg = ["r16"],
+        r17: reg = ["r17"],
+        r18: reg = ["r18"],
+        r19: reg = ["r19"],
+        r20: reg = ["r20"],
+        r21: reg = ["r21"],
+        r22: reg = ["r22"],
+        r23: reg = ["r23"],
+        r24: reg = ["r24"],
+        r25: reg = ["r25"],
+        r26: reg = ["r26"],
+        r27: reg = ["r27"],
+        r28: reg = ["r28"],
+        #error = ["r29", "sp"] =>
+            "the stack pointer cannot be used as an operand for inline asm",
+        #error = ["r30", "fr"] =>
+            "the frame register cannot be used as an operand for inline asm",
+        #error = ["r31", "lr"] =>
+            "the link register cannot be used as an operand for inline asm",
+    }
+}
+
+impl HexagonInlineAsmReg {
+    pub fn emit(
+        self,
+        out: &mut dyn fmt::Write,
+        _arch: InlineAsmArch,
+        _modifier: Option<char>,
+    ) -> fmt::Result {
+        out.write_str(self.name())
+    }
+
+    pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {}
+}
index a18a4dbd3e214f9a764fac279df862e3f5373981..ccec17817d37df6b0de2920cbe2a7d95fb862fef 100644 (file)
@@ -1,4 +1,5 @@
 use crate::abi::Size;
+use crate::spec::Target;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
@@ -83,12 +84,13 @@ pub fn reg_class(self) -> $arch_regclass {
             pub fn parse(
                 _arch: super::InlineAsmArch,
                 mut _has_feature: impl FnMut(&str) -> bool,
+                _target: &crate::spec::Target,
                 name: &str,
             ) -> Result<Self, &'static str> {
                 match name {
                     $(
                         $($alias)|* | $reg_name => {
-                            $($filter(_arch, &mut _has_feature, false)?;)?
+                            $($filter(_arch, &mut _has_feature, _target, false)?;)?
                             Ok(Self::$reg)
                         }
                     )*
@@ -103,6 +105,7 @@ pub fn parse(
         pub(super) fn fill_reg_map(
             _arch: super::InlineAsmArch,
             mut _has_feature: impl FnMut(&str) -> bool,
+            _target: &crate::spec::Target,
             _map: &mut rustc_data_structures::fx::FxHashMap<
                 super::InlineAsmRegClass,
                 rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
@@ -111,7 +114,7 @@ pub(super) fn fill_reg_map(
             #[allow(unused_imports)]
             use super::{InlineAsmReg, InlineAsmRegClass};
             $(
-                if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true {
+                if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true {
                     if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
                         set.insert(InlineAsmReg::$arch($arch_reg::$reg));
                     }
@@ -148,12 +151,14 @@ macro_rules! types {
 
 mod aarch64;
 mod arm;
+mod hexagon;
 mod nvptx;
 mod riscv;
 mod x86;
 
 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
 pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
@@ -167,6 +172,7 @@ pub enum InlineAsmArch {
     RiscV32,
     RiscV64,
     Nvptx64,
+    Hexagon,
 }
 
 impl FromStr for InlineAsmArch {
@@ -181,6 +187,7 @@ fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
             "riscv32" => Ok(Self::RiscV32),
             "riscv64" => Ok(Self::RiscV64),
             "nvptx64" => Ok(Self::Nvptx64),
+            "hexagon" => Ok(Self::Hexagon),
             _ => Err(()),
         }
     }
@@ -203,6 +210,7 @@ pub enum InlineAsmReg {
     AArch64(AArch64InlineAsmReg),
     RiscV(RiscVInlineAsmReg),
     Nvptx(NvptxInlineAsmReg),
+    Hexagon(HexagonInlineAsmReg),
 }
 
 impl InlineAsmReg {
@@ -212,6 +220,7 @@ pub fn name(self) -> &'static str {
             Self::Arm(r) => r.name(),
             Self::AArch64(r) => r.name(),
             Self::RiscV(r) => r.name(),
+            Self::Hexagon(r) => r.name(),
         }
     }
 
@@ -221,12 +230,14 @@ pub fn reg_class(self) -> InlineAsmRegClass {
             Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()),
             Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()),
             Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
+            Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
         }
     }
 
     pub fn parse(
         arch: InlineAsmArch,
         has_feature: impl FnMut(&str) -> bool,
+        target: &Target,
         name: Symbol,
     ) -> Result<Self, &'static str> {
         // FIXME: use direct symbol comparison for register names
@@ -234,17 +245,22 @@ pub fn parse(
         let name = name.as_str();
         Ok(match arch {
             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
-                Self::X86(X86InlineAsmReg::parse(arch, has_feature, &name)?)
+                Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
+            }
+            InlineAsmArch::Arm => {
+                Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
-            InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, &name)?),
             InlineAsmArch::AArch64 => {
-                Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, &name)?)
+                Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
-                Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?)
+                Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
             InlineAsmArch::Nvptx64 => {
-                Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
+                Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
+            }
+            InlineAsmArch::Hexagon => {
+                Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
         })
     }
@@ -262,6 +278,7 @@ pub fn emit(
             Self::Arm(r) => r.emit(out, arch, modifier),
             Self::AArch64(r) => r.emit(out, arch, modifier),
             Self::RiscV(r) => r.emit(out, arch, modifier),
+            Self::Hexagon(r) => r.emit(out, arch, modifier),
         }
     }
 
@@ -271,6 +288,7 @@ pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
             Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
             Self::AArch64(_) => cb(self),
             Self::RiscV(_) => cb(self),
+            Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
         }
     }
 }
@@ -292,6 +310,7 @@ pub enum InlineAsmRegClass {
     AArch64(AArch64InlineAsmRegClass),
     RiscV(RiscVInlineAsmRegClass),
     Nvptx(NvptxInlineAsmRegClass),
+    Hexagon(HexagonInlineAsmRegClass),
 }
 
 impl InlineAsmRegClass {
@@ -302,6 +321,7 @@ pub fn name(self) -> &'static str {
             Self::AArch64(r) => r.name(),
             Self::RiscV(r) => r.name(),
             Self::Nvptx(r) => r.name(),
+            Self::Hexagon(r) => r.name(),
         }
     }
 
@@ -315,6 +335,7 @@ pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Sel
             Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64),
             Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV),
             Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
+            Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
         }
     }
 
@@ -335,6 +356,7 @@ pub fn suggest_modifier(
             Self::AArch64(r) => r.suggest_modifier(arch, ty),
             Self::RiscV(r) => r.suggest_modifier(arch, ty),
             Self::Nvptx(r) => r.suggest_modifier(arch, ty),
+            Self::Hexagon(r) => r.suggest_modifier(arch, ty),
         }
     }
 
@@ -351,6 +373,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
             Self::AArch64(r) => r.default_modifier(arch),
             Self::RiscV(r) => r.default_modifier(arch),
             Self::Nvptx(r) => r.default_modifier(arch),
+            Self::Hexagon(r) => r.default_modifier(arch),
         }
     }
 
@@ -366,6 +389,7 @@ pub fn supported_types(
             Self::AArch64(r) => r.supported_types(arch),
             Self::RiscV(r) => r.supported_types(arch),
             Self::Nvptx(r) => r.supported_types(arch),
+            Self::Hexagon(r) => r.supported_types(arch),
         }
     }
 
@@ -384,6 +408,9 @@ pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
                     Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?)
                 }
                 InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?),
+                InlineAsmArch::Hexagon => {
+                    Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
+                }
             })
         })
     }
@@ -397,6 +424,7 @@ pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
             Self::AArch64(r) => r.valid_modifiers(arch),
             Self::RiscV(r) => r.valid_modifiers(arch),
             Self::Nvptx(r) => r.valid_modifiers(arch),
+            Self::Hexagon(r) => r.valid_modifiers(arch),
         }
     }
 }
@@ -514,31 +542,37 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub fn allocatable_registers(
     arch: InlineAsmArch,
     has_feature: impl FnMut(&str) -> bool,
+    target: &crate::spec::Target,
 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
     match arch {
         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
             let mut map = x86::regclass_map();
-            x86::fill_reg_map(arch, has_feature, &mut map);
+            x86::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
         InlineAsmArch::Arm => {
             let mut map = arm::regclass_map();
-            arm::fill_reg_map(arch, has_feature, &mut map);
+            arm::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
         InlineAsmArch::AArch64 => {
             let mut map = aarch64::regclass_map();
-            aarch64::fill_reg_map(arch, has_feature, &mut map);
+            aarch64::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
             let mut map = riscv::regclass_map();
-            riscv::fill_reg_map(arch, has_feature, &mut map);
+            riscv::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
         InlineAsmArch::Nvptx64 => {
             let mut map = nvptx::regclass_map();
-            nvptx::fill_reg_map(arch, has_feature, &mut map);
+            nvptx::fill_reg_map(arch, has_feature, target, &mut map);
+            map
+        }
+        InlineAsmArch::Hexagon => {
+            let mut map = hexagon::regclass_map();
+            hexagon::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
     }
index 3ff542247ff02c4a438e413c5ce637d46fa33ec3..ced7483b00571580ea8879be8d511013bbfda31e 100644 (file)
@@ -1,4 +1,5 @@
 use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::Target;
 use rustc_macros::HashStable_Generic;
 use std::fmt;
 
@@ -50,6 +51,7 @@ pub fn supported_types(
 fn not_e(
     _arch: InlineAsmArch,
     mut has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
     _allocating: bool,
 ) -> Result<(), &'static str> {
     if has_feature("e") {
index ed51b526414d138bf78af559094348bfffd95ea5..0f62c19e1a3cde0ec0fcef2ff01bf788cfb34004 100644 (file)
@@ -1,4 +1,5 @@
 use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::Target;
 use rustc_macros::HashStable_Generic;
 use std::fmt;
 
@@ -131,6 +132,7 @@ pub fn supported_types(
 fn x86_64_only(
     arch: InlineAsmArch,
     _has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
     _allocating: bool,
 ) -> Result<(), &'static str> {
     match arch {
@@ -143,6 +145,7 @@ fn x86_64_only(
 fn high_byte(
     arch: InlineAsmArch,
     _has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
     allocating: bool,
 ) -> Result<(), &'static str> {
     match arch {
index c2cdd2fd3ecf615b5fc3a6d3796244b3f338379f..ec6deb5b0595254f069d9c11441aaf35ad5714ee 100644 (file)
@@ -9,7 +9,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![feature(bool_to_option)]
-#![feature(const_if_match)]
+#![cfg_attr(bootstrap, feature(const_if_match))]
 #![feature(const_fn)]
 #![feature(const_panic)]
 #![feature(nll)]
index b07c2aef1caca004bbc07a3844652ad43157070f..0d0a0da9d1c4cb9a2ff069dfc5fd0a8b2706d7a0 100644 (file)
@@ -141,7 +141,6 @@ pub fn opts(arch: Arch, os: AppleOS) -> Result<TargetOptions, String> {
     let pre_link_args = build_pre_link_args(arch, os)?;
     Ok(TargetOptions {
         cpu: target_cpu(arch),
-        dynamic_linking: false,
         executables: true,
         pre_link_args,
         link_env_remove: link_env_remove(arch),
index 81974769cafb8b0113a45411efc70aa409204984..d01545619c8fa22527adc559943cd8a00301eef4 100644 (file)
@@ -48,8 +48,10 @@ pub fn target() -> Result<Target, String> {
         "ENCLAVE_SIZE",
         "CFGDATA_BASE",
         "DEBUG",
-        "EH_FRM_HDR_BASE",
-        "EH_FRM_HDR_SIZE",
+        "EH_FRM_HDR_OFFSET",
+        "EH_FRM_HDR_LEN",
+        "EH_FRM_OFFSET",
+        "EH_FRM_LEN",
         "TEXT_BASE",
         "TEXT_SIZE",
     ];
index 34c628e8f67bd2da63dd3ee11f6bd269f4f403f9..3a22290da68583ceef070dcdfa1898d6237b42b5 100644 (file)
@@ -6,6 +6,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
+    base.static_position_independent_executables = true;
 
     Ok(Target {
         llvm_target: "x86_64-unknown-linux-musl".to_string(),
diff --git a/src/librustc_trait_selection/autoderef.rs b/src/librustc_trait_selection/autoderef.rs
new file mode 100644 (file)
index 0000000..d542e16
--- /dev/null
@@ -0,0 +1,229 @@
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{self, TraitEngine};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{ToPredicate, TypeFoldable};
+use rustc_session::DiagnosticMessageId;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+#[derive(Copy, Clone, Debug)]
+pub enum AutoderefKind {
+    Builtin,
+    Overloaded,
+}
+
+struct AutoderefSnapshot<'tcx> {
+    at_start: bool,
+    reached_recursion_limit: bool,
+    steps: Vec<(Ty<'tcx>, AutoderefKind)>,
+    cur_ty: Ty<'tcx>,
+    obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+pub struct Autoderef<'a, 'tcx> {
+    // Meta infos:
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    span: Span,
+    body_id: hir::HirId,
+    param_env: ty::ParamEnv<'tcx>,
+
+    // Current state:
+    state: AutoderefSnapshot<'tcx>,
+
+    // Configurations:
+    include_raw_pointers: bool,
+    silence_errors: bool,
+}
+
+impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
+    type Item = (Ty<'tcx>, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let tcx = self.infcx.tcx;
+
+        debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty);
+        if self.state.at_start {
+            self.state.at_start = false;
+            debug!("autoderef stage #0 is {:?}", self.state.cur_ty);
+            return Some((self.state.cur_ty, 0));
+        }
+
+        // If we have reached the recursion limit, error gracefully.
+        if !tcx.sess.recursion_limit().value_within_limit(self.state.steps.len()) {
+            if !self.silence_errors {
+                report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty);
+            }
+            self.state.reached_recursion_limit = true;
+            return None;
+        }
+
+        if self.state.cur_ty.is_ty_var() {
+            return None;
+        }
+
+        // Otherwise, deref if type is derefable:
+        let (kind, new_ty) =
+            if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
+                (AutoderefKind::Builtin, mt.ty)
+            } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+                (AutoderefKind::Overloaded, ty)
+            } else {
+                return None;
+            };
+
+        if new_ty.references_error() {
+            return None;
+        }
+
+        self.state.steps.push((self.state.cur_ty, kind));
+        debug!(
+            "autoderef stage #{:?} is {:?} from {:?}",
+            self.step_count(),
+            new_ty,
+            (self.state.cur_ty, kind)
+        );
+        self.state.cur_ty = new_ty;
+
+        Some((self.state.cur_ty, self.step_count()))
+    }
+}
+
+impl<'a, 'tcx> Autoderef<'a, 'tcx> {
+    pub fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+        span: Span,
+        base_ty: Ty<'tcx>,
+    ) -> Autoderef<'a, 'tcx> {
+        Autoderef {
+            infcx,
+            span,
+            body_id,
+            param_env,
+            state: AutoderefSnapshot {
+                steps: vec![],
+                cur_ty: infcx.resolve_vars_if_possible(&base_ty),
+                obligations: vec![],
+                at_start: true,
+                reached_recursion_limit: false,
+            },
+            include_raw_pointers: false,
+            silence_errors: false,
+        }
+    }
+
+    fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+        debug!("overloaded_deref_ty({:?})", ty);
+
+        let tcx = self.infcx.tcx;
+
+        // <ty as Deref>
+        let trait_ref = TraitRef {
+            def_id: tcx.lang_items().deref_trait()?,
+            substs: tcx.mk_substs_trait(ty, &[]),
+        };
+
+        let cause = traits::ObligationCause::misc(self.span, self.body_id);
+
+        let obligation = traits::Obligation::new(
+            cause.clone(),
+            self.param_env,
+            trait_ref.without_const().to_predicate(tcx),
+        );
+        if !self.infcx.predicate_may_hold(&obligation) {
+            debug!("overloaded_deref_ty: cannot match obligation");
+            return None;
+        }
+
+        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+        let normalized_ty = fulfillcx.normalize_projection_type(
+            &self.infcx,
+            self.param_env,
+            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
+            cause,
+        );
+        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+            // This shouldn't happen, except for evaluate/fulfill mismatches,
+            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+            // by design).
+            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
+            return None;
+        }
+        let obligations = fulfillcx.pending_obligations();
+        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
+        self.state.obligations.extend(obligations);
+
+        Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
+    }
+
+    /// Returns the final type we ended up with, which may be an inference
+    /// variable (we will resolve it first, if we want).
+    pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> {
+        if resolve {
+            self.infcx.resolve_vars_if_possible(&self.state.cur_ty)
+        } else {
+            self.state.cur_ty
+        }
+    }
+
+    pub fn step_count(&self) -> usize {
+        self.state.steps.len()
+    }
+
+    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+        self.state.obligations
+    }
+
+    pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
+        &self.state.steps
+    }
+
+    pub fn span(&self) -> Span {
+        self.span.clone()
+    }
+
+    pub fn reached_recursion_limit(&self) -> bool {
+        self.state.reached_recursion_limit
+    }
+
+    /// also dereference through raw pointer types
+    /// e.g., assuming ptr_to_Foo is the type `*const Foo`
+    /// fcx.autoderef(span, ptr_to_Foo)  => [*const Foo]
+    /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
+    pub fn include_raw_pointers(mut self) -> Self {
+        self.include_raw_pointers = true;
+        self
+    }
+
+    pub fn silence_errors(mut self) -> Self {
+        self.silence_errors = true;
+        self
+    }
+}
+
+pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
+    // We've reached the recursion limit, error gracefully.
+    let suggested_limit = tcx.sess.recursion_limit() * 2;
+    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
+    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
+    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
+    if fresh {
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0055,
+            "reached the recursion limit while auto-dereferencing `{:?}`",
+            ty
+        )
+        .span_label(span, "deref recursion limit reached")
+        .help(&format!(
+            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
+            suggested_limit, tcx.crate_name,
+        ))
+        .emit();
+    }
+}
index f244785b49d2fdf3dd5e4050543217b5549171e5..dc895ad34a93205017fdd623c22e083b606e9dfa 100644 (file)
@@ -44,7 +44,7 @@ fn type_is_copy_modulo_regions(
         let ty = self.resolve_vars_if_possible(&ty);
 
         if !(param_env, ty).needs_infer() {
-            return ty.is_copy_modulo_regions(self.tcx, param_env, span);
+            return ty.is_copy_modulo_regions(self.tcx.at(span), param_env);
         }
 
         let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
index ea886cd1f9e9b38c394184ed4f0eb0bbc9279bc9..4692fa04ed58718466a0e8d7cf8cc94eb36edacb 100644 (file)
@@ -28,6 +28,7 @@
 #[macro_use]
 extern crate rustc_middle;
 
+pub mod autoderef;
 pub mod infer;
 pub mod opaque_types;
 pub mod traits;
index d53a0ec9ef884ff336a6c2f2199795b79f3e2039..adccdd0b2617a4760602c13c8569fe0fd6c13492 100644 (file)
@@ -941,7 +941,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                             )
                             .emit();
 
-                        self.tcx().types.err
+                        self.tcx().ty_error()
                     }
                 }
             }
@@ -974,7 +974,7 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
                             )
                             .emit();
 
-                        self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty })
+                        self.tcx().const_error(ct.ty)
                     }
                 }
             }
@@ -1002,7 +1002,7 @@ fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T)
             tcx,
             ty_op: |ty| {
                 if ty.references_error() {
-                    return tcx.types.err;
+                    return tcx.ty_error();
                 } else if let ty::Opaque(def_id, substs) = ty.kind {
                     // Check that this is `impl Trait` type is
                     // declared by `parent_def_id` -- i.e., one whose
index 2d4d582c939b6e925a64c4399a97a3809e8b879f..2ade48927526215ac45c883b53aa41833643dbbb 100644 (file)
@@ -7,17 +7,17 @@
     ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode,
     ObligationCause, PredicateObligation, SelectionError, TraitEngine,
 };
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub struct FulfillmentContext<'tcx> {
-    obligations: FxHashSet<PredicateObligation<'tcx>>,
+    obligations: FxIndexSet<PredicateObligation<'tcx>>,
 }
 
 impl FulfillmentContext<'tcx> {
     crate fn new() -> Self {
-        FulfillmentContext { obligations: FxHashSet::default() }
+        FulfillmentContext { obligations: FxIndexSet::default() }
     }
 }
 
@@ -79,7 +79,7 @@ enum NodeKind {
     };
 
     // FIXME(eddyb) isn't the unordered nature of this a hazard?
-    let mut inputs = FxHashSet::default();
+    let mut inputs = FxIndexSet::default();
 
     match node_kind {
         // In a trait impl, we assume that the header trait ref and all its
@@ -87,7 +87,9 @@ enum NodeKind {
         NodeKind::TraitImpl => {
             let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
 
-            inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
+            // FIXME(chalk): this has problems because of late-bound regions
+            //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
+            inputs.extend(trait_ref.substs.iter());
         }
 
         // In an inherent impl, we assume that the receiver type and all its
@@ -136,7 +138,10 @@ fn in_environment(
     let environment = match obligation.param_env.def_id {
         Some(def_id) => environment(infcx.tcx, def_id),
         None if obligation.param_env.caller_bounds.is_empty() => ty::List::empty(),
-        _ => bug!("non-empty `ParamEnv` with no def-id"),
+        // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl
+        // and ui/generics/generic-static-methods
+        //_ => bug!("non-empty `ParamEnv` with no def-id"),
+        _ => ty::List::empty(),
     };
 
     ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
@@ -191,7 +196,7 @@ fn select_where_possible(
         infcx: &InferCtxt<'_, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
         let mut errors = Vec::new();
-        let mut next_round = FxHashSet::default();
+        let mut next_round = FxIndexSet::default();
         let mut making_progress;
 
         loop {
@@ -199,7 +204,7 @@ fn select_where_possible(
 
             // We iterate over all obligations, and record if we are able
             // to unambiguously prove at least one obligation.
-            for obligation in self.obligations.drain() {
+            for obligation in self.obligations.drain(..) {
                 let goal_in_environment = in_environment(infcx, &obligation);
                 let mut orig_values = OriginalQueryValues::default();
                 let canonical_goal =
index 85c2f9246afcc6e92b8d2d07136414fb9511c2b0..3ec7fe2bf25c68f2635fb64f117a8487ee374bde 100644 (file)
@@ -120,12 +120,13 @@ fn overlap<'cx, 'tcx>(
     debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
 
     selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
-        overlap_within_probe(selcx, a_def_id, b_def_id, snapshot)
+        overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot)
     })
 }
 
 fn overlap_within_probe(
     selcx: &mut SelectionContext<'cx, 'tcx>,
+    skip_leak_check: SkipLeakCheck,
     a_def_id: DefId,
     b_def_id: DefId,
     snapshot: &CombinedSnapshot<'_, 'tcx>,
@@ -180,6 +181,13 @@ fn overlap_within_probe(
         return None;
     }
 
+    if !skip_leak_check.is_yes() {
+        if let Err(_) = infcx.leak_check(true, snapshot) {
+            debug!("overlap: leak check failed");
+            return None;
+        }
+    }
+
     let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header);
     let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
     debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
@@ -565,7 +573,7 @@ fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>>
             }
         }
 
-        ty::Error => None,
+        ty::Error(_) => None,
 
         ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
             bug!("ty_is_local invoked on unexpected type: {:?}", ty)
index d31e04cffd55f57cbb03e39c75268960b50f5b95..fd0c1a54d27adec8a6fcbca44a7c9f026a025e31 100644 (file)
@@ -15,6 +15,7 @@
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
@@ -25,7 +26,7 @@
     TypeFoldable, WithConstness,
 };
 use rustc_session::DiagnosticMessageId;
-use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -401,6 +402,7 @@ fn report_selection_error(
                             err.span_label(enclosing_scope_span, s.as_str());
                         }
 
+                        self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg);
                         self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
                         self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
                         self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
@@ -1246,7 +1248,7 @@ fn type_category(t: Ty<'_>) -> Option<u32> {
                 ty::Generator(..) => Some(18),
                 ty::Foreign(..) => Some(19),
                 ty::GeneratorWitness(..) => Some(20),
-                ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None,
+                ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
 
@@ -1695,36 +1697,95 @@ fn suggest_unsized_bound_if_applicable(
         err: &mut DiagnosticBuilder<'tcx>,
         obligation: &PredicateObligation<'tcx>,
     ) {
-        if let (
-            ty::PredicateKind::Trait(pred, _),
-            ObligationCauseCode::BindingObligation(item_def_id, span),
-        ) = (obligation.predicate.kind(), &obligation.cause.code)
-        {
-            if let (Some(generics), true) = (
-                self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()),
-                Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
-            ) {
-                for param in generics.params {
-                    if param.span == *span
-                        && !param.bounds.iter().any(|bound| {
-                            bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
-                                == self.tcx.lang_items().sized_trait()
-                        })
-                    {
-                        let (span, separator) = match param.bounds {
-                            [] => (span.shrink_to_hi(), ":"),
-                            [.., bound] => (bound.span().shrink_to_hi(), " +"),
-                        };
-                        err.span_suggestion_verbose(
-                            span,
-                            "consider relaxing the implicit `Sized` restriction",
-                            format!("{} ?Sized", separator),
-                            Applicability::MachineApplicable,
+        let (pred, item_def_id, span) =
+            match (obligation.predicate.kind(), &obligation.cause.code.peel_derives()) {
+                (
+                    ty::PredicateKind::Trait(pred, _),
+                    ObligationCauseCode::BindingObligation(item_def_id, span),
+                ) => (pred, item_def_id, span),
+                _ => return,
+            };
+
+        let node = match (
+            self.tcx.hir().get_if_local(*item_def_id),
+            Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
+        ) {
+            (Some(node), true) => node,
+            _ => return,
+        };
+        let generics = match node.generics() {
+            Some(generics) => generics,
+            None => return,
+        };
+        for param in generics.params {
+            if param.span != *span
+                || param.bounds.iter().any(|bound| {
+                    bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
+                        == self.tcx.lang_items().sized_trait()
+                })
+            {
+                continue;
+            }
+            match node {
+                hir::Node::Item(
+                    item
+                    @
+                    hir::Item {
+                        kind:
+                            hir::ItemKind::Enum(..)
+                            | hir::ItemKind::Struct(..)
+                            | hir::ItemKind::Union(..),
+                        ..
+                    },
+                ) => {
+                    // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
+                    // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
+                    // is not.
+                    let mut visitor = FindTypeParam {
+                        param: param.name.ident().name,
+                        invalid_spans: vec![],
+                        nested: false,
+                    };
+                    visitor.visit_item(item);
+                    if !visitor.invalid_spans.is_empty() {
+                        let mut multispan: MultiSpan = param.span.into();
+                        multispan.push_span_label(
+                            param.span,
+                            format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
+                        );
+                        for sp in visitor.invalid_spans {
+                            multispan.push_span_label(
+                                sp,
+                                format!(
+                                    "...if indirection was used here: `Box<{}>`",
+                                    param.name.ident(),
+                                ),
+                            );
+                        }
+                        err.span_help(
+                            multispan,
+                            &format!(
+                                "you could relax the implicit `Sized` bound on `{T}` if it were \
+                                 used through indirection like `&{T}` or `Box<{T}>`",
+                                T = param.name.ident(),
+                            ),
                         );
                         return;
                     }
                 }
+                _ => {}
             }
+            let (span, separator) = match param.bounds {
+                [] => (span.shrink_to_hi(), ":"),
+                [.., bound] => (bound.span().shrink_to_hi(), " +"),
+            };
+            err.span_suggestion_verbose(
+                span,
+                "consider relaxing the implicit `Sized` restriction",
+                format!("{} ?Sized", separator),
+                Applicability::MachineApplicable,
+            );
+            return;
         }
     }
 
@@ -1744,6 +1805,50 @@ fn is_recursive_obligation(
     }
 }
 
+/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
+/// `param: ?Sized` would be a valid constraint.
+struct FindTypeParam {
+    param: rustc_span::Symbol,
+    invalid_spans: Vec<Span>,
+    nested: bool,
+}
+
+impl<'v> Visitor<'v> for FindTypeParam {
+    type Map = rustc_hir::intravisit::ErasedMap<'v>;
+
+    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+        hir::intravisit::NestedVisitorMap::None
+    }
+
+    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+        // We collect the spans of all uses of the "bare" type param, like in `field: T` or
+        // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
+        // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
+        // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
+        // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
+        // in that case should make what happened clear enough.
+        match ty.kind {
+            hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {}
+            hir::TyKind::Path(hir::QPath::Resolved(None, path))
+                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+            {
+                if !self.nested {
+                    self.invalid_spans.push(ty.span);
+                }
+            }
+            hir::TyKind::Path(_) => {
+                let prev = self.nested;
+                self.nested = true;
+                hir::intravisit::walk_ty(self, ty);
+                self.nested = prev;
+            }
+            _ => {
+                hir::intravisit::walk_ty(self, ty);
+            }
+        }
+    }
+}
+
 pub fn recursive_type_with_infinite_size_error(
     tcx: TyCtxt<'tcx>,
     type_def_id: DefId,
index 8796cfb52165df6039f37e48d2d74fd23228775f..176bd90303dddfe93230763329fd14597dd5a59e 100644 (file)
@@ -3,6 +3,7 @@
     SelectionContext,
 };
 
+use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
 use crate::traits::normalize_projection_type;
 
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
-use rustc_middle::ty::TypeckTables;
 use rustc_middle::ty::{
     self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
     TyCtxt, TypeFoldable, WithConstness,
 };
+use rustc_middle::ty::{TypeAndMut, TypeckTables};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
@@ -48,6 +49,14 @@ fn suggest_borrow_on_unsized_slice(
         err: &mut DiagnosticBuilder<'_>,
     );
 
+    fn suggest_dereferences(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'tcx>,
+        trait_ref: &ty::PolyTraitRef<'tcx>,
+        points_at_arg: bool,
+    );
+
     fn get_closure_name(
         &self,
         def_id: DefId,
@@ -450,6 +459,62 @@ fn suggest_restricting_param_bound(
         }
     }
 
+    /// When after several dereferencing, the reference satisfies the trait
+    /// binding. This function provides dereference suggestion for this
+    /// specific situation.
+    fn suggest_dereferences(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'tcx>,
+        trait_ref: &ty::PolyTraitRef<'tcx>,
+        points_at_arg: bool,
+    ) {
+        // It only make sense when suggesting dereferences for arguments
+        if !points_at_arg {
+            return;
+        }
+        let param_env = obligation.param_env;
+        let body_id = obligation.cause.body_id;
+        let span = obligation.cause.span;
+        let real_trait_ref = match &obligation.cause.code {
+            ObligationCauseCode::ImplDerivedObligation(cause)
+            | ObligationCauseCode::DerivedObligation(cause)
+            | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref,
+            _ => trait_ref,
+        };
+        let real_ty = match real_trait_ref.self_ty().no_bound_vars() {
+            Some(ty) => ty,
+            None => return,
+        };
+
+        if let ty::Ref(region, base_ty, mutbl) = real_ty.kind {
+            let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty);
+            if let Some(steps) = autoderef.find_map(|(ty, steps)| {
+                // Re-add the `&`
+                let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
+                let obligation =
+                    self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty);
+                Some(steps).filter(|_| self.predicate_may_hold(&obligation))
+            }) {
+                if steps > 0 {
+                    if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) {
+                        // Don't care about `&mut` because `DerefMut` is used less
+                        // often and user will not expect autoderef happens.
+                        if src.starts_with("&") && !src.starts_with("&mut ") {
+                            let derefs = "*".repeat(steps);
+                            err.span_suggestion(
+                                span,
+                                "consider adding dereference here",
+                                format!("&{}{}", derefs, &src[1..]),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
     /// suggestion to borrow the initializer in order to use have a slice instead.
     fn suggest_borrow_on_unsized_slice(
@@ -948,7 +1013,7 @@ fn suggest_impl_trait(
              ty| {
                 let ty = self.resolve_vars_if_possible(&ty);
                 same &=
-                    ty.kind != ty::Error
+                    !matches!(ty.kind, ty::Error(_))
                         && last_ty.map_or(true, |last_ty| {
                             // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes
                             // *after* in the dependency graph.
@@ -1992,8 +2057,8 @@ fn suggest_await_before_try(
 /// Collect all the returned expressions within the input expression.
 /// Used to point at the return spans when we want to suggest some change to them.
 #[derive(Default)]
-struct ReturnsVisitor<'v> {
-    returns: Vec<&'v hir::Expr<'v>>,
+pub struct ReturnsVisitor<'v> {
+    pub returns: Vec<&'v hir::Expr<'v>>,
     in_block_tail: bool,
 }
 
index 106753ed809a5944fe365b3513fb8e7eac9419a6..32ab63458e7528aa65a9b2a72cf98ccc9ad2ca33 100644 (file)
@@ -321,7 +321,7 @@ fn process_obligation(
             ty::PredicateKind::Trait(ref data, _) => {
                 let trait_obligation = obligation.with(*data);
 
-                if data.is_global() {
+                if obligation.predicate.is_global() {
                     // no type variables present, can use evaluation for better caching.
                     // FIXME: consider caching errors too.
                     if infcx.predicate_must_hold_considering_regions(&obligation) {
index 9492c3c340995091fb75041c1833ab4eae55d3fc..f71b3fcf129da4e9225f4d67f80e613866ea37d6 100644 (file)
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
+use rustc_hir::lang_items::{FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem};
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 
 pub use rustc_middle::traits::Reveal;
@@ -148,15 +149,12 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>(
     debug!("poly_project_and_unify_type(obligation={:?})", obligation);
 
     let infcx = selcx.infcx();
-    infcx.commit_if_ok(|snapshot| {
-        let (placeholder_predicate, placeholder_map) =
+    infcx.commit_if_ok(|_snapshot| {
+        let (placeholder_predicate, _) =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
         let result = project_and_unify_type(selcx, &placeholder_obligation)?;
-        infcx
-            .leak_check(false, &placeholder_map, snapshot)
-            .map_err(|err| MismatchedProjectionTypes { err })?;
         Ok(result)
     })
 }
@@ -360,7 +358,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 // handle normalization within binders because
                 // otherwise we wind up a need to normalize when doing
                 // trait matching (since you can have a trait
-                // obligation like `for<'a> T::B : Fn(&'a int)`), but
+                // obligation like `for<'a> T::B: Fn(&'a i32)`), but
                 // we can't normalize with bound regions in scope. So
                 // far now we just ignore binders but only normalize
                 // if all bound regions are gone (and then we still
@@ -784,7 +782,7 @@ struct Progress<'tcx> {
 
 impl<'tcx> Progress<'tcx> {
     fn error(tcx: TyCtxt<'tcx>) -> Self {
-        Progress { ty: tcx.types.err, obligations: vec![] }
+        Progress { ty: tcx.ty_error(), obligations: vec![] }
     }
 
     fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
@@ -895,9 +893,12 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
 
     let tcx = selcx.tcx();
     // Check whether the self-type is itself a projection.
-    let (def_id, substs) = match obligation_trait_ref.self_ty().kind {
-        ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs),
-        ty::Opaque(def_id, substs) => (def_id, substs),
+    // If so, extract what we know from the trait and try to come up with a good answer.
+    let bounds = match obligation_trait_ref.self_ty().kind {
+        ty::Projection(ref data) => {
+            tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
+        }
+        ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
         ty::Infer(ty::TyVar(_)) => {
             // If the self-type is an inference variable, then it MAY wind up
             // being a projected type, so induce an ambiguity.
@@ -907,17 +908,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
         _ => return,
     };
 
-    // If so, extract what we know from the trait and try to come up with a good answer.
-    let trait_predicates = tcx.predicates_of(def_id);
-    let bounds = trait_predicates.instantiate(tcx, substs);
-    let bounds = elaborate_predicates(tcx, bounds.predicates.into_iter()).map(|o| o.predicate);
     assemble_candidates_from_predicates(
         selcx,
         obligation,
         obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::TraitDef,
-        bounds,
+        bounds.iter(),
     )
 }
 
@@ -1085,7 +1082,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     | ty::Bound(..)
                     | ty::Placeholder(..)
                     | ty::Infer(..)
-                    | ty::Error => false,
+                    | ty::Error(_) => false,
                 }
             }
             super::ImplSourceParam(..) => {
@@ -1146,7 +1143,7 @@ fn confirm_candidate<'cx, 'tcx>(
 ) -> Progress<'tcx> {
     debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
 
-    match candidate {
+    let mut progress = match candidate {
         ProjectionTyCandidate::ParamEnv(poly_projection)
         | ProjectionTyCandidate::TraitDef(poly_projection) => {
             confirm_param_env_candidate(selcx, obligation, poly_projection)
@@ -1155,7 +1152,16 @@ fn confirm_candidate<'cx, 'tcx>(
         ProjectionTyCandidate::Select(impl_source) => {
             confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source)
         }
+    };
+    // When checking for cycle during evaluation, we compare predicates with
+    // "syntactic" equality. Since normalization generally introduces a type
+    // with new region variables, we need to resolve them to existing variables
+    // when possible for this to work. See `auto-trait-projection-recursion.rs`
+    // for a case where this matters.
+    if progress.ty.has_infer_regions() {
+        progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
     }
+    progress
 }
 
 fn confirm_select_candidate<'cx, 'tcx>(
@@ -1393,8 +1399,8 @@ fn confirm_callable_candidate<'cx, 'tcx>(
 
     debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
 
-    // the `Output` associated type is declared on `FnOnce`
     let fn_once_def_id = tcx.require_lang_item(FnOnceTraitLangItem, None);
+    let fn_once_output_def_id = tcx.require_lang_item(FnOnceOutputLangItem, None);
 
     let predicate = super::util::closure_trait_ref_and_return_type(
         tcx,
@@ -1404,11 +1410,10 @@ fn confirm_callable_candidate<'cx, 'tcx>(
         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),
-        ),
+        projection_ty: ty::ProjectionTy {
+            substs: trait_ref.substs,
+            item_def_id: fn_once_output_def_id,
+        },
         ty: ret_type,
     });
 
@@ -1440,8 +1445,8 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
                 obligation, poly_cache_entry, e,
             );
             debug!("confirm_param_env_candidate: {}", msg);
-            infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg);
-            Progress { ty: infcx.tcx.types.err, obligations: vec![] }
+            let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
+            Progress { ty: err, obligations: vec![] }
         }
     }
 }
@@ -1460,7 +1465,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     let param_env = obligation.param_env;
     let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) {
         Ok(assoc_ty) => assoc_ty,
-        Err(ErrorReported) => return Progress { ty: tcx.types.err, obligations: nested },
+        Err(ErrorReported) => return Progress { ty: tcx.ty_error(), obligations: nested },
     };
 
     if !assoc_ty.item.defaultness.has_value() {
@@ -1472,16 +1477,24 @@ fn confirm_impl_candidate<'cx, 'tcx>(
             "confirm_impl_candidate: no associated type {:?} for {:?}",
             assoc_ty.item.ident, obligation.predicate
         );
-        return Progress { ty: tcx.types.err, obligations: nested };
+        return Progress { ty: tcx.ty_error(), obligations: nested };
     }
+    // If we're trying to normalize `<Vec<u32> as X>::A<S>` using
+    //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
+    //
+    // * `obligation.predicate.substs` is `[Vec<u32>, S]`
+    // * `substs` is `[u32]`
+    // * `substs` ends up as `[u32, S]`
     let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
     let substs =
         translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
     let ty = tcx.type_of(assoc_ty.item.def_id);
     if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
-        tcx.sess
-            .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts");
-        Progress { ty: tcx.types.err, obligations: nested }
+        let err = tcx.ty_error_with_message(
+            DUMMY_SP,
+            "impl item and trait item have different parameter counts",
+        );
+        Progress { ty: err, obligations: nested }
     } else {
         Progress { ty: ty.subst(tcx, substs), obligations: nested }
     }
index 856a2111fc82c8da116de604909a7ddef4f4b789..d07c95270e0040411e00fe825053eb5c15cd85cc 100644 (file)
@@ -101,7 +101,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Ref(..)
         | ty::Str
         | ty::Foreign(..)
-        | ty::Error => true,
+        | ty::Error(_) => true,
 
         // [T; N] and [T] have same properties as T.
         ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
index 3e7749356d212ac439bf4deea5821456f9e7d257..ca49ff5884f98a7080dd4b6cd7fbf12e19e26787 100644 (file)
@@ -145,7 +145,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 // handle normalization within binders because
                 // otherwise we wind up a need to normalize when doing
                 // trait matching (since you can have a trait
-                // obligation like `for<'a> T::B : Fn(&'a int)`), but
+                // obligation like `for<'a> T::B: Fn(&'a i32)`), but
                 // we can't normalize with bound regions in scope. So
                 // far now we just ignore binders but only normalize
                 // if all bound regions are gone (and then we still
index 9045451056b1991d40965a24b3f7251bc48e09c3..4dab5814f7b7ea8d6d0c177a71703a250fdafe7c 100644 (file)
@@ -163,9 +163,9 @@ fn assemble_candidates_from_projected_tys(
             _ => return,
         }
 
-        let result = self.infcx.probe(|snapshot| {
-            self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
-        });
+        let result = self
+            .infcx
+            .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
 
         if result {
             candidates.vec.push(ProjectionCandidate);
@@ -345,8 +345,8 @@ fn assemble_candidates_from_impls(
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
-                self.infcx.probe(|snapshot| {
-                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) {
+                self.infcx.probe(|_| {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation) {
                         candidates.vec.push(ImplCandidate(impl_def_id));
                     }
                 });
index f8d26c06a219d8546aa3471be5532a89ef7e1fb0..834bf17227d2ebe05bfb34cb6a784818ec26ee0a 100644 (file)
@@ -121,9 +121,8 @@ pub(super) fn confirm_candidate(
     }
 
     fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.commit_unconditionally(|snapshot| {
-            let result =
-                self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
+        self.infcx.commit_unconditionally(|_| {
+            let result = self.match_projection_obligation_against_definition_bounds(obligation);
             assert!(result);
         })
     }
@@ -265,8 +264,8 @@ fn confirm_impl_candidate(
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.commit_unconditionally(|snapshot| {
-            let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
+        self.infcx.commit_unconditionally(|_| {
+            let substs = self.rematch_impl(impl_def_id, obligation);
             debug!("confirm_impl_candidate: substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
             ensure_sufficient_stack(|| {
@@ -553,14 +552,14 @@ fn confirm_closure_candidate(
     ///
     /// Here is an example. Imagine we have a closure expression
     /// and we desugared it so that the type of the expression is
-    /// `Closure`, and `Closure` expects an int as argument. Then it
+    /// `Closure`, and `Closure` expects `i32` as argument. Then it
     /// is "as if" the compiler generated this impl:
     ///
-    ///     impl Fn(int) for Closure { ... }
+    ///     impl Fn(i32) for Closure { ... }
     ///
-    /// Now imagine our obligation is `Fn(usize) for Closure`. So far
+    /// Now imagine our obligation is `Closure: Fn(usize)`. So far
     /// we have matched the self type `Closure`. At this point we'll
-    /// compare the `int` to `usize` and generate an error.
+    /// compare the `i32` to `usize` and generate an error.
     ///
     /// Note that this checking occurs *after* the impl has selected,
     /// because these output type parameters should not affect the
@@ -612,24 +611,10 @@ fn confirm_builtin_unsize_candidate(
 
                 // Require that the traits involved in this upcast are **equal**;
                 // only the **lifetime bound** is changed.
-                //
-                // FIXME: This condition is arguably too strong -- it would
-                // suffice for the source trait to be a *subtype* of the target
-                // trait. In particular, changing from something like
-                // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
-                // permitted. And, indeed, in the in commit
-                // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
-                // condition was loosened. However, when the leak check was
-                // added back, using subtype here actually guides the coercion
-                // code in such a way that it accepts `old-lub-glb-object.rs`.
-                // This is probably a good thing, but I've modified this to `.eq`
-                // because I want to continue rejecting that test (as we have
-                // done for quite some time) before we are firmly comfortable
-                // with what our behavior should be there. -nikomatsakis
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .eq(target, source_trait) // FIXME -- see below
+                    .sup(target, source_trait)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
index 7ebf30f61c0956f0a981f4ccdadd4f21607b199e..cff5efbfd0fd169ec6e9c1e514b2df761681a6dd 100644 (file)
@@ -21,7 +21,7 @@
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 use super::{Overflow, SelectionError, Unimplemented};
 
-use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
+use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::traits::error_reporting::InferCtxtExt;
 use crate::traits::project::ProjectionCacheKeyExt;
 use rustc_ast::attr;
@@ -347,6 +347,12 @@ fn evaluation_probe(
     ) -> Result<EvaluationResult, OverflowError> {
         self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
             let result = op(self)?;
+
+            match self.infcx.leak_check(true, snapshot) {
+                Ok(()) => {}
+                Err(_) => return Ok(EvaluatedToErr),
+            }
+
             match self.infcx.region_constraints_added_in_snapshot(snapshot) {
                 None => Ok(result),
                 Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
@@ -1262,10 +1268,9 @@ fn insert_candidate_cache(
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
-        let (placeholder_trait_predicate, placeholder_map) =
+        let (placeholder_trait_predicate, _) =
             self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
             "match_projection_obligation_against_definition_bounds: \
@@ -1273,9 +1278,12 @@ fn match_projection_obligation_against_definition_bounds(
             placeholder_trait_predicate,
         );
 
-        let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind {
-            ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
-            ty::Opaque(def_id, substs) => (def_id, substs),
+        let tcx = self.infcx.tcx;
+        let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind {
+            ty::Projection(ref data) => {
+                tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
+            }
+            ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
             _ => {
                 span_bug!(
                     obligation.cause.span,
@@ -1285,32 +1293,17 @@ fn match_projection_obligation_against_definition_bounds(
                 );
             }
         };
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             def_id={:?}, substs={:?}",
-            def_id, substs
-        );
-
-        let predicates_of = self.tcx().predicates_of(def_id);
-        let bounds = predicates_of.instantiate(self.tcx(), substs);
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             bounds={:?}",
-            bounds
-        );
 
-        let elaborated_predicates =
-            util::elaborate_predicates(self.tcx(), bounds.predicates.into_iter());
-        let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| {
-            self.infcx.probe(|_| {
-                self.match_projection(
-                    obligation,
-                    *bound,
-                    placeholder_trait_predicate.trait_ref,
-                    &placeholder_map,
-                    snapshot,
-                )
-            })
+        let matching_bound = predicates.iter().find_map(|bound| {
+            if let ty::PredicateKind::Trait(bound, _) = bound.kind() {
+                let bound = bound.to_poly_trait_ref();
+                if self.infcx.probe(|_| {
+                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref)
+                }) {
+                    return Some(bound);
+                }
+            }
+            None
         });
 
         debug!(
@@ -1322,13 +1315,8 @@ fn match_projection_obligation_against_definition_bounds(
             None => false,
             Some(bound) => {
                 // Repeat the successful match, if any, this time outside of a probe.
-                let result = self.match_projection(
-                    obligation,
-                    bound,
-                    placeholder_trait_predicate.trait_ref,
-                    &placeholder_map,
-                    snapshot,
-                );
+                let result =
+                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref);
 
                 assert!(result);
                 true
@@ -1341,15 +1329,12 @@ fn match_projection(
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
         placeholder_trait_ref: ty::TraitRef<'tcx>,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
         self.infcx
             .at(&obligation.cause, obligation.param_env)
             .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .is_ok()
-            && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
     }
 
     fn evaluate_where_clause<'o>(
@@ -1569,7 +1554,7 @@ fn sized_conditions(
             | ty::Array(..)
             | ty::Closure(..)
             | ty::Never
-            | ty::Error => {
+            | ty::Error(_) => {
                 // safe for everything
                 Where(ty::Binder::dummy(Vec::new()))
             }
@@ -1613,7 +1598,7 @@ fn copy_clone_conditions(
             | ty::Infer(ty::FloatVar(_))
             | ty::FnDef(..)
             | ty::FnPtr(_)
-            | ty::Error => Where(ty::Binder::dummy(Vec::new())),
+            | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())),
 
             ty::Uint(_)
             | ty::Int(_)
@@ -1690,7 +1675,7 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
             | ty::FnDef(..)
             | ty::FnPtr(_)
             | ty::Str
-            | ty::Error
+            | ty::Error(_)
             | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Never
             | ty::Char => Vec::new(),
@@ -1754,27 +1739,26 @@ fn collect_predicates_for_types(
     ) -> Vec<PredicateObligation<'tcx>> {
         // Because the types were potentially derived from
         // higher-ranked obligations they may reference late-bound
-        // regions. For example, `for<'a> Foo<&'a int> : Copy` would
-        // yield a type like `for<'a> &'a int`. In general, we
+        // regions. For example, `for<'a> Foo<&'a i32> : Copy` would
+        // yield a type like `for<'a> &'a i32`. In general, we
         // maintain the invariant that we never manipulate bound
         // regions, so we have to process these bound regions somehow.
         //
         // The strategy is to:
         //
         // 1. Instantiate those regions to placeholder regions (e.g.,
-        //    `for<'a> &'a int` becomes `&0 int`.
-        // 2. Produce something like `&'0 int : Copy`
-        // 3. Re-bind the regions back to `for<'a> &'a int : Copy`
+        //    `for<'a> &'a i32` becomes `&0 i32`.
+        // 2. Produce something like `&'0 i32 : Copy`
+        // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy`
 
         types
-            .skip_binder()
+            .skip_binder() // binder moved -\
             .iter()
             .flat_map(|ty| {
-                // binder moved -\
                 let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
 
                 self.infcx.commit_unconditionally(|_| {
-                    let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
+                    let (placeholder_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
                     let Normalized { value: normalized_ty, mut obligations } =
                         ensure_sufficient_stack(|| {
                             project::normalize_with_depth(
@@ -1782,10 +1766,10 @@ fn collect_predicates_for_types(
                                 param_env,
                                 cause.clone(),
                                 recursion_depth,
-                                &skol_ty,
+                                &placeholder_ty,
                             )
                         });
-                    let skol_obligation = predicate_for_trait_def(
+                    let placeholder_obligation = predicate_for_trait_def(
                         self.tcx(),
                         param_env,
                         cause.clone(),
@@ -1794,7 +1778,7 @@ fn collect_predicates_for_types(
                         normalized_ty,
                         &[],
                     );
-                    obligations.push(skol_obligation);
+                    obligations.push(placeholder_obligation);
                     obligations
                 })
             })
@@ -1815,9 +1799,8 @@ fn rematch_impl(
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Normalized<'tcx, SubstsRef<'tcx>> {
-        match self.match_impl(impl_def_id, obligation, snapshot) {
+        match self.match_impl(impl_def_id, obligation) {
             Ok(substs) => substs,
             Err(()) => {
                 bug!(
@@ -1833,7 +1816,6 @@ fn match_impl(
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
@@ -1844,9 +1826,9 @@ fn match_impl(
             return Err(());
         }
 
-        let (skol_obligation, placeholder_map) =
+        let (placeholder_obligation, _) =
             self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
-        let skol_obligation_trait_ref = skol_obligation.trait_ref;
+        let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
 
         let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
 
@@ -1865,22 +1847,17 @@ fn match_impl(
 
         debug!(
             "match_impl(impl_def_id={:?}, obligation={:?}, \
-             impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
-            impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref
+             impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})",
+            impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref
         );
 
         let InferOk { obligations, .. } = self
             .infcx
             .at(&obligation.cause, obligation.param_env)
-            .eq(skol_obligation_trait_ref, impl_trait_ref)
+            .eq(placeholder_obligation_trait_ref, impl_trait_ref)
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
         nested_obligations.extend(obligations);
 
-        if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) {
-            debug!("match_impl: failed leak check due to `{}`", e);
-            return Err(());
-        }
-
         if !self.intercrate
             && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
         {
index 2b596be95426704a6a41526c81b4f1ba2ddeaa66..42901102c10760d0c92f077221501c04e9cb0e3f 100644 (file)
@@ -130,7 +130,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
 
     // We determine whether there's a subset relationship by:
     //
-    // - skolemizing impl1,
+    // - replacing bound vars with placeholders in impl1,
     // - assuming the where clauses for impl1,
     // - instantiating impl2 with fresh inference variables,
     // - unifying,
index c4deb639140ca3119191d60e7376e4526f70395c..201edf27a655cbba3d77ea2eb6e96492c8c8f26c 100644 (file)
@@ -219,7 +219,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
             ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
             }
-            ty::Error => {
+            ty::Error(_) => {
                 self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                 // We still want to check other types after encountering an error,
                 // as this may still emit relevant errors.
index 8b5b4128e6672e726248d98c7581b64daa23a82e..d3484b8af89fd54f9eb67e2f51350cc8e8dd0592 100644 (file)
@@ -302,7 +302,7 @@ pub fn get_vtable_index_of_object_method<N>(
 ) -> usize {
     // Count number of methods preceding the one we are selecting and
     // add them to the total offset.
-    // Skip over associated types and constants.
+    // Skip over associated types and constants, as those aren't stored in the vtable.
     let mut entries = object.vtable_base;
     for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
         if trait_item.def_id == method_def_id {
index 90a9b876d8ddf3b9fafecd9220156be29d545e22..1825c159ff3fba47bedffdf47e277c2becd5b95f 100644 (file)
@@ -392,7 +392,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                                 ));
                             }
                         }
-                        ty::ConstKind::Error
+                        ty::ConstKind::Error(_)
                         | ty::ConstKind::Param(_)
                         | ty::ConstKind::Bound(..)
                         | ty::ConstKind::Placeholder(..) => {
@@ -412,7 +412,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 | ty::Int(..)
                 | ty::Uint(..)
                 | ty::Float(..)
-                | ty::Error
+                | ty::Error(_)
                 | ty::Str
                 | ty::GeneratorWitness(..)
                 | ty::Never
index e485bc2929bdb9feee7287acb626c05703cf048c..079b9b10fd0901162a3745fd58f8ae3ecaf0dd0b 100644 (file)
@@ -16,9 +16,8 @@ rustc_hir = { path = "../librustc_hir" }
 rustc_index = { path = "../librustc_index" }
 rustc_ast = { path = "../librustc_ast" }
 rustc_span = { path = "../librustc_span" }
-chalk-ir = "0.10.0"
-chalk-rust-ir = "0.10.0"
-chalk-solve = "0.10.0"
+chalk-ir = "0.14.0"
+chalk-solve = "0.14.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_infer = { path = "../librustc_infer" }
 rustc_trait_selection = { path = "../librustc_trait_selection" }
index a2aee9b6ef74d777d9a6c8dc6e6dfe73e6a27511..715e5299a37bda7ec2e9e83595276e8190061969 100644 (file)
@@ -6,7 +6,7 @@
 //! either the `TyCtxt` (for information about types) or
 //! `crate::chalk::lowering` (to lower rustc types into Chalk types).
 
-use rustc_middle::traits::{ChalkRustDefId as RustDefId, ChalkRustInterner as RustInterner};
+use rustc_middle::traits::ChalkRustInterner as RustInterner;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt};
 
@@ -38,11 +38,8 @@ fn interner(&self) -> &RustInterner<'tcx> {
     fn associated_ty_data(
         &self,
         assoc_type_id: chalk_ir::AssocTypeId<RustInterner<'tcx>>,
-    ) -> Arc<chalk_rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
-        let def_id = match assoc_type_id.0 {
-            RustDefId::AssocTy(def_id) => def_id,
-            _ => bug!("Did not use `AssocTy` variant when expecting associated type."),
-        };
+    ) -> Arc<chalk_solve::rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
+        let def_id = assoc_type_id.0;
         let assoc_item = self.tcx.associated_item(def_id);
         let trait_def_id = match assoc_item.container {
             AssocItemContainer::TraitContainer(def_id) => def_id,
@@ -63,13 +60,13 @@ fn associated_ty_data(
             .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
 
-        Arc::new(chalk_rust_ir::AssociatedTyDatum {
-            trait_id: chalk_ir::TraitId(RustDefId::Trait(trait_def_id)),
+        Arc::new(chalk_solve::rust_ir::AssociatedTyDatum {
+            trait_id: chalk_ir::TraitId(trait_def_id),
             id: assoc_type_id,
             name: (),
             binders: chalk_ir::Binders::new(
                 binders,
-                chalk_rust_ir::AssociatedTyDatumBound { bounds: vec![], where_clauses },
+                chalk_solve::rust_ir::AssociatedTyDatumBound { bounds: vec![], where_clauses },
             ),
         })
     }
@@ -77,11 +74,8 @@ fn associated_ty_data(
     fn trait_datum(
         &self,
         trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
-    ) -> Arc<chalk_rust_ir::TraitDatum<RustInterner<'tcx>>> {
-        let def_id = match trait_id.0 {
-            RustDefId::Trait(def_id) => def_id,
-            _ => bug!("Did not use `Trait` variant when expecting trait."),
-        };
+    ) -> Arc<chalk_solve::rust_ir::TraitDatum<RustInterner<'tcx>>> {
+        let def_id = trait_id.0;
         let trait_def = self.tcx.trait_def(def_id);
 
         let bound_vars = bound_vars_for_item(self.tcx, def_id);
@@ -91,24 +85,39 @@ fn trait_datum(
             .iter()
             .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+        let associated_ty_ids: Vec<_> = self
+            .tcx
+            .associated_items(def_id)
+            .in_definition_order()
+            .filter(|i| i.kind == AssocKind::Type)
+            .map(|i| chalk_ir::AssocTypeId(i.def_id))
+            .collect();
 
         let well_known =
             if self.tcx.lang_items().sized_trait().map(|t| def_id == t).unwrap_or(false) {
-                Some(chalk_rust_ir::WellKnownTrait::SizedTrait)
+                Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
             } else if self.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) {
-                Some(chalk_rust_ir::WellKnownTrait::CopyTrait)
+                Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
             } else if self.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) {
-                Some(chalk_rust_ir::WellKnownTrait::CloneTrait)
+                Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
+            } else if self.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
+            } else if self.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
+            } else if self.tcx.lang_items().fn_once_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce)
+            } else if self.tcx.lang_items().fn_mut_trait().map(|t| def_id == t).unwrap_or(false) {
+                Some(chalk_solve::rust_ir::WellKnownTrait::FnMut)
             } else {
                 None
             };
-        Arc::new(chalk_rust_ir::TraitDatum {
+        Arc::new(chalk_solve::rust_ir::TraitDatum {
             id: trait_id,
             binders: chalk_ir::Binders::new(
                 binders,
-                chalk_rust_ir::TraitDatumBound { where_clauses },
+                chalk_solve::rust_ir::TraitDatumBound { where_clauses },
             ),
-            flags: chalk_rust_ir::TraitFlags {
+            flags: chalk_solve::rust_ir::TraitFlags {
                 auto: trait_def.has_auto_impl,
                 marker: trait_def.is_marker,
                 upstream: !def_id.is_local(),
@@ -116,106 +125,108 @@ fn trait_datum(
                 non_enumerable: true,
                 coinductive: false,
             },
-            associated_ty_ids: vec![],
+            associated_ty_ids,
             well_known,
         })
     }
 
-    fn struct_datum(
+    fn adt_datum(
         &self,
-        struct_id: chalk_ir::StructId<RustInterner<'tcx>>,
-    ) -> Arc<chalk_rust_ir::StructDatum<RustInterner<'tcx>>> {
-        match struct_id.0 {
-            RustDefId::Adt(adt_def_id) => {
-                let adt_def = self.tcx.adt_def(adt_def_id);
+        adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
+    ) -> Arc<chalk_solve::rust_ir::AdtDatum<RustInterner<'tcx>>> {
+        let adt_def = adt_id.0;
 
-                let bound_vars = bound_vars_for_item(self.tcx, adt_def_id);
-                let binders = binders_for(&self.interner, bound_vars);
+        let bound_vars = bound_vars_for_item(self.tcx, adt_def.did);
+        let binders = binders_for(&self.interner, bound_vars);
 
-                let predicates = self.tcx.predicates_of(adt_def_id).predicates;
-                let where_clauses: Vec<_> = predicates
+        let predicates = self.tcx.predicates_of(adt_def.did).predicates;
+        let where_clauses: Vec<_> = predicates
+            .into_iter()
+            .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
+            .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
+            .collect();
+        let fields = match adt_def.adt_kind() {
+            ty::AdtKind::Struct | ty::AdtKind::Union => {
+                let variant = adt_def.non_enum_variant();
+                variant
+                    .fields
                     .iter()
-                    .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
-                    .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
-                    .collect();
-                let fields = match adt_def.adt_kind() {
-                    ty::AdtKind::Struct | ty::AdtKind::Union => {
-                        let variant = adt_def.non_enum_variant();
-                        variant
-                            .fields
-                            .iter()
-                            .map(|field| {
-                                self.tcx
-                                    .type_of(field.did)
-                                    .subst(self.tcx, bound_vars)
-                                    .lower_into(&self.interner)
-                            })
-                            .collect()
-                    }
-                    // FIXME(chalk): handle enums; force_impl_for requires this
-                    ty::AdtKind::Enum => vec![],
-                };
-                let struct_datum = Arc::new(chalk_rust_ir::StructDatum {
-                    id: struct_id,
-                    binders: chalk_ir::Binders::new(
-                        binders,
-                        chalk_rust_ir::StructDatumBound { fields, where_clauses },
-                    ),
-                    flags: chalk_rust_ir::StructFlags {
-                        upstream: !adt_def_id.is_local(),
-                        fundamental: adt_def.is_fundamental(),
-                    },
-                });
-                struct_datum
-            }
-            RustDefId::Ref(_) => Arc::new(chalk_rust_ir::StructDatum {
-                id: struct_id,
-                binders: chalk_ir::Binders::new(
-                    chalk_ir::ParameterKinds::from(
-                        &self.interner,
-                        vec![
-                            chalk_ir::ParameterKind::Lifetime(()),
-                            chalk_ir::ParameterKind::Ty(()),
-                        ],
-                    ),
-                    chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
-                ),
-                flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
-            }),
-            RustDefId::Array | RustDefId::Slice => Arc::new(chalk_rust_ir::StructDatum {
-                id: struct_id,
-                binders: chalk_ir::Binders::new(
-                    chalk_ir::ParameterKinds::from(
-                        &self.interner,
-                        Some(chalk_ir::ParameterKind::Ty(())),
-                    ),
-                    chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
-                ),
-                flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
-            }),
-            RustDefId::Str | RustDefId::Never | RustDefId::FnDef(_) => {
-                Arc::new(chalk_rust_ir::StructDatum {
-                    id: struct_id,
-                    binders: chalk_ir::Binders::new(
-                        chalk_ir::ParameterKinds::new(&self.interner),
-                        chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
-                    ),
-                    flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
-                })
+                    .map(|field| {
+                        self.tcx
+                            .type_of(field.did)
+                            .subst(self.tcx, bound_vars)
+                            .lower_into(&self.interner)
+                    })
+                    .collect()
             }
+            // FIXME(chalk): handle enums; force_impl_for requires this
+            ty::AdtKind::Enum => vec![],
+        };
+        let struct_datum = Arc::new(chalk_solve::rust_ir::AdtDatum {
+            id: adt_id,
+            binders: chalk_ir::Binders::new(
+                binders,
+                chalk_solve::rust_ir::AdtDatumBound { fields, where_clauses },
+            ),
+            flags: chalk_solve::rust_ir::AdtFlags {
+                upstream: !adt_def.did.is_local(),
+                fundamental: adt_def.is_fundamental(),
+                phantom_data: adt_def.is_phantom_data(),
+            },
+        });
+        return struct_datum;
+    }
 
-            _ => bug!("Used not struct variant when expecting struct variant."),
-        }
+    fn fn_def_datum(
+        &self,
+        fn_def_id: chalk_ir::FnDefId<RustInterner<'tcx>>,
+    ) -> Arc<chalk_solve::rust_ir::FnDefDatum<RustInterner<'tcx>>> {
+        let def_id = fn_def_id.0;
+        let bound_vars = bound_vars_for_item(self.tcx, def_id);
+        let binders = binders_for(&self.interner, bound_vars);
+
+        let predicates = self.tcx.predicates_defined_on(def_id).predicates;
+        let where_clauses: Vec<_> = predicates
+            .into_iter()
+            .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
+            .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+
+        let sig = self.tcx.fn_sig(def_id);
+        let inputs_and_output = sig.inputs_and_output();
+        let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
+            &self.interner,
+            self.tcx,
+            &inputs_and_output,
+        );
+
+        let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
+            .iter()
+            .map(|t| t.subst(self.tcx, &bound_vars).lower_into(&self.interner))
+            .collect();
+
+        let return_type = inputs_and_output[inputs_and_output.len() - 1]
+            .subst(self.tcx, &bound_vars)
+            .lower_into(&self.interner);
+
+        let bound = chalk_solve::rust_ir::FnDefDatumBound {
+            inputs_and_output: chalk_ir::Binders::new(
+                iobinders,
+                chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type },
+            ),
+            where_clauses,
+        };
+        Arc::new(chalk_solve::rust_ir::FnDefDatum {
+            id: fn_def_id,
+            abi: sig.abi(),
+            binders: chalk_ir::Binders::new(binders, bound),
+        })
     }
 
     fn impl_datum(
         &self,
         impl_id: chalk_ir::ImplId<RustInterner<'tcx>>,
-    ) -> Arc<chalk_rust_ir::ImplDatum<RustInterner<'tcx>>> {
-        let def_id = match impl_id.0 {
-            RustDefId::Impl(def_id) => def_id,
-            _ => bug!("Did not use `Impl` variant when expecting impl."),
-        };
+    ) -> Arc<chalk_solve::rust_ir::ImplDatum<RustInterner<'tcx>>> {
+        let def_id = impl_id.0;
         let bound_vars = bound_vars_for_item(self.tcx, def_id);
         let binders = binders_for(&self.interner, bound_vars);
 
@@ -228,15 +239,15 @@ fn impl_datum(
             .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
 
-        let value = chalk_rust_ir::ImplDatumBound {
+        let value = chalk_solve::rust_ir::ImplDatumBound {
             trait_ref: trait_ref.lower_into(&self.interner),
             where_clauses,
         };
 
-        Arc::new(chalk_rust_ir::ImplDatum {
-            polarity: chalk_rust_ir::Polarity::Positive,
+        Arc::new(chalk_solve::rust_ir::ImplDatum {
+            polarity: chalk_solve::rust_ir::Polarity::Positive,
             binders: chalk_ir::Binders::new(binders, value),
-            impl_type: chalk_rust_ir::ImplType::Local,
+            impl_type: chalk_solve::rust_ir::ImplType::Local,
             associated_ty_value_ids: vec![],
         })
     }
@@ -244,12 +255,9 @@ fn impl_datum(
     fn impls_for_trait(
         &self,
         trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
-        parameters: &[chalk_ir::Parameter<RustInterner<'tcx>>],
+        parameters: &[chalk_ir::GenericArg<RustInterner<'tcx>>],
     ) -> Vec<chalk_ir::ImplId<RustInterner<'tcx>>> {
-        let def_id: DefId = match trait_id.0 {
-            RustDefId::Trait(def_id) => def_id,
-            _ => bug!("Did not use `Trait` variant when expecting trait."),
-        };
+        let def_id = trait_id.0;
 
         // FIXME(chalk): use TraitDef::for_each_relevant_impl, but that will
         // require us to be able to interconvert `Ty<'tcx>`, and we're
@@ -268,32 +276,24 @@ fn impls_for_trait(
             parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty)
         });
 
-        let impls = matched_impls
-            .map(|matched_impl| chalk_ir::ImplId(RustDefId::Impl(matched_impl)))
-            .collect();
+        let impls = matched_impls.map(|matched_impl| chalk_ir::ImplId(matched_impl)).collect();
         impls
     }
 
     fn impl_provided_for(
         &self,
         auto_trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
-        struct_id: chalk_ir::StructId<RustInterner<'tcx>>,
+        adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
     ) -> bool {
-        let trait_def_id: DefId = match auto_trait_id.0 {
-            RustDefId::Trait(def_id) => def_id,
-            _ => bug!("Did not use `Trait` variant when expecting trait."),
-        };
-        let adt_def_id: DefId = match struct_id.0 {
-            RustDefId::Adt(def_id) => def_id,
-            _ => bug!("Did not use `Adt` variant when expecting adt."),
-        };
+        let trait_def_id = auto_trait_id.0;
+        let adt_def = adt_id.0;
         let all_impls = self.tcx.all_impls(trait_def_id);
         for impl_def_id in all_impls {
             let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
             let self_ty = trait_ref.self_ty();
             match self_ty.kind {
-                ty::Adt(adt_def, _) => {
-                    if adt_def.did == adt_def_id {
+                ty::Adt(impl_adt_def, _) => {
+                    if impl_adt_def == adt_def {
                         return true;
                     }
                 }
@@ -305,12 +305,9 @@ fn impl_provided_for(
 
     fn associated_ty_value(
         &self,
-        associated_ty_id: chalk_rust_ir::AssociatedTyValueId<RustInterner<'tcx>>,
-    ) -> Arc<chalk_rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
-        let def_id = match associated_ty_id.0 {
-            RustDefId::AssocTy(def_id) => def_id,
-            _ => bug!("Did not use `AssocTy` variant when expecting associated type."),
-        };
+        associated_ty_id: chalk_solve::rust_ir::AssociatedTyValueId<RustInterner<'tcx>>,
+    ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
+        let def_id = associated_ty_id.0;
         let assoc_item = self.tcx.associated_item(def_id);
         let impl_id = match assoc_item.container {
             AssocItemContainer::TraitContainer(def_id) => def_id,
@@ -324,12 +321,12 @@ fn associated_ty_value(
         let binders = binders_for(&self.interner, bound_vars);
         let ty = self.tcx.type_of(def_id);
 
-        Arc::new(chalk_rust_ir::AssociatedTyValue {
-            impl_id: chalk_ir::ImplId(RustDefId::Impl(impl_id)),
-            associated_ty_id: chalk_ir::AssocTypeId(RustDefId::AssocTy(def_id)),
+        Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
+            impl_id: chalk_ir::ImplId(impl_id),
+            associated_ty_id: chalk_ir::AssocTypeId(def_id),
             value: chalk_ir::Binders::new(
                 binders,
-                chalk_rust_ir::AssociatedTyValueBound { ty: ty.lower_into(&self.interner) },
+                chalk_solve::rust_ir::AssociatedTyValueBound { ty: ty.lower_into(&self.interner) },
             ),
         })
     }
@@ -347,9 +344,23 @@ fn local_impls_to_coherence_check(
 
     fn opaque_ty_data(
         &self,
-        _id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
-    ) -> Arc<chalk_rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
-        unimplemented!()
+        opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
+    ) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
+        let bound_vars = bound_vars_for_item(self.tcx, opaque_ty_id.0);
+        let binders = binders_for(&self.interner, bound_vars);
+        let predicates = self.tcx.predicates_defined_on(opaque_ty_id.0).predicates;
+        let where_clauses: Vec<_> = predicates
+            .iter()
+            .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
+            .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
+
+        let value = chalk_solve::rust_ir::OpaqueTyDatumBound {
+            bounds: chalk_ir::Binders::new(binders, where_clauses),
+        };
+        Arc::new(chalk_solve::rust_ir::OpaqueTyDatum {
+            opaque_ty_id,
+            bound: chalk_ir::Binders::new(chalk_ir::VariableKinds::new(&self.interner), value),
+        })
     }
 
     /// Since Chalk can't handle all Rust types currently, we have to handle
@@ -357,74 +368,53 @@ fn opaque_ty_data(
     /// `None` and eventually this function will be removed.
     fn force_impl_for(
         &self,
-        well_known: chalk_rust_ir::WellKnownTrait,
+        well_known: chalk_solve::rust_ir::WellKnownTrait,
         ty: &chalk_ir::TyData<RustInterner<'tcx>>,
     ) -> Option<bool> {
         use chalk_ir::TyData::*;
         match well_known {
-            chalk_rust_ir::WellKnownTrait::SizedTrait => match ty {
+            chalk_solve::rust_ir::WellKnownTrait::Sized => match ty {
                 Apply(apply) => match apply.name {
-                    chalk_ir::TypeName::Struct(chalk_ir::StructId(rust_def_id)) => {
-                        use rustc_middle::traits::ChalkRustDefId::*;
-                        match rust_def_id {
-                            Never | Array | RawPtr | FnDef(_) | Ref(_) => Some(true),
-
-                            Adt(adt_def_id) => {
-                                let adt_def = self.tcx.adt_def(adt_def_id);
-                                match adt_def.adt_kind() {
-                                    ty::AdtKind::Struct | ty::AdtKind::Union => None,
-                                    ty::AdtKind::Enum => {
-                                        let constraint = self.tcx.adt_sized_constraint(adt_def_id);
-                                        if !constraint.0.is_empty() {
-                                            unimplemented!()
-                                        } else {
-                                            Some(true)
-                                        }
-                                    }
-                                }
-                            }
-
-                            Str | Slice => Some(false),
-
-                            Trait(_) | Impl(_) | AssocTy(_) => panic!(),
+                    chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() {
+                        ty::AdtKind::Struct | ty::AdtKind::Union => None,
+                        ty::AdtKind::Enum => {
+                            let constraint = self.tcx.adt_sized_constraint(adt_def.did);
+                            if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
                         }
-                    }
+                    },
                     _ => None,
                 },
-                Dyn(_) | Alias(_) | Placeholder(_) | Function(_) | InferenceVar(_)
+                Dyn(_)
+                | Alias(_)
+                | Placeholder(_)
+                | Function(_)
+                | InferenceVar(_, _)
                 | BoundVar(_) => None,
             },
-            chalk_rust_ir::WellKnownTrait::CopyTrait
-            | chalk_rust_ir::WellKnownTrait::CloneTrait => match ty {
+            chalk_solve::rust_ir::WellKnownTrait::Copy
+            | chalk_solve::rust_ir::WellKnownTrait::Clone => match ty {
                 Apply(apply) => match apply.name {
-                    chalk_ir::TypeName::Struct(chalk_ir::StructId(rust_def_id)) => {
-                        use rustc_middle::traits::ChalkRustDefId::*;
-                        match rust_def_id {
-                            Never | RawPtr | Ref(_) | Str | Slice => Some(false),
-                            FnDef(_) | Array => Some(true),
-                            Adt(adt_def_id) => {
-                                let adt_def = self.tcx.adt_def(adt_def_id);
-                                match adt_def.adt_kind() {
-                                    ty::AdtKind::Struct | ty::AdtKind::Union => None,
-                                    ty::AdtKind::Enum => {
-                                        let constraint = self.tcx.adt_sized_constraint(adt_def_id);
-                                        if !constraint.0.is_empty() {
-                                            unimplemented!()
-                                        } else {
-                                            Some(true)
-                                        }
-                                    }
-                                }
-                            }
-                            Trait(_) | Impl(_) | AssocTy(_) => panic!(),
+                    chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() {
+                        ty::AdtKind::Struct | ty::AdtKind::Union => None,
+                        ty::AdtKind::Enum => {
+                            let constraint = self.tcx.adt_sized_constraint(adt_def.did);
+                            if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
                         }
-                    }
+                    },
                     _ => None,
                 },
-                Dyn(_) | Alias(_) | Placeholder(_) | Function(_) | InferenceVar(_)
+                Dyn(_)
+                | Alias(_)
+                | Placeholder(_)
+                | Function(_)
+                | InferenceVar(_, _)
                 | BoundVar(_) => None,
             },
-            chalk_rust_ir::WellKnownTrait::DropTrait => None,
+            chalk_solve::rust_ir::WellKnownTrait::Drop => None,
+            chalk_solve::rust_ir::WellKnownTrait::Fn => None,
+            chalk_solve::rust_ir::WellKnownTrait::FnMut => None,
+            chalk_solve::rust_ir::WellKnownTrait::FnOnce => None,
+            chalk_solve::rust_ir::WellKnownTrait::Unsize => None,
         }
     }
 
@@ -437,36 +427,113 @@ fn program_clauses_for_env(
 
     fn well_known_trait_id(
         &self,
-        well_known_trait: chalk_rust_ir::WellKnownTrait,
+        well_known_trait: chalk_solve::rust_ir::WellKnownTrait,
     ) -> Option<chalk_ir::TraitId<RustInterner<'tcx>>> {
-        use chalk_rust_ir::WellKnownTrait::*;
-        let t = match well_known_trait {
-            SizedTrait => self
-                .tcx
-                .lang_items()
-                .sized_trait()
-                .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
-                .unwrap(),
-            CopyTrait => self
-                .tcx
-                .lang_items()
-                .copy_trait()
-                .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
-                .unwrap(),
-            CloneTrait => self
-                .tcx
-                .lang_items()
-                .clone_trait()
-                .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
-                .unwrap(),
-            DropTrait => self
-                .tcx
-                .lang_items()
-                .drop_trait()
-                .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
-                .unwrap(),
+        use chalk_solve::rust_ir::WellKnownTrait::*;
+        let def_id = match well_known_trait {
+            Sized => self.tcx.lang_items().sized_trait(),
+            Copy => self.tcx.lang_items().copy_trait(),
+            Clone => self.tcx.lang_items().clone_trait(),
+            Drop => self.tcx.lang_items().drop_trait(),
+            Fn => self.tcx.lang_items().fn_trait(),
+            FnMut => self.tcx.lang_items().fn_mut_trait(),
+            FnOnce => self.tcx.lang_items().fn_once_trait(),
+            Unsize => self.tcx.lang_items().unsize_trait(),
         };
-        Some(t)
+        def_id.map(|t| chalk_ir::TraitId(t))
+    }
+
+    fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
+        self.tcx.is_object_safe(trait_id.0)
+    }
+
+    fn hidden_opaque_type(
+        &self,
+        _id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
+    ) -> chalk_ir::Ty<RustInterner<'tcx>> {
+        // FIXME(chalk): actually get hidden ty
+        self.tcx.mk_ty(ty::Tuple(self.tcx.intern_substs(&[]))).lower_into(&self.interner)
+    }
+
+    fn closure_kind(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_solve::rust_ir::ClosureKind {
+        let kind = &substs.parameters(&self.interner)[substs.len(&self.interner) - 3];
+        match kind.assert_ty_ref(&self.interner).data(&self.interner) {
+            chalk_ir::TyData::Apply(apply) => match apply.name {
+                chalk_ir::TypeName::Scalar(scalar) => match scalar {
+                    chalk_ir::Scalar::Int(int_ty) => match int_ty {
+                        chalk_ir::IntTy::I8 => chalk_solve::rust_ir::ClosureKind::Fn,
+                        chalk_ir::IntTy::I16 => chalk_solve::rust_ir::ClosureKind::FnMut,
+                        chalk_ir::IntTy::I32 => chalk_solve::rust_ir::ClosureKind::FnOnce,
+                        _ => bug!("bad closure kind"),
+                    },
+                    _ => bug!("bad closure kind"),
+                },
+                _ => bug!("bad closure kind"),
+            },
+            _ => bug!("bad closure kind"),
+        }
+    }
+
+    fn closure_inputs_and_output(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_ir::Binders<chalk_solve::rust_ir::FnDefInputsAndOutputDatum<RustInterner<'tcx>>>
+    {
+        let sig = &substs.parameters(&self.interner)[substs.len(&self.interner) - 2];
+        match sig.assert_ty_ref(&self.interner).data(&self.interner) {
+            chalk_ir::TyData::Function(f) => {
+                let substitution = f.substitution.parameters(&self.interner);
+                let return_type =
+                    substitution.last().unwrap().assert_ty_ref(&self.interner).clone();
+                // Closure arguments are tupled
+                let argument_tuple = substitution[0].assert_ty_ref(&self.interner);
+                let argument_types = match argument_tuple.data(&self.interner) {
+                    chalk_ir::TyData::Apply(apply) => match apply.name {
+                        chalk_ir::TypeName::Tuple(_) => apply
+                            .substitution
+                            .iter(&self.interner)
+                            .map(|arg| arg.assert_ty_ref(&self.interner))
+                            .cloned()
+                            .collect(),
+                        _ => bug!("Expecting closure FnSig args to be tupled."),
+                    },
+                    _ => bug!("Expecting closure FnSig args to be tupled."),
+                };
+
+                chalk_ir::Binders::new(
+                    chalk_ir::VariableKinds::from(
+                        &self.interner,
+                        (0..f.num_binders).map(|_| chalk_ir::VariableKind::Lifetime),
+                    ),
+                    chalk_solve::rust_ir::FnDefInputsAndOutputDatum { argument_types, return_type },
+                )
+            }
+            _ => panic!("Invalid sig."),
+        }
+    }
+
+    fn closure_upvars(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_ir::Binders<chalk_ir::Ty<RustInterner<'tcx>>> {
+        let inputs_and_output = self.closure_inputs_and_output(_closure_id, substs);
+        let tuple = substs.parameters(&self.interner).last().unwrap().assert_ty_ref(&self.interner);
+        inputs_and_output.map_ref(|_| tuple.clone())
+    }
+
+    fn closure_fn_substitution(
+        &self,
+        _closure_id: chalk_ir::ClosureId<RustInterner<'tcx>>,
+        substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
+    ) -> chalk_ir::Substitution<RustInterner<'tcx>> {
+        let substitution = &substs.parameters(&self.interner)[0..substs.len(&self.interner) - 3];
+        chalk_ir::Substitution::from(&self.interner, substitution)
     }
 }
 
@@ -505,13 +572,17 @@ fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
 fn binders_for<'tcx>(
     interner: &RustInterner<'tcx>,
     bound_vars: SubstsRef<'tcx>,
-) -> chalk_ir::ParameterKinds<RustInterner<'tcx>> {
-    chalk_ir::ParameterKinds::from(
+) -> chalk_ir::VariableKinds<RustInterner<'tcx>> {
+    chalk_ir::VariableKinds::from(
         interner,
         bound_vars.iter().map(|arg| match arg.unpack() {
-            ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::ParameterKind::Lifetime(()),
-            ty::subst::GenericArgKind::Type(_ty) => chalk_ir::ParameterKind::Ty(()),
-            ty::subst::GenericArgKind::Const(_const) => chalk_ir::ParameterKind::Ty(()),
+            ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::VariableKind::Lifetime,
+            ty::subst::GenericArgKind::Type(_ty) => {
+                chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)
+            }
+            ty::subst::GenericArgKind::Const(c) => {
+                chalk_ir::VariableKind::Const(c.ty.lower_into(interner))
+            }
         }),
     )
 }
index 9530b07e47cdb054ed552c57ad3391ac564d26f2..e09359b8b3fc13ba6d02e1d1b8dafedc80fa89f2 100644 (file)
@@ -32,8 +32,7 @@
 //! variables from the current `Binder`.
 
 use rustc_middle::traits::{
-    ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustDefId as RustDefId,
-    ChalkRustInterner as RustInterner,
+    ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner,
 };
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
@@ -44,6 +43,8 @@
 
 use std::collections::btree_map::{BTreeMap, Entry};
 
+use chalk_ir::fold::shift::Shift;
+
 /// Essentially an `Into` with a `&RustInterner` parameter
 crate trait LowerInto<'tcx, T> {
     /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`.
@@ -62,7 +63,7 @@ fn lower_into(
 impl<'tcx> LowerInto<'tcx, chalk_ir::AliasTy<RustInterner<'tcx>>> for ty::ProjectionTy<'tcx> {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::AliasTy<RustInterner<'tcx>> {
         chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
-            associated_ty_id: chalk_ir::AssocTypeId(RustDefId::AssocTy(self.item_def_id)),
+            associated_ty_id: chalk_ir::AssocTypeId(self.item_def_id),
             substitution: self.substs.lower_into(interner),
         })
     }
@@ -83,7 +84,7 @@ fn lower_into(
                             collect_bound_vars(interner, interner.tcx, predicate);
 
                         Some(
-                            chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
+                            chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
                                 binders,
                                 chalk_ir::ProgramClauseImplication {
                                     consequence: chalk_ir::DomainGoal::FromEnv(
@@ -98,15 +99,37 @@ fn lower_into(
                             .intern(interner),
                         )
                     }
-                    // FIXME(chalk): need to add RegionOutlives/TypeOutlives
-                    ty::PredicateKind::RegionOutlives(_) => None,
+                    ty::PredicateKind::RegionOutlives(predicate) => {
+                        let (predicate, binders, _named_regions) =
+                            collect_bound_vars(interner, interner.tcx, predicate);
+
+                        Some(
+                            chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
+                                binders,
+                                chalk_ir::ProgramClauseImplication {
+                                    consequence: chalk_ir::DomainGoal::Holds(
+                                        chalk_ir::WhereClause::LifetimeOutlives(
+                                            chalk_ir::LifetimeOutlives {
+                                                a: predicate.0.lower_into(interner),
+                                                b: predicate.1.lower_into(interner),
+                                            },
+                                        ),
+                                    ),
+                                    conditions: chalk_ir::Goals::new(interner),
+                                    priority: chalk_ir::ClausePriority::High,
+                                },
+                            ))
+                            .intern(interner),
+                        )
+                    }
+                    // FIXME(chalk): need to add TypeOutlives
                     ty::PredicateKind::TypeOutlives(_) => None,
                     ty::PredicateKind::Projection(predicate) => {
                         let (predicate, binders, _named_regions) =
                             collect_bound_vars(interner, interner.tcx, predicate);
 
                         Some(
-                            chalk_ir::ProgramClauseData::ForAll(chalk_ir::Binders::new(
+                            chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
                                 binders,
                                 chalk_ir::ProgramClauseImplication {
                                     consequence: chalk_ir::DomainGoal::Holds(
@@ -132,13 +155,16 @@ fn lower_into(
                 }
             }
             ChalkEnvironmentClause::TypeFromEnv(ty) => Some(
-                chalk_ir::ProgramClauseData::Implies(chalk_ir::ProgramClauseImplication {
-                    consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
-                        ty.lower_into(interner),
-                    )),
-                    conditions: chalk_ir::Goals::new(interner),
-                    priority: chalk_ir::ClausePriority::High,
-                })
+                chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
+                    chalk_ir::VariableKinds::new(interner),
+                    chalk_ir::ProgramClauseImplication {
+                        consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
+                            ty.lower_into(interner).shifted_in(interner),
+                        )),
+                        conditions: chalk_ir::Goals::new(interner),
+                        priority: chalk_ir::ClausePriority::High,
+                    },
+                ))
                 .intern(interner),
             ),
         });
@@ -157,30 +183,36 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
         match self.kind() {
             ty::PredicateKind::Trait(predicate, _) => predicate.lower_into(interner),
-            // FIXME(chalk): we need to register constraints.
-            ty::PredicateKind::RegionOutlives(_predicate) => {
-                chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
+            ty::PredicateKind::RegionOutlives(predicate) => {
+                let (predicate, binders, _named_regions) =
+                    collect_bound_vars(interner, interner.tcx, predicate);
+
+                chalk_ir::GoalData::Quantified(
+                    chalk_ir::QuantifierKind::ForAll,
+                    chalk_ir::Binders::new(
+                        binders,
+                        chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
+                            chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+                                a: predicate.0.lower_into(interner),
+                                b: predicate.1.lower_into(interner),
+                            }),
+                        ))
+                        .intern(interner),
+                    ),
+                )
             }
+            // FIXME(chalk): TypeOutlives
             ty::PredicateKind::TypeOutlives(_predicate) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
             }
             ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner),
             ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
                 GenericArgKind::Type(ty) => match ty.kind {
-                    // These types are always WF.
-                    ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => {
-                        chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
-                    }
-
-                    // FIXME(chalk): Well-formed only if ref lifetime outlives type
-                    ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
+                    // FIXME(chalk): In Chalk, a placeholder is WellFormed if it
+                    // `FromEnv`. However, when we "lower" Params, we don't update
+                    // the environment.
+                    ty::Placeholder(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
 
-                    ty::Param(..) => panic!("No Params expected."),
-
-                    // FIXME(chalk) -- ultimately I think this is what we
-                    // want to do, and we just have rules for how to prove
-                    // `WellFormed` for everything above, instead of
-                    // inlining a bit the rules of the proof here.
                     _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed(
                         chalk_ir::WellFormed::Ty(ty.lower_into(interner)),
                     )),
@@ -192,12 +224,15 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInt
                 GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt),
             },
 
+            ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(
+                chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(*t)),
+            ),
+
             // FIXME(chalk): other predicates
             //
             // We can defer this, but ultimately we'll want to express
             // some of these in terms of chalk operations.
-            ty::PredicateKind::ObjectSafe(..)
-            | ty::PredicateKind::ClosureKind(..)
+            ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..) => {
@@ -212,7 +247,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::TraitRef<RustInterner<'tcx>>>
 {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::TraitRef<RustInterner<'tcx>> {
         chalk_ir::TraitRef {
-            trait_id: chalk_ir::TraitId(RustDefId::Trait(self.def_id)),
+            trait_id: chalk_ir::TraitId(self.def_id),
             substitution: self.substs.lower_into(interner),
         }
     }
@@ -274,7 +309,8 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<
         use TyKind::*;
 
         let empty = || chalk_ir::Substitution::empty(interner);
-        let struct_ty = |def_id| chalk_ir::TypeName::Struct(chalk_ir::StructId(def_id));
+        let struct_ty =
+            |def_id| chalk_ir::TypeName::Adt(chalk_ir::AdtId(interner.tcx.adt_def(def_id)));
         let apply = |name, substitution| {
             TyData::Apply(chalk_ir::ApplicationTy { name, substitution }).intern(interner)
         };
@@ -305,39 +341,72 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<
                 ast::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
                 ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
             },
-            Adt(def, substs) => {
-                apply(struct_ty(RustDefId::Adt(def.did)), substs.lower_into(interner))
-            }
+            Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)),
             Foreign(_def_id) => unimplemented!(),
-            Str => apply(struct_ty(RustDefId::Str), empty()),
-            Array(ty, _) => apply(
-                struct_ty(RustDefId::Array),
-                chalk_ir::Substitution::from1(
-                    interner,
-                    chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner),
-                ),
-            ),
+            Str => apply(chalk_ir::TypeName::Str, empty()),
+            Array(ty, len) => {
+                let value = match len.val {
+                    ty::ConstKind::Value(val) => {
+                        chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val })
+                    }
+                    ty::ConstKind::Bound(db, bound) => {
+                        chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new(
+                            chalk_ir::DebruijnIndex::new(db.as_u32()),
+                            bound.index(),
+                        ))
+                    }
+                    _ => unimplemented!("Const not implemented. {:?}", len.val),
+                };
+                apply(
+                    chalk_ir::TypeName::Array,
+                    chalk_ir::Substitution::from(
+                        interner,
+                        &[
+                            chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
+                            chalk_ir::GenericArgData::Const(
+                                chalk_ir::ConstData { ty: len.ty.lower_into(interner), value }
+                                    .intern(interner),
+                            )
+                            .intern(interner),
+                        ],
+                    ),
+                )
+            }
             Slice(ty) => apply(
-                struct_ty(RustDefId::Slice),
+                chalk_ir::TypeName::Slice,
                 chalk_ir::Substitution::from1(
                     interner,
-                    chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner),
+                    chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
                 ),
             ),
-            RawPtr(_) => apply(struct_ty(RustDefId::RawPtr), empty()),
-            Ref(region, ty, mutability) => apply(
-                struct_ty(RustDefId::Ref(mutability)),
-                chalk_ir::Substitution::from(
-                    interner,
-                    [
-                        chalk_ir::ParameterKind::Lifetime(region.lower_into(interner))
-                            .intern(interner),
-                        chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner),
-                    ]
-                    .iter(),
-                ),
+            RawPtr(ptr) => {
+                let name = match ptr.mutbl {
+                    ast::Mutability::Mut => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Mut),
+                    ast::Mutability::Not => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Not),
+                };
+                apply(name, chalk_ir::Substitution::from1(interner, ptr.ty.lower_into(interner)))
+            }
+            Ref(region, ty, mutability) => {
+                let name = match mutability {
+                    ast::Mutability::Mut => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Mut),
+                    ast::Mutability::Not => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Not),
+                };
+                apply(
+                    name,
+                    chalk_ir::Substitution::from(
+                        interner,
+                        &[
+                            chalk_ir::GenericArgData::Lifetime(region.lower_into(interner))
+                                .intern(interner),
+                            chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
+                        ],
+                    ),
+                )
+            }
+            FnDef(def_id, substs) => apply(
+                chalk_ir::TypeName::FnDef(chalk_ir::FnDefId(def_id)),
+                substs.lower_into(interner),
             ),
-            FnDef(def_id, _) => apply(struct_ty(RustDefId::FnDef(def_id)), empty()),
             FnPtr(sig) => {
                 let (inputs_and_outputs, binders, _named_regions) =
                     collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output());
@@ -346,22 +415,35 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<
                     substitution: chalk_ir::Substitution::from(
                         interner,
                         inputs_and_outputs.iter().map(|ty| {
-                            chalk_ir::ParameterKind::Ty(ty.lower_into(interner)).intern(interner)
+                            chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner)
                         }),
                     ),
                 })
                 .intern(interner)
             }
-            Dynamic(_, _) => unimplemented!(),
-            Closure(_def_id, _) => unimplemented!(),
+            Dynamic(predicates, region) => TyData::Dyn(chalk_ir::DynTy {
+                bounds: predicates.lower_into(interner),
+                lifetime: region.lower_into(interner),
+            })
+            .intern(interner),
+            Closure(def_id, substs) => apply(
+                chalk_ir::TypeName::Closure(chalk_ir::ClosureId(def_id)),
+                substs.lower_into(interner),
+            ),
             Generator(_def_id, _substs, _) => unimplemented!(),
             GeneratorWitness(_) => unimplemented!(),
-            Never => apply(struct_ty(RustDefId::Never), empty()),
+            Never => apply(chalk_ir::TypeName::Never, empty()),
             Tuple(substs) => {
                 apply(chalk_ir::TypeName::Tuple(substs.len()), substs.lower_into(interner))
             }
             Projection(proj) => TyData::Alias(proj.lower_into(interner)).intern(interner),
-            Opaque(_def_id, _substs) => unimplemented!(),
+            Opaque(def_id, substs) => {
+                TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
+                    opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
+                    substitution: substs.lower_into(interner),
+                }))
+                .intern(interner)
+            }
             // This should have been done eagerly prior to this, and all Params
             // should have been substituted to placeholders
             Param(_) => panic!("Lowering Param when not expected."),
@@ -376,7 +458,7 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<
             })
             .intern(interner),
             Infer(_infer) => unimplemented!(),
-            Error => unimplemented!(),
+            Error(_) => apply(chalk_ir::TypeName::Error, empty()),
         }
     }
 }
@@ -401,6 +483,7 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInt
                 ty::BrEnv => unimplemented!(),
             },
             ReFree(_) => unimplemented!(),
+            // FIXME(chalk): need to handle ReStatic
             ReStatic => unimplemented!(),
             ReVar(_) => unimplemented!(),
             RePlaceholder(placeholder_region) => {
@@ -411,21 +494,22 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInt
                 .intern(interner)
             }
             ReEmpty(_) => unimplemented!(),
+            // FIXME(chalk): need to handle ReErased
             ReErased => unimplemented!(),
         }
     }
 }
 
-impl<'tcx> LowerInto<'tcx, chalk_ir::Parameter<RustInterner<'tcx>>> for GenericArg<'tcx> {
-    fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Parameter<RustInterner<'tcx>> {
+impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg<RustInterner<'tcx>>> for GenericArg<'tcx> {
+    fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GenericArg<RustInterner<'tcx>> {
         match self.unpack() {
             ty::subst::GenericArgKind::Type(ty) => {
-                chalk_ir::ParameterKind::Ty(ty.lower_into(interner))
+                chalk_ir::GenericArgData::Ty(ty.lower_into(interner))
             }
             ty::subst::GenericArgKind::Lifetime(lifetime) => {
-                chalk_ir::ParameterKind::Lifetime(lifetime.lower_into(interner))
+                chalk_ir::GenericArgData::Lifetime(lifetime.lower_into(interner))
             }
-            ty::subst::GenericArgKind::Const(_) => chalk_ir::ParameterKind::Ty(
+            ty::subst::GenericArgKind::Const(_) => chalk_ir::GenericArgData::Ty(
                 chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
                     name: chalk_ir::TypeName::Tuple(0),
                     substitution: chalk_ir::Substitution::empty(interner),
@@ -458,7 +542,18 @@ fn lower_into(
                     chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)),
                 ))
             }
-            ty::PredicateKind::RegionOutlives(_predicate) => None,
+            ty::PredicateKind::RegionOutlives(predicate) => {
+                let (predicate, binders, _named_regions) =
+                    collect_bound_vars(interner, interner.tcx, predicate);
+
+                Some(chalk_ir::Binders::new(
+                    binders,
+                    chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+                        a: predicate.0.lower_into(interner),
+                        b: predicate.1.lower_into(interner),
+                    }),
+                ))
+            }
             ty::PredicateKind::TypeOutlives(_predicate) => None,
             ty::PredicateKind::Projection(_predicate) => None,
             ty::PredicateKind::WellFormed(_ty) => None,
@@ -472,6 +567,39 @@ fn lower_into(
     }
 }
 
+impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>>>
+    for Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>
+{
+    fn lower_into(
+        self,
+        interner: &RustInterner<'tcx>,
+    ) -> chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>> {
+        let (predicates, binders, _named_regions) =
+            collect_bound_vars(interner, interner.tcx, &self);
+        let where_clauses = predicates.into_iter().map(|predicate| match predicate {
+            ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => {
+                chalk_ir::Binders::new(
+                    chalk_ir::VariableKinds::new(interner),
+                    chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
+                        trait_id: chalk_ir::TraitId(def_id),
+                        substitution: substs.lower_into(interner),
+                    }),
+                )
+            }
+            ty::ExistentialPredicate::Projection(_predicate) => unimplemented!(),
+            ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
+                chalk_ir::VariableKinds::new(interner),
+                chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
+                    trait_id: chalk_ir::TraitId(def_id),
+                    substitution: chalk_ir::Substitution::empty(interner),
+                }),
+            ),
+        });
+        let value = chalk_ir::QuantifiedWhereClauses::from(interner, where_clauses);
+        chalk_ir::Binders::new(binders, value)
+    }
+}
+
 /// To collect bound vars, we have to do two passes. In the first pass, we
 /// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then
 /// replace `BrNamed` into `BrAnon`. The two separate passes are important,
@@ -485,7 +613,7 @@ fn lower_into(
     interner: &RustInterner<'tcx>,
     tcx: TyCtxt<'tcx>,
     ty: &'a Binder<T>,
-) -> (T, chalk_ir::ParameterKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
+) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
     let mut bound_vars_collector = BoundVarsCollector::new();
     ty.skip_binder().visit_with(&mut bound_vars_collector);
     let mut parameters = bound_vars_collector.parameters;
@@ -500,25 +628,25 @@ fn lower_into(
     let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
 
     for var in named_parameters.values() {
-        parameters.insert(*var, chalk_ir::ParameterKind::Lifetime(()));
+        parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
     }
 
     (0..parameters.len()).for_each(|i| {
-        parameters.get(&(i as u32)).expect("Skipped bound var index.");
+        parameters.get(&(i as u32)).expect(&format!("Skipped bound var index `{:?}`.", i));
     });
 
-    let binders = chalk_ir::ParameterKinds::from(interner, parameters.into_iter().map(|(_, v)| v));
+    let binders = chalk_ir::VariableKinds::from(interner, parameters.into_iter().map(|(_, v)| v));
 
     (new_ty, binders, named_parameters)
 }
 
-crate struct BoundVarsCollector {
+crate struct BoundVarsCollector<'tcx> {
     binder_index: ty::DebruijnIndex,
-    crate parameters: BTreeMap<u32, chalk_ir::ParameterKind<()>>,
+    crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
     crate named_parameters: Vec<DefId>,
 }
 
-impl BoundVarsCollector {
+impl<'tcx> BoundVarsCollector<'tcx> {
     crate fn new() -> Self {
         BoundVarsCollector {
             binder_index: ty::INNERMOST,
@@ -528,7 +656,7 @@ impl BoundVarsCollector {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector {
+impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
     fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
         self.binder_index.shift_in(1);
         let result = t.super_visit_with(self);
@@ -541,11 +669,12 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
                 match self.parameters.entry(bound_ty.var.as_u32()) {
                     Entry::Vacant(entry) => {
-                        entry.insert(chalk_ir::ParameterKind::Ty(()));
-                    }
-                    Entry::Occupied(entry) => {
-                        entry.get().assert_ty_ref();
+                        entry.insert(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General));
                     }
+                    Entry::Occupied(entry) => match entry.get() {
+                        chalk_ir::VariableKind::Ty(_) => {}
+                        _ => panic!(),
+                    },
                 }
             }
 
@@ -566,11 +695,12 @@ fn visit_region(&mut self, r: Region<'tcx>) -> bool {
 
                 ty::BoundRegion::BrAnon(var) => match self.parameters.entry(*var) {
                     Entry::Vacant(entry) => {
-                        entry.insert(chalk_ir::ParameterKind::Lifetime(()));
-                    }
-                    Entry::Occupied(entry) => {
-                        entry.get().assert_lifetime_ref();
+                        entry.insert(chalk_ir::VariableKind::Lifetime);
                     }
+                    Entry::Occupied(entry) => match entry.get() {
+                        chalk_ir::VariableKind::Lifetime => {}
+                        _ => panic!(),
+                    },
                 },
 
                 ty::BrEnv => unimplemented!(),
index 4e635b9db0901b49d9c772bbea39f8045f3a5fe3..52ec0f2409dce47acb64cec990cafa8a7bf72e95 100644 (file)
@@ -22,7 +22,7 @@
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
 };
-use rustc_infer::traits::{self, ChalkCanonicalGoal, ChalkRustDefId as RustDefId};
+use rustc_infer::traits::{self, ChalkCanonicalGoal};
 
 use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
 use crate::chalk::lowering::{LowerInto, ParamsSubstitutor};
                     CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(),
                     CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(),
                     CanonicalVarKind::Ty(ty) => match ty {
-                        CanonicalTyVarKind::General(ui) => {
-                            chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex {
-                                counter: ui.index(),
-                            })
-                        }
-                        CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => {
-                            // FIXME(chalk) - this is actually really important
-                            // These variable kinds put some limits on the
-                            // types that can be substituted (floats or ints).
-                            // While it's unclear exactly the design here, we
-                            // probably want some way to "register" these.
-                            chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::root())
-                        }
+                        CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new(
+                            chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General),
+                            chalk_ir::UniverseIndex { counter: ui.index() },
+                        ),
+                        CanonicalTyVarKind::Int => chalk_ir::WithKind::new(
+                            chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Integer),
+                            chalk_ir::UniverseIndex::root(),
+                        ),
+                        CanonicalTyVarKind::Float => chalk_ir::WithKind::new(
+                            chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Float),
+                            chalk_ir::UniverseIndex::root(),
+                        ),
                     },
-                    CanonicalVarKind::Region(ui) => {
-                        chalk_ir::ParameterKind::Lifetime(chalk_ir::UniverseIndex {
-                            counter: ui.index(),
-                        })
-                    }
+                    CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new(
+                        chalk_ir::VariableKind::Lifetime,
+                        chalk_ir::UniverseIndex { counter: ui.index() },
+                    ),
                     CanonicalVarKind::Const(_ui) => unimplemented!(),
                     CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
                 }),
             // essentially inverse of lowering a `GenericArg`.
             let _data = p.data(&interner);
             match _data {
-                chalk_ir::ParameterKind::Ty(_t) => {
+                chalk_ir::GenericArgData::Ty(_t) => {
                     use chalk_ir::TyData;
                     use rustc_ast::ast;
 
                     let _data = _t.data(&interner);
                     let kind = match _data {
                         TyData::Apply(_application_ty) => match _application_ty.name {
-                            chalk_ir::TypeName::Struct(_struct_id) => match _struct_id.0 {
-                                RustDefId::Array => unimplemented!(),
-                                RustDefId::Slice => unimplemented!(),
-                                _ => unimplemented!(),
-                            },
+                            chalk_ir::TypeName::Adt(_struct_id) => unimplemented!(),
                             chalk_ir::TypeName::Scalar(scalar) => match scalar {
                                 chalk_ir::Scalar::Bool => ty::Bool,
                                 chalk_ir::Scalar::Char => ty::Char,
                                     chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64),
                                 },
                             },
+                            chalk_ir::TypeName::Array => unimplemented!(),
+                            chalk_ir::TypeName::FnDef(_) => unimplemented!(),
+                            chalk_ir::TypeName::Closure(_) => unimplemented!(),
+                            chalk_ir::TypeName::Never => unimplemented!(),
                             chalk_ir::TypeName::Tuple(_size) => unimplemented!(),
+                            chalk_ir::TypeName::Slice => unimplemented!(),
+                            chalk_ir::TypeName::Raw(_) => unimplemented!(),
+                            chalk_ir::TypeName::Ref(_) => unimplemented!(),
+                            chalk_ir::TypeName::Str => unimplemented!(),
                             chalk_ir::TypeName::OpaqueType(_ty) => unimplemented!(),
                             chalk_ir::TypeName::AssociatedType(_assoc_ty) => unimplemented!(),
                             chalk_ir::TypeName::Error => unimplemented!(),
                                 kind: ty::BoundTyKind::Anon,
                             },
                         ),
-                        TyData::InferenceVar(_) => unimplemented!(),
+                        TyData::InferenceVar(_, _) => unimplemented!(),
                         TyData::Dyn(_) => unimplemented!(),
                     };
                     let _ty: Ty<'_> = tcx.mk_ty(kind);
                     let _arg: GenericArg<'_> = _ty.into();
                     var_values.push(_arg);
                 }
-                chalk_ir::ParameterKind::Lifetime(_l) => {
+                chalk_ir::GenericArgData::Lifetime(_l) => {
                     let _data = _l.data(&interner);
                     let _lifetime: Region<'_> = match _data {
                         chalk_ir::LifetimeData::BoundVar(_var) => {
                     let _arg: GenericArg<'_> = _lifetime.into();
                     var_values.push(_arg);
                 }
+                chalk_ir::GenericArgData::Const(_) => unimplemented!(),
             }
         });
         let sol = Canonical {
         .map(|s| match s {
             Solution::Unique(_subst) => {
                 // FIXME(chalk): handle constraints
-                assert!(_subst.value.constraints.is_empty());
                 make_solution(_subst.value.subst)
             }
             Solution::Ambig(_guidance) => {
index 11c48559bd68320ca76e5758822024180b816e3c..6339f8288d54e7f3c370b574099aeffc4e9451fd 100644 (file)
@@ -271,7 +271,7 @@ fn dtorck_constraint_for_ty<'tcx>(
             constraints.dtorck_types.push(ty);
         }
 
-        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => {
+        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
             // By the time this code runs, all type variables ought to
             // be fully resolved.
             return Err(NoSolution);
index 439bec1702eaed10e2d4dc133a8d5f281246d7cf..7880c09c2ad81a04ad3284ab97fd1b2093a014c9 100644 (file)
@@ -91,7 +91,7 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
 
             for component in components {
                 match component.kind {
-                    _ if component.is_copy_modulo_regions(tcx, self.param_env, DUMMY_SP) => (),
+                    _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
 
                     ty::Closure(_, substs) => {
                         for upvar_ty in substs.as_closure().upvar_tys() {
index 99094246a637861154157420e102c85d54658f71..595992d01dd2d00f43096896ae8de9e538b845e5 100644 (file)
@@ -1,8 +1,10 @@
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_infer::traits::util;
 use rustc_middle::hir::map as hir_map;
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_session::CrateDisambiguator;
 use rustc_span::symbol::Symbol;
@@ -20,7 +22,7 @@ fn sized_constraint_for_ty<'tcx>(
         Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
         | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],
 
-        Str | Dynamic(..) | Slice(_) | Foreign(..) | Error | GeneratorWitness(..) => {
+        Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => {
             // these are never sized - return the target type
             vec![ty]
         }
@@ -365,6 +367,133 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
     fn_like.asyncness()
 }
 
+/// For associated types we allow bounds written on the associated type
+/// (`type X: Trait`) to be used as candidates. We also allow the same bounds
+/// when desugared as bounds on the trait `where Self::X: Trait`.
+///
+/// Note that this filtering is done with the items identity substs to
+/// simplify checking that these bounds are met in impls. This means that
+/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
+/// `hr-associated-type-bound-1.rs`.
+fn associated_type_projection_predicates(
+    tcx: TyCtxt<'_>,
+    assoc_item_def_id: DefId,
+) -> &'_ ty::List<ty::Predicate<'_>> {
+    let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id);
+    // We include predicates from the trait as well to handle
+    // `where Self::X: Trait`.
+    let item_bounds = generic_trait_bounds.instantiate_identity(tcx);
+    let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter());
+
+    let assoc_item_ty = ty::ProjectionTy {
+        item_def_id: assoc_item_def_id,
+        substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
+    };
+
+    let predicates = item_predicates.filter_map(|obligation| {
+        let pred = obligation.predicate;
+        match pred.kind() {
+            ty::PredicateKind::Trait(tr, _) => {
+                if let ty::Projection(p) = tr.skip_binder().self_ty().kind {
+                    if p == assoc_item_ty {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::Projection(proj) => {
+                if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind {
+                    if p == assoc_item_ty {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::TypeOutlives(outlives) => {
+                if let ty::Projection(p) = outlives.skip_binder().0.kind {
+                    if p == assoc_item_ty {
+                        return Some(pred);
+                    }
+                }
+            }
+            _ => {}
+        }
+        None
+    });
+
+    let result = tcx.mk_predicates(predicates);
+    debug!(
+        "associated_type_projection_predicates({}) = {:?}",
+        tcx.def_path_str(assoc_item_def_id),
+        result
+    );
+    result
+}
+
+/// Opaque types don't have the same issues as associated types: the only
+/// predicates on an opaque type (excluding those it inherits from its parent
+/// item) should be of the form we're expecting.
+fn opaque_type_projection_predicates(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> &'_ ty::List<ty::Predicate<'_>> {
+    let substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+    let bounds = tcx.predicates_of(def_id);
+    let predicates =
+        util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred));
+
+    let filtered_predicates = predicates.filter_map(|obligation| {
+        let pred = obligation.predicate;
+        match pred.kind() {
+            ty::PredicateKind::Trait(tr, _) => {
+                if let ty::Opaque(opaque_def_id, opaque_substs) = tr.skip_binder().self_ty().kind {
+                    if opaque_def_id == def_id && opaque_substs == substs {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::Projection(proj) => {
+                if let ty::Opaque(opaque_def_id, opaque_substs) =
+                    proj.skip_binder().projection_ty.self_ty().kind
+                {
+                    if opaque_def_id == def_id && opaque_substs == substs {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::TypeOutlives(outlives) => {
+                if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind {
+                    if opaque_def_id == def_id && opaque_substs == substs {
+                        return Some(pred);
+                    }
+                } else {
+                    // These can come from elaborating other predicates
+                    return None;
+                }
+            }
+            // These can come from elaborating other predicates
+            ty::PredicateKind::RegionOutlives(_) => return None,
+            _ => {}
+        }
+        tcx.sess.delay_span_bug(
+            obligation.cause.span(tcx),
+            &format!("unexpected predicate {:?} on opaque type", pred),
+        );
+        None
+    });
+
+    let result = tcx.mk_predicates(filtered_predicates);
+    debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result);
+    result
+}
+
+fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
+    match tcx.def_kind(def_id) {
+        DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id),
+        DefKind::OpaqueTy => opaque_type_projection_predicates(tcx, def_id),
+        k => bug!("projection_predicates called on {}", k.descr(def_id)),
+    }
+}
+
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     *providers = ty::query::Providers {
         asyncness,
@@ -381,6 +510,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
+        projection_predicates,
         ..*providers
     };
 }
index 267f3d9f3ef6e6dc02dbfe7436bc375181174a30..1b08bf2fc7710c4c6d00518972b524ec4fe53e57 100644 (file)
@@ -8,8 +8,7 @@
 use crate::collect::PlaceholderHirTyCollector;
 use crate::middle::resolve_lifetime as rl;
 use crate::require_c_abi_if_c_variadic;
-use rustc_ast::ast::ParamKindOrd;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
+use rustc_ast::{ast::ParamKindOrd, util::lev_distance::find_best_match_for_name};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::ErrorReported;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, FatalError};
@@ -27,7 +26,7 @@
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS};
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
@@ -475,7 +474,12 @@ fn check_generic_arg_count(
 
     /// Report an error that a generic argument did not match the generic parameter that was
     /// expected.
-    fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) {
+    fn generic_arg_mismatch_err(
+        sess: &Session,
+        arg: &GenericArg<'_>,
+        kind: &'static str,
+        help: Option<&str>,
+    ) {
         let mut err = struct_span_err!(
             sess,
             arg.span(),
@@ -503,6 +507,10 @@ fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static
         let (first, last) =
             if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
         err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+
+        if let Some(help) = help {
+            err.help(help);
+        }
         err.emit();
     }
 
@@ -648,7 +656,60 @@ pub fn create_substs_for_generic_args<'b>(
                                 if arg_count.correct.is_ok()
                                     && arg_count.explicit_late_bound == ExplicitLateBound::No
                                 {
-                                    Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr());
+                                    // We're going to iterate over the parameters to sort them out, and
+                                    // show that order to the user as a possible order for the parameters
+                                    let mut param_types_present = defs
+                                        .params
+                                        .clone()
+                                        .into_iter()
+                                        .map(|param| {
+                                            (
+                                                match param.kind {
+                                                    GenericParamDefKind::Lifetime => {
+                                                        ParamKindOrd::Lifetime
+                                                    }
+                                                    GenericParamDefKind::Type { .. } => {
+                                                        ParamKindOrd::Type
+                                                    }
+                                                    GenericParamDefKind::Const => {
+                                                        ParamKindOrd::Const
+                                                    }
+                                                },
+                                                param,
+                                            )
+                                        })
+                                        .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
+                                    param_types_present.sort_by_key(|(ord, _)| *ord);
+                                    let (mut param_types_present, ordered_params): (
+                                        Vec<ParamKindOrd>,
+                                        Vec<GenericParamDef>,
+                                    ) = param_types_present.into_iter().unzip();
+                                    param_types_present.dedup();
+
+                                    Self::generic_arg_mismatch_err(
+                                        tcx.sess,
+                                        arg,
+                                        kind.descr(),
+                                        Some(&format!(
+                                            "reorder the arguments: {}: `<{}>`",
+                                            param_types_present
+                                                .into_iter()
+                                                .map(|ord| format!("{}s", ord.to_string()))
+                                                .collect::<Vec<String>>()
+                                                .join(", then "),
+                                            ordered_params
+                                                .into_iter()
+                                                .filter_map(|param| {
+                                                    if param.name == kw::SelfUpper {
+                                                        None
+                                                    } else {
+                                                        Some(param.name.to_string())
+                                                    }
+                                                })
+                                                .collect::<Vec<String>>()
+                                                .join(", ")
+                                        )),
+                                    );
                                 }
 
                                 // We've reported the error, but we want to make sure that this
@@ -680,7 +741,7 @@ pub fn create_substs_for_generic_args<'b>(
                             assert_eq!(kind, "lifetime");
                             let provided =
                                 force_infer_lt.expect("lifetimes ought to have been inferred");
-                            Self::generic_arg_mismatch_err(tcx.sess, provided, kind);
+                            Self::generic_arg_mismatch_err(tcx.sess, provided, kind, None);
                         }
 
                         break;
@@ -819,7 +880,7 @@ fn create_substs_for_ast_path<'a>(
                 (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
                     if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) {
                         inferred_params.push(ty.span);
-                        tcx.types.err.into()
+                        tcx.ty_error().into()
                     } else {
                         self.ast_ty_to_ty(&ty).into()
                     }
@@ -845,7 +906,7 @@ fn create_substs_for_ast_path<'a>(
                             // careful!
                             if default_needs_object_self(param) {
                                 missing_type_params.push(param.name.to_string());
-                                tcx.types.err.into()
+                                tcx.ty_error().into()
                             } else {
                                 // This is a default type parameter.
                                 self.normalize_ty(
@@ -865,7 +926,7 @@ fn create_substs_for_ast_path<'a>(
                             self.ty_infer(param, span).into()
                         } else {
                             // We've already errored above about the mismatch.
-                            tcx.types.err.into()
+                            tcx.ty_error().into()
                         }
                     }
                     GenericParamDefKind::Const => {
@@ -876,7 +937,7 @@ fn create_substs_for_ast_path<'a>(
                             self.ct_infer(ty, Some(param), span).into()
                         } else {
                             // We've already errored above about the mismatch.
-                            tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty }).into()
+                            tcx.const_error(ty).into()
                         }
                     }
                 }
@@ -1394,13 +1455,13 @@ fn add_predicates_for_ast_type_binding(
             // That is, consider this case:
             //
             // ```
-            // trait SubTrait: SuperTrait<int> { }
+            // trait SubTrait: SuperTrait<i32> { }
             // trait SuperTrait<A> { type T; }
             //
             // ... B: SubTrait<T = foo> ...
             // ```
             //
-            // We want to produce `<B as SuperTrait<int>>::T == foo`.
+            // We want to produce `<B as SuperTrait<i32>>::T == foo`.
 
             // Find any late-bound regions declared in `ty` that are not
             // declared in the trait-ref. These are not well-formed.
@@ -1607,7 +1668,7 @@ fn conv_object_ty_poly_trait_ref(
                 "at least one trait is required for an object type"
             )
             .emit();
-            return tcx.types.err;
+            return tcx.ty_error();
         }
 
         // Check that there are no gross object safety violations;
@@ -1624,7 +1685,7 @@ fn conv_object_ty_poly_trait_ref(
                     &object_safety_violations[..],
                 )
                 .emit();
-                return tcx.types.err;
+                return tcx.ty_error();
             }
         }
 
@@ -2434,7 +2495,7 @@ fn qpath_to_ty(
                 &path_str,
                 item_segment.ident.name,
             );
-            return tcx.types.err;
+            return tcx.ty_error();
         };
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
@@ -2787,12 +2848,12 @@ pub fn res_to_ty(
                     hir::PrimTy::Int(it) => tcx.mk_mach_int(it),
                     hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit),
                     hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft),
-                    hir::PrimTy::Str => tcx.mk_str(),
+                    hir::PrimTy::Str => tcx.types.str_,
                 }
             }
             Res::Err => {
                 self.set_tainted_by_errors();
-                self.tcx().types.err
+                self.tcx().ty_error()
             }
             _ => span_bug!(span, "unexpected resolution: {:?}", path.res),
         }
@@ -2860,7 +2921,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
                 };
                 self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false)
                     .map(|(ty, _, _)| ty)
-                    .unwrap_or(tcx.types.err)
+                    .unwrap_or_else(|_| tcx.ty_error())
             }
             hir::TyKind::Array(ref ty, ref length) => {
                 let length_def_id = tcx.hir().local_def_id(length.hir_id);
@@ -2878,7 +2939,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
                 .span_label(ast_ty.span, "reserved keyword")
                 .emit();
 
-                tcx.types.err
+                tcx.ty_error()
             }
             hir::TyKind::Infer => {
                 // Infer also appears as the type of arguments or return
@@ -2887,7 +2948,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(None, ast_ty.span)
             }
-            hir::TyKind::Err => tcx.types.err,
+            hir::TyKind::Err => tcx.ty_error(),
         };
 
         debug!("ast_ty_to_ty: result_ty={:?}", result_ty);
index fb139b5033b3b40b6571331624344cb3e1e843e9..9e23f5df3c6a8a367d9fc5821979f40ec464be49 100644 (file)
@@ -105,7 +105,7 @@ pub fn check_match(
                 && i != 0
                 && self.if_fallback_coercion(expr.span, &arms[0].body, &mut coercion)
             {
-                tcx.types.err
+                tcx.ty_error()
             } else {
                 // Only call this if this is not an `if` expr with an expected type and no `else`
                 // clause to avoid duplicated type errors. (#60254)
index 73d4e2b78206d98300bce537efa8f31aebf2df0b..97d2b3e5a8e45c8b1e121bb5b5654e36c9685a89 100644 (file)
+//! Some helper functions for `AutoDeref`
 use super::method::MethodCallee;
-use super::{FnCtxt, Needs, PlaceOp};
+use super::{FnCtxt, PlaceOp};
 
-use rustc_errors::struct_span_err;
-use rustc_hir as hir;
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::InferOk;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
-use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
-use rustc_middle::ty::{ToPredicate, TypeFoldable};
-use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::Ident;
+use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{self, TraitEngine};
+use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind};
 
 use std::iter;
 
-#[derive(Copy, Clone, Debug)]
-enum AutoderefKind {
-    Builtin,
-    Overloaded,
-}
-
-pub struct Autoderef<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    body_id: hir::HirId,
-    param_env: ty::ParamEnv<'tcx>,
-    steps: Vec<(Ty<'tcx>, AutoderefKind)>,
-    cur_ty: Ty<'tcx>,
-    obligations: Vec<traits::PredicateObligation<'tcx>>,
-    at_start: bool,
-    include_raw_pointers: bool,
-    span: Span,
-    silence_errors: bool,
-    reached_recursion_limit: bool,
-}
-
-impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
-    type Item = (Ty<'tcx>, usize);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let tcx = self.infcx.tcx;
-
-        debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, self.cur_ty);
-        if self.at_start {
-            self.at_start = false;
-            debug!("autoderef stage #0 is {:?}", self.cur_ty);
-            return Some((self.cur_ty, 0));
-        }
-
-        if !tcx.sess.recursion_limit().value_within_limit(self.steps.len()) {
-            if !self.silence_errors {
-                report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
-            }
-            self.reached_recursion_limit = true;
-            return None;
-        }
-
-        if self.cur_ty.is_ty_var() {
-            return None;
-        }
-
-        // Otherwise, deref if type is derefable:
-        let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers)
-        {
-            (AutoderefKind::Builtin, mt.ty)
-        } else {
-            let ty = self.overloaded_deref_ty(self.cur_ty)?;
-            (AutoderefKind::Overloaded, ty)
-        };
-
-        if new_ty.references_error() {
-            return None;
-        }
-
-        self.steps.push((self.cur_ty, kind));
-        debug!(
-            "autoderef stage #{:?} is {:?} from {:?}",
-            self.steps.len(),
-            new_ty,
-            (self.cur_ty, kind)
-        );
-        self.cur_ty = new_ty;
-
-        Some((self.cur_ty, self.steps.len()))
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
     }
-}
 
-impl<'a, 'tcx> Autoderef<'a, 'tcx> {
-    pub fn new(
-        infcx: &'a InferCtxt<'a, 'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+    pub fn try_overloaded_deref(
+        &self,
         span: Span,
         base_ty: Ty<'tcx>,
-    ) -> Autoderef<'a, 'tcx> {
-        Autoderef {
-            infcx,
-            body_id,
-            param_env,
-            steps: vec![],
-            cur_ty: infcx.resolve_vars_if_possible(&base_ty),
-            obligations: vec![],
-            at_start: true,
-            include_raw_pointers: false,
-            silence_errors: false,
-            reached_recursion_limit: false,
-            span,
-        }
-    }
-
-    fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-        debug!("overloaded_deref_ty({:?})", ty);
-
-        let tcx = self.infcx.tcx;
-
-        // <ty as Deref>
-        let trait_ref = TraitRef {
-            def_id: tcx.lang_items().deref_trait()?,
-            substs: tcx.mk_substs_trait(ty, &[]),
-        };
-
-        let cause = traits::ObligationCause::misc(self.span, self.body_id);
-
-        let obligation = traits::Obligation::new(
-            cause.clone(),
-            self.param_env,
-            trait_ref.without_const().to_predicate(tcx),
-        );
-        if !self.infcx.predicate_may_hold(&obligation) {
-            debug!("overloaded_deref_ty: cannot match obligation");
-            return None;
-        }
-
-        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
-        let normalized_ty = fulfillcx.normalize_projection_type(
-            &self.infcx,
-            self.param_env,
-            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
-            cause,
-        );
-        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
-            // This shouldn't happen, except for evaluate/fulfill mismatches,
-            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
-            // by design).
-            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
-            return None;
-        }
-        let obligations = fulfillcx.pending_obligations();
-        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
-        self.obligations.extend(obligations);
-
-        Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
-    }
-
-    /// Returns the final type, generating an error if it is an
-    /// unresolved inference variable.
-    pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
-        fcx.structurally_resolved_type(self.span, self.cur_ty)
-    }
-
-    /// Returns the final type we ended up with, which may well be an
-    /// inference variable (we will resolve it first, if possible).
-    pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
-        self.infcx.resolve_vars_if_possible(&self.cur_ty)
-    }
-
-    pub fn step_count(&self) -> usize {
-        self.steps.len()
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
     }
 
     /// Returns the adjustment steps.
-    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec<Adjustment<'tcx>> {
-        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
+    pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
+        self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef))
     }
 
     pub fn adjust_steps_as_infer_ok(
         &self,
-        fcx: &FnCtxt<'a, 'tcx>,
-        needs: Needs,
+        autoderef: &Autoderef<'a, 'tcx>,
     ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
         let mut obligations = vec![];
-        let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty));
-        let steps: Vec<_> = self
-            .steps
+        let steps = autoderef.steps();
+        let targets =
+            steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
+        let steps: Vec<_> = steps
             .iter()
             .map(|&(source, kind)| {
                 if let AutoderefKind::Overloaded = kind {
-                    fcx.try_overloaded_deref(self.span, source, needs).and_then(
+                    self.try_overloaded_deref(autoderef.span(), source).and_then(
                         |InferOk { value: method, obligations: o }| {
                             obligations.extend(o);
                             if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
@@ -206,68 +60,4 @@ pub fn adjust_steps_as_infer_ok(
 
         InferOk { obligations, value: steps }
     }
-
-    /// also dereference through raw pointer types
-    /// e.g., assuming ptr_to_Foo is the type `*const Foo`
-    /// fcx.autoderef(span, ptr_to_Foo)  => [*const Foo]
-    /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
-    pub fn include_raw_pointers(mut self) -> Self {
-        self.include_raw_pointers = true;
-        self
-    }
-
-    pub fn silence_errors(mut self) -> Self {
-        self.silence_errors = true;
-        self
-    }
-
-    pub fn reached_recursion_limit(&self) -> bool {
-        self.reached_recursion_limit
-    }
-
-    pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) {
-        fcx.register_predicates(self.into_obligations());
-    }
-
-    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
-        self.obligations
-    }
-}
-
-pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
-    // We've reached the recursion limit, error gracefully.
-    let suggested_limit = tcx.sess.recursion_limit() * 2;
-    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
-    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
-    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
-    if fresh {
-        struct_span_err!(
-            tcx.sess,
-            span,
-            E0055,
-            "reached the recursion limit while auto-dereferencing `{:?}`",
-            ty
-        )
-        .span_label(span, "deref recursion limit reached")
-        .help(&format!(
-            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
-            suggested_limit, tcx.crate_name,
-        ))
-        .emit();
-    }
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
-        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
-    }
-
-    pub fn try_overloaded_deref(
-        &self,
-        span: Span,
-        base_ty: Ty<'tcx>,
-        needs: Needs,
-    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref)
-    }
 }
index aa316105f7f11be99809a1e6d5ca07e683939591..308ed5d8402021864d830170422fc7f86a151430 100644 (file)
@@ -1,6 +1,5 @@
-use super::autoderef::Autoderef;
 use super::method::MethodCallee;
-use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
 use crate::type_error_struct;
 
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -17,6 +16,7 @@
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_target::spec::abi;
+use rustc_trait_selection::autoderef::Autoderef;
 
 /// Checks that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
@@ -72,7 +72,7 @@ pub fn check_call(
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
         }
-        autoderef.finalize(self);
+        self.register_predicates(autoderef.into_obligations());
 
         let output = match result {
             None => {
@@ -106,7 +106,8 @@ fn try_overloaded_call_step(
         arg_exprs: &'tcx [hir::Expr<'tcx>],
         autoderef: &Autoderef<'a, 'tcx>,
     ) -> Option<CallStep<'tcx>> {
-        let adjusted_ty = autoderef.unambiguous_final_ty(self);
+        let adjusted_ty =
+            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
         debug!(
             "try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
             call_expr, adjusted_ty
@@ -115,7 +116,7 @@ fn try_overloaded_call_step(
         // If the callee is a bare function or a closure, then we're all set.
         match adjusted_ty.kind {
             ty::FnDef(..) | ty::FnPtr(_) => {
-                let adjustments = autoderef.adjust_steps(self, Needs::None);
+                let adjustments = self.adjust_steps(autoderef);
                 self.apply_adjustments(callee_expr, adjustments);
                 return Some(CallStep::Builtin(adjusted_ty));
             }
@@ -135,7 +136,7 @@ fn try_overloaded_call_step(
                             &closure_sig,
                         )
                         .0;
-                    let adjustments = autoderef.adjust_steps(self, Needs::None);
+                    let adjustments = self.adjust_steps(autoderef);
                     self.record_deferred_call_resolution(
                         def_id,
                         DeferredCallResolution {
@@ -176,7 +177,7 @@ fn try_overloaded_call_step(
         self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs))
             .or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None))
             .map(|(autoref, method)| {
-                let mut adjustments = autoderef.adjust_steps(self, Needs::None);
+                let mut adjustments = self.adjust_steps(autoderef);
                 adjustments.extend(autoref);
                 self.apply_adjustments(callee_expr, adjustments);
                 CallStep::Overloaded(method)
@@ -220,21 +221,28 @@ fn try_overloaded_call_traits(
                 let method = self.register_infer_ok_obligations(ok);
                 let mut autoref = None;
                 if borrow {
-                    if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
-                        let mutbl = match mutbl {
-                            hir::Mutability::Not => AutoBorrowMutability::Not,
-                            hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                                // For initial two-phase borrow
-                                // deployment, conservatively omit
-                                // overloaded function call ops.
-                                allow_two_phase_borrow: AllowTwoPhase::No,
-                            },
-                        };
-                        autoref = Some(Adjustment {
-                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
-                            target: method.sig.inputs()[0],
-                        });
-                    }
+                    // Check for &self vs &mut self in the method signature. Since this is either
+                    // the Fn or FnMut trait, it should be one of those.
+                    let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind
+                    {
+                        (r, mutbl)
+                    } else {
+                        span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
+                    };
+
+                    let mutbl = match mutbl {
+                        hir::Mutability::Not => AutoBorrowMutability::Not,
+                        hir::Mutability::Mut => AutoBorrowMutability::Mut {
+                            // For initial two-phase borrow
+                            // deployment, conservatively omit
+                            // overloaded function call ops.
+                            allow_two_phase_borrow: AllowTwoPhase::No,
+                        },
+                    };
+                    autoref = Some(Adjustment {
+                        kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+                        target: method.sig.inputs()[0],
+                    });
                 }
                 return Some((autoref, method));
             }
@@ -383,7 +391,7 @@ fn confirm_builtin_call(
                 (
                     ty::Binder::bind(self.tcx.mk_fn_sig(
                         self.err_args(arg_exprs.len()).into_iter(),
-                        self.tcx.types.err,
+                        self.tcx.ty_error(),
                         false,
                         hir::Unsafety::Normal,
                         abi::Abi::Rust,
index 46d6706cbf42925e674fb8d71c4b05ba94ea6e44..1ea7bf25ef2ed67436f99a84f428ef3c200efe8a 100644 (file)
@@ -43,6 +43,7 @@
 use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
 use rustc_session::lint;
 use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
@@ -135,7 +136,7 @@ fn pointer_kind(
             | ty::Generator(..)
             | ty::Adt(..)
             | ty::Never
-            | ty::Error => {
+            | ty::Error(_) => {
                 self.tcx
                     .sess
                     .delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t));
@@ -333,10 +334,11 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                     "only `u8` can be cast as `char`, not `{}`",
                     self.expr_ty
                 )
+                .span_label(self.span, "invalid cast")
                 .emit();
             }
             CastError::NonScalar => {
-                type_error_struct!(
+                let mut err = type_error_struct!(
                     fcx.tcx.sess,
                     self.span,
                     self.expr_ty,
@@ -344,12 +346,75 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                     "non-primitive cast: `{}` as `{}`",
                     self.expr_ty,
                     fcx.ty_to_string(self.cast_ty)
-                )
-                .note(
-                    "an `as` expression can only be used to convert between \
-                                         primitive types. Consider using the `From` trait",
-                )
-                .emit();
+                );
+                let mut sugg = None;
+                if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind {
+                    if fcx
+                        .try_coerce(
+                            self.expr,
+                            fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+                            self.cast_ty,
+                            AllowTwoPhase::No,
+                        )
+                        .is_ok()
+                    {
+                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                    }
+                }
+                if let Some(sugg) = sugg {
+                    err.span_label(self.span, "invalid cast");
+                    err.span_suggestion_verbose(
+                        self.expr.span.shrink_to_lo(),
+                        "borrow the value for the cast to be valid",
+                        sugg,
+                        Applicability::MachineApplicable,
+                    );
+                } else if !matches!(
+                    self.cast_ty.kind,
+                    ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
+                ) {
+                    let mut label = true;
+                    // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
+                    if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                        if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) {
+                            let ty = fcx.resolve_vars_if_possible(&self.cast_ty);
+                            // Erase regions to avoid panic in `prove_value` when calling
+                            // `type_implements_trait`.
+                            let ty = fcx.tcx.erase_regions(&ty);
+                            let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty);
+                            let expr_ty = fcx.tcx.erase_regions(&expr_ty);
+                            let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
+                            // Check for infer types because cases like `Option<{integer}>` would
+                            // panic otherwise.
+                            if !expr_ty.has_infer_types()
+                                && fcx.tcx.type_implements_trait((
+                                    from_trait,
+                                    ty,
+                                    ty_params,
+                                    fcx.param_env,
+                                ))
+                            {
+                                label = false;
+                                err.span_suggestion(
+                                    self.span,
+                                    "consider using the `From` trait instead",
+                                    format!("{}::from({})", self.cast_ty, snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                    }
+                    let msg = "an `as` expression can only be used to convert between primitive \
+                               types or to coerce to a specific trait object";
+                    if label {
+                        err.span_label(self.span, msg);
+                    } else {
+                        err.note(msg);
+                    }
+                } else {
+                    err.span_label(self.span, "invalid cast");
+                }
+                err.emit();
             }
             CastError::SizedUnsizedCast => {
                 use crate::structured_errors::{SizedUnsizedCastError, StructuredDiagnostic};
@@ -370,21 +435,22 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 };
                 let mut err = struct_span_err!(
                     fcx.tcx.sess,
-                    self.span,
+                    if unknown_cast_to { self.cast_span } else { self.span },
                     E0641,
                     "cannot cast {} a pointer of an unknown kind",
                     if unknown_cast_to { "to" } else { "from" }
                 );
-                err.note(
-                    "the type information given here is insufficient to check whether \
-                          the pointer cast is valid",
-                );
                 if unknown_cast_to {
-                    err.span_suggestion_short(
-                        self.cast_span,
-                        "consider giving more type information",
-                        String::new(),
-                        Applicability::Unspecified,
+                    err.span_label(self.cast_span, "needs more type information");
+                    err.note(
+                        "the type information given here is insufficient to check whether \
+                        the pointer cast is valid",
+                    );
+                } else {
+                    err.span_label(
+                        self.span,
+                        "the type information given here is insufficient to check whether \
+                        the pointer cast is valid",
                     );
                 }
                 err.emit();
@@ -438,13 +504,16 @@ fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) {
                     Ok(s) => {
                         err.span_suggestion(
                             self.cast_span,
-                            "try casting to a `Box` instead",
+                            "you can cast to a `Box` instead",
                             format!("Box<{}>", s),
                             Applicability::MachineApplicable,
                         );
                     }
                     Err(_) => {
-                        err.span_help(self.cast_span, &format!("did you mean `Box<{}>`?", tstr));
+                        err.span_help(
+                            self.cast_span,
+                            &format!("you might have meant `Box<{}>`", tstr),
+                        );
                     }
                 }
             }
@@ -609,7 +678,10 @@ fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
             (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
 
             // prim -> prim
-            (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
+            (Int(CEnum), Int(_)) => {
+                self.cenum_impl_drop_lint(fcx);
+                Ok(CastKind::EnumCast)
+            }
             (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
 
             (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
@@ -706,11 +778,13 @@ fn check_ref_cast(
                 // Coerce to a raw pointer so that we generate AddressOf in MIR.
                 let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
                 fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
-                    .unwrap_or_else(|_| bug!(
+                    .unwrap_or_else(|_| {
+                        bug!(
                         "could not cast from reference to array to pointer to array ({:?} to {:?})",
                         self.expr_ty,
                         array_ptr_type,
-                    ));
+                    )
+                    });
 
                 // this will report a type mismatch if needed
                 fcx.demand_eqtype(self.span, ety, m_cast.ty);
@@ -740,6 +814,25 @@ fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::Typ
             Err(err) => Err(err),
         }
     }
+
+    fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
+        if let ty::Adt(d, _) = self.expr_ty.kind {
+            if d.has_dtor(fcx.tcx) {
+                fcx.tcx.struct_span_lint_hir(
+                    lint::builtin::CENUM_IMPL_DROP_CAST,
+                    self.expr.hir_id,
+                    self.span,
+                    |err| {
+                        err.build(&format!(
+                            "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
+                            self.expr_ty, self.cast_ty
+                        ))
+                        .emit();
+                    },
+                );
+            }
+        }
+    }
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
index 206619588c71dad3d6f5b91e752622d4090fe9eb..6d09ddc925ffe1f22ec44e5cf5f10326a4899cee 100644 (file)
@@ -700,7 +700,7 @@ fn error_sig_of_closure(&self, decl: &hir::FnDecl<'_>) -> ty::PolyFnSig<'tcx> {
         let supplied_arguments = decl.inputs.iter().map(|a| {
             // Convert the types that the user supplied (if any), but ignore them.
             astconv.ast_ty_to_ty(a);
-            self.tcx.types.err
+            self.tcx.ty_error()
         });
 
         if let hir::FnRetTy::Return(ref output) = decl.output {
@@ -709,7 +709,7 @@ fn error_sig_of_closure(&self, decl: &hir::FnDecl<'_>) -> ty::PolyFnSig<'tcx> {
 
         let result = ty::Binder::bind(self.tcx.mk_fn_sig(
             supplied_arguments,
-            self.tcx.types.err,
+            self.tcx.ty_error(),
             decl.c_variadic,
             hir::Unsafety::Normal,
             Abi::RustCall,
index 15ec92568fb4d1fcaec17a639d232d9098ccd901..b6cd8da236260f9e06fc34b30cfbd3f61642230c 100644 (file)
 //!
 //! Note that if we are expecting a reference, we will *reborrow*
 //! even if the argument provided was already a reference. This is
-//! useful for freezing mut/const things (that is, when the expected is &T
-//! but you have &const T or &mut T) and also for avoiding the linearity
+//! useful for freezing mut things (that is, when the expected type is &T
+//! but you have &mut T) and also for avoiding the linearity
 //! of mut things (when the expected is &mut T and you have &mut T). See
-//! the various `src/test/ui/coerce-reborrow-*.rs` tests for
+//! the various `src/test/ui/coerce/*.rs` tests for
 //! examples of where this is useful.
 //!
 //! ## Subtle note
 //!
-//! When deciding what type coercions to consider, we do not attempt to
-//! resolve any type variables we may encounter. This is because `b`
-//! represents the expected type "as the user wrote it", meaning that if
-//! the user defined a generic function like
+//! When infering the generic arguments of functions, the argument
+//! order is relevant, which can lead to the following edge case:
 //!
-//!    fn foo<A>(a: A, b: A) { ... }
+//! ```rust
+//! fn foo<T>(a: T, b: T) {
+//!     // ...
+//! }
 //!
-//! and then we wrote `foo(&1, @2)`, we will not auto-borrow
-//! either argument. In older code we went to some lengths to
-//! resolve the `b` variable, which could mean that we'd
-//! auto-borrow later arguments but not earlier ones, which
-//! seems very confusing.
+//! foo(&7i32, &mut 7i32);
+//! // This compiles, as we first infer `T` to be `&i32`,
+//! // and then coerce `&mut 7i32` to `&7i32`.
 //!
-//! ## Subtler note
-//!
-//! However, right now, if the user manually specifies the
-//! values for the type variables, as so:
-//!
-//!    foo::<&int>(@1, @2)
-//!
-//! then we *will* auto-borrow, because we can't distinguish this from a
-//! function that declared `&int`. This is inconsistent but it's easiest
-//! at the moment. The right thing to do, I think, is to consider the
-//! *unsubstituted* type when deciding whether to auto-borrow, but the
-//! *substituted* type when considering the bounds and so forth. But most
-//! of our methods don't give access to the unsubstituted type, and
-//! rightly so because they'd be error-prone. So maybe the thing to do is
-//! to actually determine the kind of coercions that should occur
-//! separately and pass them in. Or maybe it's ok as is. Anyway, it's
-//! sort of a minor point so I've opted to leave it for later -- after all,
-//! we may want to adjust precisely when coercions occur.
+//! foo(&mut 7i32, &7i32);
+//! // This does not compile, as we first infer `T` to be `&mut i32`
+//! // and are then unable to coerce `&7i32` to `&mut i32`.
+//! ```
 
 use crate::astconv::AstConv;
-use crate::check::{FnCtxt, Needs};
+use crate::check::FnCtxt;
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -96,6 +81,8 @@ fn deref(&self) -> &Self::Target {
 
 type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
 
+/// Coercing a mutable reference to an immutable works, while
+/// coercing `&T` to `&mut T` should be forbidden.
 fn coerce_mutbls<'tcx>(
     from_mutbl: hir::Mutability,
     to_mutbl: hir::Mutability,
@@ -162,7 +149,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
 
         // Just ignore error types.
         if a.references_error() || b.references_error() {
-            return success(vec![], self.fcx.tcx.types.err, vec![]);
+            return success(vec![], self.fcx.tcx.ty_error(), vec![]);
         }
 
         if a.is_never() {
@@ -421,9 +408,8 @@ fn coerce_borrowed_pointer(
             return success(vec![], ty, obligations);
         }
 
-        let needs = Needs::maybe_mut_place(mutbl_b);
         let InferOk { value: mut adjustments, obligations: o } =
-            autoderef.adjust_steps_as_infer_ok(self, needs);
+            self.adjust_steps_as_infer_ok(&autoderef);
         obligations.extend(o);
         obligations.extend(autoderef.into_obligations());
 
@@ -864,7 +850,7 @@ pub fn try_coerce(
 
         let (adjustments, _) = self.register_infer_ok_obligations(ok);
         self.apply_adjustments(expr, adjustments);
-        Ok(if expr_ty.references_error() { self.tcx.types.err } else { target })
+        Ok(if expr_ty.references_error() { self.tcx.ty_error() } else { target })
     }
 
     /// Same as `try_coerce()`, but without side-effects.
@@ -909,7 +895,12 @@ fn try_find_coercion_lub<E>(
     {
         let prev_ty = self.resolve_vars_with_obligations(prev_ty);
         let new_ty = self.resolve_vars_with_obligations(new_ty);
-        debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
+        debug!(
+            "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
+            prev_ty,
+            new_ty,
+            exprs.len()
+        );
 
         // Special-case that coercion alone cannot handle:
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
@@ -1015,6 +1006,10 @@ fn try_find_coercion_lub<E>(
                 Ok(ok) => {
                     let (adjustments, target) = self.register_infer_ok_obligations(ok);
                     self.apply_adjustments(new, adjustments);
+                    debug!(
+                        "coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
+                        prev_ty, new_ty,
+                    );
                     return Ok(target);
                 }
                 Err(e) => first_error = Some(e),
@@ -1045,6 +1040,11 @@ fn try_find_coercion_lub<E>(
             };
 
             if !noop {
+                debug!(
+                    "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB",
+                    expr,
+                );
+
                 return self
                     .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
                     .map(|ok| self.register_infer_ok_obligations(ok));
@@ -1062,6 +1062,10 @@ fn try_find_coercion_lub<E>(
                 }
             }
             Ok(ok) => {
+                debug!(
+                    "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
+                    prev_ty, new_ty,
+                );
                 let (adjustments, target) = self.register_infer_ok_obligations(ok);
                 for expr in exprs {
                     let expr = expr.as_coercion_site();
@@ -1239,7 +1243,7 @@ fn coerce_inner<'a>(
         // If we see any error types, just propagate that error
         // upwards.
         if expression_ty.references_error() || self.merged_ty().references_error() {
-            self.final_ty = Some(fcx.tcx.types.err);
+            self.final_ty = Some(fcx.tcx.ty_error());
             return;
         }
 
@@ -1396,7 +1400,7 @@ fn coerce_inner<'a>(
 
                 err.emit_unless(assign_to_bool || unsized_return);
 
-                self.final_ty = Some(fcx.tcx.types.err);
+                self.final_ty = Some(fcx.tcx.ty_error());
             }
         }
     }
index b39cfcb377595a45d7611d53a448ac70d588bb4e..4e97ba41dcbb3b0c03b899be94ce3fc0a6ab5f07 100644 (file)
@@ -4,15 +4,17 @@
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 
 use super::{potentially_plural_count, FnCtxt, Inherited};
+use std::iter;
 
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
@@ -91,14 +93,14 @@ fn compare_predicate_entailment<'tcx>(
 
     // This code is best explained by example. Consider a trait:
     //
-    //     trait Trait<'t,T> {
-    //          fn method<'a,M>(t: &'t T, m: &'a M) -> Self;
+    //     trait Trait<'t, T> {
+    //         fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
     //     }
     //
     // And an impl:
     //
     //     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
-    //          fn method<'b,N>(t: &'j &'i U, m: &'b N) -> Foo;
+    //          fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
     //     }
     //
     // We wish to decide if those two method types are compatible.
@@ -116,9 +118,9 @@ fn compare_predicate_entailment<'tcx>(
     // regions (Note: but only early-bound regions, i.e., those
     // declared on the impl or used in type parameter bounds).
     //
-    //     impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 }
+    //     impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
     //
-    // Now we can apply skol_substs to the type of the impl method
+    // Now we can apply placeholder_substs to the type of the impl method
     // to yield a new function type in terms of our fresh, placeholder
     // types:
     //
@@ -127,11 +129,11 @@ fn compare_predicate_entailment<'tcx>(
     // We now want to extract and substitute the type of the *trait*
     // method and compare it. To do so, we must create a compound
     // substitution by combining trait_to_impl_substs and
-    // impl_to_skol_substs, and also adding a mapping for the method
+    // impl_to_placeholder_substs, and also adding a mapping for the method
     // type parameters. We extend the mapping to also include
     // the method parameters.
     //
-    //     trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+    //     trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
     //
     // Applying this to the trait method type yields:
     //
@@ -145,20 +147,20 @@ fn compare_predicate_entailment<'tcx>(
     // satisfied by the implementation's method.
     //
     // We do this by creating a parameter environment which contains a
-    // substitution corresponding to impl_to_skol_substs. We then build
-    // trait_to_skol_substs and use it to convert the predicates contained
+    // substitution corresponding to impl_to_placeholder_substs. We then build
+    // trait_to_placeholder_substs and use it to convert the predicates contained
     // in the trait_m.generics to the placeholder form.
     //
     // Finally we register each of these predicates as an obligation in
     // a fresh FulfillmentCtxt, and invoke select_all_or_error.
 
     // Create mapping from impl to placeholder.
-    let impl_to_skol_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
+    let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
 
     // Create mapping from trait to placeholder.
-    let trait_to_skol_substs =
-        impl_to_skol_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
-    debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs);
+    let trait_to_placeholder_substs =
+        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
+    debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
 
     let impl_m_generics = tcx.generics_of(impl_m.def_id);
     let trait_m_generics = tcx.generics_of(trait_m.def_id);
@@ -194,7 +196,7 @@ fn compare_predicate_entailment<'tcx>(
     // if all constraints hold.
     hybrid_preds
         .predicates
-        .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
+        .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates);
 
     // Construct trait parameter environment and then shift it into the placeholder viewpoint.
     // The key step here is to update the caller_bounds's predicates to be
@@ -220,7 +222,7 @@ fn compare_predicate_entailment<'tcx>(
 
         let mut selcx = traits::SelectionContext::new(&infcx);
 
-        let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs);
+        let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
         let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
             impl_m_span,
             infer::HigherRankedType,
@@ -261,7 +263,7 @@ fn compare_predicate_entailment<'tcx>(
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
 
         let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, &tcx.fn_sig(trait_m.def_id));
-        let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs);
+        let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
         let trait_sig =
             inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &trait_sig);
         let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
@@ -1057,13 +1059,15 @@ fn nested_visit_map(
     let _: Result<(), ErrorReported> = (|| {
         compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
 
-        compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)
+        compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
+
+        compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
     })();
 }
 
 /// The equivalent of [compare_predicate_entailment], but for associated types
 /// instead of associated functions.
-fn compare_type_predicate_entailment(
+fn compare_type_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_ty: &ty::AssocItem,
     impl_ty_span: Span,
@@ -1165,6 +1169,145 @@ fn compare_type_predicate_entailment(
     })
 }
 
+/// Validate that `ProjectionCandidate`s created for this associated type will
+/// be valid.
+///
+/// Usually given
+///
+/// trait X { type Y: Copy } impl X for T { type Y = S; }
+///
+/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
+/// impl is well-formed we have to prove `S: Copy`.
+///
+/// For default associated types the normalization is not possible (the value
+/// from the impl could be overridden). We also can't normalize generic
+/// associated types (yet) because they contain bound parameters.
+fn compare_projection_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ty: &ty::AssocItem,
+    impl_ty: &ty::AssocItem,
+    impl_ty_span: Span,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorReported> {
+    let have_gats = tcx.features().generic_associated_types;
+    if impl_ty.defaultness.is_final() && !have_gats {
+        // For "final", non-generic associate type implementations, we
+        // don't need this as described above.
+        return Ok(());
+    }
+
+    let param_env = tcx.param_env(impl_ty.def_id);
+
+    // Given
+    //
+    // impl<A, B> Foo<u32> for (A, B) {
+    //     type Bar<C> =...
+    // }
+    //
+    // - `impl_substs` would be `[A, B, C]`
+    // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
+    //    the *trait* with the generic associated type parameters.
+    let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+    let rebased_substs =
+        impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+    let impl_ty_value = tcx.type_of(impl_ty.def_id);
+
+    // Map the predicate from the trait to the corresponding one for the impl.
+    // For example:
+    //
+    // trait X<A> { type Y<'a>: PartialEq<A> } impl X for T { type Y<'a> = &'a S; }
+    // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; }
+    //
+    // For the `for<'a> <<Self as X<A>>::Y<'a>: PartialEq<A>` bound, this
+    // function would translate and partially normalize
+    // `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`.
+    let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| {
+        tcx.mk_substs(
+            iter::once(impl_ty_value.into())
+                .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))),
+        )
+    };
+
+    tcx.infer_ctxt().enter(move |infcx| {
+        let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
+        let infcx = &inh.infcx;
+        let mut selcx = traits::SelectionContext::new(&infcx);
+
+        let impl_ty_hir_id = tcx.hir().as_local_hir_id(impl_ty.def_id.expect_local());
+        let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+        let cause = ObligationCause::new(
+            impl_ty_span,
+            impl_ty_hir_id,
+            ObligationCauseCode::ItemObligation(trait_ty.def_id),
+        );
+
+        let predicates = tcx.projection_predicates(trait_ty.def_id);
+
+        debug!("compare_projection_bounds: projection_predicates={:?}", predicates);
+
+        for predicate in predicates {
+            let concrete_ty_predicate = match predicate.kind() {
+                ty::PredicateKind::Trait(poly_tr, c) => poly_tr
+                    .map_bound(|tr| {
+                        let trait_substs = translate_predicate_substs(tr.trait_ref.substs);
+                        ty::TraitRef { def_id: tr.def_id(), substs: trait_substs }
+                    })
+                    .with_constness(*c)
+                    .to_predicate(tcx),
+                ty::PredicateKind::Projection(poly_projection) => poly_projection
+                    .map_bound(|projection| {
+                        let projection_substs =
+                            translate_predicate_substs(projection.projection_ty.substs);
+                        ty::ProjectionPredicate {
+                            projection_ty: ty::ProjectionTy {
+                                substs: projection_substs,
+                                item_def_id: projection.projection_ty.item_def_id,
+                            },
+                            ty: projection.ty.subst(tcx, rebased_substs),
+                        }
+                    })
+                    .to_predicate(tcx),
+                ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives
+                    .map_bound(|outlives| {
+                        ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs))
+                    })
+                    .to_predicate(tcx),
+                _ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
+            };
+
+            let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
+                &mut selcx,
+                param_env,
+                normalize_cause.clone(),
+                &concrete_ty_predicate,
+            );
+
+            debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+
+            inh.register_predicates(obligations);
+            inh.register_predicate(traits::Obligation::new(
+                cause.clone(),
+                param_env,
+                normalized_predicate,
+            ));
+        }
+
+        // Check that all obligations are satisfied by the implementation's
+        // version.
+        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+            infcx.report_fulfillment_errors(errors, None, false);
+            return Err(ErrorReported);
+        }
+
+        // Finally, resolve all regions. This catches wily misuses of
+        // lifetime parameters.
+        let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
+        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);
+
+        Ok(())
+    })
+}
+
 fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
     match impl_item.kind {
         ty::AssocKind::Const => "const",
index 019b4ca66060c295c6b799e4e0e79dffc7790f37..85c073ca3003439aec9fd2e5a057e11e2239aa0e 100644 (file)
@@ -34,6 +34,7 @@ pub fn emit_coerce_suggestions(
         }
         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
         self.suggest_missing_await(err, expr, expected, expr_ty);
+        self.note_need_for_fn_pointer(err, expected, expr_ty);
     }
 
     // Requires that the two types unify, and prints an error message if
@@ -783,6 +784,9 @@ pub fn check_for_cast(
         let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
             if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
         };
+        let is_negative_int =
+            |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..));
+        let is_uint = |ty: Ty<'_>| matches!(ty.kind, ty::Uint(..));
 
         let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
 
@@ -807,7 +811,7 @@ pub fn check_for_cast(
                         "you can convert `{}` from `{}` to `{}`, matching the type of `{}`",
                         lhs_src, expected_ty, checked_ty, src
                     );
-                    let suggestion = format!("{}::from({})", checked_ty, lhs_src,);
+                    let suggestion = format!("{}::from({})", checked_ty, lhs_src);
                     (lhs_expr.span, msg, suggestion)
                 } else {
                     let msg = format!("{} and panic if the converted value wouldn't fit", msg);
@@ -822,8 +826,17 @@ pub fn check_for_cast(
             |err: &mut DiagnosticBuilder<'_>,
              found_to_exp_is_fallible: bool,
              exp_to_found_is_fallible: bool| {
+                let always_fallible = found_to_exp_is_fallible
+                    && (exp_to_found_is_fallible || expected_ty_expr.is_none());
                 let msg = if literal_is_ty_suffixed(expr) {
                     &lit_msg
+                } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
+                    // We now know that converting either the lhs or rhs is fallible. Before we
+                    // suggest a fallible conversion, check if the value can never fit in the
+                    // expected type.
+                    let msg = format!("`{}` cannot fit into type `{}`", src, expected_ty);
+                    err.note(&msg);
+                    return;
                 } else if in_const_context {
                     // Do not recommend `into` or `try_into` in const contexts.
                     return;
index bc3ef73d851ebcdc0258c517ea26f86de9ddda98..1eaa5a6c31e20070466b1d4941f1fe1b4bd815b2 100644 (file)
@@ -29,9 +29,7 @@
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty;
-use rustc_middle::ty::adjustment::{
-    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
-};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{AdtKind, Visibility};
@@ -113,12 +111,21 @@ pub(super) fn check_expr_with_hint(
         self.check_expr_with_expectation(expr, ExpectHasType(expected))
     }
 
-    pub(super) fn check_expr_with_expectation(
+    fn check_expr_with_expectation_and_needs(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
+        needs: Needs,
     ) -> Ty<'tcx> {
-        self.check_expr_with_expectation_and_needs(expr, expected, Needs::None)
+        let ty = self.check_expr_with_expectation(expr, expected);
+
+        // If the expression is used in a place whether mutable place is required
+        // e.g. LHS of assignment, perform the conversion.
+        if let Needs::MutPlace = needs {
+            self.convert_place_derefs_to_mutable(expr);
+        }
+
+        ty
     }
 
     pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
@@ -143,11 +150,10 @@ pub(super) fn check_expr_with_needs(
     /// Note that inspecting a type's structure *directly* may expose the fact
     /// that there are actually multiple representations for `Error`, so avoid
     /// that when err needs to be handled differently.
-    fn check_expr_with_expectation_and_needs(
+    pub(super) fn check_expr_with_expectation(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        needs: Needs,
     ) -> Ty<'tcx> {
         debug!(">> type-checking: expr={:?} expected={:?}", expr, expected);
 
@@ -171,7 +177,7 @@ fn check_expr_with_expectation_and_needs(
         let old_diverges = self.diverges.replace(Diverges::Maybe);
         let old_has_errors = self.has_errors.replace(false);
 
-        let ty = self.check_expr_kind(expr, expected, needs);
+        let ty = self.check_expr_kind(expr, expected);
 
         // Warn for non-block expressions with diverging children.
         match expr.kind {
@@ -213,9 +219,8 @@ fn check_expr_kind(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        needs: Needs,
     ) -> Ty<'tcx> {
-        debug!("check_expr_kind(expr={:?}, expected={:?}, needs={:?})", expr, expected, needs,);
+        debug!("check_expr_kind(expr={:?}, expected={:?})", expr, expected);
 
         let tcx = self.tcx;
         match expr.kind {
@@ -226,9 +231,7 @@ fn check_expr_kind(
                 self.check_expr_assign(expr, expected, lhs, rhs, span)
             }
             ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs),
-            ExprKind::Unary(unop, ref oprnd) => {
-                self.check_expr_unary(unop, oprnd, expected, needs, expr)
-            }
+            ExprKind::Unary(unop, ref oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
             ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
                 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
             }
@@ -248,7 +251,7 @@ fn check_expr_kind(
                     tcx.types.never
                 } else {
                     // There was an error; make type-check fail.
-                    tcx.types.err
+                    tcx.ty_error()
                 }
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
@@ -264,7 +267,7 @@ fn check_expr_kind(
             ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected),
             ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected),
             ExprKind::MethodCall(ref segment, span, ref args, _) => {
-                self.check_method_call(expr, segment, span, args, expected, needs)
+                self.check_method_call(expr, segment, span, args, expected)
             }
             ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr),
             ExprKind::Type(ref e, ref t) => {
@@ -281,10 +284,10 @@ fn check_expr_kind(
             ExprKind::Struct(ref qpath, fields, ref base_expr) => {
                 self.check_expr_struct(expr, expected, qpath, fields, base_expr)
             }
-            ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field),
-            ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr),
+            ExprKind::Field(ref base, field) => self.check_field(expr, &base, field),
+            ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, expr),
             ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src),
-            hir::ExprKind::Err => tcx.types.err,
+            hir::ExprKind::Err => tcx.ty_error(),
         }
     }
 
@@ -302,7 +305,6 @@ fn check_expr_unary(
         unop: hir::UnOp,
         oprnd: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        needs: Needs,
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
@@ -310,40 +312,14 @@ fn check_expr_unary(
             hir::UnOp::UnNot | hir::UnOp::UnNeg => expected,
             hir::UnOp::UnDeref => NoExpectation,
         };
-        let needs = match unop {
-            hir::UnOp::UnDeref => needs,
-            _ => Needs::None,
-        };
-        let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, expected_inner, needs);
+        let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner);
 
         if !oprnd_t.references_error() {
             oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
             match unop {
                 hir::UnOp::UnDeref => {
-                    if let Some(mt) = oprnd_t.builtin_deref(true) {
-                        oprnd_t = mt.ty;
-                    } else if let Some(ok) = self.try_overloaded_deref(expr.span, oprnd_t, needs) {
-                        let method = self.register_infer_ok_obligations(ok);
-                        if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
-                            let mutbl = match mutbl {
-                                hir::Mutability::Not => AutoBorrowMutability::Not,
-                                hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                                    // (It shouldn't actually matter for unary ops whether
-                                    // we enable two-phase borrows or not, since a unary
-                                    // op has no additional operands.)
-                                    allow_two_phase_borrow: AllowTwoPhase::No,
-                                },
-                            };
-                            self.apply_adjustments(
-                                oprnd,
-                                vec![Adjustment {
-                                    kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
-                                    target: method.sig.inputs()[0],
-                                }],
-                            );
-                        }
-                        oprnd_t = self.make_overloaded_place_return_type(method).ty;
-                        self.write_method_call(expr.hir_id, method);
+                    if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
+                        oprnd_t = ty;
                     } else {
                         let mut err = type_error_struct!(
                             tcx.sess,
@@ -360,7 +336,7 @@ fn check_expr_unary(
                             tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp, None);
                         }
                         err.emit();
-                        oprnd_t = tcx.types.err;
+                        oprnd_t = tcx.ty_error();
                     }
                 }
                 hir::UnOp::UnNot => {
@@ -405,12 +381,12 @@ fn check_expr_addr_of(
                 _ => NoExpectation,
             }
         });
-        let needs = Needs::maybe_mut_place(mutbl);
-        let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs);
+        let ty =
+            self.check_expr_with_expectation_and_needs(&oprnd, hint, Needs::maybe_mut_place(mutbl));
 
         let tm = ty::TypeAndMut { ty, mutbl };
         match kind {
-            _ if tm.ty.references_error() => self.tcx.types.err,
+            _ if tm.ty.references_error() => self.tcx.ty_error(),
             hir::BorrowKind::Raw => {
                 self.check_named_place_expr(oprnd);
                 self.tcx.mk_ptr(tm)
@@ -476,11 +452,11 @@ fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -
         let ty = match res {
             Res::Err => {
                 self.set_tainted_by_errors();
-                tcx.types.err
+                tcx.ty_error()
             }
             Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => {
                 report_unexpected_variant_res(tcx, res, expr.span);
-                tcx.types.err
+                tcx.ty_error()
             }
             _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
         };
@@ -560,11 +536,10 @@ fn check_expr_break(
                         Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()),
                         None => {
                             // Avoid ICE when `break` is inside a closure (#65383).
-                            self.tcx.sess.delay_span_bug(
+                            return tcx.ty_error_with_message(
                                 expr.span,
                                 "break was outside loop, but no error was emitted",
                             );
-                            return tcx.types.err;
                         }
                     }
                 };
@@ -572,7 +547,7 @@ fn check_expr_break(
                 // If the loop context is not a `loop { }`, then break with
                 // a value is illegal, and `opt_coerce_to` will be `None`.
                 // Just set expectation to error in that case.
-                let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err);
+                let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error());
 
                 // Recurse without `enclosing_breakables` borrowed.
                 e_ty = self.check_expr_with_hint(e, coerce_to);
@@ -592,11 +567,10 @@ fn check_expr_break(
                 Some(ctxt) => ctxt,
                 None => {
                     // Avoid ICE when `break` is inside a closure (#65383).
-                    self.tcx.sess.delay_span_bug(
+                    return tcx.ty_error_with_message(
                         expr.span,
                         "break was outside loop, but no error was emitted",
                     );
-                    return tcx.types.err;
                 }
             };
 
@@ -649,14 +623,15 @@ fn check_expr_break(
             // this can only happen if the `break` was not
             // inside a loop at all, which is caught by the
             // loop-checking pass.
-            self.tcx
-                .sess
-                .delay_span_bug(expr.span, "break was outside loop, but no error was emitted");
+            let err = self.tcx.ty_error_with_message(
+                expr.span,
+                "break was outside loop, but no error was emitted",
+            );
 
             // We still need to assign a type to the inner expression to
             // prevent the ICE in #43162.
             if let Some(ref e) = expr_opt {
-                self.check_expr_with_hint(e, tcx.types.err);
+                self.check_expr_with_hint(e, err);
 
                 // ... except when we try to 'break rust;'.
                 // ICE this expression in particular (see #43162).
@@ -666,8 +641,9 @@ fn check_expr_break(
                     }
                 }
             }
+
             // There was an error; make type-check fail.
-            tcx.types.err
+            err
         }
     }
 
@@ -803,7 +779,7 @@ fn check_expr_assign(
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
         if lhs_ty.references_error() || rhs_ty.references_error() {
-            self.tcx.types.err
+            self.tcx.ty_error()
         } else {
             self.tcx.mk_unit()
         }
@@ -861,10 +837,9 @@ fn check_method_call(
         span: Span,
         args: &'tcx [hir::Expr<'tcx>],
         expected: Expectation<'tcx>,
-        needs: Needs,
     ) -> Ty<'tcx> {
         let rcvr = &args[0];
-        let rcvr_t = self.check_expr_with_needs(&rcvr, needs);
+        let rcvr_t = self.check_expr(&rcvr);
         // no need to check for bot/err -- callee does that
         let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
 
@@ -913,10 +888,16 @@ fn report_extended_method_error(
                     rcvr,
                     probe::ProbeScope::AllTraits,
                 ) {
-                    err.span_label(
-                        pick.item.ident.span,
-                        &format!("the method is available for `{}` here", new_rcvr_t),
-                    );
+                    debug!("try_alt_rcvr: pick candidate {:?}", pick);
+                    // Make sure the method is defined for the *actual* receiver:
+                    // we don't want to treat `Box<Self>` as a receiver if
+                    // it only works because of an autoderef to `&self`
+                    if pick.autoderefs == 0 {
+                        err.span_label(
+                            pick.item.ident.span,
+                            &format!("the method is available for `{}` here", new_rcvr_t),
+                        );
+                    }
                 }
             }
         };
@@ -957,7 +938,7 @@ fn check_expr_cast(
 
         // Eagerly check for some obvious errors.
         if t_expr.references_error() || t_cast.references_error() {
-            self.tcx.types.err
+            self.tcx.ty_error()
         } else {
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
@@ -966,7 +947,7 @@ fn check_expr_cast(
                     deferred_cast_checks.push(cast_check);
                     t_cast
                 }
-                Err(ErrorReported) => self.tcx.types.err,
+                Err(ErrorReported) => self.tcx.ty_error(),
             }
         }
     }
@@ -1041,7 +1022,7 @@ fn check_expr_repeat(
         };
 
         if element_ty.references_error() {
-            return tcx.types.err;
+            return tcx.ty_error();
         }
 
         tcx.mk_ty(ty::Array(t, count))
@@ -1071,7 +1052,7 @@ fn check_expr_tuple(
         });
         let tuple = self.tcx.mk_tup(elt_ts_iter);
         if tuple.references_error() {
-            self.tcx.types.err
+            self.tcx.ty_error()
         } else {
             self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
             tuple
@@ -1092,7 +1073,7 @@ fn check_expr_struct(
             variant_ty
         } else {
             self.check_struct_fields_on_error(fields, base_expr);
-            return self.tcx.types.err;
+            return self.tcx.ty_error();
         };
 
         let path_span = match *qpath {
@@ -1233,7 +1214,7 @@ fn check_expr_struct_fields(
                     self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span);
                 }
 
-                tcx.types.err
+                tcx.ty_error()
             };
 
             // Make sure to give a type to the field even if there's
@@ -1443,11 +1424,10 @@ fn name_series_display(&self, names: Vec<Symbol>) -> String {
     fn check_field(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
-        needs: Needs,
         base: &'tcx hir::Expr<'tcx>,
         field: Ident,
     ) -> Ty<'tcx> {
-        let expr_t = self.check_expr_with_needs(base, needs);
+        let expr_t = self.check_expr(base);
         let expr_t = self.structurally_resolved_type(base.span, expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
@@ -1467,9 +1447,9 @@ fn check_field(
                         // of error recovery.
                         self.write_field_index(expr.hir_id, index);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = autoderef.adjust_steps(self, needs);
+                            let adjustments = self.adjust_steps(&autoderef);
                             self.apply_adjustments(base, adjustments);
-                            autoderef.finalize(self);
+                            self.register_predicates(autoderef.into_obligations());
 
                             self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span);
                             return field_ty;
@@ -1482,9 +1462,9 @@ fn check_field(
                     if let Ok(index) = fstr.parse::<usize>() {
                         if fstr == index.to_string() {
                             if let Some(field_ty) = tys.get(index) {
-                                let adjustments = autoderef.adjust_steps(self, needs);
+                                let adjustments = self.adjust_steps(&autoderef);
                                 self.apply_adjustments(base, adjustments);
-                                autoderef.finalize(self);
+                                self.register_predicates(autoderef.into_obligations());
 
                                 self.write_field_index(expr.hir_id, index);
                                 return field_ty.expect_ty();
@@ -1495,7 +1475,7 @@ fn check_field(
                 _ => {}
             }
         }
-        autoderef.unambiguous_final_ty(self);
+        self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
 
         if let Some((did, field_ty)) = private_candidate {
             self.ban_private_field_access(expr, expr_t, field, did);
@@ -1519,7 +1499,7 @@ fn check_field(
             .emit();
         }
 
-        self.tcx().types.err
+        self.tcx().ty_error()
     }
 
     fn ban_nonexisting_field(
@@ -1721,10 +1701,9 @@ fn check_expr_index(
         &self,
         base: &'tcx hir::Expr<'tcx>,
         idx: &'tcx hir::Expr<'tcx>,
-        needs: Needs,
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
-        let base_t = self.check_expr_with_needs(&base, needs);
+        let base_t = self.check_expr(&base);
         let idx_t = self.check_expr(&idx);
 
         if base_t.references_error() {
@@ -1733,7 +1712,7 @@ fn check_expr_index(
             idx_t
         } else {
             let base_t = self.structurally_resolved_type(base.span, base_t);
-            match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
+            match self.lookup_indexing(expr, base, base_t, idx_t) {
                 Some((index_ty, element_ty)) => {
                     // two-phase not needed because index_ty is never mutable
                     self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
@@ -1775,7 +1754,7 @@ fn check_expr_index(
                         }
                     }
                     err.emit();
-                    self.tcx.types.err
+                    self.tcx.ty_error()
                 }
             }
         }
@@ -1887,7 +1866,7 @@ pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
         ty::Char => "'a'",
         ty::Int(_) | ty::Uint(_) => "42",
         ty::Float(_) => "3.14159",
-        ty::Error | ty::Never => return None,
+        ty::Error(_) | ty::Never => return None,
         _ => "value",
     })
 }
index bded2c695c9db50f8df0275e2d1f383d92296df1..1c0b22ca7370bd5da2bdad633619a2abe85058c4 100644 (file)
@@ -74,9 +74,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
         | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add"
         | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz"
         | "bswap" | "bitreverse" | "discriminant_value" | "type_id" | "likely" | "unlikely"
-        | "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name" => {
-            hir::Unsafety::Normal
-        }
+        | "ptr_guaranteed_eq" | "ptr_guaranteed_ne" | "minnumf32" | "minnumf64" | "maxnumf32"
+        | "maxnumf64" | "type_name" | "variant_count" => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
     }
 }
@@ -138,7 +137,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         let unsafety = intrinsic_operation_unsafety(&name[..]);
         let (n_tps, inputs, output) = match &name[..] {
             "breakpoint" => (0, Vec::new(), tcx.mk_unit()),
-            "size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
+            "size_of" | "pref_align_of" | "min_align_of" | "variant_count" => {
+                (1, Vec::new(), tcx.types.usize)
+            }
             "size_of_val" | "min_align_of_val" => {
                 (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize)
             }
@@ -258,6 +259,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
             }
 
+            "ptr_guaranteed_eq" | "ptr_guaranteed_ne" => {
+                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
+            }
+
             "ptr_offset_from" => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
             }
@@ -347,6 +352,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 return;
             }
 
+            "count_code_region" => (0, vec![tcx.types.u32], tcx.mk_unit()),
+
             ref other => {
                 struct_span_err!(
                     tcx.sess,
index 007794ce1b7ffff34401b193375b5fbd6752b291..1c3d23a3a241f4bf751ad6490235491317ad26d2 100644 (file)
@@ -1,12 +1,12 @@
 use super::{probe, MethodCallee};
 
 use crate::astconv::AstConv;
-use crate::check::{callee, FnCtxt, Needs, PlaceOp};
+use crate::check::{callee, FnCtxt};
 use crate::hir::def_id::DefId;
 use crate::hir::GenericArg;
 use rustc_hir as hir;
 use rustc_infer::infer::{self, InferOk};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
@@ -119,11 +119,6 @@ fn confirm(
 
         // Create the final `MethodCallee`.
         let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig };
-
-        if let Some(hir::Mutability::Mut) = pick.autoref {
-            self.convert_place_derefs_to_mutable();
-        }
-
         ConfirmResult { callee, illegal_sized_bound }
     }
 
@@ -141,18 +136,18 @@ fn adjust_self_ty(
         let (_, n) = match autoderef.nth(pick.autoderefs) {
             Some(n) => n,
             None => {
-                self.tcx.sess.delay_span_bug(
+                return self.tcx.ty_error_with_message(
                     rustc_span::DUMMY_SP,
                     &format!("failed autoderef {}", pick.autoderefs),
                 );
-                return self.tcx.types.err;
             }
         };
         assert_eq!(n, pick.autoderefs);
 
-        let mut adjustments = autoderef.adjust_steps(self, Needs::None);
+        let mut adjustments = self.adjust_steps(&autoderef);
 
-        let mut target = autoderef.unambiguous_final_ty(self);
+        let mut target =
+            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
 
         if let Some(mutbl) = pick.autoref {
             let region = self.next_region_var(infer::Autoref(self.span));
@@ -182,7 +177,7 @@ fn adjust_self_ty(
             assert!(pick.unsize.is_none());
         }
 
-        autoderef.finalize(self);
+        self.register_predicates(autoderef.into_obligations());
 
         // Write out the final adjustments.
         self.apply_adjustments(self.self_expr, adjustments);
@@ -416,151 +411,6 @@ fn add_obligations(
         self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation);
     }
 
-    ///////////////////////////////////////////////////////////////////////////
-    // RECONCILIATION
-
-    /// When we select a method with a mutable autoref, we have to go convert any
-    /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
-    /// respectively.
-    fn convert_place_derefs_to_mutable(&self) {
-        // Gather up expressions we want to munge.
-        let mut exprs = vec![self.self_expr];
-
-        loop {
-            match exprs.last().unwrap().kind {
-                hir::ExprKind::Field(ref expr, _)
-                | hir::ExprKind::Index(ref expr, _)
-                | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
-                _ => break,
-            }
-        }
-
-        debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
-
-        // Fix up autoderefs and derefs.
-        for (i, &expr) in exprs.iter().rev().enumerate() {
-            debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
-
-            // Fix up the autoderefs. Autorefs can only occur immediately preceding
-            // overloaded place ops, and will be fixed by them in order to get
-            // the correct region.
-            let mut source = self.node_ty(expr.hir_id);
-            // Do not mutate adjustments in place, but rather take them,
-            // and replace them after mutating them, to avoid having the
-            // tables borrowed during (`deref_mut`) method resolution.
-            let previous_adjustments =
-                self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
-            if let Some(mut adjustments) = previous_adjustments {
-                let needs = Needs::MutPlace;
-                for adjustment in &mut adjustments {
-                    if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
-                        if let Some(ok) = self.try_overloaded_deref(expr.span, source, needs) {
-                            let method = self.register_infer_ok_obligations(ok);
-                            if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
-                                *deref = OverloadedDeref { region, mutbl };
-                            }
-                        }
-                    }
-                    source = adjustment.target;
-                }
-                self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
-            }
-
-            match expr.kind {
-                hir::ExprKind::Index(ref base_expr, ref index_expr) => {
-                    // We need to get the final type in case dereferences were needed for the trait
-                    // to apply (#72002).
-                    let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
-                    self.convert_place_op_to_mutable(
-                        PlaceOp::Index,
-                        expr,
-                        base_expr,
-                        &[index_expr_ty],
-                    );
-                }
-                hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
-                    self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
-                }
-                _ => {}
-            }
-        }
-    }
-
-    fn convert_place_op_to_mutable(
-        &self,
-        op: PlaceOp,
-        expr: &hir::Expr<'_>,
-        base_expr: &hir::Expr<'_>,
-        arg_tys: &[Ty<'tcx>],
-    ) {
-        debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
-        if !self.tables.borrow().is_method_call(expr) {
-            debug!("convert_place_op_to_mutable - builtin, nothing to do");
-            return;
-        }
-
-        let base_ty = self
-            .tables
-            .borrow()
-            .expr_adjustments(base_expr)
-            .last()
-            .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target);
-        let base_ty = self.resolve_vars_if_possible(&base_ty);
-
-        // Need to deref because overloaded place ops take self by-reference.
-        let base_ty =
-            base_ty.builtin_deref(false).expect("place op takes something that is not a ref").ty;
-
-        let method = self.try_overloaded_place_op(expr.span, base_ty, arg_tys, Needs::MutPlace, op);
-        let method = match method {
-            Some(ok) => self.register_infer_ok_obligations(ok),
-            None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed"),
-        };
-        debug!("convert_place_op_to_mutable: method={:?}", method);
-        self.write_method_call(expr.hir_id, method);
-
-        let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind {
-            (r, mutbl)
-        } else {
-            span_bug!(expr.span, "input to place op is not a ref?");
-        };
-
-        // Convert the autoref in the base expr to mutable with the correct
-        // region and mutability.
-        let base_expr_ty = self.node_ty(base_expr.hir_id);
-        if let Some(adjustments) =
-            self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
-        {
-            let mut source = base_expr_ty;
-            for adjustment in &mut adjustments[..] {
-                if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
-                    debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
-                    let mutbl = match mutbl {
-                        hir::Mutability::Not => AutoBorrowMutability::Not,
-                        hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                            // For initial two-phase borrow
-                            // deployment, conservatively omit
-                            // overloaded operators.
-                            allow_two_phase_borrow: AllowTwoPhase::No,
-                        },
-                    };
-                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
-                    adjustment.target =
-                        self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
-                }
-                source = adjustment.target;
-            }
-
-            // If we have an autoref followed by unsizing at the end, fix the unsize target.
-
-            if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
-                adjustments[..]
-            {
-                *target = method.sig.inputs()[0];
-            }
-        }
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // MISCELLANY
 
index ac3fa15417e9cc3bc02289781ea7dfff5ed1176c..7bdf137f116c858f0284b31764aef60105280f54 100644 (file)
@@ -194,11 +194,10 @@ pub fn lookup_method(
             self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
 
         for import_id in &pick.import_ids {
-            let import_def_id = self.tcx.hir().local_def_id(*import_id);
-            debug!("used_trait_import: {:?}", import_def_id);
+            debug!("used_trait_import: {:?}", import_id);
             Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
                 .unwrap()
-                .insert(import_def_id.to_def_id());
+                .insert(*import_id);
         }
 
         self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span);
@@ -296,8 +295,7 @@ pub fn lookup_method_in_trait(
         opt_input_types: Option<&[Ty<'tcx>]>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         debug!(
-            "lookup_in_trait_adjusted(self_ty={:?}, \
-                m_name={}, trait_def_id={:?})",
+            "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?})",
             self_ty, m_name, trait_def_id
         );
 
@@ -461,9 +459,8 @@ pub fn resolve_ufcs(
             let mut tables = self.tables.borrow_mut();
             let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap();
             for import_id in pick.import_ids {
-                let import_def_id = tcx.hir().local_def_id(import_id);
-                debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
-                used_trait_imports.insert(import_def_id.to_def_id());
+                debug!("resolve_ufcs: used_trait_import: {:?}", import_id);
+                used_trait_imports.insert(import_id);
             }
         }
 
index 37652330108c9b806cfa6a8657c41be8d03b6777..8842ca877268a00bcb3aa98ec78f2a214cab2860 100644 (file)
@@ -3,7 +3,6 @@
 use super::NoMatchData;
 use super::{CandidateSource, ImplSource, TraitSource};
 
-use crate::check::autoderef::{self, Autoderef};
 use crate::check::FnCtxt;
 use crate::hir::def::DefKind;
 use crate::hir::def_id::DefId;
@@ -28,7 +27,9 @@
 };
 use rustc_session::config::nightly_options;
 use rustc_session::lint;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::autoderef::{self, Autoderef};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
 use rustc_trait_selection::traits::query::method_autoderef::{
@@ -129,7 +130,7 @@ struct Candidate<'tcx> {
     xform_ret_ty: Option<Ty<'tcx>>,
     item: ty::AssocItem,
     kind: CandidateKind<'tcx>,
-    import_ids: SmallVec<[hir::HirId; 1]>,
+    import_ids: SmallVec<[LocalDefId; 1]>,
 }
 
 #[derive(Debug)]
@@ -158,7 +159,7 @@ enum ProbeResult {
 pub struct Pick<'tcx> {
     pub item: ty::AssocItem,
     pub kind: PickKind<'tcx>,
-    pub import_ids: SmallVec<[hir::HirId; 1]>,
+    pub import_ids: SmallVec<[LocalDefId; 1]>,
 
     // Indicates that the source expression should be autoderef'd N times
     //
@@ -379,8 +380,8 @@ fn probe_op<OP, R>(
                         self.tcx.sess,
                         span,
                         E0699,
-                        "the type of this value must be known \
-                               to call a method on a raw pointer on it"
+                        "the type of this value must be known to call a method on a raw pointer on \
+                         it"
                     )
                     .emit();
                 } else {
@@ -400,7 +401,7 @@ fn probe_op<OP, R>(
                     .probe_instantiate_query_response(span, &orig_values, ty)
                     .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
                 let ty = self.structurally_resolved_type(span, ty.value);
-                assert_eq!(ty, self.tcx.types.err);
+                assert!(matches!(ty.kind, ty::Error(_)));
                 return Err(MethodError::NoMatch(NoMatchData::new(
                     Vec::new(),
                     Vec::new(),
@@ -476,9 +477,9 @@ fn method_autoderef_steps<'tcx>(
             })
             .collect();
 
-        let final_ty = autoderef.maybe_ambiguous_final_ty();
+        let final_ty = autoderef.final_ty(true);
         let opt_bad_ty = match final_ty.kind {
-            ty::Infer(ty::TyVar(_)) | ty::Error => Some(MethodAutoderefBadTy {
+            ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
                 reached_raw_pointer,
                 ty: infcx
                     .make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
@@ -930,7 +931,7 @@ pub fn matches_return_type(
 
     fn assemble_extension_candidates_for_trait(
         &mut self,
-        import_ids: &SmallVec<[hir::HirId; 1]>,
+        import_ids: &SmallVec<[LocalDefId; 1]>,
         trait_def_id: DefId,
     ) -> Result<(), MethodError<'tcx>> {
         debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
@@ -1467,7 +1468,7 @@ fn consider_probe(
     ///
     /// ```
     /// trait Foo { ... }
-    /// impl Foo for Vec<int> { ... }
+    /// impl Foo for Vec<i32> { ... }
     /// impl Foo for Vec<usize> { ... }
     /// ```
     ///
index c26acd7a47703828078b3c927d640473de3b8204..7c4048ab223023f3b56bd3671a3043a1bca01131 100644 (file)
@@ -79,6 +79,7 @@
 pub mod method;
 mod op;
 mod pat;
+mod place_op;
 mod regionck;
 mod upvar;
 mod wfcheck;
@@ -96,7 +97,7 @@
 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, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items::{
 use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::adjustment::{
-    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
+    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::query::Providers;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl};
 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
+use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
-use self::autoderef::Autoderef;
 use self::callee::DeferredCallResolution;
 use self::coercion::{CoerceMany, DynamicCoerceMany};
 use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
@@ -736,7 +737,7 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) {
     tcx.hir().krate().par_visit_all_item_likes(&visit);
 }
 
-fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
 }
 
@@ -839,7 +840,7 @@ fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
-fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &DefIdSet {
+fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
     &*tcx.typeck_tables_of(def_id).used_trait_imports
 }
 
@@ -967,8 +968,7 @@ fn diagnostic_only_typeck_tables_of<'tcx>(
 ) -> &ty::TypeckTables<'tcx> {
     let fallback = move || {
         let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id));
-        tcx.sess.delay_span_bug(span, "diagnostic only typeck table used");
-        tcx.types.err
+        tcx.ty_error_with_message(span, "diagnostic only typeck table used")
     };
     typeck_tables_of_with_fallback(tcx, def_id, fallback)
 }
@@ -1711,6 +1711,173 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
     }
 }
 
+/// Given a `DefId` for an opaque type in return position, find its parent item's return
+/// expressions.
+fn get_owner_return_paths(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> {
+    let hir_id = tcx.hir().as_local_hir_id(def_id);
+    let id = tcx.hir().get_parent_item(hir_id);
+    tcx.hir()
+        .find(id)
+        .map(|n| (id, n))
+        .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b)))
+        .map(|(hir_id, body_id)| {
+            let body = tcx.hir().body(body_id);
+            let mut visitor = ReturnsVisitor::default();
+            visitor.visit_body(body);
+            (hir_id, visitor)
+        })
+}
+
+/// Emit an error for recursive opaque types.
+///
+/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
+/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
+/// `impl Trait`.
+///
+/// If all the return expressions evaluate to `!`, then we explain that the error will go away
+/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
+fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
+    let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
+
+    let mut label = false;
+    if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+        let tables = tcx.typeck_tables_of(tcx.hir().local_def_id(hir_id));
+        if visitor
+            .returns
+            .iter()
+            .filter_map(|expr| tables.node_type_opt(expr.hir_id))
+            .all(|ty| matches!(ty.kind, ty::Never))
+        {
+            let spans = visitor
+                .returns
+                .iter()
+                .filter(|expr| tables.node_type_opt(expr.hir_id).is_some())
+                .map(|expr| expr.span)
+                .collect::<Vec<Span>>();
+            let span_len = spans.len();
+            if span_len == 1 {
+                err.span_label(spans[0], "this returned value is of `!` type");
+            } else {
+                let mut multispan: MultiSpan = spans.clone().into();
+                for span in spans {
+                    multispan
+                        .push_span_label(span, "this returned value is of `!` type".to_string());
+                }
+                err.span_note(multispan, "these returned values have a concrete \"never\" type");
+            }
+            err.help("this error will resolve once the item's body returns a concrete type");
+        } else {
+            let mut seen = FxHashSet::default();
+            seen.insert(span);
+            err.span_label(span, "recursive opaque type");
+            label = true;
+            for (sp, ty) in visitor
+                .returns
+                .iter()
+                .filter_map(|e| tables.node_type_opt(e.hir_id).map(|t| (e.span, t)))
+                .filter(|(_, ty)| !matches!(ty.kind, ty::Never))
+            {
+                struct VisitTypes(Vec<DefId>);
+                impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
+                    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+                        match t.kind {
+                            ty::Opaque(def, _) => {
+                                self.0.push(def);
+                                false
+                            }
+                            _ => t.super_visit_with(self),
+                        }
+                    }
+                }
+                let mut visitor = VisitTypes(vec![]);
+                ty.visit_with(&mut visitor);
+                for def_id in visitor.0 {
+                    let ty_span = tcx.def_span(def_id);
+                    if !seen.contains(&ty_span) {
+                        err.span_label(ty_span, &format!("returning this opaque type `{}`", ty));
+                        seen.insert(ty_span);
+                    }
+                    err.span_label(sp, &format!("returning here with type `{}`", ty));
+                }
+            }
+        }
+    }
+    if !label {
+        err.span_label(span, "cannot resolve opaque type");
+    }
+    err.emit();
+}
+
+/// Emit an error for recursive opaque types in a `let` binding.
+fn binding_opaque_type_cycle_error(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    span: Span,
+    partially_expanded_type: Ty<'tcx>,
+) {
+    let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
+    err.span_label(span, "cannot resolve opaque type");
+    // Find the the owner that declared this `impl Trait` type.
+    let hir_id = tcx.hir().as_local_hir_id(def_id);
+    let mut prev_hir_id = hir_id;
+    let mut hir_id = tcx.hir().get_parent_node(hir_id);
+    while let Some(node) = tcx.hir().find(hir_id) {
+        match node {
+            hir::Node::Local(hir::Local {
+                pat,
+                init: None,
+                ty: Some(ty),
+                source: hir::LocalSource::Normal,
+                ..
+            }) => {
+                err.span_label(pat.span, "this binding might not have a concrete type");
+                err.span_suggestion_verbose(
+                    ty.span.shrink_to_hi(),
+                    "set the binding to a value for a concrete type to be resolved",
+                    " = /* value */".to_string(),
+                    Applicability::HasPlaceholders,
+                );
+            }
+            hir::Node::Local(hir::Local {
+                init: Some(expr),
+                source: hir::LocalSource::Normal,
+                ..
+            }) => {
+                let hir_id = tcx.hir().as_local_hir_id(def_id);
+                let tables =
+                    tcx.typeck_tables_of(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id)));
+                if let Some(ty) = tables.node_type_opt(expr.hir_id) {
+                    err.span_label(
+                        expr.span,
+                        &format!(
+                            "this is of type `{}`, which doesn't constrain \
+                             `{}` enough to arrive to a concrete type",
+                            ty, partially_expanded_type
+                        ),
+                    );
+                }
+            }
+            _ => {}
+        }
+        if prev_hir_id == hir_id {
+            break;
+        }
+        prev_hir_id = hir_id;
+        hir_id = tcx.hir().get_parent_node(hir_id);
+    }
+    err.emit();
+}
+
+fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
+    struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
+        .span_label(span, "recursive `async fn`")
+        .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
+        .emit();
+}
+
 /// Checks that an opaque type does not contain cycles.
 fn check_opaque_for_cycles<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -1721,21 +1888,12 @@ fn check_opaque_for_cycles<'tcx>(
 ) {
     if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
     {
-        if let hir::OpaqueTyOrigin::AsyncFn = origin {
-            struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing",)
-                .span_label(span, "recursive `async fn`")
-                .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
-                .emit();
-        } else {
-            let mut err =
-                struct_span_err!(tcx.sess, span, E0720, "opaque type expands to a recursive type",);
-            err.span_label(span, "expands to a recursive type");
-            if let ty::Opaque(..) = partially_expanded_type.kind {
-                err.note("type resolves to itself");
-            } else {
-                err.note(&format!("expanded type is `{}`", partially_expanded_type));
+        match origin {
+            hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
+            hir::OpaqueTyOrigin::Binding => {
+                binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type)
             }
-            err.emit();
+            _ => opaque_type_cycle_error(tcx, def_id, span),
         }
     }
 }
@@ -2123,7 +2281,7 @@ fn check_impl_items_against_trait<'tcx>(
                             &ty_trait_item,
                             impl_trait_ref,
                             opt_trait_span,
-                        )
+                        );
                     } else {
                         let mut err = struct_span_err!(
                             tcx.sess,
@@ -3175,6 +3333,13 @@ pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>
             return;
         }
 
+        let autoborrow_mut = adj.iter().any(|adj| {
+            matches!(adj, &Adjustment {
+                kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
+                ..
+            })
+        });
+
         match self.tables.borrow_mut().adjustments_mut().entry(expr.hir_id) {
             Entry::Vacant(entry) => {
                 entry.insert(adj);
@@ -3204,6 +3369,13 @@ pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>
                 *entry.get_mut() = adj;
             }
         }
+
+        // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
+        // In this case implicit use of `Deref` and `Index` within `<expr>` should
+        // instead be `DerefMut` and `IndexMut`, so fix those up.
+        if autoborrow_mut {
+            self.convert_place_derefs_to_mutable(expr);
+        }
     }
 
     /// Basically whenever we are converting from a type scheme into
@@ -3387,7 +3559,7 @@ fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
         match self.tables.borrow().node_types().get(id) {
             Some(&t) => t,
-            None if self.is_tainted_by_errors() => self.tcx.types.err,
+            None if self.is_tainted_by_errors() => self.tcx.ty_error(),
             None => {
                 bug!(
                     "no type for node {}: {} in fcx {}",
@@ -3501,7 +3673,7 @@ fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
 
         assert!(ty.is_ty_infer());
         let fallback = match self.type_is_unconstrained_numeric(ty) {
-            _ if self.is_tainted_by_errors() => self.tcx().types.err,
+            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
             UnconstrainedInt => self.tcx.types.i32,
             UnconstrainedFloat => self.tcx.types.f64,
             Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
@@ -3595,154 +3767,6 @@ fn make_overloaded_place_return_type(
         ret_ty.builtin_deref(true).unwrap()
     }
 
-    fn lookup_indexing(
-        &self,
-        expr: &hir::Expr<'_>,
-        base_expr: &'tcx hir::Expr<'tcx>,
-        base_ty: Ty<'tcx>,
-        idx_ty: Ty<'tcx>,
-        needs: Needs,
-    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
-        // FIXME(#18741) -- this is almost but not quite the same as the
-        // autoderef that normal method probing does. They could likely be
-        // consolidated.
-
-        let mut autoderef = self.autoderef(base_expr.span, base_ty);
-        let mut result = None;
-        while result.is_none() && autoderef.next().is_some() {
-            result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty);
-        }
-        autoderef.finalize(self);
-        result
-    }
-
-    /// To type-check `base_expr[index_expr]`, we progressively autoderef
-    /// (and otherwise adjust) `base_expr`, looking for a type which either
-    /// supports builtin indexing or overloaded indexing.
-    /// This loop implements one step in that search; the autoderef loop
-    /// is implemented by `lookup_indexing`.
-    fn try_index_step(
-        &self,
-        expr: &hir::Expr<'_>,
-        base_expr: &hir::Expr<'_>,
-        autoderef: &Autoderef<'a, 'tcx>,
-        needs: Needs,
-        index_ty: Ty<'tcx>,
-    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
-        let adjusted_ty = autoderef.unambiguous_final_ty(self);
-        debug!(
-            "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
-             index_ty={:?})",
-            expr, base_expr, adjusted_ty, index_ty
-        );
-
-        for &unsize in &[false, true] {
-            let mut self_ty = adjusted_ty;
-            if unsize {
-                // We only unsize arrays here.
-                if let ty::Array(element_ty, _) = adjusted_ty.kind {
-                    self_ty = self.tcx.mk_slice(element_ty);
-                } else {
-                    continue;
-                }
-            }
-
-            // If some lookup succeeds, write callee into table and extract index/element
-            // type from the method signature.
-            // If some lookup succeeded, install method in table
-            let input_ty = self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::AutoDeref,
-                span: base_expr.span,
-            });
-            let method = self.try_overloaded_place_op(
-                expr.span,
-                self_ty,
-                &[input_ty],
-                needs,
-                PlaceOp::Index,
-            );
-
-            let result = method.map(|ok| {
-                debug!("try_index_step: success, using overloaded indexing");
-                let method = self.register_infer_ok_obligations(ok);
-
-                let mut adjustments = autoderef.adjust_steps(self, needs);
-                if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].kind {
-                    let mutbl = match r_mutbl {
-                        hir::Mutability::Not => AutoBorrowMutability::Not,
-                        hir::Mutability::Mut => AutoBorrowMutability::Mut {
-                            // Indexing can be desugared to a method call,
-                            // so maybe we could use two-phase here.
-                            // See the documentation of AllowTwoPhase for why that's
-                            // not the case today.
-                            allow_two_phase_borrow: AllowTwoPhase::No,
-                        },
-                    };
-                    adjustments.push(Adjustment {
-                        kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
-                        target: self
-                            .tcx
-                            .mk_ref(region, ty::TypeAndMut { mutbl: r_mutbl, ty: adjusted_ty }),
-                    });
-                }
-                if unsize {
-                    adjustments.push(Adjustment {
-                        kind: Adjust::Pointer(PointerCast::Unsize),
-                        target: method.sig.inputs()[0],
-                    });
-                }
-                self.apply_adjustments(base_expr, adjustments);
-
-                self.write_method_call(expr.hir_id, method);
-                (input_ty, self.make_overloaded_place_return_type(method).ty)
-            });
-            if result.is_some() {
-                return result;
-            }
-        }
-
-        None
-    }
-
-    fn resolve_place_op(&self, op: PlaceOp, is_mut: bool) -> (Option<DefId>, Ident) {
-        let (tr, name) = match (op, is_mut) {
-            (PlaceOp::Deref, false) => (self.tcx.lang_items().deref_trait(), sym::deref),
-            (PlaceOp::Deref, true) => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
-            (PlaceOp::Index, false) => (self.tcx.lang_items().index_trait(), sym::index),
-            (PlaceOp::Index, true) => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
-        };
-        (tr, Ident::with_dummy_span(name))
-    }
-
-    fn try_overloaded_place_op(
-        &self,
-        span: Span,
-        base_ty: Ty<'tcx>,
-        arg_tys: &[Ty<'tcx>],
-        needs: Needs,
-        op: PlaceOp,
-    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        debug!("try_overloaded_place_op({:?},{:?},{:?},{:?})", span, base_ty, needs, op);
-
-        // Try Mut first, if needed.
-        let (mut_tr, mut_op) = self.resolve_place_op(op, true);
-        let method = match (needs, mut_tr) {
-            (Needs::MutPlace, Some(trait_did)) => {
-                self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys))
-            }
-            _ => None,
-        };
-
-        // Otherwise, fall back to the immutable version.
-        let (imm_tr, imm_op) = self.resolve_place_op(op, false);
-        match (method, imm_tr) {
-            (None, Some(trait_did)) => {
-                self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys))
-            }
-            (method, _) => method,
-        }
-    }
-
     fn check_method_argument_types(
         &self,
         sp: Span,
@@ -3774,7 +3798,7 @@ fn check_method_argument_types(
                 tuple_arguments,
                 None,
             );
-            return self.tcx.types.err;
+            return self.tcx.ty_error();
         }
 
         let method = method.unwrap();
@@ -4161,7 +4185,7 @@ fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
     }
 
     fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-        vec![self.tcx.types.err; len]
+        vec![self.tcx.ty_error(); len]
     }
 
     /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
@@ -4305,7 +4329,7 @@ fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_float_var())
             }
             ast::LitKind::Bool(_) => tcx.types.bool,
-            ast::LitKind::Err(_) => tcx.types.err,
+            ast::LitKind::Err(_) => tcx.ty_error(),
         }
     }
 
@@ -4442,7 +4466,7 @@ fn finish_resolving_struct_path(
                 };
                 let result =
                     AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
-                let ty = result.map(|(ty, _, _)| ty).unwrap_or(self.tcx().types.err);
+                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
 
                 // Write back the new resolution.
@@ -4570,7 +4594,7 @@ fn overwrite_local_ty_if_err(
         ty: Ty<'tcx>,
     ) {
         if ty.references_error() {
-            // Override the types everywhere with `types.err` to avoid knock on errors.
+            // Override the types everywhere with `err()` to avoid knock on errors.
             self.write_ty(local.hir_id, ty);
             self.write_ty(local.pat.hir_id, ty);
             let local_ty = LocalTy { decl_ty, revealed_ty: ty };
@@ -4790,7 +4814,7 @@ fn check_block_with_expected(
         let mut ty = ctxt.coerce.unwrap().complete(self);
 
         if self.has_errors.get() || ty.references_error() {
-            ty = self.tcx.types.err
+            ty = self.tcx.ty_error()
         }
 
         self.write_ty(blk.hir_id, ty);
@@ -5338,6 +5362,43 @@ fn suggest_missing_await(
         }
     }
 
+    fn note_need_for_fn_pointer(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        let (sig, did, substs) = match (&expected.kind, &found.kind) {
+            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                if sig1 != sig2 {
+                    return;
+                }
+                err.note(
+                    "different `fn` items always have unique types, even if their signatures are \
+                     the same",
+                );
+                (sig1, *did1, substs1)
+            }
+            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
+                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+                if sig1 != *sig2 {
+                    return;
+                }
+                (sig1, *did, substs)
+            }
+            _ => return,
+        };
+        err.help(&format!("change the expected type to be function pointer `{}`", sig));
+        err.help(&format!(
+            "if the expected type is due to type inference, cast the expected `fn` to a function \
+             pointer: `{} as {}`",
+            self.tcx.def_path_str_with_substs(did, substs),
+            sig
+        ));
+    }
+
     /// A common error is to add an extra semicolon:
     ///
     /// ```
@@ -5378,7 +5439,7 @@ fn could_remove_semicolon(
             _ => return None,
         };
         let last_expr_ty = self.node_ty(last_expr.hir_id);
-        if matches!(last_expr_ty.kind, ty::Error)
+        if matches!(last_expr_ty.kind, ty::Error(_))
             || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
         {
             return None;
@@ -5538,7 +5599,7 @@ pub fn instantiate_value_path(
                     }
                     err.emit();
 
-                    return (tcx.types.err, res);
+                    return (tcx.ty_error(), res);
                 }
             }
         } else {
@@ -5731,8 +5792,9 @@ pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
                     .note("type must be known at this point")
                     .emit();
             }
-            self.demand_suptype(sp, self.tcx.types.err, ty);
-            self.tcx.types.err
+            let err = self.tcx.ty_error();
+            self.demand_suptype(sp, err, ty);
+            err
         }
     }
 
index a3a27dc138be96f11605c2b3d898905673bc3160..94a5685a992feaeec414e9f43c4cf34a57bff810 100644 (file)
@@ -1,15 +1,18 @@
 //! Code related to processing overloaded binary and unary operators.
 
 use super::method::MethodCallee;
-use super::{FnCtxt, Needs};
+use super::FnCtxt;
 use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
+use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -165,7 +168,7 @@ fn check_overloaded_binop(
                 // trait matching creating lifetime constraints that are too strict.
                 // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
                 // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
-                let lhs_ty = self.check_expr_with_needs(lhs_expr, Needs::None);
+                let lhs_ty = self.check_expr(lhs_expr);
                 let fresh_var = self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: lhs_expr.span,
@@ -177,7 +180,7 @@ fn check_overloaded_binop(
                 // equivalence on the LHS of an assign-op like `+=`;
                 // overwritten or mutably-borrowed places cannot be
                 // coerced to a supertype.
-                self.check_expr_with_needs(lhs_expr, Needs::MutPlace)
+                self.check_expr(lhs_expr)
             }
         };
         let lhs_ty = self.resolve_vars_with_obligations(lhs_ty);
@@ -249,255 +252,230 @@ fn check_overloaded_binop(
 
                 method.sig.output()
             }
+            // error types are considered "builtin"
+            Err(()) if lhs_ty.references_error() || rhs_ty.references_error() => {
+                self.tcx.ty_error()
+            }
             Err(()) => {
-                // error types are considered "builtin"
-                if !lhs_ty.references_error() && !rhs_ty.references_error() {
-                    let source_map = self.tcx.sess.source_map();
-
-                    match is_assign {
-                        IsAssign::Yes => {
-                            let mut err = struct_span_err!(
-                                self.tcx.sess,
-                                expr.span,
-                                E0368,
-                                "binary assignment operation `{}=` cannot be applied to type `{}`",
-                                op.node.as_str(),
+                let source_map = self.tcx.sess.source_map();
+                let (mut err, missing_trait, use_output, involves_fn) = match is_assign {
+                    IsAssign::Yes => {
+                        let mut err = struct_span_err!(
+                            self.tcx.sess,
+                            expr.span,
+                            E0368,
+                            "binary assignment operation `{}=` cannot be applied to type `{}`",
+                            op.node.as_str(),
+                            lhs_ty,
+                        );
+                        err.span_label(
+                            lhs_expr.span,
+                            format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty),
+                        );
+                        let missing_trait = match op.node {
+                            hir::BinOpKind::Add => Some("std::ops::AddAssign"),
+                            hir::BinOpKind::Sub => Some("std::ops::SubAssign"),
+                            hir::BinOpKind::Mul => Some("std::ops::MulAssign"),
+                            hir::BinOpKind::Div => Some("std::ops::DivAssign"),
+                            hir::BinOpKind::Rem => Some("std::ops::RemAssign"),
+                            hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"),
+                            hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"),
+                            hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"),
+                            hir::BinOpKind::Shl => Some("std::ops::ShlAssign"),
+                            hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
+                            _ => None,
+                        };
+                        (err, missing_trait, false, false)
+                    }
+                    IsAssign::No => {
+                        let (message, missing_trait, use_output) = match op.node {
+                            hir::BinOpKind::Add => (
+                                format!("cannot add `{}` to `{}`", rhs_ty, lhs_ty),
+                                Some("std::ops::Add"),
+                                true,
+                            ),
+                            hir::BinOpKind::Sub => (
+                                format!("cannot subtract `{}` from `{}`", rhs_ty, lhs_ty),
+                                Some("std::ops::Sub"),
+                                true,
+                            ),
+                            hir::BinOpKind::Mul => (
+                                format!("cannot multiply `{}` to `{}`", rhs_ty, lhs_ty),
+                                Some("std::ops::Mul"),
+                                true,
+                            ),
+                            hir::BinOpKind::Div => (
+                                format!("cannot divide `{}` by `{}`", lhs_ty, rhs_ty),
+                                Some("std::ops::Div"),
+                                true,
+                            ),
+                            hir::BinOpKind::Rem => (
+                                format!("cannot mod `{}` by `{}`", lhs_ty, rhs_ty),
+                                Some("std::ops::Rem"),
+                                true,
+                            ),
+                            hir::BinOpKind::BitAnd => (
+                                format!("no implementation for `{} & {}`", lhs_ty, rhs_ty),
+                                Some("std::ops::BitAnd"),
+                                true,
+                            ),
+                            hir::BinOpKind::BitXor => (
+                                format!("no implementation for `{} ^ {}`", lhs_ty, rhs_ty),
+                                Some("std::ops::BitXor"),
+                                true,
+                            ),
+                            hir::BinOpKind::BitOr => (
+                                format!("no implementation for `{} | {}`", lhs_ty, rhs_ty),
+                                Some("std::ops::BitOr"),
+                                true,
+                            ),
+                            hir::BinOpKind::Shl => (
+                                format!("no implementation for `{} << {}`", lhs_ty, rhs_ty),
+                                Some("std::ops::Shl"),
+                                true,
+                            ),
+                            hir::BinOpKind::Shr => (
+                                format!("no implementation for `{} >> {}`", lhs_ty, rhs_ty),
+                                Some("std::ops::Shr"),
+                                true,
+                            ),
+                            hir::BinOpKind::Eq | hir::BinOpKind::Ne => (
+                                format!(
+                                    "binary operation `{}` cannot be applied to type `{}`",
+                                    op.node.as_str(),
+                                    lhs_ty
+                                ),
+                                Some("std::cmp::PartialEq"),
+                                false,
+                            ),
+                            hir::BinOpKind::Lt
+                            | hir::BinOpKind::Le
+                            | hir::BinOpKind::Gt
+                            | hir::BinOpKind::Ge => (
+                                format!(
+                                    "binary operation `{}` cannot be applied to type `{}`",
+                                    op.node.as_str(),
+                                    lhs_ty
+                                ),
+                                Some("std::cmp::PartialOrd"),
+                                false,
+                            ),
+                            _ => (
+                                format!(
+                                    "binary operation `{}` cannot be applied to type `{}`",
+                                    op.node.as_str(),
+                                    lhs_ty
+                                ),
+                                None,
+                                false,
+                            ),
+                        };
+                        let mut err =
+                            struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str());
+                        let mut involves_fn = false;
+                        if !lhs_expr.span.eq(&rhs_expr.span) {
+                            involves_fn |= self.add_type_neq_err_label(
+                                &mut err,
+                                lhs_expr.span,
                                 lhs_ty,
+                                rhs_ty,
+                                op,
+                                is_assign,
                             );
-                            err.span_label(
-                                lhs_expr.span,
-                                format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty),
+                            involves_fn |= self.add_type_neq_err_label(
+                                &mut err,
+                                rhs_expr.span,
+                                rhs_ty,
+                                lhs_ty,
+                                op,
+                                is_assign,
                             );
-                            let mut suggested_deref = false;
-                            if let Ref(_, rty, _) = lhs_ty.kind {
-                                if {
-                                    self.infcx.type_is_copy_modulo_regions(
-                                        self.param_env,
-                                        rty,
-                                        lhs_expr.span,
-                                    ) && self
-                                        .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
-                                        .is_ok()
-                                } {
-                                    if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
-                                        let msg = &format!(
-                                            "`{}=` can be used on '{}', you can dereference `{}`",
-                                            op.node.as_str(),
-                                            rty.peel_refs(),
-                                            lstring,
-                                        );
-                                        err.span_suggestion(
-                                            lhs_expr.span,
-                                            msg,
-                                            format!("*{}", lstring),
-                                            rustc_errors::Applicability::MachineApplicable,
-                                        );
-                                        suggested_deref = true;
-                                    }
-                                }
-                            }
-                            let missing_trait = match op.node {
-                                hir::BinOpKind::Add => Some("std::ops::AddAssign"),
-                                hir::BinOpKind::Sub => Some("std::ops::SubAssign"),
-                                hir::BinOpKind::Mul => Some("std::ops::MulAssign"),
-                                hir::BinOpKind::Div => Some("std::ops::DivAssign"),
-                                hir::BinOpKind::Rem => Some("std::ops::RemAssign"),
-                                hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"),
-                                hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"),
-                                hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"),
-                                hir::BinOpKind::Shl => Some("std::ops::ShlAssign"),
-                                hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
-                                _ => None,
-                            };
-                            if let Some(missing_trait) = missing_trait {
-                                if op.node == hir::BinOpKind::Add
-                                    && self.check_str_addition(
-                                        lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, true, op,
-                                    )
-                                {
-                                    // This has nothing here because it means we did string
-                                    // concatenation (e.g., "Hello " += "World!"). This means
-                                    // we don't want the note in the else clause to be emitted
-                                } else if let ty::Param(p) = lhs_ty.kind {
-                                    suggest_constraining_param(
-                                        self.tcx,
-                                        self.body_id,
-                                        &mut err,
-                                        lhs_ty,
-                                        rhs_ty,
-                                        missing_trait,
-                                        p,
-                                        false,
-                                    );
-                                } else if !suggested_deref {
-                                    suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
-                                }
-                            }
-                            err.emit();
                         }
-                        IsAssign::No => {
-                            let (message, missing_trait, use_output) = match op.node {
-                                hir::BinOpKind::Add => (
-                                    format!("cannot add `{}` to `{}`", rhs_ty, lhs_ty),
-                                    Some("std::ops::Add"),
-                                    true,
-                                ),
-                                hir::BinOpKind::Sub => (
-                                    format!("cannot subtract `{}` from `{}`", rhs_ty, lhs_ty),
-                                    Some("std::ops::Sub"),
-                                    true,
-                                ),
-                                hir::BinOpKind::Mul => (
-                                    format!("cannot multiply `{}` to `{}`", rhs_ty, lhs_ty),
-                                    Some("std::ops::Mul"),
-                                    true,
-                                ),
-                                hir::BinOpKind::Div => (
-                                    format!("cannot divide `{}` by `{}`", lhs_ty, rhs_ty),
-                                    Some("std::ops::Div"),
-                                    true,
-                                ),
-                                hir::BinOpKind::Rem => (
-                                    format!("cannot mod `{}` by `{}`", lhs_ty, rhs_ty),
-                                    Some("std::ops::Rem"),
-                                    true,
-                                ),
-                                hir::BinOpKind::BitAnd => (
-                                    format!("no implementation for `{} & {}`", lhs_ty, rhs_ty),
-                                    Some("std::ops::BitAnd"),
-                                    true,
-                                ),
-                                hir::BinOpKind::BitXor => (
-                                    format!("no implementation for `{} ^ {}`", lhs_ty, rhs_ty),
-                                    Some("std::ops::BitXor"),
-                                    true,
-                                ),
-                                hir::BinOpKind::BitOr => (
-                                    format!("no implementation for `{} | {}`", lhs_ty, rhs_ty),
-                                    Some("std::ops::BitOr"),
-                                    true,
-                                ),
-                                hir::BinOpKind::Shl => (
-                                    format!("no implementation for `{} << {}`", lhs_ty, rhs_ty),
-                                    Some("std::ops::Shl"),
-                                    true,
-                                ),
-                                hir::BinOpKind::Shr => (
-                                    format!("no implementation for `{} >> {}`", lhs_ty, rhs_ty),
-                                    Some("std::ops::Shr"),
-                                    true,
-                                ),
-                                hir::BinOpKind::Eq | hir::BinOpKind::Ne => (
-                                    format!(
-                                        "binary operation `{}` cannot be applied to type `{}`",
-                                        op.node.as_str(),
-                                        lhs_ty
-                                    ),
-                                    Some("std::cmp::PartialEq"),
-                                    false,
-                                ),
-                                hir::BinOpKind::Lt
-                                | hir::BinOpKind::Le
-                                | hir::BinOpKind::Gt
-                                | hir::BinOpKind::Ge => (
-                                    format!(
-                                        "binary operation `{}` cannot be applied to type `{}`",
-                                        op.node.as_str(),
-                                        lhs_ty
-                                    ),
-                                    Some("std::cmp::PartialOrd"),
-                                    false,
-                                ),
-                                _ => (
-                                    format!(
-                                        "binary operation `{}` cannot be applied to type `{}`",
-                                        op.node.as_str(),
-                                        lhs_ty
-                                    ),
-                                    None,
-                                    false,
-                                ),
-                            };
-                            let mut err = struct_span_err!(
-                                self.tcx.sess,
-                                op.span,
-                                E0369,
-                                "{}",
-                                message.as_str()
+                        (err, missing_trait, use_output, involves_fn)
+                    }
+                };
+                let mut suggested_deref = false;
+                if let Ref(_, rty, _) = lhs_ty.kind {
+                    if {
+                        self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
+                            && self
+                                .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
+                                .is_ok()
+                    } {
+                        if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
+                            let msg = &format!(
+                                "`{}{}` can be used on `{}`, you can dereference `{}`",
+                                op.node.as_str(),
+                                match is_assign {
+                                    IsAssign::Yes => "=",
+                                    IsAssign::No => "",
+                                },
+                                rty.peel_refs(),
+                                lstring,
                             );
-
-                            let mut involves_fn = false;
-                            if !lhs_expr.span.eq(&rhs_expr.span) {
-                                involves_fn |= self.add_type_neq_err_label(
-                                    &mut err,
-                                    lhs_expr.span,
-                                    lhs_ty,
-                                    rhs_ty,
-                                    op,
-                                    is_assign,
-                                );
-                                involves_fn |= self.add_type_neq_err_label(
+                            err.span_suggestion_verbose(
+                                lhs_expr.span.shrink_to_lo(),
+                                msg,
+                                "*".to_string(),
+                                rustc_errors::Applicability::MachineApplicable,
+                            );
+                            suggested_deref = true;
+                        }
+                    }
+                }
+                if let Some(missing_trait) = missing_trait {
+                    let mut visitor = TypeParamVisitor(vec![]);
+                    visitor.visit_ty(lhs_ty);
+
+                    if op.node == hir::BinOpKind::Add
+                        && self.check_str_addition(
+                            lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, is_assign, op,
+                        )
+                    {
+                        // This has nothing here because it means we did string
+                        // concatenation (e.g., "Hello " + "World!"). This means
+                        // we don't want the note in the else clause to be emitted
+                    } else if let [ty] = &visitor.0[..] {
+                        if let ty::Param(p) = ty.kind {
+                            // Check if the method would be found if the type param wasn't
+                            // involved. If so, it means that adding a trait bound to the param is
+                            // enough. Otherwise we do not give the suggestion.
+                            let mut eraser = TypeParamEraser(&self, expr.span);
+                            let needs_bound = self
+                                .lookup_op_method(
+                                    eraser.fold_ty(lhs_ty),
+                                    &[eraser.fold_ty(rhs_ty)],
+                                    Op::Binary(op, is_assign),
+                                )
+                                .is_ok();
+                            if needs_bound {
+                                suggest_constraining_param(
+                                    self.tcx,
+                                    self.body_id,
                                     &mut err,
-                                    rhs_expr.span,
+                                    ty,
                                     rhs_ty,
-                                    lhs_ty,
-                                    op,
-                                    is_assign,
+                                    missing_trait,
+                                    p,
+                                    use_output,
                                 );
+                            } else if *ty != lhs_ty {
+                                // When we know that a missing bound is responsible, we don't show
+                                // this note as it is redundant.
+                                err.note(&format!(
+                                    "the trait `{}` is not implemented for `{}`",
+                                    missing_trait, lhs_ty
+                                ));
                             }
-
-                            let mut suggested_deref = false;
-                            if let Ref(_, rty, _) = lhs_ty.kind {
-                                if {
-                                    self.infcx.type_is_copy_modulo_regions(
-                                        self.param_env,
-                                        rty,
-                                        lhs_expr.span,
-                                    ) && self
-                                        .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
-                                        .is_ok()
-                                } {
-                                    if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
-                                        err.help(&format!(
-                                            "`{}` can be used on '{}', you can \
-                                            dereference `{2}`: `*{2}`",
-                                            op.node.as_str(),
-                                            rty.peel_refs(),
-                                            lstring
-                                        ));
-                                        suggested_deref = true;
-                                    }
-                                }
-                            }
-                            if let Some(missing_trait) = missing_trait {
-                                if op.node == hir::BinOpKind::Add
-                                    && self.check_str_addition(
-                                        lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, false, op,
-                                    )
-                                {
-                                    // This has nothing here because it means we did string
-                                    // concatenation (e.g., "Hello " + "World!"). This means
-                                    // we don't want the note in the else clause to be emitted
-                                } else if let ty::Param(p) = lhs_ty.kind {
-                                    suggest_constraining_param(
-                                        self.tcx,
-                                        self.body_id,
-                                        &mut err,
-                                        lhs_ty,
-                                        rhs_ty,
-                                        missing_trait,
-                                        p,
-                                        use_output,
-                                    );
-                                } else if !suggested_deref && !involves_fn {
-                                    suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
-                                }
-                            }
-                            err.emit();
+                        } else {
+                            bug!("type param visitor stored a non type param: {:?}", ty.kind);
                         }
+                    } else if !suggested_deref && !involves_fn {
+                        suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
                     }
                 }
-                self.tcx.types.err
+                err.emit();
+                self.tcx.ty_error()
             }
         };
 
@@ -570,7 +548,7 @@ fn check_str_addition(
         lhs_ty: Ty<'tcx>,
         rhs_ty: Ty<'tcx>,
         err: &mut rustc_errors::DiagnosticBuilder<'_>,
-        is_assign: bool,
+        is_assign: IsAssign,
         op: hir::BinOp,
     ) -> bool {
         let source_map = self.tcx.sess.source_map();
@@ -593,7 +571,7 @@ fn check_str_addition(
                         &format!("{:?}", rhs_ty) == "&&str"
                     ) =>
             {
-                if !is_assign { // Do not supply this message if `&str += &str`
+                if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str`
                     err.span_label(
                         op.span,
                         "`+` cannot be used to concatenate two `&str` strings",
@@ -634,7 +612,7 @@ fn check_str_addition(
                     source_map.span_to_snippet(rhs_expr.span),
                     is_assign,
                 ) {
-                    (Ok(l), Ok(r), false) => {
+                    (Ok(l), Ok(r), IsAssign::No) => {
                         let to_string = if l.starts_with('&') {
                             // let a = String::new(); let b = String::new();
                             // let _ = &a + b;
@@ -686,11 +664,7 @@ pub fn check_user_unop(
                     );
                     err.span_label(
                         ex.span,
-                        format!(
-                            "cannot apply unary \
-                                                    operator `{}`",
-                            op.as_str()
-                        ),
+                        format!("cannot apply unary operator `{}`", op.as_str()),
                     );
                     match actual.kind {
                         Uint(_) if op == hir::UnOp::UnNeg => {
@@ -709,7 +683,7 @@ pub fn check_user_unop(
                     }
                     err.emit();
                 }
-                self.tcx.types.err
+                self.tcx.ty_error()
             }
         }
     }
@@ -928,8 +902,7 @@ fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_tra
     if let Adt(def, _) = ty.peel_refs().kind {
         if def.did.is_local() {
             err.note(&format!(
-                "an implementation of `{}` might \
-                be missing for `{}`",
+                "an implementation of `{}` might be missing for `{}`",
                 missing_trait, ty
             ));
         }
@@ -975,3 +948,32 @@ fn suggest_constraining_param(
         err.span_label(span, msg);
     }
 }
+
+struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
+
+impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+        if let ty::Param(_) = ty.kind {
+            self.0.push(ty);
+        }
+        ty.super_visit_with(self)
+    }
+}
+
+struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
+
+impl TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.0.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        match ty.kind {
+            ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::MiscVariable,
+                span: self.1,
+            }),
+            _ => ty.super_fold_with(self),
+        }
+    }
+}
index 8a10427260eee23ff71213ced558a099747476d8..ea47ae68ce7d36c63220b15c2140602a7765cc14 100644 (file)
@@ -212,7 +212,7 @@ fn check_pat(
         // errors in some cases, such as this one:
         //
         // ```
-        // fn foo<'x>(x: &'x int) {
+        // fn foo<'x>(x: &'x i32) {
         //    let a = 1;
         //    let mut z = x;
         //    z = &a;
@@ -220,7 +220,7 @@ fn check_pat(
         // ```
         //
         // The reason we might get an error is that `z` might be
-        // assigned a type like `&'x int`, and then we would have
+        // assigned a type like `&'x i32`, and then we would have
         // a problem when we try to assign `&a` to `z`, because
         // the lifetime of `&a` (i.e., the enclosing block) is
         // shorter than `'x`.
@@ -229,11 +229,11 @@ fn check_pat(
         // expected type here is whatever type the user wrote, not
         // the initializer's type. In this case the user wrote
         // nothing, so we are going to create a type variable `Z`.
-        // Then we will assign the type of the initializer (`&'x
-        // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
-        // will instantiate `Z` as a type `&'0 int` where `'0` is
-        // a fresh region variable, with the constraint that `'x :
-        // '0`.  So basically we're all set.
+        // Then we will assign the type of the initializer (`&'x i32`)
+        // as a subtype of `Z`: `&'x i32 <: Z`. And hence we
+        // will instantiate `Z` as a type `&'0 i32` where `'0` is
+        // a fresh region variable, with the constraint that `'x : '0`.
+        // So basically we're all set.
         //
         // Note that there are two tests to check that this remains true
         // (`regions-reassign-{match,let}-bound-pointer.rs`).
@@ -442,7 +442,7 @@ fn check_pat_range(
             // 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;
+            return self.tcx.ty_error();
         }
 
         // Now that we know the types can be unified we find the unified type
@@ -673,11 +673,12 @@ fn check_pat_struct(
         {
             variant_ty
         } else {
+            let err = self.tcx.ty_error();
             for field in fields {
                 let ti = TopInfo { parent_pat: Some(&pat), ..ti };
-                self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti);
+                self.check_pat(&field.pat, err, def_bm, ti);
             }
-            return self.tcx.types.err;
+            return err;
         };
 
         // Type-check the path.
@@ -687,7 +688,7 @@ fn check_pat_struct(
         if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) {
             pat_ty
         } else {
-            self.tcx.types.err
+            self.tcx.ty_error()
         }
     }
 
@@ -705,11 +706,11 @@ fn check_pat_path(
         match res {
             Res::Err => {
                 self.set_tainted_by_errors();
-                return tcx.types.err;
+                return tcx.ty_error();
             }
             Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => {
                 report_unexpected_variant_res(tcx, res, pat.span);
-                return tcx.types.err;
+                return tcx.ty_error();
             }
             Res::SelfCtor(..)
             | Res::Def(
@@ -788,7 +789,7 @@ fn check_pat_tuple_struct(
         let on_error = || {
             let parent_pat = Some(pat);
             for pat in subpats {
-                self.check_pat(&pat, tcx.types.err, def_bm, TopInfo { parent_pat, ..ti });
+                self.check_pat(&pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti });
             }
         };
         let report_unexpected_res = |res: Res| {
@@ -824,7 +825,7 @@ fn check_pat_tuple_struct(
         if res == Res::Err {
             self.set_tainted_by_errors();
             on_error();
-            return self.tcx.types.err;
+            return self.tcx.ty_error();
         }
 
         // Type-check the path.
@@ -832,18 +833,18 @@ fn check_pat_tuple_struct(
             self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id);
         if !pat_ty.is_fn() {
             report_unexpected_res(res);
-            return tcx.types.err;
+            return tcx.ty_error();
         }
 
         let variant = match res {
             Res::Err => {
                 self.set_tainted_by_errors();
                 on_error();
-                return tcx.types.err;
+                return tcx.ty_error();
             }
             Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
                 report_unexpected_res(res);
-                return tcx.types.err;
+                return tcx.ty_error();
             }
             Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
             _ => bug!("unexpected pattern resolution: {:?}", res),
@@ -880,7 +881,7 @@ fn check_pat_tuple_struct(
             // Pattern has wrong number of fields.
             self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
             on_error();
-            return tcx.types.err;
+            return tcx.ty_error();
         }
         pat_ty
     }
@@ -1001,9 +1002,9 @@ fn check_pat_tuple(
             err.emit();
             // Walk subpatterns with an expected type of `err` in this case to silence
             // further errors being emitted when using the bindings. #50333
-            let element_tys_iter = (0..max_len).map(|_| tcx.types.err);
+            let element_tys_iter = (0..max_len).map(|_| tcx.ty_error());
             for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                self.check_pat(elem, &tcx.types.err, def_bm, ti);
+                self.check_pat(elem, &tcx.ty_error(), def_bm, ti);
             }
             tcx.mk_tup(element_tys_iter)
         } else {
@@ -1052,7 +1053,7 @@ fn check_struct_pat_fields(
                 Occupied(occupied) => {
                     self.error_field_already_bound(span, field.ident, *occupied.get());
                     no_field_errors = false;
-                    tcx.types.err
+                    tcx.ty_error()
                 }
                 Vacant(vacant) => {
                     vacant.insert(span);
@@ -1066,7 +1067,7 @@ fn check_struct_pat_fields(
                         .unwrap_or_else(|| {
                             inexistent_fields.push(field.ident);
                             no_field_errors = false;
-                            tcx.types.err
+                            tcx.ty_error()
                         })
                 }
             };
@@ -1281,7 +1282,8 @@ fn check_pat_box(
             self.demand_eqtype_pat(span, expected, box_ty, ti);
             (box_ty, inner_ty)
         } else {
-            (tcx.types.err, tcx.types.err)
+            let err = tcx.ty_error();
+            (err, err)
         };
         self.check_pat(&inner, inner_ty, def_bm, ti);
         box_ty
@@ -1327,7 +1329,8 @@ fn check_pat_ref(
                 }
             }
         } else {
-            (tcx.types.err, tcx.types.err)
+            let err = tcx.ty_error();
+            (err, err)
         };
         self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
         rptr_ty
@@ -1378,7 +1381,7 @@ fn check_pat_slice(
                 if !expected.references_error() {
                     self.error_expected_array_or_slice(span, expected);
                 }
-                let err = self.tcx.types.err;
+                let err = self.tcx.ty_error();
                 (err, Some(err), err)
             }
         };
@@ -1445,7 +1448,7 @@ fn check_array_pat_len(
         }
 
         // If we get here, we must have emitted an error.
-        (Some(self.tcx.types.err), arr_ty)
+        (Some(self.tcx.ty_error()), arr_ty)
     }
 
     fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) {
diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs
new file mode 100644 (file)
index 0000000..b7c8f31
--- /dev/null
@@ -0,0 +1,337 @@
+use crate::check::method::MethodCallee;
+use crate::check::{FnCtxt, PlaceOp};
+use rustc_hir as hir;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::InferOk;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
+use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::Span;
+use rustc_trait_selection::autoderef::Autoderef;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
+    pub(super) fn lookup_derefing(
+        &self,
+        expr: &hir::Expr<'_>,
+        oprnd_expr: &'tcx hir::Expr<'tcx>,
+        oprnd_ty: Ty<'tcx>,
+    ) -> Option<Ty<'tcx>> {
+        if let Some(mt) = oprnd_ty.builtin_deref(true) {
+            return Some(mt.ty);
+        }
+
+        let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?;
+        let method = self.register_infer_ok_obligations(ok);
+        if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind {
+            self.apply_adjustments(
+                oprnd_expr,
+                vec![Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+                    target: method.sig.inputs()[0],
+                }],
+            );
+        } else {
+            span_bug!(expr.span, "input to deref is not a ref?");
+        }
+        let ty = self.make_overloaded_place_return_type(method).ty;
+        self.write_method_call(expr.hir_id, method);
+        Some(ty)
+    }
+
+    /// Type-check `*base_expr[index_expr]` with `base_expr` and `index_expr` type-checked already.
+    pub(super) fn lookup_indexing(
+        &self,
+        expr: &hir::Expr<'_>,
+        base_expr: &'tcx hir::Expr<'tcx>,
+        base_ty: Ty<'tcx>,
+        idx_ty: Ty<'tcx>,
+    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
+        // FIXME(#18741) -- this is almost but not quite the same as the
+        // autoderef that normal method probing does. They could likely be
+        // consolidated.
+
+        let mut autoderef = self.autoderef(base_expr.span, base_ty);
+        let mut result = None;
+        while result.is_none() && autoderef.next().is_some() {
+            result = self.try_index_step(expr, base_expr, &autoderef, idx_ty);
+        }
+        self.register_predicates(autoderef.into_obligations());
+        result
+    }
+
+    /// To type-check `base_expr[index_expr]`, we progressively autoderef
+    /// (and otherwise adjust) `base_expr`, looking for a type which either
+    /// supports builtin indexing or overloaded indexing.
+    /// This loop implements one step in that search; the autoderef loop
+    /// is implemented by `lookup_indexing`.
+    fn try_index_step(
+        &self,
+        expr: &hir::Expr<'_>,
+        base_expr: &hir::Expr<'_>,
+        autoderef: &Autoderef<'a, 'tcx>,
+        index_ty: Ty<'tcx>,
+    ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
+        let adjusted_ty =
+            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
+        debug!(
+            "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
+             index_ty={:?})",
+            expr, base_expr, adjusted_ty, index_ty
+        );
+
+        for &unsize in &[false, true] {
+            let mut self_ty = adjusted_ty;
+            if unsize {
+                // We only unsize arrays here.
+                if let ty::Array(element_ty, _) = adjusted_ty.kind {
+                    self_ty = self.tcx.mk_slice(element_ty);
+                } else {
+                    continue;
+                }
+            }
+
+            // If some lookup succeeds, write callee into table and extract index/element
+            // type from the method signature.
+            // If some lookup succeeded, install method in table
+            let input_ty = self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::AutoDeref,
+                span: base_expr.span,
+            });
+            let method =
+                self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index);
+
+            let result = method.map(|ok| {
+                debug!("try_index_step: success, using overloaded indexing");
+                let method = self.register_infer_ok_obligations(ok);
+
+                let mut adjustments = self.adjust_steps(autoderef);
+                if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind {
+                    adjustments.push(Adjustment {
+                        kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+                        target: self.tcx.mk_ref(
+                            region,
+                            ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
+                        ),
+                    });
+                } else {
+                    span_bug!(expr.span, "input to index is not a ref?");
+                }
+                if unsize {
+                    adjustments.push(Adjustment {
+                        kind: Adjust::Pointer(PointerCast::Unsize),
+                        target: method.sig.inputs()[0],
+                    });
+                }
+                self.apply_adjustments(base_expr, adjustments);
+
+                self.write_method_call(expr.hir_id, method);
+                (input_ty, self.make_overloaded_place_return_type(method).ty)
+            });
+            if result.is_some() {
+                return result;
+            }
+        }
+
+        None
+    }
+
+    /// Try to resolve an overloaded place op. We only deal with the immutable
+    /// variant here (Deref/Index). In some contexts we would need the mutable
+    /// variant (DerefMut/IndexMut); those would be later converted by
+    /// `convert_place_derefs_to_mutable`.
+    pub(super) fn try_overloaded_place_op(
+        &self,
+        span: Span,
+        base_ty: Ty<'tcx>,
+        arg_tys: &[Ty<'tcx>],
+        op: PlaceOp,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
+
+        let (imm_tr, imm_op) = match op {
+            PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
+            PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
+        };
+        imm_tr.and_then(|trait_did| {
+            self.lookup_method_in_trait(
+                span,
+                Ident::with_dummy_span(imm_op),
+                trait_did,
+                base_ty,
+                Some(arg_tys),
+            )
+        })
+    }
+
+    fn try_mutable_overloaded_place_op(
+        &self,
+        span: Span,
+        base_ty: Ty<'tcx>,
+        arg_tys: &[Ty<'tcx>],
+        op: PlaceOp,
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
+
+        let (mut_tr, mut_op) = match op {
+            PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
+            PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
+        };
+        mut_tr.and_then(|trait_did| {
+            self.lookup_method_in_trait(
+                span,
+                Ident::with_dummy_span(mut_op),
+                trait_did,
+                base_ty,
+                Some(arg_tys),
+            )
+        })
+    }
+
+    /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
+    /// into `DerefMut` and `IndexMut` respectively.
+    ///
+    /// This is a second pass of typechecking derefs/indices. We need this we do not
+    /// always know whether a place needs to be mutable or not in the first pass.
+    /// This happens whether there is an implicit mutable reborrow, e.g. when the type
+    /// is used as the receiver of a method call.
+    pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
+        // Gather up expressions we want to munge.
+        let mut exprs = vec![expr];
+
+        loop {
+            match exprs.last().unwrap().kind {
+                hir::ExprKind::Field(ref expr, _)
+                | hir::ExprKind::Index(ref expr, _)
+                | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
+                _ => break,
+            }
+        }
+
+        debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
+
+        // Fix up autoderefs and derefs.
+        for (i, &expr) in exprs.iter().rev().enumerate() {
+            debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
+
+            // Fix up the autoderefs. Autorefs can only occur immediately preceding
+            // overloaded place ops, and will be fixed by them in order to get
+            // the correct region.
+            let mut source = self.node_ty(expr.hir_id);
+            // Do not mutate adjustments in place, but rather take them,
+            // and replace them after mutating them, to avoid having the
+            // tables borrowed during (`deref_mut`) method resolution.
+            let previous_adjustments =
+                self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id);
+            if let Some(mut adjustments) = previous_adjustments {
+                for adjustment in &mut adjustments {
+                    if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
+                        if let Some(ok) = self.try_mutable_overloaded_place_op(
+                            expr.span,
+                            source,
+                            &[],
+                            PlaceOp::Deref,
+                        ) {
+                            let method = self.register_infer_ok_obligations(ok);
+                            if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
+                                *deref = OverloadedDeref { region, mutbl };
+                            }
+                        }
+                    }
+                    source = adjustment.target;
+                }
+                self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
+            }
+
+            match expr.kind {
+                hir::ExprKind::Index(ref base_expr, ref index_expr) => {
+                    // We need to get the final type in case dereferences were needed for the trait
+                    // to apply (#72002).
+                    let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr);
+                    self.convert_place_op_to_mutable(
+                        PlaceOp::Index,
+                        expr,
+                        base_expr,
+                        &[index_expr_ty],
+                    );
+                }
+                hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
+                    self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]);
+                }
+                _ => {}
+            }
+        }
+    }
+
+    fn convert_place_op_to_mutable(
+        &self,
+        op: PlaceOp,
+        expr: &hir::Expr<'_>,
+        base_expr: &hir::Expr<'_>,
+        arg_tys: &[Ty<'tcx>],
+    ) {
+        debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys);
+        if !self.tables.borrow().is_method_call(expr) {
+            debug!("convert_place_op_to_mutable - builtin, nothing to do");
+            return;
+        }
+
+        // Need to deref because overloaded place ops take self by-reference.
+        let base_ty = self
+            .tables
+            .borrow()
+            .expr_ty_adjusted(base_expr)
+            .builtin_deref(false)
+            .expect("place op takes something that is not a ref")
+            .ty;
+
+        let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
+        let method = match method {
+            Some(ok) => self.register_infer_ok_obligations(ok),
+            // Couldn't find the mutable variant of the place op, keep the
+            // current, immutable version.
+            None => return,
+        };
+        debug!("convert_place_op_to_mutable: method={:?}", method);
+        self.write_method_call(expr.hir_id, method);
+
+        let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind {
+            r
+        } else {
+            span_bug!(expr.span, "input to mutable place op is not a mut ref?");
+        };
+
+        // Convert the autoref in the base expr to mutable with the correct
+        // region and mutability.
+        let base_expr_ty = self.node_ty(base_expr.hir_id);
+        if let Some(adjustments) =
+            self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id)
+        {
+            let mut source = base_expr_ty;
+            for adjustment in &mut adjustments[..] {
+                if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind {
+                    debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment);
+                    let mutbl = AutoBorrowMutability::Mut {
+                        // Deref/indexing can be desugared to a method call,
+                        // so maybe we could use two-phase here.
+                        // See the documentation of AllowTwoPhase for why that's
+                        // not the case today.
+                        allow_two_phase_borrow: AllowTwoPhase::No,
+                    };
+                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
+                    adjustment.target =
+                        self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+                }
+                source = adjustment.target;
+            }
+
+            // If we have an autoref followed by unsizing at the end, fix the unsize target.
+            if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
+                adjustments[..]
+            {
+                *target = method.sig.inputs()[0];
+            }
+        }
+    }
+}
index 90ba15aa089887d70283db8b1687c17e87cee56d..d3bccaaa3e4b98e3f8977c6b1964f995140cfd5c 100644 (file)
@@ -439,7 +439,10 @@ fn with_mc<F, R>(&self, f: F) -> R
 
     /// Invoked on any adjustments that occur. Checks that if this is a region pointer being
     /// dereferenced, the lifetime of the pointer includes the deref expr.
-    fn constrain_adjustments(&mut self, expr: &hir::Expr<'_>) -> mc::McResult<mc::Place<'tcx>> {
+    fn constrain_adjustments(
+        &mut self,
+        expr: &hir::Expr<'_>,
+    ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
         debug!("constrain_adjustments(expr={:?})", expr);
 
         let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
@@ -480,12 +483,12 @@ fn constrain_adjustments(&mut self, expr: &hir::Expr<'_>) -> mc::McResult<mc::Pl
 
     fn check_safety_of_rvalue_destructor_if_necessary(
         &mut self,
-        place: &mc::Place<'tcx>,
+        place_with_id: &mc::PlaceWithHirId<'tcx>,
         span: Span,
     ) {
-        if let mc::PlaceBase::Rvalue = place.base {
-            if place.projections.is_empty() {
-                let typ = self.resolve_type(place.ty);
+        if let mc::PlaceBase::Rvalue = place_with_id.place.base {
+            if place_with_id.place.projections.is_empty() {
+                let typ = self.resolve_type(place_with_id.place.ty);
                 let body_id = self.body_id;
                 let _ = dropck::check_drop_obligations(self, typ, span, body_id);
             }
@@ -570,7 +573,7 @@ fn link_fn_params(&self, params: &[hir::Param<'_>]) {
 
     /// Link lifetimes of any ref bindings in `root_pat` to the pointers found
     /// in the discriminant, if needed.
-    fn link_pattern(&self, discr_cmt: mc::Place<'tcx>, root_pat: &hir::Pat<'_>) {
+    fn link_pattern(&self, discr_cmt: mc::PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
         debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
         ignore_err!(self.with_mc(|mc| {
             mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| {
@@ -591,7 +594,7 @@ fn link_pattern(&self, discr_cmt: mc::Place<'tcx>, root_pat: &hir::Pat<'_>) {
     fn link_autoref(
         &self,
         expr: &hir::Expr<'_>,
-        expr_cmt: &mc::Place<'tcx>,
+        expr_cmt: &mc::PlaceWithHirId<'tcx>,
         autoref: &adjustment::AutoBorrow<'tcx>,
     ) {
         debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
@@ -612,7 +615,7 @@ fn link_region_from_node_type(
         span: Span,
         id: hir::HirId,
         mutbl: hir::Mutability,
-        cmt_borrowed: &mc::Place<'tcx>,
+        cmt_borrowed: &mc::PlaceWithHirId<'tcx>,
     ) {
         debug!(
             "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
@@ -635,12 +638,12 @@ fn link_region(
         span: Span,
         borrow_region: ty::Region<'tcx>,
         borrow_kind: ty::BorrowKind,
-        borrow_place: &mc::Place<'tcx>,
+        borrow_place: &mc::PlaceWithHirId<'tcx>,
     ) {
-        let origin = infer::DataBorrowed(borrow_place.ty, span);
-        self.type_must_outlive(origin, borrow_place.ty, borrow_region);
+        let origin = infer::DataBorrowed(borrow_place.place.ty, span);
+        self.type_must_outlive(origin, borrow_place.place.ty, borrow_region);
 
-        for pointer_ty in borrow_place.deref_tys() {
+        for pointer_ty in borrow_place.place.deref_tys() {
             debug!(
                 "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})",
                 borrow_region, borrow_kind, borrow_place
@@ -656,7 +659,7 @@ fn link_region(
                 _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty),
             }
         }
-        if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.base {
+        if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.place.base {
             self.link_upvar_region(span, borrow_region, upvar_id);
         }
     }
index 19a23e5a594788b52a8c5e02a98fa74ce1233623..0f3133e0695f10b5a35c7883a96c03ff46d80398 100644 (file)
@@ -91,7 +91,7 @@ fn analyze_closure(
         let (closure_def_id, substs) = match ty.kind {
             ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
             ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
-            ty::Error => {
+            ty::Error(_) => {
                 // #51714: skip analysis when we have already encountered type errors
                 return;
             }
@@ -270,10 +270,13 @@ struct InferBorrowKind<'a, 'tcx> {
 impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
     fn adjust_upvar_borrow_kind_for_consume(
         &mut self,
-        place: &mc::Place<'tcx>,
+        place_with_id: &mc::PlaceWithHirId<'tcx>,
         mode: euv::ConsumeMode,
     ) {
-        debug!("adjust_upvar_borrow_kind_for_consume(place={:?}, mode={:?})", place, mode);
+        debug!(
+            "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, mode={:?})",
+            place_with_id, mode
+        );
 
         // we only care about moves
         match mode {
@@ -284,7 +287,7 @@ fn adjust_upvar_borrow_kind_for_consume(
         }
 
         let tcx = self.fcx.tcx;
-        let upvar_id = if let PlaceBase::Upvar(upvar_id) = place.base {
+        let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             upvar_id
         } else {
             return;
@@ -296,22 +299,22 @@ fn adjust_upvar_borrow_kind_for_consume(
         self.adjust_closure_kind(
             upvar_id.closure_expr_id,
             ty::ClosureKind::FnOnce,
-            place.span,
+            tcx.hir().span(place_with_id.hir_id),
             var_name(tcx, upvar_id.var_path.hir_id),
         );
 
         self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue);
     }
 
-    /// Indicates that `place` is being directly mutated (e.g., assigned
+    /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
     /// to). If the place is based on a by-ref upvar, this implies that
     /// the upvar must be borrowed using an `&mut` borrow.
-    fn adjust_upvar_borrow_kind_for_mut(&mut self, place: &mc::Place<'tcx>) {
-        debug!("adjust_upvar_borrow_kind_for_mut(place={:?})", place);
+    fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) {
+        debug!("adjust_upvar_borrow_kind_for_mut(place_with_id={:?})", place_with_id);
 
-        if let PlaceBase::Upvar(upvar_id) = place.base {
+        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             let mut borrow_kind = ty::MutBorrow;
-            for pointer_ty in place.deref_tys() {
+            for pointer_ty in place_with_id.place.deref_tys() {
                 match pointer_ty.kind {
                     // Raw pointers don't inherit mutability.
                     ty::RawPtr(_) => return,
@@ -323,20 +326,28 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, place: &mc::Place<'tcx>) {
                     _ => (),
                 }
             }
-            self.adjust_upvar_deref(upvar_id, place.span, borrow_kind);
+            self.adjust_upvar_deref(
+                upvar_id,
+                self.fcx.tcx.hir().span(place_with_id.hir_id),
+                borrow_kind,
+            );
         }
     }
 
-    fn adjust_upvar_borrow_kind_for_unique(&mut self, place: &mc::Place<'tcx>) {
-        debug!("adjust_upvar_borrow_kind_for_unique(place={:?})", place);
+    fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) {
+        debug!("adjust_upvar_borrow_kind_for_unique(place_with_id={:?})", place_with_id);
 
-        if let PlaceBase::Upvar(upvar_id) = place.base {
-            if place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
+        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
+            if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
                 // Raw pointers don't inherit mutability.
                 return;
             }
             // for a borrowed pointer to be unique, its base must be unique
-            self.adjust_upvar_deref(upvar_id, place.span, ty::UniqueImmBorrow);
+            self.adjust_upvar_deref(
+                upvar_id,
+                self.fcx.tcx.hir().span(place_with_id.hir_id),
+                ty::UniqueImmBorrow,
+            );
         }
     }
 
@@ -453,26 +464,26 @@ fn adjust_closure_kind(
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
-    fn consume(&mut self, place: &mc::Place<'tcx>, mode: euv::ConsumeMode) {
-        debug!("consume(place={:?},mode={:?})", place, mode);
-        self.adjust_upvar_borrow_kind_for_consume(place, mode);
+    fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) {
+        debug!("consume(place_with_id={:?},mode={:?})", place_with_id, mode);
+        self.adjust_upvar_borrow_kind_for_consume(place_with_id, mode);
     }
 
-    fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind) {
-        debug!("borrow(place={:?}, bk={:?})", place, bk);
+    fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
+        debug!("borrow(place_with_id={:?}, bk={:?})", place_with_id, bk);
 
         match bk {
             ty::ImmBorrow => {}
             ty::UniqueImmBorrow => {
-                self.adjust_upvar_borrow_kind_for_unique(place);
+                self.adjust_upvar_borrow_kind_for_unique(place_with_id);
             }
             ty::MutBorrow => {
-                self.adjust_upvar_borrow_kind_for_mut(place);
+                self.adjust_upvar_borrow_kind_for_mut(place_with_id);
             }
         }
     }
 
-    fn mutate(&mut self, assignee_place: &mc::Place<'tcx>) {
+    fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>) {
         debug!("mutate(assignee_place={:?})", assignee_place);
 
         self.adjust_upvar_borrow_kind_for_mut(assignee_place);
index f3297ed67434758441bc026443e54aab1384d847..d1a86a7ee89a8af5f7d3e8a6b3d54cf761bdcae6 100644 (file)
@@ -1118,7 +1118,7 @@ fn receiver_is_valid<'fcx, 'tcx>(
             );
 
             if can_eq_self(potential_self_ty) {
-                autoderef.finalize(fcx);
+                fcx.register_predicates(autoderef.into_obligations());
 
                 if let Some(mut err) =
                     fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty)
index 159d3d7a538a668e18c5b20910e3e0f06caa7c8c..4704d8fc7666f09eec5d394a4a4439ed7b7396aa 100644 (file)
@@ -4,10 +4,8 @@
 
 use crate::check::FnCtxt;
 
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefIdSet;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::InferCtxt;
@@ -67,10 +65,7 @@ pub fn resolve_type_vars_in_body(
         wbcx.visit_user_provided_sigs();
         wbcx.visit_generator_interior_types();
 
-        let used_trait_imports = mem::replace(
-            &mut self.tables.borrow_mut().used_trait_imports,
-            Lrc::new(DefIdSet::default()),
-        );
+        let used_trait_imports = mem::take(&mut self.tables.borrow_mut().used_trait_imports);
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
         wbcx.tables.used_trait_imports = used_trait_imports;
 
@@ -208,11 +203,10 @@ fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
                     // to access an unexistend index. We assume that more relevant errors will
                     // already have been emitted, so we only gate on this with an ICE if no
                     // error has been emitted. (#64638)
-                    self.tcx().sess.delay_span_bug(
+                    self.fcx.tcx.ty_error_with_message(
                         e.span,
                         &format!("bad index {:?} for base: `{:?}`", index, base),
-                    );
-                    self.fcx.tcx.types.err
+                    )
                 });
                 let index_ty = self.fcx.resolve_vars_if_possible(&index_ty);
 
@@ -681,7 +675,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
                 self.report_type_error(t);
                 self.replaced_with_error = true;
-                self.tcx().types.err
+                self.tcx().ty_error()
             }
         }
     }
@@ -698,7 +692,7 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
                 debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
                 self.report_const_error(ct);
                 self.replaced_with_error = true;
-                self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty })
+                self.tcx().const_error(ct.ty)
             }
         }
     }
index eaaff70472bfb212e2c59e661ca9946b780587ac..81daf064bb36866a74d90663460cbfd2958766de 100644 (file)
@@ -1,14 +1,14 @@
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint;
 use rustc_span::{Span, Symbol};
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
-    let mut used_trait_imports = DefIdSet::default();
+    let mut used_trait_imports = FxHashSet::default();
     for &body_id in tcx.hir().krate().bodies.keys() {
         let item_def_id = tcx.hir().body_owner_def_id(body_id);
         let imports = tcx.used_trait_imports(item_def_id);
@@ -39,7 +39,7 @@ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
 
 struct CheckVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    used_trait_imports: DefIdSet,
+    used_trait_imports: FxHashSet<LocalDefId>,
 }
 
 impl CheckVisitor<'tcx> {
@@ -49,7 +49,7 @@ fn check_import(&self, id: hir::HirId, span: Span) {
             return;
         }
 
-        if self.used_trait_imports.contains(&def_id.to_def_id()) {
+        if self.used_trait_imports.contains(&def_id) {
             return;
         }
 
index c5dd314dc655881fa8f6ee2c82b98b9fb96cfe1e..8c6161a62647346b780450776524de5e5228a51d 100644 (file)
@@ -50,7 +50,7 @@ fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
 
 fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     // Destructors only work on nominal types.
-    if let ty::Adt(..) | ty::Error = tcx.type_of(impl_did).kind {
+    if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind {
         return;
     }
 
index 653b7b8f2a5ba1a4c3c9044ae8cfe694a577cfaf..93ee87f6c572ee5bd164247dcb11fefcabfe8789 100644 (file)
@@ -296,7 +296,7 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
                     item.span,
                 );
             }
-            ty::Error => {}
+            ty::Error(_) => {}
             _ => {
                 struct_span_err!(
                     self.tcx.sess,
index 1d59d749634ee1cae5ac8913cf7ba5c8f6bdf596..b486e3d3536c99f4e0f1e69d62be93f56deb8fff 100644 (file)
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
 use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
+use rustc_session::config::SanitizerSet;
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -54,7 +55,7 @@
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
-fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
         &mut CollectItemTypesVisitor { tcx }.as_deep_visitor(),
@@ -307,8 +308,7 @@ fn allow_ty_infer(&self) -> bool {
     }
 
     fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
-        self.tcx().sess.delay_span_bug(span, "bad placeholder type");
-        self.tcx().types.err
+        self.tcx().ty_error_with_message(span, "bad_placeholder_type")
     }
 
     fn ct_infer(
@@ -318,8 +318,7 @@ fn ct_infer(
         span: Span,
     ) -> &'tcx Const<'tcx> {
         bad_placeholder_type(self.tcx(), vec![span]).emit();
-
-        self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty })
+        self.tcx().const_error(ty)
     }
 
     fn projected_ty_from_poly_trait_ref(
@@ -419,7 +418,7 @@ fn projected_ty_from_poly_trait_ref(
                 _ => {}
             }
             err.emit();
-            self.tcx().types.err
+            self.tcx().ty_error()
         }
     }
 
@@ -1465,7 +1464,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     visitor.visit_ty(ty);
                     let mut diag = bad_placeholder_type(tcx, visitor.0);
                     let ret_ty = fn_sig.output();
-                    if ret_ty != tcx.types.err {
+                    if ret_ty != tcx.ty_error() {
                         diag.span_suggestion(
                             ty.span,
                             "replace with the correct return type",
@@ -1693,6 +1692,7 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
 
     let mut is_trait = None;
     let mut is_default_impl_trait = None;
+    let mut is_trait_associated_type = None;
 
     let icx = ItemCtxt::new(tcx, def_id);
     let constness = icx.default_constness_for_trait_bounds();
@@ -1702,7 +1702,12 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
     let mut predicates = UniquePredicates::new();
 
     let ast_generics = match node {
-        Node::TraitItem(item) => &item.generics,
+        Node::TraitItem(item) => {
+            if let hir::TraitItemKind::Type(bounds, _) = item.kind {
+                is_trait_associated_type = Some((bounds, item.span));
+            }
+            &item.generics
+        }
 
         Node::ImplItem(item) => &item.generics,
 
@@ -1926,10 +1931,21 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
         }
     }
 
-    // Add predicates from associated type bounds.
-    if let Some((self_trait_ref, trait_items)) = is_trait {
+    // Add predicates from associated type bounds (`type X: Bound`)
+    if tcx.features().generic_associated_types {
+        // New behavior: bounds declared on associate type are predicates of that
+        // associated type. Not the default because it needs more testing.
+        if let Some((bounds, span)) = is_trait_associated_type {
+            let projection_ty =
+                tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id));
+
+            predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span))
+        }
+    } else if let Some((self_trait_ref, trait_items)) = is_trait {
+        // Current behavior: bounds declared on associate type are predicates
+        // of its parent trait.
         predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
-            associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
+            trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
         }))
     }
 
@@ -1959,7 +1975,7 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
     result
 }
 
-fn associated_item_predicates(
+fn trait_associated_item_predicates(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     self_trait_ref: ty::TraitRef<'tcx>,
@@ -1972,93 +1988,40 @@ fn associated_item_predicates(
         _ => return Vec::new(),
     };
 
-    let is_gat = !tcx.generics_of(item_def_id).params.is_empty();
-
-    let mut had_error = false;
-
-    let mut unimplemented_error = |arg_kind: &str| {
-        if !had_error {
-            tcx.sess
-                .struct_span_err(
-                    trait_item.span,
-                    &format!("{}-generic associated types are not yet implemented", arg_kind),
-                )
-                .note(
-                    "for more information, see issue #44265 \
-                     <https://github.com/rust-lang/rust/issues/44265> for more information",
-                )
-                .emit();
-            had_error = true;
-        }
-    };
-
-    let mk_bound_param = |param: &ty::GenericParamDef, _: &_| {
-        match param.kind {
-            ty::GenericParamDefKind::Lifetime => tcx
-                .mk_region(ty::RegionKind::ReLateBound(
-                    ty::INNERMOST,
-                    ty::BoundRegion::BrNamed(param.def_id, param.name),
-                ))
-                .into(),
-            // FIXME(generic_associated_types): Use bound types and constants
-            // once they are handled by the trait system.
-            ty::GenericParamDefKind::Type { .. } => {
-                unimplemented_error("type");
-                tcx.types.err.into()
-            }
-            ty::GenericParamDefKind::Const => {
-                unimplemented_error("const");
-                tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: tcx.type_of(param.def_id) })
-                    .into()
-            }
-        }
-    };
+    if !tcx.generics_of(item_def_id).params.is_empty() {
+        // For GATs the substs provided to the mk_projection call below are
+        // wrong. We should emit a feature gate error if we get here so skip
+        // this type.
+        tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate");
+        return Vec::new();
+    }
 
-    let bound_substs = if is_gat {
-        // Given:
-        //
-        // trait X<'a, B, const C: usize> {
-        //     type T<'d, E, const F: usize>: Default;
-        // }
-        //
-        // We need to create predicates on the trait:
-        //
-        // for<'d, E, const F: usize>
-        // <Self as X<'a, B, const C: usize>>::T<'d, E, const F: usize>: Sized + Default
-        //
-        // We substitute escaping bound parameters for the generic
-        // arguments to the associated type which are then bound by
-        // the `Binder` around the the predicate.
-        //
-        // FIXME(generic_associated_types): Currently only lifetimes are handled.
-        self_trait_ref.substs.extend_to(tcx, item_def_id.to_def_id(), mk_bound_param)
-    } else {
-        self_trait_ref.substs
-    };
+    let assoc_ty = tcx.mk_projection(
+        tcx.hir().local_def_id(trait_item.hir_id).to_def_id(),
+        self_trait_ref.substs,
+    );
 
-    let assoc_ty =
-        tcx.mk_projection(tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), bound_substs);
+    associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span)
+}
 
+fn associated_item_bounds(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    bounds: &'tcx [hir::GenericBound<'tcx>],
+    projection_ty: Ty<'tcx>,
+    span: Span,
+) -> Vec<(ty::Predicate<'tcx>, Span)> {
     let bounds = AstConv::compute_bounds(
         &ItemCtxt::new(tcx, def_id),
-        assoc_ty,
+        projection_ty,
         bounds,
         SizedByDefault::Yes,
-        trait_item.span,
+        span,
     );
 
-    let predicates = bounds.predicates(tcx, assoc_ty);
+    let predicates = bounds.predicates(tcx, projection_ty);
 
-    if is_gat {
-        // We use shifts to get the regions that we're substituting to
-        // be bound by the binders in the `Predicate`s rather that
-        // escaping.
-        let shifted_in = ty::fold::shift_vars(tcx, &predicates, 1);
-        let substituted = shifted_in.subst(tcx, bound_substs);
-        ty::fold::shift_out_vars(tcx, &substituted, 1)
-    } else {
-        predicates
-    }
+    predicates
 }
 
 /// Converts a specific `GenericBound` from the AST into a set of
@@ -2453,11 +2416,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             if let Some(list) = attr.meta_item_list() {
                 for item in list.iter() {
                     if item.check_name(sym::address) {
-                        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_ADDRESS;
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
                     } else if item.check_name(sym::memory) {
-                        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_MEMORY;
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
                     } else if item.check_name(sym::thread) {
-                        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_THREAD;
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
                     } else {
                         tcx.sess
                             .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
@@ -2557,7 +2520,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         }
     }
 
-    if codegen_fn_attrs.flags.intersects(CodegenFnAttrFlags::NO_SANITIZE_ANY) {
+    if !codegen_fn_attrs.no_sanitize.is_empty() {
         if codegen_fn_attrs.inline == InlineAttr::Always {
             if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
                 let hir_id = tcx.hir().as_local_hir_id(id.expect_local());
index 549a20531e2994b5d6688ec43938d2b6ce096f4b..3dd9c9c5c39dbc4781a60c55d671057248371d4c 100644 (file)
@@ -10,8 +10,7 @@
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
-use rustc_session::parse::feature_err;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
@@ -127,7 +126,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                                 // Some error in the
                                 // owner fn prevented us from populating
                                 // the `concrete_opaque_types` table.
-                                tcx.types.err
+                                tcx.ty_error()
                             } else {
                                 // We failed to resolve the opaque type or it
                                 // resolves to itself. Return the non-revealed
@@ -217,11 +216,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         })
                         | Node::TraitRef(&TraitRef { path, .. }) => &*path,
                         _ => {
-                            tcx.sess.delay_span_bug(
+                            return tcx.ty_error_with_message(
                                 DUMMY_SP,
                                 &format!("unexpected const parent path {:?}", parent_node),
                             );
-                            return tcx.types.err;
                         }
                     };
 
@@ -254,14 +252,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         }
                         Res::Def(_, def_id) => tcx.generics_of(def_id),
                         res => {
-                            tcx.sess.delay_span_bug(
+                            return tcx.ty_error_with_message(
                                 DUMMY_SP,
                                 &format!(
                                     "unexpected anon const res {:?} in path: {:?}",
                                     res, path,
                                 ),
-                            );
-                            return tcx.types.err;
+                                );
                         }
                     };
 
@@ -283,24 +280,21 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     } else {
                         // This is no generic parameter associated with the arg. This is
                         // probably from an extra arg where one is not needed.
-                        tcx.sess.delay_span_bug(
+                        tcx.ty_error_with_message(
                             DUMMY_SP,
                             &format!(
-                                "missing generic parameter for `AnonConst`, parent: {:?}, res: {:?}",
+                                "missing generic parameter for `AnonConst`, \
+                                 parent: {:?}, res: {:?}",
                                 parent_node, res
                             ),
-                        );
-                        tcx.types.err
+                        )
                     }
                 }
 
-                x => {
-                    tcx.sess.delay_span_bug(
-                        DUMMY_SP,
-                        &format!("unexpected const parent in type_of_def_id(): {:?}", x),
-                    );
-                    tcx.types.err
-                }
+                x => tcx.ty_error_with_message(
+                    DUMMY_SP,
+                    &format!("unexpected const parent in type_of_def_id(): {:?}", x),
+                ),
             }
         }
 
@@ -308,25 +302,22 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
             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,
+                let err = match ty.peel_refs().kind {
+                    ty::FnPtr(_) => Some("function pointers"),
+                    ty::RawPtr(_) => Some("raw pointers"),
+                    _ => None,
+                };
+                if let Some(unsupported_type) = err {
+                    tcx.sess
+                        .struct_span_err(
                             hir_ty.span,
                             &format!(
-                                "using {} as const generic parameters is unstable",
+                                "using {} as const generic parameters is forbidden",
                                 unsupported_type
                             ),
                         )
                         .emit();
-                    };
-                }
+                };
                 if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
                     .is_some()
                 {
@@ -568,7 +559,7 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
         None => {
             let span = tcx.def_span(def_id);
             tcx.sess.span_err(span, "could not find defining uses");
-            tcx.types.err
+            tcx.ty_error()
         }
     }
 }
@@ -605,7 +596,7 @@ fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty
             if let Some(ErrorReported) = owner_tables.tainted_by_errors {
                 // Some error in the owner fn prevented us from populating the
                 // `concrete_opaque_types` table.
-                tcx.types.err
+                tcx.ty_error()
             } else {
                 // We failed to resolve the opaque type or it resolves to
                 // itself. Return the non-revealed type, which should result in
@@ -655,7 +646,7 @@ fn infer_placeholder_type(
         }
         None => {
             let mut diag = bad_placeholder_type(tcx, vec![span]);
-            if ty != tcx.types.err {
+            if !matches!(ty.kind, ty::Error(_)) {
                 diag.span_suggestion(
                     span,
                     "replace `_` with the correct type",
index 6baadb8febd3689724696c7c8d5916abcb863287..b72fae96e4ca0ac25d6d047c57c35ff140522ccd 100644 (file)
@@ -5,7 +5,7 @@
 pub use self::ConsumeMode::*;
 
 // Export these here so that Clippy can use them.
-pub use mc::{Place, PlaceBase, Projection};
+pub use mc::{PlaceBase, PlaceWithHirId, Projection};
 
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 pub trait Delegate<'tcx> {
     // The value found at `place` is either copied or moved, depending
     // on mode.
-    fn consume(&mut self, place: &mc::Place<'tcx>, mode: ConsumeMode);
+    fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: ConsumeMode);
 
     // The value found at `place` is being borrowed with kind `bk`.
-    fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind);
+    fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind);
 
-    // The path at `place` is being assigned to.
-    fn mutate(&mut self, assignee_place: &mc::Place<'tcx>);
+    // The path at `place_with_id` is being assigned to.
+    fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>);
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -113,11 +113,11 @@ fn tcx(&self) -> TyCtxt<'tcx> {
         self.mc.tcx()
     }
 
-    fn delegate_consume(&mut self, place: &Place<'tcx>) {
-        debug!("delegate_consume(place={:?})", place);
+    fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>) {
+        debug!("delegate_consume(place_with_id={:?})", place_with_id);
 
-        let mode = copy_or_move(&self.mc, place);
-        self.delegate.consume(place, mode);
+        let mode = copy_or_move(&self.mc, place_with_id);
+        self.delegate.consume(place_with_id, mode);
     }
 
     fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
@@ -129,22 +129,22 @@ fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
     pub fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
         debug!("consume_expr(expr={:?})", expr);
 
-        let place = return_if_err!(self.mc.cat_expr(expr));
-        self.delegate_consume(&place);
+        let place_with_id = return_if_err!(self.mc.cat_expr(expr));
+        self.delegate_consume(&place_with_id);
         self.walk_expr(expr);
     }
 
     fn mutate_expr(&mut self, expr: &hir::Expr<'_>) {
-        let place = return_if_err!(self.mc.cat_expr(expr));
-        self.delegate.mutate(&place);
+        let place_with_id = return_if_err!(self.mc.cat_expr(expr));
+        self.delegate.mutate(&place_with_id);
         self.walk_expr(expr);
     }
 
     fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) {
         debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
 
-        let place = return_if_err!(self.mc.cat_expr(expr));
-        self.delegate.borrow(&place, bk);
+        let place_with_id = return_if_err!(self.mc.cat_expr(expr));
+        self.delegate.borrow(&place_with_id, bk);
 
         self.walk_expr(expr)
     }
@@ -384,7 +384,7 @@ fn walk_struct_expr(
 
         // Select just those fields of the `with`
         // expression that will actually be used
-        match with_place.ty.kind {
+        match with_place.place.ty.kind {
             ty::Adt(adt, substs) if adt.is_struct() => {
                 // Consume those fields of the with expression that are needed.
                 for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
@@ -422,14 +422,14 @@ fn walk_struct_expr(
     // process.
     fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
         let adjustments = self.mc.tables.expr_adjustments(expr);
-        let mut place = return_if_err!(self.mc.cat_expr_unadjusted(expr));
+        let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
             match adjustment.kind {
                 adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
-                    self.delegate_consume(&place);
+                    self.delegate_consume(&place_with_id);
                 }
 
                 adjustment::Adjust::Deref(None) => {}
@@ -441,14 +441,15 @@ fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
                 // this is an autoref of `x`.
                 adjustment::Adjust::Deref(Some(ref deref)) => {
                     let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
-                    self.delegate.borrow(&place, bk);
+                    self.delegate.borrow(&place_with_id, bk);
                 }
 
                 adjustment::Adjust::Borrow(ref autoref) => {
-                    self.walk_autoref(expr, &place, autoref);
+                    self.walk_autoref(expr, &place_with_id, autoref);
                 }
             }
-            place = return_if_err!(self.mc.cat_expr_adjusted(expr, place, &adjustment));
+            place_with_id =
+                return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment));
         }
     }
 
@@ -458,7 +459,7 @@ fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
     fn walk_autoref(
         &mut self,
         expr: &hir::Expr<'_>,
-        base_place: &mc::Place<'tcx>,
+        base_place: &mc::PlaceWithHirId<'tcx>,
         autoref: &adjustment::AutoBorrow<'tcx>,
     ) {
         debug!(
@@ -479,7 +480,7 @@ fn walk_autoref(
         }
     }
 
-    fn walk_arm(&mut self, discr_place: &Place<'tcx>, arm: &hir::Arm<'_>) {
+    fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
         self.walk_pat(discr_place, &arm.pat);
 
         if let Some(hir::Guard::If(ref e)) = arm.guard {
@@ -491,12 +492,12 @@ fn walk_arm(&mut self, discr_place: &Place<'tcx>, arm: &hir::Arm<'_>) {
 
     /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
     /// let binding, and *not* a match arm or nested pat.)
-    fn walk_irrefutable_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) {
+    fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
         self.walk_pat(discr_place, pat);
     }
 
     /// The core driver for walking a pattern
-    fn walk_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) {
+    fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
         debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
 
         let tcx = self.tcx();
@@ -569,7 +570,7 @@ fn cat_captured_var(
         closure_hir_id: hir::HirId,
         closure_span: Span,
         var_id: hir::HirId,
-    ) -> mc::McResult<mc::Place<'tcx>> {
+    ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> {
         // Create the place for the variable being borrowed, from the
         // perspective of the creator (parent) of the closure.
         let var_ty = self.mc.node_ty(var_id)?;
@@ -579,7 +580,14 @@ fn cat_captured_var(
 
 fn copy_or_move<'a, 'tcx>(
     mc: &mc::MemCategorizationContext<'a, 'tcx>,
-    place: &Place<'tcx>,
+    place_with_id: &PlaceWithHirId<'tcx>,
 ) -> ConsumeMode {
-    if !mc.type_is_copy_modulo_regions(place.ty, place.span) { Move } else { Copy }
+    if !mc.type_is_copy_modulo_regions(
+        place_with_id.place.ty,
+        mc.tcx().hir().span(place_with_id.hir_id),
+    ) {
+        Move
+    } else {
+        Copy
+    }
 }
index 37d383db68ab6ae917ca7efb6d2c086031c1513b..77cd1b3de0106723004e428c9aab4773e1efd4be 100644 (file)
@@ -14,7 +14,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
@@ -59,11 +59,11 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) {
     // but it's one that we must perform earlier than the rest of
     // WfCheck.
     for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module).to_def_id());
+        tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module));
     }
 }
 
-fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: DefId) {
+fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let min_specialization = tcx.features().min_specialization;
     tcx.hir()
         .visit_item_likes_in_module(module_def_id, &mut ImplWfCheck { tcx, min_specialization });
index 93d01ccd66f1e1059876a9c1fdbca0c23cf41001..d619d37be2d7b9ef201c9037d63dd7f24de4f149 100644 (file)
@@ -74,22 +74,24 @@ pub enum PlaceBase {
 }
 
 #[derive(Clone, Debug)]
-pub enum Projection<'tcx> {
+pub enum ProjectionKind<'tcx> {
     /// A dereference of a pointer, reference or `Box<T>` of the given type
     Deref(Ty<'tcx>),
     /// An index or a field
     Other,
 }
 
+#[derive(Clone, Debug)]
+pub struct Projection<'tcx> {
+    /// Defines the type of access
+    kind: ProjectionKind<'tcx>,
+}
+
 /// A `Place` represents how a value is located in memory.
 ///
 /// This is an HIR version of `mir::Place`
 #[derive(Clone, Debug)]
 pub struct Place<'tcx> {
-    /// `HirId` of the expression or pattern producing this value.
-    pub hir_id: hir::HirId,
-    /// The `Span` of the expression or pattern producing this value.
-    pub span: Span,
     /// The type of the `Place`
     pub ty: Ty<'tcx>,
     /// The "outermost" place that holds this value.
@@ -98,6 +100,32 @@ pub struct Place<'tcx> {
     pub projections: Vec<Projection<'tcx>>,
 }
 
+/// A `PlaceWithHirId` represents how a value is located in memory.
+///
+/// This is an HIR version of `mir::Place`
+#[derive(Clone, Debug)]
+pub struct PlaceWithHirId<'tcx> {
+    /// `HirId` of the expression or pattern producing this value.
+    pub hir_id: hir::HirId,
+
+    /// Information about the `Place`
+    pub place: Place<'tcx>,
+}
+
+impl<'tcx> PlaceWithHirId<'tcx> {
+    crate fn new(
+        hir_id: hir::HirId,
+        ty: Ty<'tcx>,
+        base: PlaceBase,
+        projections: Vec<Projection<'tcx>>,
+    ) -> PlaceWithHirId<'tcx> {
+        PlaceWithHirId {
+            hir_id: hir_id,
+            place: Place { ty: ty, base: base, projections: projections },
+        }
+    }
+}
+
 impl<'tcx> Place<'tcx> {
     /// Returns an iterator of the types that have to be dereferenced to access
     /// the `Place`.
@@ -107,7 +135,7 @@ impl<'tcx> Place<'tcx> {
     ///`*const u32` then `&*const u32`.
     crate fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
         self.projections.iter().rev().filter_map(|proj| {
-            if let Projection::Deref(deref_ty) = *proj { Some(deref_ty) } else { None }
+            if let ProjectionKind::Deref(deref_ty) = proj.kind { Some(deref_ty) } else { None }
         })
     }
 }
@@ -280,14 +308,14 @@ fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
         Ok(ret_ty)
     }
 
-    crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<Place<'tcx>> {
+    crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
         // This recursion helper avoids going through *too many*
         // adjustments, since *only* non-overloaded deref recurses.
         fn helper<'a, 'tcx>(
             mc: &MemCategorizationContext<'a, 'tcx>,
             expr: &hir::Expr<'_>,
             adjustments: &[adjustment::Adjustment<'tcx>],
-        ) -> McResult<Place<'tcx>> {
+        ) -> McResult<PlaceWithHirId<'tcx>> {
             match adjustments.split_last() {
                 None => mc.cat_expr_unadjusted(expr),
                 Some((adjustment, previous)) => {
@@ -302,9 +330,9 @@ fn helper<'a, 'tcx>(
     crate fn cat_expr_adjusted(
         &self,
         expr: &hir::Expr<'_>,
-        previous: Place<'tcx>,
+        previous: PlaceWithHirId<'tcx>,
         adjustment: &adjustment::Adjustment<'tcx>,
-    ) -> McResult<Place<'tcx>> {
+    ) -> McResult<PlaceWithHirId<'tcx>> {
         self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
     }
 
@@ -313,9 +341,9 @@ fn cat_expr_adjusted_with<F>(
         expr: &hir::Expr<'_>,
         previous: F,
         adjustment: &adjustment::Adjustment<'tcx>,
-    ) -> McResult<Place<'tcx>>
+    ) -> McResult<PlaceWithHirId<'tcx>>
     where
-        F: FnOnce() -> McResult<Place<'tcx>>,
+        F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
     {
         debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
         let target = self.resolve_vars_if_possible(&adjustment.target);
@@ -342,7 +370,7 @@ fn cat_expr_adjusted_with<F>(
         }
     }
 
-    crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<Place<'tcx>> {
+    crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
         debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
 
         let expr_ty = self.expr_ty(expr)?;
@@ -418,7 +446,7 @@ fn cat_expr_adjusted_with<F>(
         span: Span,
         expr_ty: Ty<'tcx>,
         res: Res,
-    ) -> McResult<Place<'tcx>> {
+    ) -> McResult<PlaceWithHirId<'tcx>> {
         debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
 
         match res {
@@ -433,25 +461,15 @@ fn cat_expr_adjusted_with<F>(
             )
             | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)),
 
-            Res::Def(DefKind::Static, _) => Ok(Place {
-                hir_id,
-                span,
-                ty: expr_ty,
-                base: PlaceBase::StaticItem,
-                projections: Vec::new(),
-            }),
+            Res::Def(DefKind::Static, _) => {
+                Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
+            }
 
             Res::Local(var_id) => {
                 if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) {
-                    self.cat_upvar(hir_id, span, var_id)
+                    self.cat_upvar(hir_id, var_id)
                 } else {
-                    Ok(Place {
-                        hir_id,
-                        span,
-                        ty: expr_ty,
-                        base: PlaceBase::Local(var_id),
-                        projections: Vec::new(),
-                    })
+                    Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
                 }
             }
 
@@ -464,12 +482,7 @@ fn cat_expr_adjusted_with<F>(
     /// Note: the actual upvar access contains invisible derefs of closure
     /// environment and upvar reference as appropriate. Only regionck cares
     /// about these dereferences, so we let it compute them as needed.
-    fn cat_upvar(
-        &self,
-        hir_id: hir::HirId,
-        span: Span,
-        var_id: hir::HirId,
-    ) -> McResult<Place<'tcx>> {
+    fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
         let closure_expr_def_id = self.body_owner;
 
         let upvar_id = ty::UpvarId {
@@ -478,22 +491,20 @@ fn cat_upvar(
         };
         let var_ty = self.node_ty(var_id)?;
 
-        let ret = Place {
-            hir_id,
-            span,
-            ty: var_ty,
-            base: PlaceBase::Upvar(upvar_id),
-            projections: Vec::new(),
-        };
+        let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
 
         debug!("cat_upvar ret={:?}", ret);
         Ok(ret)
     }
 
-    crate fn cat_rvalue(&self, hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>) -> Place<'tcx> {
+    crate fn cat_rvalue(
+        &self,
+        hir_id: hir::HirId,
+        span: Span,
+        expr_ty: Ty<'tcx>,
+    ) -> PlaceWithHirId<'tcx> {
         debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
-        let ret =
-            Place { hir_id, span, base: PlaceBase::Rvalue, projections: Vec::new(), ty: expr_ty };
+        let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
         debug!("cat_rvalue ret={:?}", ret);
         ret
     }
@@ -501,18 +512,12 @@ fn cat_upvar(
     crate fn cat_projection<N: HirNode>(
         &self,
         node: &N,
-        base_place: Place<'tcx>,
+        base_place: PlaceWithHirId<'tcx>,
         ty: Ty<'tcx>,
-    ) -> Place<'tcx> {
-        let mut projections = base_place.projections;
-        projections.push(Projection::Other);
-        let ret = Place {
-            hir_id: node.hir_id(),
-            span: node.span(),
-            ty,
-            base: base_place.base,
-            projections,
-        };
+    ) -> PlaceWithHirId<'tcx> {
+        let mut projections = base_place.place.projections;
+        projections.push(Projection { kind: ProjectionKind::Other });
+        let ret = PlaceWithHirId::new(node.hir_id(), ty, base_place.place.base, projections);
         debug!("cat_field ret {:?}", ret);
         ret
     }
@@ -521,7 +526,7 @@ fn cat_overloaded_place(
         &self,
         expr: &hir::Expr<'_>,
         base: &hir::Expr<'_>,
-    ) -> McResult<Place<'tcx>> {
+    ) -> McResult<PlaceWithHirId<'tcx>> {
         debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
 
         // Reconstruct the output assuming it's a reference with the
@@ -540,10 +545,14 @@ fn cat_overloaded_place(
         self.cat_deref(expr, base)
     }
 
-    fn cat_deref(&self, node: &impl HirNode, base_place: Place<'tcx>) -> McResult<Place<'tcx>> {
+    fn cat_deref(
+        &self,
+        node: &impl HirNode,
+        base_place: PlaceWithHirId<'tcx>,
+    ) -> McResult<PlaceWithHirId<'tcx>> {
         debug!("cat_deref: base_place={:?}", base_place);
 
-        let base_ty = base_place.ty;
+        let base_ty = base_place.place.ty;
         let deref_ty = match base_ty.builtin_deref(true) {
             Some(mt) => mt.ty,
             None => {
@@ -551,28 +560,22 @@ fn cat_deref(&self, node: &impl HirNode, base_place: Place<'tcx>) -> McResult<Pl
                 return Err(());
             }
         };
-        let mut projections = base_place.projections;
-        projections.push(Projection::Deref(base_ty));
-
-        let ret = Place {
-            hir_id: node.hir_id(),
-            span: node.span(),
-            ty: deref_ty,
-            base: base_place.base,
-            projections,
-        };
+        let mut projections = base_place.place.projections;
+        projections.push(Projection { kind: ProjectionKind::Deref(base_ty) });
+
+        let ret = PlaceWithHirId::new(node.hir_id(), deref_ty, base_place.place.base, projections);
         debug!("cat_deref ret {:?}", ret);
         Ok(ret)
     }
 
     crate fn cat_pattern<F>(
         &self,
-        place: Place<'tcx>,
+        place: PlaceWithHirId<'tcx>,
         pat: &hir::Pat<'_>,
         mut op: F,
     ) -> McResult<()>
     where
-        F: FnMut(&Place<'tcx>, &hir::Pat<'_>),
+        F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
     {
         self.cat_pattern_(place, pat, &mut op)
     }
@@ -580,24 +583,24 @@ fn cat_deref(&self, node: &impl HirNode, base_place: Place<'tcx>) -> McResult<Pl
     // FIXME(#19596) This is a workaround, but there should be a better way to do this
     fn cat_pattern_<F>(
         &self,
-        mut place: Place<'tcx>,
+        mut place_with_id: PlaceWithHirId<'tcx>,
         pat: &hir::Pat<'_>,
         op: &mut F,
     ) -> McResult<()>
     where
-        F: FnMut(&Place<'tcx>, &hir::Pat<'_>),
+        F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
     {
-        // Here, `place` is the `Place` being matched and pat is the pattern it
+        // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
         // is being matched against.
         //
         // In general, the way that this works is that we walk down the pattern,
-        // constructing a `Place` that represents the path that will be taken
+        // constructing a `PlaceWithHirId` that represents the path that will be taken
         // to reach the value being matched.
 
-        debug!("cat_pattern(pat={:?}, place={:?})", pat, place);
+        debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
 
-        // If (pattern) adjustments are active for this pattern, adjust the `Place` correspondingly.
-        // `Place`s are constructed differently from patterns. For example, in
+        // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
+        // `PlaceWithHirId`s are constructed differently from patterns. For example, in
         //
         // ```
         // match foo {
@@ -607,7 +610,7 @@ fn cat_pattern_<F>(
         // ```
         //
         // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
-        // corresponding `Place` we start with the `Place` for `foo`, and then, by traversing the
+        // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the
         // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
         //
         // `&&Some(x,)` `place_foo`
@@ -629,29 +632,29 @@ fn cat_pattern_<F>(
         // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
         // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
         for _ in 0..self.tables.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0) {
-            debug!("cat_pattern: applying adjustment to place={:?}", place);
-            place = self.cat_deref(pat, place)?;
+            debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
+            place_with_id = self.cat_deref(pat, place_with_id)?;
         }
-        let place = place; // lose mutability
-        debug!("cat_pattern: applied adjustment derefs to get place={:?}", place);
+        let place_with_id = place_with_id; // lose mutability
+        debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
 
-        // Invoke the callback, but only now, after the `place` has adjusted.
+        // Invoke the callback, but only now, after the `place_with_id` has adjusted.
         //
         // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
-        // case, the initial `place` will be that for `&Some(3)` and the pattern is `Some(x)`. We
+        // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
         // don't want to call `op` with these incompatible values. As written, what happens instead
         // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
         // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
         // result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
         // that (where the `ref` on `x` is implied).
-        op(&place, pat);
+        op(&place_with_id, pat);
 
         match pat.kind {
             PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => {
                 // S(p1, ..., pN) or (p1, ..., pN)
                 for subpat in subpats.iter() {
                     let subpat_ty = self.pat_ty_adjusted(&subpat)?;
-                    let sub_place = self.cat_projection(pat, place.clone(), subpat_ty);
+                    let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty);
                     self.cat_pattern_(sub_place, &subpat, op)?;
                 }
             }
@@ -660,44 +663,44 @@ fn cat_pattern_<F>(
                 // S { f1: p1, ..., fN: pN }
                 for fp in field_pats {
                     let field_ty = self.pat_ty_adjusted(&fp.pat)?;
-                    let field_place = self.cat_projection(pat, place.clone(), field_ty);
+                    let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty);
                     self.cat_pattern_(field_place, &fp.pat, op)?;
                 }
             }
 
             PatKind::Or(pats) => {
                 for pat in pats {
-                    self.cat_pattern_(place.clone(), &pat, op)?;
+                    self.cat_pattern_(place_with_id.clone(), &pat, op)?;
                 }
             }
 
             PatKind::Binding(.., Some(ref subpat)) => {
-                self.cat_pattern_(place, &subpat, op)?;
+                self.cat_pattern_(place_with_id, &subpat, op)?;
             }
 
             PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
                 // box p1, &p1, &mut p1.  we can ignore the mutability of
                 // PatKind::Ref since that information is already contained
                 // in the type.
-                let subplace = self.cat_deref(pat, place)?;
+                let subplace = self.cat_deref(pat, place_with_id)?;
                 self.cat_pattern_(subplace, &subpat, op)?;
             }
 
             PatKind::Slice(before, ref slice, after) => {
-                let element_ty = match place.ty.builtin_index() {
+                let element_ty = match place_with_id.place.ty.builtin_index() {
                     Some(ty) => ty,
                     None => {
-                        debug!("explicit index of non-indexable type {:?}", place);
+                        debug!("explicit index of non-indexable type {:?}", place_with_id);
                         return Err(());
                     }
                 };
-                let elt_place = self.cat_projection(pat, place.clone(), element_ty);
+                let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty);
                 for before_pat in before {
                     self.cat_pattern_(elt_place.clone(), &before_pat, op)?;
                 }
                 if let Some(ref slice_pat) = *slice {
                     let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?;
-                    let slice_place = self.cat_projection(pat, place, slice_pat_ty);
+                    let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty);
                     self.cat_pattern_(slice_place, &slice_pat, op)?;
                 }
                 for after_pat in after {
index eee0f764373a4d2acc864125e22d16cb4da1be93..cae09267994e3fe94af54dc80e41d95cedb4c0a1 100644 (file)
@@ -339,7 +339,7 @@ fn add_constraints_from_ty(
                 self.add_constraints_from_sig(current, sig, variance);
             }
 
-            ty::Error => {
+            ty::Error(_) => {
                 // we encounter this when walking the trait references for object
                 // types, where we use Error as the Self type
             }
index 08e04f719e9ba692d86b263c129e6b8844a6aba5..78628b198a3c3f73ab6740774273aecf31825f73 100644 (file)
@@ -278,7 +278,7 @@ fn build_type_alias_type(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type>
     type_.def_id().and_then(|did| build_ty(cx, did))
 }
 
-pub fn build_ty(cx: &DocContext, did: DefId) -> Option<clean::Type> {
+pub fn build_ty(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type> {
     match cx.tcx.def_kind(did) {
         DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Const | DefKind::Static => {
             Some(cx.tcx.type_of(did).clean(cx))
index adb2ae9a5d660766984c58170ac41f3b73596132..73fe87b05d477e6f3d25ed64e24c7252b03a976e 100644 (file)
@@ -1717,7 +1717,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Type {
             ty::Placeholder(..) => panic!("Placeholder"),
             ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
             ty::Infer(..) => panic!("Infer"),
-            ty::Error => panic!("Error"),
+            ty::Error(_) => panic!("Error"),
         }
     }
 }
index 5c76c840b1ddd1910238457bd4aadbdd011fe404..6dec016cc2ee3d7a0c70de06ce58d2567510d912 100644 (file)
@@ -486,6 +486,33 @@ pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> {
         })
     }
 
+    /// Enforce the format of attributes inside `#[doc(...)]`.
+    pub fn check_doc_attributes(
+        diagnostic: &::rustc_errors::Handler,
+        mi: &ast::MetaItem,
+    ) -> Option<(String, String)> {
+        mi.meta_item_list().and_then(|list| {
+            for meta in list {
+                if meta.check_name(sym::alias) {
+                    if !meta.is_value_str()
+                        || meta
+                            .value_str()
+                            .map(|s| s.to_string())
+                            .unwrap_or_else(String::new)
+                            .is_empty()
+                    {
+                        diagnostic.span_err(
+                            meta.span(),
+                            "doc alias attribute expects a string: #[doc(alias = \"0\")]",
+                        );
+                    }
+                }
+            }
+
+            None
+        })
+    }
+
     pub fn has_doc_flag(&self, flag: Symbol) -> bool {
         for attr in &self.other_attrs {
             if !attr.check_name(sym::doc) {
@@ -529,6 +556,7 @@ pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute])
                 } else {
                     if attr.check_name(sym::doc) {
                         if let Some(mi) = attr.meta() {
+                            Attributes::check_doc_attributes(&diagnostic, &mi);
                             if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
                                 // Extracted #[doc(cfg(...))]
                                 match Cfg::parse(cfg_mi) {
index c4e4802db6c0716f85d731689289ee37e9327c51..832b2420c238999fcf526f1f6158fca02c2b5b5b 100644 (file)
@@ -328,7 +328,7 @@ pub fn strip_path(path: &Path) -> Path {
     Path { global: path.global, res: path.res, segments }
 }
 
-pub fn qpath_to_string(p: &hir::QPath) -> String {
+pub fn qpath_to_string(p: &hir::QPath<'_>) -> String {
     let segments = match *p {
         hir::QPath::Resolved(_, ref path) => &path.segments,
         hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
@@ -417,7 +417,7 @@ fn to_src(&self, cx: &DocContext<'_>) -> String {
     }
 }
 
-pub fn name_from_pat(p: &hir::Pat) -> String {
+pub fn name_from_pat(p: &hir::Pat<'_>) -> String {
     use rustc_hir::*;
     debug!("trying to get a name from pattern: {:?}", p);
 
@@ -481,8 +481,8 @@ pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String {
         _ => {
             let mut s = n.to_string();
             // array lengths are obviously usize
-            if s.ends_with("usize") {
-                let n = s.len() - "usize".len();
+            if s.ends_with("_usize") {
+                let n = s.len() - "_usize".len();
                 s.truncate(n);
                 if s.ends_with(": ") {
                     let n = s.len() - ": ".len();
index 5dbcc5c9ec8b9dcfb5757304bc2e2a444ca94cc0..35b15cf717cee1270b687315e450e8dacf8717c7 100644 (file)
@@ -123,10 +123,6 @@ 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!
@@ -177,8 +173,6 @@ 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)
@@ -250,6 +244,10 @@ pub struct RenderOptions {
     pub generate_search_filter: bool,
     /// Option (disabled by default) to generate files used by RLS and some other tools.
     pub generate_redirect_pages: bool,
+    /// Document items that have lower than `pub` visibility.
+    pub document_private: bool,
+    /// Document items that have `doc(hidden)`.
+    pub document_hidden: bool,
 }
 
 impl Options {
@@ -567,8 +565,6 @@ fn println_condition(condition: Condition) {
             should_test,
             test_args,
             default_passes,
-            document_private,
-            document_hidden,
             manual_passes,
             display_warnings,
             show_coverage,
@@ -597,6 +593,8 @@ fn println_condition(condition: Condition) {
                 markdown_playground_url,
                 generate_search_filter,
                 generate_redirect_pages,
+                document_private,
+                document_hidden,
             },
             output_format,
         })
index 1690b946bb625050fde5de6d9a8c5c7926c412f1..38f202e84accba9b69a3fc303205a9041ff12351 100644 (file)
@@ -62,6 +62,8 @@ pub struct DocContext<'tcx> {
     // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
     pub generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
     pub auto_traits: Vec<DefId>,
+    /// The options given to rustdoc that could be relevant to a pass.
+    pub render_options: RenderOptions,
 }
 
 impl<'tcx> DocContext<'tcx> {
@@ -191,8 +193,15 @@ pub fn new_handler(
                 Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty()))
             });
             Box::new(
-                JsonEmitter::stderr(None, source_map, pretty, json_rendered, false)
-                    .ui_testing(debugging_opts.ui_testing),
+                JsonEmitter::stderr(
+                    None,
+                    source_map,
+                    pretty,
+                    json_rendered,
+                    debugging_opts.terminal_width,
+                    false,
+                )
+                .ui_testing(debugging_opts.ui_testing),
             )
         }
     };
@@ -281,8 +290,6 @@ 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,
@@ -448,6 +455,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                         .cloned()
                         .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
                         .collect(),
+                    render_options,
                 };
                 debug!("crate: {:?}", tcx.hir().krate());
 
@@ -524,7 +532,7 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
                     }
 
                     if attr.is_word() && name == sym::document_private_items {
-                        document_private = true;
+                        ctxt.render_options.document_private = true;
                     }
                 }
 
@@ -544,9 +552,9 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
                 for p in passes {
                     let run = match p.condition {
                         Always => true,
-                        WhenDocumentPrivate => document_private,
-                        WhenNotDocumentPrivate => !document_private,
-                        WhenNotDocumentHidden => !document_hidden,
+                        WhenDocumentPrivate => ctxt.render_options.document_private,
+                        WhenNotDocumentPrivate => !ctxt.render_options.document_private,
+                        WhenNotDocumentHidden => !ctxt.render_options.document_hidden,
                     };
                     if run {
                         debug!("running pass {}", p.pass.name);
@@ -556,7 +564,7 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
 
                 ctxt.sess().abort_if_errors();
 
-                (krate, ctxt.renderinfo.into_inner(), render_options)
+                (krate, ctxt.renderinfo.into_inner(), ctxt.render_options)
             })
         })
     })
index 5b13832742770fd2f5b927ba45c11a44e111baeb..943729a74ab2d7e07040ac17df31eb459ff583c5 100644 (file)
@@ -262,7 +262,7 @@ pub struct ProcMacro<'hir> {
     pub whence: Span,
 }
 
-pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType {
+pub fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
     match *vdata {
         hir::VariantData::Struct(..) => Plain,
         hir::VariantData::Tuple(..) => Tuple,
index e60ff37fd279aa9725c27cc43232b1d086a6c5c0..a453a8b3dcb2ae23cec835fe71c990c960740a9d 100644 (file)
@@ -468,7 +468,7 @@ impl clean::Path {
 
 pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
     let cache = cache();
-    if !did.is_local() && !cache.access_levels.is_public(did) {
+    if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
         return None;
     }
 
index c129e54c0f28ae3e92f5748c073ce6aa569fc9fe..7a6626766d38830c27283ad336f69ee03aae2435 100644 (file)
@@ -192,6 +192,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
     fn next(&mut self) -> Option<Self::Item> {
         let event = self.inner.next();
         let compile_fail;
+        let should_panic;
         let ignore;
         let edition;
         if let Some(Event::Start(Tag::CodeBlock(kind))) = event {
@@ -205,6 +206,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 return Some(Event::Start(Tag::CodeBlock(kind)));
             }
             compile_fail = parse_result.compile_fail;
+            should_panic = parse_result.should_panic;
             ignore = parse_result.ignore;
             edition = parse_result.edition;
         } else {
@@ -280,6 +282,8 @@ fn dont_escape(c: u8) -> bool {
             Some(("This example is not tested".to_owned(), "ignore"))
         } else if compile_fail {
             Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
+        } else if should_panic {
+            Some(("This example panics".to_owned(), "should_panic"))
         } else if explicit_edition {
             Some((format!("This code runs with edition {}", edition), "edition"))
         } else {
@@ -295,6 +299,8 @@ fn dont_escape(c: u8) -> bool {
                         " ignore"
                     } else if compile_fail {
                         " compile_fail"
+                    } else if should_panic {
+                        " should_panic"
                     } else if explicit_edition {
                         " edition "
                     } else {
@@ -314,6 +320,8 @@ fn dont_escape(c: u8) -> bool {
                         " ignore"
                     } else if compile_fail {
                         " compile_fail"
+                    } else if should_panic {
+                        " should_panic"
                     } else if explicit_edition {
                         " edition "
                     } else {
index 1681b73d0c25721a7d034d0a7aa711c56080af42..04c4685213b2e7df6ad05df902306e7c7156afef 100644 (file)
@@ -469,6 +469,7 @@ pub fn run(
         static_root_path,
         generate_search_filter,
         generate_redirect_pages,
+        document_private,
         ..
     } = options;
 
@@ -546,7 +547,7 @@ pub fn run(
     scx.ensure_dir(&dst)?;
     krate = sources::render(&dst, &mut scx, krate)?;
     let (new_crate, index, cache) =
-        Cache::from_krate(renderinfo, &extern_html_root_urls, &dst, krate);
+        Cache::from_krate(renderinfo, document_private, &extern_html_root_urls, &dst, krate);
     krate = new_crate;
     let cache = Arc::new(cache);
     let mut cx = Context {
index 225940773413e4519ff23bdc5a0afde3bbd1267b..1b5c8a9378e41efbd55ce77343bd0817b63e86e7 100644 (file)
@@ -91,6 +91,10 @@ pub enum ExternalLocation {
     /// The version of the crate being documented, if given from the `--crate-version` flag.
     pub crate_version: Option<String>,
 
+    /// Whether to document private items.
+    /// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
+    pub document_private: bool,
+
     // Private fields only used when initially crawling a crate to build a cache
     stack: Vec<String>,
     parent_stack: Vec<DefId>,
@@ -126,6 +130,7 @@ pub enum ExternalLocation {
 impl Cache {
     pub fn from_krate(
         renderinfo: RenderInfo,
+        document_private: bool,
         extern_html_root_urls: &BTreeMap<String, String>,
         dst: &Path,
         mut krate: clean::Crate,
@@ -160,6 +165,7 @@ pub fn from_krate(
             stripped_mod: false,
             access_levels,
             crate_version: krate.version.take(),
+            document_private,
             orphan_impl_items: Vec::new(),
             orphan_trait_impls: Vec::new(),
             traits: krate.external_traits.replace(Default::default()),
index 953f61a3772dc724b7aed6c2878ae5fa14f9792f..62a23298c1b9f215bb09bab134a21c90acb56ea4 100644 (file)
@@ -100,6 +100,8 @@ function defocusSearchBar() {
     // 2 for "In Return Types"
     var currentTab = 0;
 
+    var mouseMovedAfterSearch = true;
+
     var titleBeforeSearch = document.title;
 
     function clearInputTimeout() {
@@ -162,6 +164,7 @@ function defocusSearchBar() {
         }
         addClass(main, "hidden");
         removeClass(search, "hidden");
+        mouseMovedAfterSearch = false;
     }
 
     function hideSearchResults(search) {
@@ -424,6 +427,12 @@ function defocusSearchBar() {
     document.addEventListener("keypress", handleShortcut);
     document.addEventListener("keydown", handleShortcut);
 
+    function resetMouseMoved(ev) {
+        mouseMovedAfterSearch = true;
+    }
+
+    document.addEventListener("mousemove", resetMouseMoved);
+
     var handleSourceHighlight = (function() {
         var prev_line_id = 0;
 
@@ -1006,12 +1015,13 @@ function defocusSearchBar() {
                 var aliases = [];
                 var crateAliases = [];
                 var i;
-                if (filterCrates !== undefined &&
-                        ALIASES[filterCrates] &&
-                        ALIASES[filterCrates][query.search]) {
-                    for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
-                        aliases.push(
-                            createAliasFromItem(searchIndex[ALIASES[filterCrates][query.search]]));
+                if (filterCrates !== undefined) {
+                    if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
+                        for (i = 0; i < ALIASES[filterCrates][query.search].length; ++i) {
+                            aliases.push(
+                                createAliasFromItem(
+                                    searchIndex[ALIASES[filterCrates][query.search][i]]));
+                        }
                     }
                 } else {
                     Object.keys(ALIASES).forEach(function(crate) {
@@ -1353,20 +1363,22 @@ function defocusSearchBar() {
                 }
             };
             var mouseover_func = function(e) {
-                var el = e.target;
-                // to retrieve the real "owner" of the event.
-                while (el.tagName !== "TR") {
-                    el = el.parentNode;
-                }
-                clearTimeout(hoverTimeout);
-                hoverTimeout = setTimeout(function() {
-                    onEachLazy(document.getElementsByClassName("search-results"), function(e) {
-                        onEachLazy(e.getElementsByClassName("result"), function(i_e) {
-                            removeClass(i_e, "highlighted");
+                if (mouseMovedAfterSearch) {
+                    var el = e.target;
+                    // to retrieve the real "owner" of the event.
+                    while (el.tagName !== "TR") {
+                        el = el.parentNode;
+                    }
+                    clearTimeout(hoverTimeout);
+                    hoverTimeout = setTimeout(function() {
+                        onEachLazy(document.getElementsByClassName("search-results"), function(e) {
+                            onEachLazy(e.getElementsByClassName("result"), function(i_e) {
+                                removeClass(i_e, "highlighted");
+                            });
                         });
-                    });
-                    addClass(el, "highlighted");
-                }, 20);
+                        addClass(el, "highlighted");
+                    }, 20);
+                }
             };
             onEachLazy(document.getElementsByClassName("search-results"), function(e) {
                 onEachLazy(e.getElementsByClassName("result"), function(i_e) {
@@ -1396,6 +1408,7 @@ function defocusSearchBar() {
 
                     addClass(actives[currentTab][0].previousElementSibling, "highlighted");
                     removeClass(actives[currentTab][0], "highlighted");
+                    e.preventDefault();
                 } else if (e.which === 40) { // down
                     if (!actives[currentTab].length) {
                         var results = document.getElementById("results").childNodes;
@@ -1409,6 +1422,7 @@ function defocusSearchBar() {
                         addClass(actives[currentTab][0].nextElementSibling, "highlighted");
                         removeClass(actives[currentTab][0], "highlighted");
                     }
+                    e.preventDefault();
                 } else if (e.which === 13) { // return
                     if (actives[currentTab].length) {
                         document.location.href =
index 2cb3347135c1b4de185c3a1e84bd1d0f14419229..9c6dd25394db0e8ed4d1c1c0beffbf9cd36eaa3e 100644 (file)
@@ -1089,7 +1089,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
        border-style: solid;
 }
 
-.tooltip.compile_fail, .tooltip.ignore {
+.tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
        font-weight: bold;
        font-size: 20px;
 }
index a2986c7b927e24fc5da504050259d85a57c30691..41dcb5c24507c6c38dfe99a66bd3f84ac20cde81 100644 (file)
@@ -283,6 +283,14 @@ pre.compile_fail:hover, .information:hover + pre.compile_fail {
        border-left: 2px solid #f00;
 }
 
+pre.should_panic {
+       border-left: 2px solid rgba(255,0,0,.8);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+       border-left: 2px solid #f00;
+}
+
 pre.ignore {
        border-left: 2px solid rgba(255,142,0,.6);
 }
@@ -299,6 +307,14 @@ pre.ignore:hover, .information:hover + pre.ignore {
        color: #f00;
 }
 
+.tooltip.should_panic {
+       color: rgba(255,0,0,.8);
+}
+
+.information > .should_panic:hover {
+       color: #f00;
+}
+
 .tooltip.ignore {
        color: rgba(255,142,0,.6);
 }
index be173d8eb46d3bd6c0d0c4497732b6c771148a3e..386fe2398e63aec931bb665ea82dea7db5c0f0ef 100644 (file)
@@ -278,6 +278,14 @@ pre.compile_fail:hover, .information:hover + pre.compile_fail {
        border-left: 2px solid #f00;
 }
 
+pre.should_panic {
+       border-left: 2px solid rgba(255,0,0,.5);
+}
+
+pre.should_panic:hover, .information:hover + pre.should_panic {
+       border-left: 2px solid #f00;
+}
+
 pre.ignore {
        border-left: 2px solid rgba(255,142,0,.6);
 }
@@ -294,6 +302,14 @@ pre.ignore:hover, .information:hover + pre.ignore {
        color: #f00;
 }
 
+.tooltip.should_panic {
+       color: rgba(255,0,0,.5);
+}
+
+.information > .should_panic:hover {
+       color: #f00;
+}
+
 .tooltip.ignore {
        color: rgba(255,142,0,.6);
 }
index 82d6cda986a9ace3c7a9f6f3a5a8c42b46985656..de6fa3dbd4a89135d7a83f8843f49d148c51ce9e 100644 (file)
@@ -9,7 +9,6 @@
 #![feature(nll)]
 #![feature(or_patterns)]
 #![feature(test)]
-#![feature(vec_remove_item)]
 #![feature(ptr_offset_from)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
@@ -165,9 +164,8 @@ fn opts() -> Vec<RustcOptGroup> {
             o.optmulti(
                 "",
                 "passes",
-                "list of passes to also run, you might want \
-                        to pass it multiple times; a value of `list` \
-                        will print available passes",
+                "list of passes to also run, you might want to pass it multiple times; a value of \
+                        `list` will print available passes",
                 "PASSES",
             )
         }),
@@ -248,8 +246,8 @@ fn opts() -> Vec<RustcOptGroup> {
                 "e",
                 "extend-css",
                 "To add some CSS rules with a given file to generate doc with your \
-                      own theme. However, your theme might break if the rustdoc's generated HTML \
-                      changes, so be careful!",
+                        own theme. However, your theme might break if the rustdoc's generated HTML \
+                        changes, so be careful!",
                 "PATH",
             )
         }),
@@ -262,7 +260,7 @@ fn opts() -> Vec<RustcOptGroup> {
                 "",
                 "playground-url",
                 "URL to send code snippets to, may be reset by --markdown-playground-url \
-                      or `#![doc(html_playground_url=...)]`",
+                        or `#![doc(html_playground_url=...)]`",
                 "URL",
             )
         }),
@@ -276,8 +274,7 @@ fn opts() -> Vec<RustcOptGroup> {
             o.optflag(
                 "",
                 "sort-modules-by-appearance",
-                "sort modules by where they appear in the \
-                                                         program, rather than alphabetically",
+                "sort modules by where they appear in the program, rather than alphabetically",
             )
         }),
         stable("theme", |o| {
@@ -358,7 +355,7 @@ fn opts() -> Vec<RustcOptGroup> {
                 "",
                 "static-root-path",
                 "Path string to force loading static files from in output pages. \
-                      If not set, uses combinations of '../' to reach the documentation root.",
+                        If not set, uses combinations of '../' to reach the documentation root.",
                 "PATH",
             )
         }),
index f5b2f1bb5b17844a6f89e1fd700b129deddd26af..8da74f375d9ceb1916e17c5da9e584e545a84268 100644 (file)
@@ -178,6 +178,7 @@ fn resolve(
             let result = cx.enter_resolver(|resolver| {
                 resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
             });
+            debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
             let result = match result {
                 Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure),
                 _ => result.map_err(|_| ErrorKind::ResolutionFailure),
@@ -202,7 +203,13 @@ fn resolve(
                         }
                         return Ok((res, Some(path_str.to_owned())));
                     }
-                    _ => return Ok((res, extra_fragment.clone())),
+                    other => {
+                        debug!(
+                            "failed to resolve {} in namespace {:?} (got {:?})",
+                            path_str, ns, other
+                        );
+                        return Ok((res, extra_fragment.clone()));
+                    }
                 };
 
                 if value != (ns == ValueNS) {
@@ -555,12 +562,13 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             } else {
                 (parts[0].to_owned(), None)
             };
+            let resolved_self;
+            let mut path_str;
             let (res, fragment) = {
                 let mut kind = None;
-                let mut path_str = if let Some(prefix) =
-                    ["struct@", "enum@", "type@", "trait@", "union@"]
-                        .iter()
-                        .find(|p| link.starts_with(**p))
+                path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"]
+                    .iter()
+                    .find(|p| link.starts_with(**p))
                 {
                     kind = Some(TypeNS);
                     link.trim_start_matches(prefix)
@@ -614,7 +622,6 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
                 let base_node =
                     if item.is_mod() && item.attrs.inner_docs { None } else { parent_node };
 
-                let resolved_self;
                 // replace `Self` with suitable item's parent name
                 if path_str.starts_with("Self::") {
                     if let Some(ref name) = parent_name {
@@ -760,6 +767,32 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
             if let Res::PrimTy(_) = res {
                 item.attrs.links.push((ori_link, None, fragment));
             } else {
+                debug!("intra-doc link to {} resolved to {:?}", path_str, res);
+                if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) {
+                    use rustc_hir::def_id::LOCAL_CRATE;
+
+                    let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
+                    if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id)
+                        && !self.cx.render_options.document_private
+                    {
+                        let item_name = item.name.as_deref().unwrap_or("<unknown>");
+                        let err_msg = format!(
+                            "public documentation for `{}` links to a private item",
+                            item_name
+                        );
+                        build_diagnostic(
+                            cx,
+                            &item,
+                            path_str,
+                            &dox,
+                            link_range,
+                            &err_msg,
+                            "this item is private",
+                            None,
+                        );
+                        continue;
+                    }
+                }
                 let id = register_res(cx, res);
                 item.attrs.links.push((ori_link, Some(id), fragment));
             }
index 21aa0ded5a4b2c186dbd7e00215de4f93ec12d88..e9504aa3af123ee5082fe51fd63771d18197d32b 100644 (file)
@@ -166,7 +166,7 @@ pub fn run(options: Options) -> Result<(), String> {
 }
 
 // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
-fn scrape_test_config(krate: &::rustc_hir::Crate) -> TestOptions {
+fn scrape_test_config(krate: &::rustc_hir::Crate<'_>) -> TestOptions {
     use rustc_ast_pretty::pprust;
 
     let mut opts =
@@ -973,7 +973,7 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
         intravisit::NestedVisitorMap::All(self.map)
     }
 
-    fn visit_item(&mut self, item: &'hir hir::Item) {
+    fn visit_item(&mut self, item: &'hir hir::Item<'_>) {
         let name = if let hir::ItemKind::Impl { ref self_ty, .. } = item.kind {
             rustc_hir_pretty::id_to_string(&self.map, self_ty.hir_id)
         } else {
@@ -985,19 +985,19 @@ fn visit_item(&mut self, item: &'hir hir::Item) {
         });
     }
 
-    fn visit_trait_item(&mut self, item: &'hir hir::TraitItem) {
+    fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) {
         self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
             intravisit::walk_trait_item(this, item);
         });
     }
 
-    fn visit_impl_item(&mut self, item: &'hir hir::ImplItem) {
+    fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) {
         self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
             intravisit::walk_impl_item(this, item);
         });
     }
 
-    fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) {
         self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
             intravisit::walk_foreign_item(this, item);
         });
@@ -1005,8 +1005,8 @@ fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem) {
 
     fn visit_variant(
         &mut self,
-        v: &'hir hir::Variant,
-        g: &'hir hir::Generics,
+        v: &'hir hir::Variant<'_>,
+        g: &'hir hir::Generics<'_>,
         item_id: hir::HirId,
     ) {
         self.visit_testable(v.ident.to_string(), &v.attrs, v.id, v.span, |this| {
@@ -1014,13 +1014,13 @@ fn visit_variant(
         });
     }
 
-    fn visit_struct_field(&mut self, f: &'hir hir::StructField) {
+    fn visit_struct_field(&mut self, f: &'hir hir::StructField<'_>) {
         self.visit_testable(f.ident.to_string(), &f.attrs, f.hir_id, f.span, |this| {
             intravisit::walk_struct_field(this, f);
         });
     }
 
-    fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef) {
+    fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef<'_>) {
         self.visit_testable(
             macro_def.ident.to_string(),
             &macro_def.attrs,
index d2a950027cf877981574e461b04a3dd1ba150884..c18f417e4f8e1173ab61fcb969df0bd53ef83e8f 100644 (file)
@@ -62,7 +62,7 @@ fn store_path(&mut self, did: DefId) {
         self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did));
     }
 
-    pub fn visit(mut self, krate: &'tcx hir::Crate) -> Module<'tcx> {
+    pub fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
         let mut module = self.visit_mod_contents(
             krate.item.span,
             krate.item.attrs,
@@ -84,10 +84,10 @@ pub fn visit(mut self, krate: &'tcx hir::Crate) -> Module<'tcx> {
 
     fn visit_variant_data(
         &mut self,
-        item: &'tcx hir::Item,
+        item: &'tcx hir::Item<'_>,
         name: Symbol,
-        sd: &'tcx hir::VariantData,
-        generics: &'tcx hir::Generics,
+        sd: &'tcx hir::VariantData<'_>,
+        generics: &'tcx hir::Generics<'_>,
     ) -> Struct<'tcx> {
         debug!("visiting struct");
         let struct_type = struct_type_from_def(&*sd);
@@ -105,10 +105,10 @@ fn visit_variant_data(
 
     fn visit_union_data(
         &mut self,
-        item: &'tcx hir::Item,
+        item: &'tcx hir::Item<'_>,
         name: Symbol,
-        sd: &'tcx hir::VariantData,
-        generics: &'tcx hir::Generics,
+        sd: &'tcx hir::VariantData<'_>,
+        generics: &'tcx hir::Generics<'_>,
     ) -> Union<'tcx> {
         debug!("visiting union");
         let struct_type = struct_type_from_def(&*sd);
@@ -126,10 +126,10 @@ fn visit_union_data(
 
     fn visit_enum_def(
         &mut self,
-        it: &'tcx hir::Item,
+        it: &'tcx hir::Item<'_>,
         name: Symbol,
-        def: &'tcx hir::EnumDef,
-        generics: &'tcx hir::Generics,
+        def: &'tcx hir::EnumDef<'_>,
+        generics: &'tcx hir::Generics<'_>,
     ) -> Enum<'tcx> {
         debug!("visiting enum");
         Enum {
@@ -156,11 +156,11 @@ fn visit_enum_def(
     fn visit_fn(
         &mut self,
         om: &mut Module<'tcx>,
-        item: &'tcx hir::Item,
+        item: &'tcx hir::Item<'_>,
         name: Symbol,
-        decl: &'tcx hir::FnDecl,
+        decl: &'tcx hir::FnDecl<'_>,
         header: hir::FnHeader,
-        generics: &'tcx hir::Generics,
+        generics: &'tcx hir::Generics<'_>,
         body: hir::BodyId,
     ) {
         debug!("visiting fn");
@@ -231,7 +231,7 @@ fn visit_mod_contents(
         &mut self,
         span: Span,
         attrs: &'tcx [ast::Attribute],
-        vis: &'tcx hir::Visibility,
+        vis: &'tcx hir::Visibility<'_>,
         id: hir::HirId,
         m: &'tcx hir::Mod<'tcx>,
         name: Option<Symbol>,
@@ -375,7 +375,12 @@ fn inherits_doc_hidden(cx: &core::DocContext<'_>, mut node: hir::HirId) -> bool
         ret
     }
 
-    fn visit_item(&mut self, item: &'tcx hir::Item, renamed: Option<Ident>, om: &mut Module<'tcx>) {
+    fn visit_item(
+        &mut self,
+        item: &'tcx hir::Item<'_>,
+        renamed: Option<Ident>,
+        om: &mut Module<'tcx>,
+    ) {
         debug!("visiting item {:?}", item);
         let ident = renamed.unwrap_or(item.ident);
 
@@ -587,7 +592,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item, renamed: Option<Ident>, om: &mut
 
     fn visit_foreign_item(
         &mut self,
-        item: &'tcx hir::ForeignItem,
+        item: &'tcx hir::ForeignItem<'_>,
         renamed: Option<Ident>,
         om: &mut Module<'tcx>,
     ) {
@@ -607,7 +612,11 @@ fn visit_foreign_item(
     }
 
     // Convert each `exported_macro` into a doc item.
-    fn visit_local_macro(&self, def: &'tcx hir::MacroDef, renamed: Option<Symbol>) -> Macro<'tcx> {
+    fn visit_local_macro(
+        &self,
+        def: &'tcx hir::MacroDef<'_>,
+        renamed: Option<Symbol>,
+    ) -> Macro<'tcx> {
         debug!("visit_local_macro: {}", def.ident);
         let tts = def.ast.body.inner_tokens().trees().collect::<Vec<_>>();
         // Extract the spans of all matchers. They represent the "interface" of the macro.
index 83029a8642097e107b7223322e99ff838e9469b7..490afb5a0438f9088c545d4ede084e4b3797d927 100644 (file)
@@ -74,3 +74,8 @@ std_detect_dlsym_getauxval = []
 threads = 125
 # Maximum heap size
 heap_size = 0x8000000
+
+[[bench]]
+name = "stdbenches"
+path = "benches/lib.rs"
+test = true
index d752ba89a276d9762263c6f4fdeccbaed45a12ee..b392d6e7226d2d7bba2080ebefae53cd89626c45 100644 (file)
@@ -832,11 +832,7 @@ pub fn tanh(self) -> f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn asinh(self) -> f32 {
-        if self == Self::NEG_INFINITY {
-            Self::NEG_INFINITY
-        } else {
-            (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
-        }
+        (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
     }
 
     /// Inverse hyperbolic cosine function.
@@ -1413,6 +1409,8 @@ fn test_asinh() {
         assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271
         assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
         assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
+        // regression test for the catastrophic cancellation fixed in 72486
+        assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32);
     }
 
     #[test]
index 9cd60d846a7073dd8610977c5edc9e19e2c5a717..72268d2cc2f984be863501d2e4df84197d3fbb61 100644 (file)
@@ -834,11 +834,7 @@ pub fn tanh(self) -> f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn asinh(self) -> f64 {
-        if self == Self::NEG_INFINITY {
-            Self::NEG_INFINITY
-        } else {
-            (self + ((self * self) + 1.0).sqrt()).ln().copysign(self)
-        }
+        (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self)
     }
 
     /// Inverse hyperbolic cosine function.
@@ -1442,6 +1438,8 @@ fn test_asinh() {
         // issue 63271
         assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
         assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
+        // regression test for the catastrophic cancellation fixed in 72486
+        assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083);
     }
 
     #[test]
index f4c164a324e32e387bd157dbc6f2f78993e7d348..17f890375f843bb8ce212e894be57b91f0199ee2 100644 (file)
@@ -1033,8 +1033,16 @@ pub fn is_dir(&self) -> bool {
     /// [`is_dir`], and will be false for symlink metadata
     /// obtained from [`symlink_metadata`].
     ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
     /// [`is_dir`]: struct.Metadata.html#method.is_dir
     /// [`symlink_metadata`]: fn.symlink_metadata.html
+    /// [`File::open`]: struct.File.html#method.open
+    /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
     ///
     /// # Examples
     ///
@@ -1307,8 +1315,16 @@ pub fn is_dir(&self) -> bool {
     /// [`is_dir`] and [`is_symlink`]; only zero or one of these
     /// tests may pass.
     ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
     /// [`is_dir`]: struct.FileType.html#method.is_dir
     /// [`is_symlink`]: struct.FileType.html#method.is_symlink
+    /// [`File::open`]: struct.File.html#method.open
+    /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
     ///
     /// # Examples
     ///
@@ -1429,7 +1445,10 @@ pub fn path(&self) -> PathBuf {
     /// Returns the metadata for the file that this entry points at.
     ///
     /// This function will not traverse symlinks if this entry points at a
-    /// symlink.
+    /// symlink. To traverse symlinks use [`fs::metadata`] or [`fs::File::metadata`].
+    ///
+    /// [`fs::metadata`]: fn.metadata.html
+    /// [`fs::File::metadata`]: struct.File.html#method.metadata
     ///
     /// # Platform-specific behavior
     ///
index 0737008a94c9a57369f85f28433f0f0c38ab0a9c..b4c91cced43bfd407e3a40c8dc209746012c4ae1 100644 (file)
@@ -400,7 +400,7 @@ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
 /// in memory, like a `Vec<u8>`.
 ///
 /// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
-/// dropping will attempt to flush the the contents of the buffer, any errors
+/// dropping will attempt to flush the contents of the buffer, any errors
 /// that happen in the process of dropping will be ignored. Calling [`flush`]
 /// ensures that the buffer is empty and thus dropping will not even attempt
 /// file operations.
index d80a38819ead0db6ad0441e4d62a31753b372b0d..f7248e7547e27620b766649e48a7514a7a1ad158 100644 (file)
@@ -160,6 +160,11 @@ pub enum ErrorKind {
     #[stable(feature = "rust1", since = "1.0.0")]
     Interrupted,
     /// Any I/O error not part of this list.
+    ///
+    /// Errors that are `Other` now may move to a different or a new
+    /// [`ErrorKind`] variant in the future. It is not recommended to match
+    /// an error against `Other` and to expect any additional characteristics,
+    /// e.g., a specific [`Error::raw_os_error`] return value.
     #[stable(feature = "rust1", since = "1.0.0")]
     Other,
 
index b65b150d2c3a18ef41bf55d91b36abbce3dd5dac..d6b7ad6254a8cba2cad3a43bfe8f5e3f7c5e0599 100644 (file)
@@ -96,7 +96,20 @@ fn is_read_vectored(&self) -> bool {
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
+    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+        self.0.read_to_string(buf)
+    }
+
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        self.0.read_exact(buf)
+    }
 }
+
 impl Write for StdoutRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
@@ -114,7 +127,20 @@ fn is_write_vectored(&self) -> bool {
     fn flush(&mut self) -> io::Result<()> {
         self.0.flush()
     }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.0.write_all(buf)
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.0.write_all_vectored(bufs)
+    }
+
+    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+        self.0.write_fmt(fmt)
+    }
 }
+
 impl Write for StderrRaw {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
@@ -132,6 +158,18 @@ fn is_write_vectored(&self) -> bool {
     fn flush(&mut self) -> io::Result<()> {
         self.0.flush()
     }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.0.write_all(buf)
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.0.write_all_vectored(bufs)
+    }
+
+    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+        self.0.write_fmt(fmt)
+    }
 }
 
 enum Maybe<T> {
@@ -420,6 +458,18 @@ fn is_read_vectored(&self) -> bool {
     unsafe fn initializer(&self) -> Initializer {
         Initializer::nop()
     }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
+
+    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
+        self.inner.read_to_string(buf)
+    }
+
+    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+        self.inner.read_exact(buf)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -427,9 +477,18 @@ impl BufRead for StdinLock<'_> {
     fn fill_buf(&mut self) -> io::Result<&[u8]> {
         self.inner.fill_buf()
     }
+
     fn consume(&mut self, n: usize) {
         self.inner.consume(n)
     }
+
+    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_until(byte, buf)
+    }
+
+    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+        self.inner.read_line(buf)
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -593,6 +652,9 @@ fn flush(&mut self) -> io::Result<()> {
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
         self.lock().write_all(buf)
     }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.lock().write_all_vectored(bufs)
+    }
     fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
         self.lock().write_fmt(args)
     }
@@ -612,6 +674,12 @@ fn is_write_vectored(&self) -> bool {
     fn flush(&mut self) -> io::Result<()> {
         self.inner.borrow_mut().flush()
     }
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all(buf)
+    }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all_vectored(bufs)
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -767,6 +835,9 @@ fn flush(&mut self) -> io::Result<()> {
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
         self.lock().write_all(buf)
     }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.lock().write_all_vectored(bufs)
+    }
     fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
         self.lock().write_fmt(args)
     }
@@ -786,6 +857,12 @@ fn is_write_vectored(&self) -> bool {
     fn flush(&mut self) -> io::Result<()> {
         self.inner.borrow_mut().flush()
     }
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all(buf)
+    }
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        self.inner.borrow_mut().write_all_vectored(bufs)
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
index a4996d9eee810d0c2654aedda0fe3b048684522d..d972cf6db18cf15d224c7cbe0e6d65f77705a1f6 100644 (file)
@@ -913,10 +913,28 @@ mod match_keyword {}
 //
 /// Organize code into [modules].
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// Use `mod` to create new [modules] to encapsulate code, including other
+/// modules:
+///
+/// ```
+/// mod foo {
+///     mod bar {
+///         type MyType = (u8, u8);
+///         fn baz() {}
+///     }
+/// }
+/// ```
+///
+/// Like [`struct`]s and [`enum`]s, a module and its content are private by
+/// default, unaccessible to code outside of the module.
+///
+/// To learn more about allowing access, see the documentation for the [`pub`]
+/// keyword.
 ///
+/// [`enum`]: keyword.enum.html
+/// [`pub`]: keyword.pub.html
+/// [`struct`]: keyword.struct.html
 /// [modules]: ../reference/items/modules.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
 mod mod_keyword {}
 
 #[doc(keyword = "move")]
@@ -965,11 +983,61 @@ mod move_keyword {}
 
 #[doc(keyword = "mut")]
 //
-/// A mutable binding, reference, or pointer.
+/// A mutable variable, reference, or pointer.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `mut` can be used in several situations. The first is mutable variables,
+/// which can be used anywhere you can bind a value to a variable name. Some
+/// examples:
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// ```rust
+/// // A mutable variable in the parameter list of a function.
+/// fn foo(mut x: u8, y: u8) -> u8 {
+///     x += y;
+///     x
+/// }
+///
+/// // Modifying a mutable variable.
+/// # #[allow(unused_assignments)]
+/// let mut a = 5;
+/// a = 6;
+///
+/// assert_eq!(foo(3, 4), 7);
+/// assert_eq!(a, 6);
+/// ```
+///
+/// The second is mutable references. They can be created from `mut` variables
+/// and must be unique: no other variables can have a mutable reference, nor a
+/// shared reference.
+///
+/// ```rust
+/// // Taking a mutable reference.
+/// fn push_two(v: &mut Vec<u8>) {
+///     v.push(2);
+/// }
+///
+/// // A mutable reference cannot be taken to a non-mutable variable.
+/// let mut v = vec![0, 1];
+/// // Passing a mutable reference.
+/// push_two(&mut v);
+///
+/// assert_eq!(v, vec![0, 1, 2]);
+/// ```
+///
+/// ```rust,compile_fail,E0502
+/// let mut v = vec![0, 1];
+/// let mut_ref_v = &mut v;
+/// ##[allow(unused)]
+/// let ref_v = &v;
+/// mut_ref_v.push(2);
+/// ```
+///
+/// Mutable raw pointers work much like mutable references, with the added
+/// possibility of not pointing to a valid object. The syntax is `*mut Type`.
+///
+/// More information on mutable references and pointers can be found in```
+/// [Reference].
+///
+/// [Reference]: ../reference/types/pointer.html#mutable-references-mut
 mod mut_keyword {}
 
 #[doc(keyword = "pub")]
@@ -1000,18 +1068,148 @@ mod ref_keyword {}
 //
 /// Return a value from a function.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// A `return` marks the end of an execution path in a function:
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// ```
+/// fn foo() -> i32 {
+///     return 3;
+/// }
+/// assert_eq!(foo(), 3);
+/// ```
+///
+/// `return` is not needed when the returned value is the last expression in the
+/// function. In this case the `;` is omitted:
+///
+/// ```
+/// fn foo() -> i32 {
+///     3
+/// }
+/// assert_eq!(foo(), 3);
+/// ```
+///
+/// `return` returns from the function immediately (an "early return"):
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::{Error, ErrorKind, Read, Result};
+///
+/// fn main() -> Result<()> {
+///     let mut file = match File::open("foo.txt") {
+///         Ok(f) => f,
+///         Err(e) => return Err(e),
+///     };
+///
+///     let mut contents = String::new();
+///     let size = match file.read_to_string(&mut contents) {
+///         Ok(s) => s,
+///         Err(e) => return Err(e),
+///     };
+///
+///     if contents.contains("impossible!") {
+///         return Err(Error::new(ErrorKind::Other, "oh no!"));
+///     }
+///
+///     if size > 9000 {
+///         return Err(Error::new(ErrorKind::Other, "over 9000!"));
+///     }
+///
+///     assert_eq!(contents, "Hello, world!");
+///     Ok(())
+/// }
+/// ```
 mod return_keyword {}
 
 #[doc(keyword = "self")]
 //
 /// The receiver of a method, or the current module.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `self` is used in two situations: referencing the current module and marking
+/// the receiver of a method.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// In paths, `self` can be used to refer to the current module, either in a
+/// [`use`] statement or in a path to access an element:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io::{self, Read};
+/// ```
+///
+/// Is functionally the same as:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::io;
+/// use std::io::Read;
+/// ```
+///
+/// Using `self` to access an element in the current module:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// # fn main() {}
+/// fn foo() {}
+/// fn bar() {
+///     self::foo()
+/// }
+/// ```
+///
+/// `self` as the current receiver for a method allows to omit the parameter
+/// type most of the time. With the exception of this particularity, `self` is
+/// used much like any other parameter:
+///
+/// ```
+/// struct Foo(i32);
+///
+/// impl Foo {
+///     // No `self`.
+///     fn new() -> Self {
+///         Self(0)
+///     }
+///
+///     // Consuming `self`.
+///     fn consume(self) -> Self {
+///         Self(self.0 + 1)
+///     }
+///
+///     // Borrowing `self`.
+///     fn borrow(&self) -> &i32 {
+///         &self.0
+///     }
+///
+///     // Borrowing `self` mutably.
+///     fn borrow_mut(&mut self) -> &mut i32 {
+///         &mut self.0
+///     }
+/// }
+///
+/// // This method must be called with a `Type::` prefix.
+/// let foo = Foo::new();
+/// assert_eq!(foo.0, 0);
+///
+/// // Those two calls produces the same result.
+/// let foo = Foo::consume(foo);
+/// assert_eq!(foo.0, 1);
+/// let foo = foo.consume();
+/// assert_eq!(foo.0, 2);
+///
+/// // Borrowing is handled automatically with the second syntax.
+/// let borrow_1 = Foo::borrow(&foo);
+/// let borrow_2 = foo.borrow();
+/// assert_eq!(borrow_1, borrow_2);
+///
+/// // Borrowing mutably is handled automatically too with the second syntax.
+/// let mut foo = Foo::new();
+/// *Foo::borrow_mut(&mut foo) += 1;
+/// assert_eq!(foo.0, 1);
+/// *foo.borrow_mut() += 1;
+/// assert_eq!(foo.0, 2);
+/// ```
+///
+/// Note that this automatic conversion when calling `foo.method()` is not
+/// limited to the examples above. See the [Reference] for more information.
+///
+/// [`use`]: keyword.use.html
+/// [Reference]: ../reference/items/associated-items.html#methods
 mod self_keyword {}
 
 #[doc(keyword = "Self")]
@@ -1019,11 +1217,66 @@ mod self_keyword {}
 /// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type
 /// definition.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// Within a type definition:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// struct Node {
+///     elem: i32,
+///     // `Self` is a `Node` here.
+///     next: Option<Box<Self>>,
+/// }
+/// ```
+///
+/// In an [`impl`] block:
+///
+/// ```
+/// struct Foo(i32);
+///
+/// impl Foo {
+///     fn new() -> Self {
+///         Self(0)
+///     }
+/// }
+///
+/// assert_eq!(Foo::new().0, Foo(0).0);
+/// ```
+///
+/// Generic parameters are implicit with `Self`:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// struct Wrap<T> {
+///     elem: T,
+/// }
+///
+/// impl<T> Wrap<T> {
+///     fn new(elem: T) -> Self {
+///         Self { elem }
+///     }
+/// }
+/// ```
+///
+/// In a [`trait`] definition and related [`impl`] block:
+///
+/// ```
+/// trait Example {
+///     fn example() -> Self;
+/// }
+///
+/// struct Foo(i32);
+///
+/// impl Example for Foo {
+///     fn example() -> Self {
+///         Self(42)
+///     }
+/// }
+///
+/// assert_eq!(Foo::example().0, Foo(42).0);
+/// ```
 ///
 /// [`impl`]: keyword.impl.html
 /// [`trait`]: keyword.trait.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
 mod self_upper_keyword {}
 
 #[doc(keyword = "static")]
@@ -1147,10 +1400,26 @@ mod struct_keyword {}
 //
 /// The parent of the current [module].
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// ```rust
+/// # #![allow(dead_code)]
+/// # fn main() {}
+/// mod a {
+///     pub fn foo() {}
+/// }
+/// mod b {
+///     pub fn foo() {
+///         super::a::foo(); // call a's foo function
+///     }
+/// }
+/// ```
+///
+/// It is also possible to use `super` multiple times: `super::super::foo`,
+/// going up the ancestor chain.
+///
+/// See the [Reference] for more information.
 ///
 /// [module]: ../reference/items/modules.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// [Reference]: ../reference/paths.html#super
 mod super_keyword {}
 
 #[doc(keyword = "trait")]
index d6493454db591a2ad8cc15b398f628c39ec318ca..ef699ede2a140bc50a85d8a0d0aac2e73c39c571 100644 (file)
 #![feature(prelude_import)]
 #![feature(ptr_internals)]
 #![feature(raw)]
+#![feature(raw_ref_macros)]
 #![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
index b8fa1a7f744d3ca432d5338cb80ad31bf77569ce..8c8d1aadf48e2076b8e685ce434daffb45883091 100644 (file)
@@ -964,6 +964,14 @@ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
     }
 }
 
+#[stable(feature = "string_u16_to_socket_addrs", since = "1.46.0")]
+impl ToSocketAddrs for (String, u16) {
+    type Iter = vec::IntoIter<SocketAddr>;
+    fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+        (&*self.0, self.1).to_socket_addrs()
+    }
+}
+
 // accepts strings like 'localhost:12345'
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToSocketAddrs for str {
index 2abbf1fa9fa16197ef270fd9e1bd50ae3c8ec73c..b668aa2595d67bc4dc81fe18ba7ea69f26f9e20c 100644 (file)
@@ -1,7 +1,5 @@
 #![stable(feature = "metadata_ext", since = "1.1.0")]
 
-use libc;
-
 use crate::fs::Metadata;
 use crate::sys_common::AsInner;
 
index d22ac1d53858429dcc45c9fcbd9c16ce98926400..97d62d958ca4f873462378bac4a8d7b0ec3add64 100644 (file)
@@ -170,7 +170,7 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
 fn default_hook(info: &PanicInfo<'_>) {
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
-    let backtrace_env = if update_panic_count(0) >= 2 {
+    let backtrace_env = if panic_count::get() >= 2 {
         RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
     } else {
         backtrace::rust_backtrace_env()
@@ -221,19 +221,65 @@ fn default_hook(info: &PanicInfo<'_>) {
 #[cfg(not(test))]
 #[doc(hidden)]
 #[unstable(feature = "update_panic_count", issue = "none")]
-pub fn update_panic_count(amt: isize) -> usize {
+pub mod panic_count {
     use crate::cell::Cell;
-    thread_local! { static PANIC_COUNT: Cell<usize> = Cell::new(0) }
+    use crate::sync::atomic::{AtomicUsize, Ordering};
+
+    // Panic count for the current thread.
+    thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = Cell::new(0) }
+
+    // Sum of panic counts from all threads. The purpose of this is to have
+    // a fast path in `is_zero` (which is used by `panicking`). Access to
+    // this variable can be always be done with relaxed ordering because
+    // it is always guaranteed that, if `GLOBAL_PANIC_COUNT` is zero,
+    // `LOCAL_PANIC_COUNT` will be zero.
+    static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
+
+    pub fn increase() -> usize {
+        GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
+        LOCAL_PANIC_COUNT.with(|c| {
+            let next = c.get() + 1;
+            c.set(next);
+            next
+        })
+    }
+
+    pub fn decrease() -> usize {
+        GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed);
+        LOCAL_PANIC_COUNT.with(|c| {
+            let next = c.get() - 1;
+            c.set(next);
+            next
+        })
+    }
 
-    PANIC_COUNT.with(|c| {
-        let next = (c.get() as isize + amt) as usize;
-        c.set(next);
-        next
-    })
+    pub fn get() -> usize {
+        LOCAL_PANIC_COUNT.with(|c| c.get())
+    }
+
+    #[inline]
+    pub fn is_zero() -> bool {
+        if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) == 0 {
+            // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads
+            // (including the current one) will have `LOCAL_PANIC_COUNT`
+            // equal to zero, so TLS access can be avoided.
+            true
+        } else {
+            is_zero_slow_path()
+        }
+    }
+
+    // Slow path is in a separate function to reduce the amount of code
+    // inlined from `is_zero`.
+    #[inline(never)]
+    #[cold]
+    fn is_zero_slow_path() -> bool {
+        LOCAL_PANIC_COUNT.with(|c| c.get() == 0)
+    }
 }
 
 #[cfg(test)]
-pub use realstd::rt::update_panic_count;
+pub use realstd::rt::panic_count;
 
 /// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
 pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
@@ -283,7 +329,7 @@ union Data<F, R> {
     #[cold]
     unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
         let obj = Box::from_raw(__rust_panic_cleanup(payload));
-        update_panic_count(-1);
+        panic_count::decrease();
         obj
     }
 
@@ -312,8 +358,9 @@ fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
 }
 
 /// Determines whether the current thread is unwinding because of panic.
+#[inline]
 pub fn panicking() -> bool {
-    update_panic_count(0) != 0
+    !panic_count::is_zero()
 }
 
 /// The entry point for panicking with a formatted message.
@@ -445,7 +492,7 @@ fn rust_panic_with_hook(
     message: Option<&fmt::Arguments<'_>>,
     location: &Location<'_>,
 ) -> ! {
-    let panics = update_panic_count(1);
+    let panics = panic_count::increase();
 
     // If this is the third nested call (e.g., panics == 2, this is 0-indexed),
     // the panic hook probably triggered the last panic, otherwise the
@@ -495,7 +542,7 @@ fn rust_panic_with_hook(
 /// This is the entry point for `resume_unwind`.
 /// It just forwards the payload to the panic runtime.
 pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
-    update_panic_count(1);
+    panic_count::increase();
 
     struct RewrapBox(Box<dyn Any + Send>);
 
index 8ff7508ba6457b5042ca2e2a5f498cca2b56748c..f14a9ff72f62f473ef8437ed5c63650cbab30785 100644 (file)
@@ -2503,11 +2503,20 @@ pub fn exists(&self) -> bool {
     /// # See Also
     ///
     /// This is a convenience function that coerces errors to false. If you want to
-    /// check errors, call [fs::metadata] and handle its Result. Then call
-    /// [fs::Metadata::is_file] if it was Ok.
-    ///
-    /// [fs::metadata]: ../../std/fs/fn.metadata.html
-    /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file
+    /// check errors, call [`fs::metadata`] and handle its Result. Then call
+    /// [`fs::Metadata::is_file`] if it was Ok.
+    ///
+    /// When the goal is simply to read from (or write to) the source, the most
+    /// reliable way to test the source can be read (or written to) is to open
+    /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+    /// a Unix-like system for example. See [`File::open`] or
+    /// [`OpenOptions::open`] for more information.
+    ///
+    /// [`fs::metadata`]: ../../std/fs/fn.metadata.html
+    /// [`fs::Metadata`]: ../../std/fs/struct.Metadata.html
+    /// [`fs::Metadata::is_file`]: ../../std/fs/struct.Metadata.html#method.is_file
+    /// [`File::open`]: ../../std/fs/struct.File.html#method.open
+    /// [`OpenOptions::open`]: ../../std/fs/struct.OpenOptions.html#method.open
     #[stable(feature = "path_ext", since = "1.5.0")]
     pub fn is_file(&self) -> bool {
         fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
index 3085c3d829653b0f6750f476e4a7666ac2be0bbe..48f7cf169885f7489d6c63e503fa7428671f29fb 100644 (file)
 //! things, particularly traits, which are used in almost every single Rust
 //! program.
 //!
-//! On a technical level, Rust inserts
-//!
-//! ```
-//! # #[allow(unused_extern_crates)]
-//! extern crate std;
-//! ```
-//!
-//! into the crate root of every crate, and
-//!
-//! ```
-//! # #[allow(unused_imports)]
-//! use std::prelude::v1::*;
-//! ```
-//!
-//! into every module.
-//!
 //! # Other preludes
 //!
 //! Preludes can be seen as a pattern to make using multiple types more
index 2426b2dead71209db4b14842c6cf7e05171ead3c..fb825ab16ebd7ef8d1dc114bd8d0a36b86a461fe 100644 (file)
@@ -15,7 +15,7 @@
 #![doc(hidden)]
 
 // Re-export some of our utilities which are expected by other crates.
-pub use crate::panicking::{begin_panic, begin_panic_fmt, update_panic_count};
+pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
 
 // To reduce the generated code of the new `lang_start`, this function is doing
 // the real work.
index 208265de465adf3a1b81120c1eabe0f7f599a159..f3654ee38716c7c54ab09e65f0230606465ba556 100644 (file)
@@ -10,19 +10,19 @@ impl Stdin {
     pub fn new() -> io::Result<Stdin> {
         Ok(Stdin)
     }
+}
 
-    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+impl io::Read for Stdin {
+    fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
         self.read_vectored(&mut [IoSliceMut::new(data)])
     }
 
-    pub fn read_vectored(&self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        //ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
-        //    .read(data)
+    fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         Ok(0)
     }
 
     #[inline]
-    pub fn is_read_vectored(&self) -> bool {
+    fn is_read_vectored(&self) -> bool {
         true
     }
 }
@@ -31,8 +31,10 @@ impl Stdout {
     pub fn new() -> io::Result<Stdout> {
         Ok(Stdout)
     }
+}
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+impl io::Write for Stdout {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
@@ -44,7 +46,7 @@ pub fn write(&self, data: &[u8]) -> io::Result<usize> {
         }
     }
 
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
@@ -57,11 +59,11 @@ pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
     }
 
     #[inline]
-    pub fn is_write_vectored(&self) -> bool {
+    fn is_write_vectored(&self) -> bool {
         true
     }
 
-    pub fn flush(&self) -> io::Result<()> {
+    fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
 }
@@ -70,8 +72,10 @@ impl Stderr {
     pub fn new() -> io::Result<Stderr> {
         Ok(Stderr)
     }
+}
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
@@ -83,7 +87,7 @@ pub fn write(&self, data: &[u8]) -> io::Result<usize> {
         }
     }
 
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
         unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
@@ -96,21 +100,12 @@ pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
     }
 
     #[inline]
-    pub fn is_write_vectored(&self) -> bool {
+    fn is_write_vectored(&self) -> bool {
         true
     }
 
-    pub fn flush(&self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-impl io::Write for Stderr {
-    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-        (&*self).write(data)
-    }
     fn flush(&mut self) -> io::Result<()> {
-        (&*self).flush()
+        Ok(())
     }
 }
 
index 2badfc973c9723b4fd2c480b805835412b32cc10..f61bcf06f081550abac509e657e152f80edac9b7 100644 (file)
@@ -11,7 +11,7 @@ IMAGE_BASE:
     .long 1                    /* type = NT_VERSION */
 0:  .asciz "toolchain-version" /* name */
 1:  .align 4
-2:  .long 0                    /* desc - toolchain version number, 32-bit LE */
+2:  .long 1                    /* desc - toolchain version number, 32-bit LE */
 3:  .align 4
 
 .section .rodata
@@ -26,18 +26,10 @@ IMAGE_BASE:
 .Lxsave_clear:
 .org .+24
 .Lxsave_mxcsr:
-    .int 0
+    .short 0x1f80
 
 /*  We can store a bunch of data in the gap between MXCSR and the XSAVE header */
 
-/* MXCSR initialization value for ABI */
-.Lmxcsr_init:
-    .int 0x1f80
-
-/* x87 FPU control word initialization value for ABI */
-.Lfpucw_init:
-    .int 0x037f
-
 /*  The following symbols point at read-only data that will be filled in by the */
 /*  post-linker. */
 
@@ -68,10 +60,14 @@ IMAGE_BASE:
     globvar TEXT_BASE 8
     /*  The size in bytes of enclacve text section */
     globvar TEXT_SIZE 8
-    /*  The base address (relative to enclave start) of the enclave EH_FRM_HDR section */
-    globvar EH_FRM_HDR_BASE 8
-    /*  The size in bytes of enclacve EH_FRM_HDR section */
-    globvar EH_FRM_HDR_SIZE 8
+    /*  The base address (relative to enclave start) of the enclave .eh_frame_hdr section */
+    globvar EH_FRM_HDR_OFFSET 8
+    /*  The size in bytes of enclave .eh_frame_hdr section */
+    globvar EH_FRM_HDR_LEN 8
+    /*  The base address (relative to enclave start) of the enclave .eh_frame section */
+    globvar EH_FRM_OFFSET 8
+    /*  The size in bytes of enclacve .eh_frame section */
+    globvar EH_FRM_LEN 8
 
 .org .Lxsave_clear+512
 .Lxsave_header:
@@ -177,13 +173,17 @@ sgx_entry:
     jz .Lskip_debug_init
     mov %r10,%gs:tcsls_debug_panic_buf_ptr
 .Lskip_debug_init:
+/*  reset cpu state */
+    mov %rdx, %r10
+    mov $-1, %rax
+    mov $-1, %rdx
+    xrstor .Lxsave_clear(%rip)
+    mov %r10, %rdx
+
 /*  check if returning from usercall */
     mov %gs:tcsls_last_rsp,%r11
     test %r11,%r11
     jnz .Lusercall_ret
-/*  reset user state */
-    ldmxcsr .Lmxcsr_init(%rip)
-    fldcw .Lfpucw_init(%rip)
 /*  setup stack */
     mov %gs:tcsls_tos,%rsp /*  initially, RSP is not set to the correct value */
                            /*  here. This is fixed below under "adjust stack". */
index 87e7a5da2b7a9b179eaa0222305f89914fbd4efb..5ef26d4cc4dc65a52d3e4e2eb6d92f4990585c22 100644 (file)
@@ -56,6 +56,7 @@
 // able to specify this
 #[cfg(not(test))]
 #[no_mangle]
+#[allow(improper_ctypes_definitions)]
 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
     // FIXME: how to support TLS in library mode?
     let tls = Box::new(tls::Tls::new());
index 4c3e8542d576df350ae060b7a4744c8eb99a7485..773fab36be22127a7b62a367a7c98e3d4636e78d 100644 (file)
@@ -205,6 +205,7 @@ pub fn args() -> Args {
         #[cfg(target_arch = "aarch64")]
         extern "C" {
             fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
+            #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
             #[link_name = "objc_msgSend"]
             fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
         }
@@ -212,6 +213,7 @@ pub fn args() -> Args {
         #[cfg(not(target_arch = "aarch64"))]
         extern "C" {
             fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+            #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))]
             #[link_name = "objc_msgSend"]
             fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
         }
index 732cd677a18594f495f651c13f6b5ec7688ab476..e4d714936047e71b03807c2afc5e24deb6eb87a7 100644 (file)
@@ -242,7 +242,8 @@ pub trait PermissionsExt {
     ///     let permissions = metadata.permissions();
     ///
     ///     println!("permissions: {:o}", permissions.mode());
-    ///     Ok(()) }
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn mode(&self) -> u32;
@@ -262,7 +263,8 @@ pub trait PermissionsExt {
     ///
     ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
     ///     assert_eq!(permissions.mode(), 0o644);
-    ///     Ok(()) }
+    ///     Ok(())
+    /// }
     /// ```
     #[stable(feature = "fs_ext", since = "1.1.0")]
     fn set_mode(&mut self, mode: u32);
index cd24605ec7ab724650fd971ba2ce96aec7c0085a..ada8eaa1c9745e61fe2810eb3d99575008574ecc 100644 (file)
@@ -2,9 +2,6 @@
 
 //! Unix-specific networking functionality
 
-#[cfg(unix)]
-use libc;
-
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
 #[cfg(not(unix))]
 #[allow(non_camel_case_types)]
index 2d7267263dedf8aa24259755c4d862c21d5df048..6e33cdd3c48269432bbcebab6fa723865157710a 100644 (file)
@@ -428,6 +428,7 @@ macro_rules! t {
     // ignored there.
     #[cfg_attr(target_arch = "arm", ignore)]
     #[cfg_attr(target_arch = "aarch64", ignore)]
+    #[cfg_attr(target_arch = "riscv64", ignore)]
     fn test_process_mask() {
         unsafe {
             // Test to make sure that a signal mask does not get inherited.
index efd615f404db6b316e89c57b3fe5bbe47ef7abd2..adff6c489bbc90b0cf27ff4a07230456f4bbf57e 100644 (file)
@@ -56,7 +56,6 @@ mod imp {
     use crate::ffi::{CStr, OsString};
     use crate::marker::PhantomData;
     use crate::ptr;
-    use libc;
 
     use crate::sys_common::mutex::Mutex;
 
index 9864a855df738ef0afc3353cfc40959f463449c3..7cc64658ee1a9d1dd6d45fe14efbe60dea4618f7 100644 (file)
@@ -6,7 +6,6 @@
 use crate::sys;
 use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-use libc;
 
 /// Unix-specific extensions to [`File`].
 ///
index 87ebd2c9593fc936a10fd699ecb3346aad22ea9d..3a1ff5fd3b9c64c4edb2ac96368b647f08aba4dd 100644 (file)
@@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 mod imp {
     use crate::io;
     use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
-    use libc;
 
     pub fn fill_bytes(v: &mut [u8]) {
         static RNG_INIT: AtomicBool = AtomicBool::new(false);
index fd2e1a6e7bcfb99311ac2d4a9d50ce1c3e8e279a..c90304c2b4a6a2d90dede9cd798a4b6d4063a8aa 100644 (file)
@@ -1,6 +1,5 @@
 use crate::cell::UnsafeCell;
 use crate::sync::atomic::{AtomicUsize, Ordering};
-use libc;
 
 pub struct RWLock {
     inner: UnsafeCell<libc::pthread_rwlock_t>,
index 8ebbf89213f321bfbdf27111ec4e3d86a57a0ef5..8365c9ee9c995dbdd70c045e30fb573dac424eeb 100644 (file)
@@ -1,7 +1,6 @@
 use crate::cmp::Ordering;
 use crate::time::Duration;
 use ::core::hash::{Hash, Hasher};
-use libc;
 
 pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
 use crate::convert::TryInto;
@@ -104,7 +103,6 @@ mod inner {
     use crate::fmt;
     use crate::sys::cvt;
     use crate::time::Duration;
-    use libc;
 
     use super::Timespec;
 
index bc614162784010e98e580f2257afbd18bf5b05fe..57187851a14e37c57cff6a173f6f6dd4cc9c152a 100644 (file)
@@ -1,7 +1,6 @@
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ptr;
 use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-use libc;
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
index 9f9e35566ecf59bcbc46291a6deed0558f09740b..78e3911dc4efea33e1edc322a40e54ab7856e2bb 100644 (file)
@@ -11,22 +11,25 @@ pub fn new() -> io::Result<Stdin> {
         Ok(Stdin)
     }
 
-    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+    #[inline]
+    pub fn as_raw_fd(&self) -> u32 {
+        0
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
         self.read_vectored(&mut [IoSliceMut::new(data)])
     }
 
-    pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+    fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data)
     }
 
     #[inline]
-    pub fn is_read_vectored(&self) -> bool {
+    fn is_read_vectored(&self) -> bool {
         true
     }
-
-    pub fn as_raw_fd(&self) -> u32 {
-        0
-    }
 }
 
 impl Stdout {
@@ -34,26 +37,28 @@ pub fn new() -> io::Result<Stdout> {
         Ok(Stdout)
     }
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+    #[inline]
+    pub fn as_raw_fd(&self) -> u32 {
+        1
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         self.write_vectored(&[IoSlice::new(data)])
     }
 
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
     }
 
     #[inline]
-    pub fn is_write_vectored(&self) -> bool {
+    fn is_write_vectored(&self) -> bool {
         true
     }
-
-    pub fn flush(&self) -> io::Result<()> {
+    fn flush(&mut self) -> io::Result<()> {
         Ok(())
     }
-
-    pub fn as_raw_fd(&self) -> u32 {
-        1
-    }
 }
 
 impl Stderr {
@@ -61,23 +66,7 @@ pub fn new() -> io::Result<Stderr> {
         Ok(Stderr)
     }
 
-    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
-        self.write_vectored(&[IoSlice::new(data)])
-    }
-
-    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
-        ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
-    }
-
     #[inline]
-    pub fn is_write_vectored(&self) -> bool {
-        true
-    }
-
-    pub fn flush(&self) -> io::Result<()> {
-        Ok(())
-    }
-
     pub fn as_raw_fd(&self) -> u32 {
         2
     }
@@ -85,11 +74,20 @@ pub fn as_raw_fd(&self) -> u32 {
 
 impl io::Write for Stderr {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-        (&*self).write(data)
+        self.write_vectored(&[IoSlice::new(data)])
+    }
+
+    fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+        ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
     }
 
     fn flush(&mut self) -> io::Result<()> {
-        (&*self).flush()
+        Ok(())
     }
 }
 
index 6115d652b0cea3975ff26d5d60e4d0c92df38d00..f440442ca306279dfb7a0f49bbabb41fc54aabca 100644 (file)
@@ -161,6 +161,8 @@ fn clone(&self) -> Self {
 
 pub const PROGRESS_CONTINUE: DWORD = 0;
 
+// List of Windows system error codes with descriptions:
+// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes
 pub const ERROR_FILE_NOT_FOUND: DWORD = 2;
 pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
 pub const ERROR_ACCESS_DENIED: DWORD = 5;
@@ -171,13 +173,26 @@ fn clone(&self) -> Self {
 pub const ERROR_INVALID_PARAMETER: DWORD = 87;
 pub const ERROR_BROKEN_PIPE: DWORD = 109;
 pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
+pub const ERROR_SEM_TIMEOUT: DWORD = 121;
 pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;
 pub const ERROR_ALREADY_EXISTS: DWORD = 183;
-pub const ERROR_NO_DATA: DWORD = 232;
 pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203;
+pub const ERROR_NO_DATA: DWORD = 232;
+pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594;
 pub const ERROR_OPERATION_ABORTED: DWORD = 995;
 pub const ERROR_IO_PENDING: DWORD = 997;
-pub const ERROR_TIMEOUT: DWORD = 0x5B4;
+pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053;
+pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121;
+pub const ERROR_TIMEOUT: DWORD = 1460;
+pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910;
+pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012;
+pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040;
+pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014;
+pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226;
+pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705;
+pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805;
+pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402;
+pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403;
 
 pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
 
index d63139d8052c23a535db8f5bbda2404a18babee5..640c9f3636d4b89262cf19045c0c9d346504ca53 100644 (file)
@@ -61,7 +61,22 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
-        c::ERROR_OPERATION_ABORTED => return ErrorKind::TimedOut,
+        c::ERROR_SEM_TIMEOUT
+        | c::WAIT_TIMEOUT
+        | c::ERROR_DRIVER_CANCEL_TIMEOUT
+        | c::ERROR_OPERATION_ABORTED
+        | c::ERROR_SERVICE_REQUEST_TIMEOUT
+        | c::ERROR_COUNTER_TIMEOUT
+        | c::ERROR_TIMEOUT
+        | c::ERROR_RESOURCE_CALL_TIMED_OUT
+        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
+        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
+        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
+        | c::ERROR_DS_TIMELIMIT_EXCEEDED
+        | c::DNS_ERROR_RECORD_TIMED_OUT
+        | c::ERROR_IPSEC_IKE_TIMED_OUT
+        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
+        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
         _ => {}
     }
 
index bc3bfde6d7559104fb50d224022ae45fb457b4e9..84fa35e01bb09898723aebd461201868eb89e810 100644 (file)
 /// }
 /// ```
 ///
+/// # OS-specific behaviors
+///
+/// An `Instant` is a wrapper around system-specific types and it may behave
+/// differently depending on the underlying operating system. For example,
+/// the following snippet is fine on Linux but panics on macOS:
+///
+/// ```no_run
+/// use std::time::{Instant, Duration};
+///
+/// let now = Instant::now();
+/// let max_nanoseconds = u64::MAX / 1_000_000_000;
+/// let duration = Duration::new(max_nanoseconds, 0);
+/// println!("{:?}", now + duration);
+/// ```
+///
 /// # Underlying System calls
 /// Currently, the following system calls are being used to get the current time using `now()`:
 ///
@@ -796,11 +811,11 @@ fn since_epoch() {
 
         // Right now for CI this test is run in an emulator, and apparently the
         // aarch64 emulator's sense of time is that we're still living in the
-        // 70s.
+        // 70s. This is also true for riscv (also qemu)
         //
         // Otherwise let's assume that we're all running computers later than
         // 2000.
-        if !cfg!(target_arch = "aarch64") {
+        if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") {
             assert!(a > thirty_years);
         }
 
index f6f16f686e55781048b787e555b30519e4a52402..31d235cf679db1ff072ce923f089f923b5004293 100644 (file)
@@ -9,6 +9,8 @@ fn main() {
     {
         // Build the unwinding from libunwind C/C++ source code.
         llvm_libunwind::compile();
+    } else if target.contains("x86_64-fortanix-unknown-sgx") {
+        llvm_libunwind::compile();
     } else if target.contains("linux") {
         if target.contains("musl") {
             // linking for musl is handled in lib.rs
@@ -55,6 +57,7 @@ mod llvm_libunwind {
 
     /// Compile the libunwind C/C++ source code.
     pub fn compile() {
+        let target = env::var("TARGET").expect("TARGET was not set");
         let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
         let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
         let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
@@ -75,6 +78,35 @@ pub fn compile() {
             cfg.flag("/EHsc");
             cfg.define("_CRT_SECURE_NO_WARNINGS", None);
             cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+        } else if target.contains("x86_64-fortanix-unknown-sgx") {
+            cfg.cpp(false);
+
+            cfg.static_flag(true);
+            cfg.opt_level(3);
+
+            cfg.flag("-nostdinc++");
+            cfg.flag("-fno-exceptions");
+            cfg.flag("-fno-rtti");
+            cfg.flag("-fstrict-aliasing");
+            cfg.flag("-funwind-tables");
+            cfg.flag("-fvisibility=hidden");
+            cfg.flag("-fno-stack-protector");
+            cfg.flag("-ffreestanding");
+            cfg.flag("-fexceptions");
+
+            // easiest way to undefine since no API available in cc::Build to undefine
+            cfg.flag("-U_FORTIFY_SOURCE");
+            cfg.define("_FORTIFY_SOURCE", "0");
+
+            cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+
+            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+            cfg.define("RUST_SGX", "1");
+            cfg.define("__NO_STRING_INLINES", None);
+            cfg.define("__NO_MATH_INLINES", None);
+            cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
+            cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
+            cfg.define("NDEBUG", None);
         } else {
             cfg.flag("-std=c99");
             cfg.flag("-std=c++11");
@@ -103,6 +135,10 @@ pub fn compile() {
             unwind_sources.push("Unwind_AppleExtras.cpp");
         }
 
+        if target.contains("x86_64-fortanix-unknown-sgx") {
+            unwind_sources.push("UnwindRustSgx.c");
+        }
+
         let root = Path::new("../llvm-project/libunwind");
         cfg.include(root.join("include"));
         for src in unwind_sources {
index 0ddefeca92b2e1835c80e9b01d9ecc7efc906b1c..6c040dd86ed62d38e585279027486e6efc42fb36 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0ddefeca92b2e1835c80e9b01d9ecc7efc906b1c
+Subproject commit 6c040dd86ed62d38e585279027486e6efc42fb36
index 3d252fe70afebaba44760c9c2b71da88ed09ecc2..41b14714842fd0f9d588621f1057005e49e0d037 100644 (file)
@@ -49,8 +49,10 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
 
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
+#if LLVM_VERSION_LT(11, 0)
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
                                    LLVMPassManagerBuilderRef)
+#endif
 
 extern "C" void LLVMInitializePasses() {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
@@ -343,17 +345,17 @@ enum class LLVMRustPassBuilderOptLevel {
 static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
   switch (Level) {
   case LLVMRustPassBuilderOptLevel::O0:
-    return PassBuilder::O0;
+    return PassBuilder::OptimizationLevel::O0;
   case LLVMRustPassBuilderOptLevel::O1:
-    return PassBuilder::O1;
+    return PassBuilder::OptimizationLevel::O1;
   case LLVMRustPassBuilderOptLevel::O2:
-    return PassBuilder::O2;
+    return PassBuilder::OptimizationLevel::O2;
   case LLVMRustPassBuilderOptLevel::O3:
-    return PassBuilder::O3;
+    return PassBuilder::OptimizationLevel::O3;
   case LLVMRustPassBuilderOptLevel::Os:
-    return PassBuilder::Os;
+    return PassBuilder::OptimizationLevel::Os;
   case LLVMRustPassBuilderOptLevel::Oz:
-    return PassBuilder::Oz;
+    return PassBuilder::OptimizationLevel::Oz;
   default:
     report_fatal_error("Bad PassBuilderOptLevel.");
   }
@@ -424,6 +426,12 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) {
   printf("Available features for this target:\n");
   for (auto &Feature : FeatTable)
     printf("    %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);
+  printf("\nRust-specific features:\n");
+  printf("    %-*s - %s.\n",
+    MaxFeatLen,
+    "crt-static",
+    "Enables libraries with C Run-time Libraries(CRT) to be statically linked"
+  );
   printf("\n");
 
   printf("Use +feature to enable a feature, or -feature to disable it.\n"
@@ -711,11 +719,12 @@ enum class LLVMRustOptStage {
 };
 
 struct LLVMRustSanitizerOptions {
+  bool SanitizeAddress;
+  bool SanitizeAddressRecover;
   bool SanitizeMemory;
+  bool SanitizeMemoryRecover;
+  int  SanitizeMemoryTrackOrigins;
   bool SanitizeThread;
-  bool SanitizeAddress;
-  bool SanitizeRecover;
-  int SanitizeMemoryTrackOrigins;
 };
 
 extern "C" void
@@ -789,8 +798,13 @@ LLVMRustOptimizeWithNewPassManager(
   // We manually collect pipeline callbacks so we can apply them at O0, where the
   // PassBuilder does not create a pipeline.
   std::vector<std::function<void(ModulePassManager &)>> PipelineStartEPCallbacks;
+#if LLVM_VERSION_GE(11, 0)
+  std::vector<std::function<void(ModulePassManager &, PassBuilder::OptimizationLevel)>>
+      OptimizerLastEPCallbacks;
+#else
   std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>>
       OptimizerLastEPCallbacks;
+#endif
 
   if (VerifyIR) {
     PipelineStartEPCallbacks.push_back([VerifyIR](ModulePassManager &MPM) {
@@ -802,8 +816,16 @@ LLVMRustOptimizeWithNewPassManager(
     if (SanitizerOptions->SanitizeMemory) {
       MemorySanitizerOptions Options(
           SanitizerOptions->SanitizeMemoryTrackOrigins,
-          SanitizerOptions->SanitizeRecover,
+          SanitizerOptions->SanitizeMemoryRecover,
           /*CompileKernel=*/false);
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [Options](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(MemorySanitizerPass(Options));
+          MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
+        }
+      );
+#else
 #if LLVM_VERSION_GE(10, 0)
       PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) {
         MPM.addPass(MemorySanitizerPass(Options));
@@ -814,9 +836,18 @@ LLVMRustOptimizeWithNewPassManager(
           FPM.addPass(MemorySanitizerPass(Options));
         }
       );
+#endif
     }
 
     if (SanitizerOptions->SanitizeThread) {
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(ThreadSanitizerPass());
+          MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
+        }
+      );
+#else
 #if LLVM_VERSION_GE(10, 0)
       PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM) {
         MPM.addPass(ThreadSanitizerPass());
@@ -827,40 +858,59 @@ LLVMRustOptimizeWithNewPassManager(
           FPM.addPass(ThreadSanitizerPass());
         }
       );
+#endif
     }
 
     if (SanitizerOptions->SanitizeAddress) {
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
+          MPM.addPass(ModuleAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
+          MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
+              /*UseAfterScope=*/true)));
+        }
+      );
+#else
       PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) {
         MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
       });
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
           FPM.addPass(AddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover,
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
               /*UseAfterScope=*/true));
         }
       );
       PipelineStartEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM) {
           MPM.addPass(ModuleAddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
         }
       );
+#endif
     }
   }
 
   ModulePassManager MPM(DebugPassManager);
   if (!NoPrepopulatePasses) {
-    if (OptLevel == PassBuilder::O0) {
+    if (OptLevel == PassBuilder::OptimizationLevel::O0) {
       for (const auto &C : PipelineStartEPCallbacks)
         C(MPM);
 
+#if LLVM_VERSION_GE(11, 0)
+      for (const auto &C : OptimizerLastEPCallbacks)
+        C(MPM, OptLevel);
+#else
       if (!OptimizerLastEPCallbacks.empty()) {
         FunctionPassManager FPM(DebugPassManager);
         for (const auto &C : OptimizerLastEPCallbacks)
           C(FPM, OptLevel);
         MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
       }
+#endif
 
       MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
 
@@ -885,12 +935,17 @@ LLVMRustOptimizeWithNewPassManager(
         break;
       case LLVMRustOptStage::PreLinkThinLTO:
         MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
+#if LLVM_VERSION_GE(11, 0)
+        for (const auto &C : OptimizerLastEPCallbacks)
+          C(MPM, OptLevel);
+#else
         if (!OptimizerLastEPCallbacks.empty()) {
           FunctionPassManager FPM(DebugPassManager);
           for (const auto &C : OptimizerLastEPCallbacks)
             C(FPM, OptLevel);
           MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
         }
+#endif
         break;
       case LLVMRustOptStage::PreLinkFatLTO:
         MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
@@ -987,10 +1042,10 @@ public:
     const Value *Value;
     if (const CallInst *CI = dyn_cast<CallInst>(I)) {
       Name = "call";
-      Value = CI->getCalledValue();
+      Value = CI->getCalledOperand();
     } else if (const InvokeInst* II = dyn_cast<InvokeInst>(I)) {
       Name = "invoke";
-      Value = II->getCalledValue();
+      Value = II->getCalledOperand();
     } else {
       // Could demangle more operations, e. g.
       // `store %place, @function`.
@@ -1328,10 +1383,33 @@ LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
 // `ProcessThinLTOModule` function. Here they're split up into separate steps
 // so rustc can save off the intermediate bytecode between each step.
 
+#if LLVM_VERSION_GE(11, 0)
+static bool
+clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
+  // When linking an ELF shared object, dso_local should be dropped. We
+  // conservatively do this for -fpic.
+  bool ClearDSOLocalOnDeclarations =
+      TM.getTargetTriple().isOSBinFormatELF() &&
+      TM.getRelocationModel() != Reloc::Static &&
+      Mod.getPIELevel() == PIELevel::Default;
+  return ClearDSOLocalOnDeclarations;
+}
+#endif
+
 extern "C" bool
-LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
+                             LLVMTargetMachineRef TM) {
   Module &Mod = *unwrap(M);
-  if (renameModuleForThinLTO(Mod, Data->Index)) {
+  TargetMachine &Target = *unwrap(TM);
+
+#if LLVM_VERSION_GE(11, 0)
+  bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
+  bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
+#else
+  bool error = renameModuleForThinLTO(Mod, Data->Index);
+#endif
+
+  if (error) {
     LLVMRustSetLastError("renameModuleForThinLTO failed");
     return false;
   }
@@ -1355,8 +1433,10 @@ LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef
 }
 
 extern "C" bool
-LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
+                             LLVMTargetMachineRef TM) {
   Module &Mod = *unwrap(M);
+  TargetMachine &Target = *unwrap(TM);
 
   const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
   auto Loader = [&](StringRef Identifier) {
@@ -1392,7 +1472,12 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
 
     return MOrErr;
   };
+#if LLVM_VERSION_GE(11, 0)
+  bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
+  FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
+#else
   FunctionImporter Importer(Data->Index, Loader);
+#endif
   Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
   if (!Result) {
     LLVMRustSetLastError(toString(Result.takeError()).c_str());
@@ -1551,22 +1636,11 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
   }
 
   // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and
-  // process it recursively. Note that we specifically iterate over instructions
-  // to ensure we feed everything into it.
+  // process it recursively. Note that we used to specifically iterate over
+  // instructions to ensure we feed everything into it, but `processModule`
+  // started doing this the same way in LLVM 7 (commit d769eb36ab2b8).
   DebugInfoFinder Finder;
   Finder.processModule(*M);
-  for (Function &F : M->functions()) {
-    for (auto &FI : F) {
-      for (Instruction &BI : FI) {
-        if (auto Loc = BI.getDebugLoc())
-          Finder.processLocation(*M, Loc);
-        if (auto DVI = dyn_cast<DbgValueInst>(&BI))
-          Finder.processValue(*M, DVI);
-        if (auto DDI = dyn_cast<DbgDeclareInst>(&BI))
-          Finder.processDeclare(*M, DDI);
-      }
-    }
-  }
 
   // After we've found all our debuginfo, rewrite all subprograms to point to
   // the same `DICompileUnit`.
index 4704622922af04fc200e70e7265f3173f59be91a..063b6acc604ea543bf828ef7ca428157e9892aeb 100644 (file)
@@ -1,10 +1,10 @@
 #include "rustllvm.h"
-#include "llvm/IR/CallSite.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Bitcode/BitcodeWriterPass.h"
@@ -213,50 +213,50 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
 
 extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index,
                                              LLVMRustAttribute RustAttr) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr));
-  Call.addAttribute(Index, Attr);
+  Call->addAttribute(Index, Attr);
 }
 
 extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
                                                  unsigned Index,
                                                  uint32_t Bytes) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   AttrBuilder B;
   B.addAlignmentAttr(Bytes);
-  Call.setAttributes(Call.getAttributes().addAttributes(
+  Call->setAttributes(Call->getAttributes().addAttributes(
       Call->getContext(), Index, B));
 }
 
 extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr,
                                                        unsigned Index,
                                                        uint64_t Bytes) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   AttrBuilder B;
   B.addDereferenceableAttr(Bytes);
-  Call.setAttributes(Call.getAttributes().addAttributes(
+  Call->setAttributes(Call->getAttributes().addAttributes(
       Call->getContext(), Index, B));
 }
 
 extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr,
                                                              unsigned Index,
                                                              uint64_t Bytes) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
   AttrBuilder B;
   B.addDereferenceableOrNullAttr(Bytes);
-  Call.setAttributes(Call.getAttributes().addAttributes(
+  Call->setAttributes(Call->getAttributes().addAttributes(
       Call->getContext(), Index, B));
 }
 
 extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index,
                                              LLVMTypeRef Ty) {
-  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  CallBase *Call = unwrap<CallBase>(Instr);
 #if LLVM_VERSION_GE(9, 0)
   Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty));
 #else
   Attribute Attr = Attribute::get(Call->getContext(), Attribute::ByVal);
 #endif
-  Call.addAttribute(Index, Attr);
+  Call->addAttribute(Index, Attr);
 }
 
 extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
@@ -335,20 +335,24 @@ extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) {
 extern "C" LLVMValueRef
 LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMValueRef Source, const char *Name,
                         LLVMAtomicOrdering Order) {
-  LoadInst *LI = new LoadInst(unwrap(Source));
+  Value *Ptr = unwrap(Source);
+  Type *Ty = Ptr->getType()->getPointerElementType();
+  LoadInst *LI = unwrap(B)->CreateLoad(Ty, Ptr, Name);
   LI->setAtomic(fromRust(Order));
-  return wrap(unwrap(B)->Insert(LI, Name));
+  return wrap(LI);
 }
 
 extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B,
                                                  LLVMValueRef V,
                                                  LLVMValueRef Target,
                                                  LLVMAtomicOrdering Order) {
-  StoreInst *SI = new StoreInst(unwrap(V), unwrap(Target));
+  StoreInst *SI = unwrap(B)->CreateStore(unwrap(V), unwrap(Target));
   SI->setAtomic(fromRust(Order));
-  return wrap(unwrap(B)->Insert(SI));
+  return wrap(SI);
 }
 
+// FIXME: Use the C-API LLVMBuildAtomicCmpXchg and LLVMSetWeak
+// once we raise our minimum support to LLVM 10.
 extern "C" LLVMValueRef
 LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target,
                            LLVMValueRef Old, LLVMValueRef Source,
@@ -964,8 +968,14 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
     const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
+#if LLVM_VERSION_GE(11, 0)
+  bool IsDefault = false; // FIXME: should we ever set this true?
+  return wrap(Builder->createTemplateTypeParameter(
+      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
+#else
   return wrap(Builder->createTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
+#endif
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
@@ -1226,12 +1236,23 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMArrayTypeKind;
   case Type::PointerTyID:
     return LLVMPointerTypeKind;
+#if LLVM_VERSION_GE(11, 0)
+  case Type::FixedVectorTyID:
+    return LLVMVectorTypeKind;
+#else
   case Type::VectorTyID:
     return LLVMVectorTypeKind;
+#endif
   case Type::X86_MMXTyID:
     return LLVMX86_MMXTypeKind;
   case Type::TokenTyID:
     return LLVMTokenTypeKind;
+#if LLVM_VERSION_GE(11, 0)
+  case Type::ScalableVectorTyID:
+    return LLVMScalableVectorTypeKind;
+  case Type::BFloatTyID:
+    return LLVMBFloatTypeKind;
+#endif
   }
   report_fatal_error("Unhandled TypeID.");
 }
@@ -1358,10 +1379,17 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
 extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
                                           LLVMValueRef *Args, unsigned NumArgs,
                                           OperandBundleDef *Bundle) {
+  Value *Callee = unwrap(Fn);
+  FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
   unsigned Len = Bundle ? 1 : 0;
   ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
   return wrap(unwrap(B)->CreateCall(
-      unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles));
+      FTy, Callee, makeArrayRef(unwrap(Args), NumArgs), Bundles));
+}
+
+extern "C" LLVMValueRef LLVMRustGetInstrprofIncrementIntrinsic(LLVMModuleRef M) {
+  return wrap(llvm::Intrinsic::getDeclaration(unwrap(M),
+              (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment));
 }
 
 extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
@@ -1416,9 +1444,11 @@ LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
                     unsigned NumArgs, LLVMBasicBlockRef Then,
                     LLVMBasicBlockRef Catch, OperandBundleDef *Bundle,
                     const char *Name) {
+  Value *Callee = unwrap(Fn);
+  FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
   unsigned Len = Bundle ? 1 : 0;
   ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
-  return wrap(unwrap(B)->CreateInvoke(unwrap(Fn), unwrap(Then), unwrap(Catch),
+  return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
                                       makeArrayRef(unwrap(Args), NumArgs),
                                       Bundles, Name));
 }
index 5e840b9db199497f6c88d9b418579a87afe4b34b..769ec669bdc8da412687430df97beaad07ea0490 100644 (file)
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.(x+1).0` for Cargo where they were released on `date`.
 
-date: 2020-06-03
+date: 2020-06-16
 rustc: beta
 cargo: beta
 
diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs
new file mode 100644 (file)
index 0000000..ba2d8a3
--- /dev/null
@@ -0,0 +1,130 @@
+// no-system-llvm
+// assembly-output: emit-asm
+// compile-flags: --target hexagon-unknown-linux-musl
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(asm_sub_register, non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! stringify {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const i32;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for f32 {}
+impl Copy for ptr {}
+extern "C" {
+    fn extern_func();
+    static extern_static: u8;
+}
+
+macro_rules! check {
+    ($func:ident $ty:ident $class:ident) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            // Hack to avoid function merging
+            extern "Rust" {
+                fn dont_merge(s: &str);
+            }
+            dont_merge(stringify!($func));
+
+            let y;
+            asm!("{} = {}", out($class) y, in($class) x);
+            y
+        }
+    };
+}
+
+// CHECK-LABEL: sym_static:
+// CHECK: InlineAsm Start
+// CHECK: r0 = #extern_static
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn sym_static() {
+    // Hack to avoid function merging
+    extern "Rust" {
+        fn dont_merge(s: &str);
+    }
+    dont_merge(stringify!($func));
+
+    asm!("r0 = #{}", sym extern_static);
+}
+
+// CHECK-LABEL: sym_fn:
+// CHECK: InlineAsm Start
+// CHECK: r0 = #extern_func
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn sym_fn() {
+    // Hack to avoid function merging
+    extern "Rust" {
+        fn dont_merge(s: &str);
+    }
+    dont_merge(stringify!($func));
+
+    asm!("r0 = #{}", sym extern_func);
+}
+
+// This is a test for multi-instruction packets,
+// which require the escaped braces.
+//
+// CHECK-LABEL: packet:
+// CHECK: InlineAsm Start
+// CHECK: {
+// CHECK:   r{{[0-9]+}} = r0
+// CHECK:   memw(r1) = r{{[0-9]+}}
+// CHECK: }
+// CHECK: InlineAsm End
+#[no_mangle]
+pub unsafe fn packet() {
+    let val = 1024;
+    asm!("{{
+        {} = r0
+        memw(r1) = {}
+    }}", out(reg) _, in(reg) &val);
+}
+
+// CHECK-LABEL: ptr:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_ptr ptr reg);
+
+// CHECK-LABEL: reg_f32:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_f32 f32 reg);
+
+// CHECK-LABEL: reg_i32:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i32 i32 reg);
+
+// CHECK-LABEL: reg_i8:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_i16:
+// CHECK: InlineAsm Start
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: InlineAsm End
+check!(reg_i16 i16 reg);
diff --git a/src/test/codegen-units/partitioning/compiler-builtins.rs b/src/test/codegen-units/partitioning/compiler-builtins.rs
deleted file mode 100644 (file)
index 2519574..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Verifies that during compiler_builtins compilation the codegen units are kept
-// unmerged. Even when only a single codegen unit is requested with -Ccodegen-units=1.
-//
-// compile-flags: -Zprint-mono-items=eager -Ccodegen-units=1
-
-#![compiler_builtins]
-#![crate_type="lib"]
-#![feature(compiler_builtins)]
-
-mod atomics {
-    //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_1[0] @@ compiler_builtins-cgu.0[External]
-    #[no_mangle]
-    pub extern "C" fn sync_1() {}
-
-    //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_2[0] @@ compiler_builtins-cgu.0[External]
-    #[no_mangle]
-    pub extern "C" fn sync_2() {}
-
-    //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_3[0] @@ compiler_builtins-cgu.0[External]
-    #[no_mangle]
-    pub extern "C" fn sync_3() {}
-}
-
-mod x {
-    //~ MONO_ITEM fn compiler_builtins::x[0]::x[0] @@ compiler_builtins-cgu.1[External]
-    #[no_mangle]
-    pub extern "C" fn x() {}
-}
-
-mod y {
-    //~ MONO_ITEM fn compiler_builtins::y[0]::y[0] @@ compiler_builtins-cgu.2[External]
-    #[no_mangle]
-    pub extern "C" fn y() {}
-}
-
-mod z {
-    //~ MONO_ITEM fn compiler_builtins::z[0]::z[0] @@ compiler_builtins-cgu.3[External]
-    #[no_mangle]
-    pub extern "C" fn z() {}
-}
diff --git a/src/test/codegen/asm-multiple-options.rs b/src/test/codegen/asm-multiple-options.rs
new file mode 100644 (file)
index 0000000..c702742
--- /dev/null
@@ -0,0 +1,53 @@
+// compile-flags: -O
+// only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm)]
+
+// CHECK-LABEL: @pure
+// CHECK-NOT: asm
+// CHECK: ret void
+#[no_mangle]
+pub unsafe fn pure(x: i32) {
+    let y: i32;
+    asm!("", out("ax") y, in("bx") x, options(pure), options(nomem));
+}
+
+pub static mut VAR: i32 = 0;
+pub static mut DUMMY_OUTPUT: i32 = 0;
+
+// CHECK-LABEL: @readonly
+// CHECK: call i32 asm
+// CHECK: ret i32 1
+#[no_mangle]
+pub unsafe fn readonly() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+    VAR
+}
+
+// CHECK-LABEL: @nomem
+// CHECK-NOT: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem));
+    VAR = 2;
+    VAR
+}
+
+// CHECK-LABEL: @not_nomem
+// CHECK: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn not_nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+    VAR = 2;
+    VAR
+}
diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs
new file mode 100644 (file)
index 0000000..4e145b8
--- /dev/null
@@ -0,0 +1,48 @@
+// Verify debuginfo for generators:
+//  - Each variant points to the file and line of its yield point
+//  - The generator types and variants are marked artificial
+//  - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2 --edition=2018
+// only-msvc
+
+async fn foo() {}
+async fn async_fn_test() {
+    foo().await;
+    let s = String::from("foo");
+    foo().await;
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// For brevity, we only check the struct name and members of the last variant.
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 12,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 14,
+// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+
+fn main() {
+    let _dummy = async_fn_test();
+}
diff --git a/src/test/codegen/async-fn-debug.rs b/src/test/codegen/async-fn-debug.rs
new file mode 100644 (file)
index 0000000..8fa4be1
--- /dev/null
@@ -0,0 +1,51 @@
+// Verify debuginfo for async fn:
+//  - Each variant points to the file and line of its yield point
+//  - The generator types and variants are marked artificial
+//  - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2 --edition=2018
+// ignore-msvc
+
+async fn foo() {}
+async fn async_fn_test() {
+    foo().await;
+    let s = String::from("foo");
+    foo().await;
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 12,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 14,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[ASYNC_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+
+fn main() {
+    let _dummy = async_fn_test();
+}
diff --git a/src/test/codegen/cdylib-external-inline-fns.rs b/src/test/codegen/cdylib-external-inline-fns.rs
new file mode 100644 (file)
index 0000000..519be6b
--- /dev/null
@@ -0,0 +1,43 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "cdylib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
+
+// CHECK: define void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
index 40a7353eac0454f7fe00699aab5d94a25eca38eb..96f9158f9d39498b17a23d3445c326822e2bb8b4 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z control_flow_guard=checks
+// compile-flags: -Z control-flow-guard=checks
 
 #![crate_type = "lib"]
 
index d1747931e15c8255959026e87f9de0204a0fc6c4..1325ffc0f2595d3b76505cdb40daebf94ba77318 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z control_flow_guard=disabled
+// compile-flags: -Z control-flow-guard=no
 
 #![crate_type = "lib"]
 
index c5d7afbae257b57276797ded41e898e9e38fdfd8..ae1de4c4d26d543b6f6c7a1a309a9f04bf14064d 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Z control_flow_guard=nochecks
+// compile-flags: -Z control-flow-guard=nochecks
 
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/debug-linkage-name.rs b/src/test/codegen/debug-linkage-name.rs
new file mode 100644 (file)
index 0000000..0d7dca3
--- /dev/null
@@ -0,0 +1,42 @@
+// Verifies that linkage name is omitted when it is
+// the same as variable / function name.
+//
+// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C debuginfo=2
+#![crate_type = "lib"]
+
+pub mod xyz {
+    // CHECK: !DIGlobalVariable(name: "A",
+    // CHECK:                   linkageName:
+    // CHECK-SAME:              line: 12,
+    pub static A: u32 = 1;
+
+    // CHECK: !DIGlobalVariable(name: "B",
+    // CHECK-NOT:               linkageName:
+    // CHECK-SAME:              line: 18,
+    #[no_mangle]
+    pub static B: u32 = 2;
+
+    // CHECK: !DIGlobalVariable(name: "C",
+    // CHECK-NOT:               linkageName:
+    // CHECK-SAME:              line: 24,
+    #[export_name = "C"]
+    pub static C: u32 = 2;
+
+    // CHECK: !DISubprogram(name: "e",
+    // CHECK:               linkageName:
+    // CHECK-SAME:          line: 29,
+    pub extern fn e() {}
+
+    // CHECK: !DISubprogram(name: "f",
+    // CHECK-NOT:           linkageName:
+    // CHECK-SAME:          line: 35,
+    #[no_mangle]
+    pub extern fn f() {}
+
+    // CHECK: !DISubprogram(name: "g",
+    // CHECK-NOT:           linkageName:
+    // CHECK-SAME:          line: 41,
+    #[export_name = "g"]
+    pub extern fn g() {}
+}
index 78d41e4be0ae9c5848bd1b4c89fb7cfb564666b1..59e97601c838d6427d6e741e1a91aa97aa64b8cc 100644 (file)
@@ -11,11 +11,21 @@ mod private {
     #[export_name = "BAR"]
     static BAR: u32 = 3;
 
-    // CHECK: void @foo()
+    // CHECK: void @a()
     #[no_mangle]
-    pub extern fn foo() {}
+    pub extern fn a() {}
 
-    // CHECK: void @bar()
-    #[export_name = "bar"]
-    extern fn bar() {}
+    // CHECK: void @b()
+    #[export_name = "b"]
+    extern fn b() {}
+
+    // CHECK: void @c()
+    #[export_name = "c"]
+    #[inline]
+    extern fn c() {}
+
+    // CHECK: void @d()
+    #[export_name = "d"]
+    #[inline(always)]
+    extern fn d() {}
 }
index 902882144996fe6ef875ecb938a5446d06d27806..41820b057f1ef27710bf098403d3829daee3dac8 100644 (file)
@@ -53,3 +53,23 @@ pub fn h() {}
         core::ptr::read_volatile(&42);
     }
 }
+
+// CHECK: define void @i()
+#[no_mangle]
+#[inline]
+fn i() {}
+
+// CHECK: define void @j()
+#[no_mangle]
+#[inline]
+pub fn j() {}
+
+// CHECK: define void @k()
+#[no_mangle]
+#[inline(always)]
+fn k() {}
+
+// CHECK: define void @l()
+#[no_mangle]
+#[inline(always)]
+pub fn l() {}
diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs
new file mode 100644 (file)
index 0000000..82a1568
--- /dev/null
@@ -0,0 +1,52 @@
+// Verify debuginfo for generators:
+//  - Each variant points to the file and line of its yield point
+//  - The generator types and variants are marked artificial
+//  - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2
+// only-msvc
+
+#![feature(generators, generator_trait)]
+use std::ops::Generator;
+
+fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
+    || {
+        yield 0;
+        let s = String::from("foo");
+        yield 1;
+    }
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// For brevity, we only check the struct name and members of the last variant.
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-SAME: file: [[FILE]], line: 17,
+// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+
+fn main() {
+    let _dummy = generator_test();
+}
diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs
new file mode 100644 (file)
index 0000000..5c7c641
--- /dev/null
@@ -0,0 +1,55 @@
+// Verify debuginfo for generators:
+//  - Each variant points to the file and line of its yield point
+//  - The generator types and variants are marked artificial
+//  - Captured vars from the source are not marked artificial
+//
+// ignore-tidy-linelength
+// compile-flags: -C debuginfo=2 --edition=2018
+// ignore-msvc
+
+#![feature(generators, generator_trait)]
+use std::ops::Generator;
+
+fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
+    || {
+        yield 0;
+        let s = String::from("foo");
+        yield 1;
+    }
+}
+
+// FIXME: No way to reliably check the filename.
+
+// CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 15,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
+// CHECK-SAME: file: [[FILE]], line: 17,
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
+// CHECK-SAME: flags: DIFlagArtificial
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
+// CHECK:      [[DISC]] = !DIDerivedType(tag: DW_TAG_member, name: "__state", scope: [[GEN_FN]],
+// CHECK-SAME: flags: DIFlagArtificial
+
+fn main() {
+    let _dummy = generator_test();
+}
diff --git a/src/test/codegen/issue-69101-bounds-check.rs b/src/test/codegen/issue-69101-bounds-check.rs
new file mode 100644 (file)
index 0000000..8ade583
--- /dev/null
@@ -0,0 +1,44 @@
+// no-system-llvm
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted in the loop when upfront slicing
+// ensures that the slices are big enough.
+// In particular, bounds checks were not always optimized out if the upfront
+// check was for a greater len than the loop requires.
+// (i.e. `already_sliced_no_bounds_check` was not always optimized even when
+// `already_sliced_no_bounds_check_exact` was)
+// CHECK-LABEL: @already_sliced_no_bounds_check
+#[no_mangle]
+pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+    // CHECK: slice_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
+    for i in 0..1024 {
+        c[i] = a[i] ^ b[i];
+    }
+}
+
+// CHECK-LABEL: @already_sliced_no_bounds_check_exact
+#[no_mangle]
+pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
+    // CHECK: slice_index_len_fail
+    // CHECK-NOT: panic_bounds_check
+    let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
+    for i in 0..1024 {
+        c[i] = a[i] ^ b[i];
+    }
+}
+
+// Make sure we're checking for the right thing: there can be a panic if the slice is too small.
+// CHECK-LABEL: @already_sliced_bounds_check
+#[no_mangle]
+pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
+    // CHECK: slice_index_len_fail
+    // CHECK: panic_bounds_check
+    let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
+    for i in 0..1024 {
+        c[i] = a[i] ^ b[i];
+    }
+}
index 8ea41c5d44bb1fe410807d3324a003fc8504d2ca..4bd50508d152056e13f7ecc21d80055ab00a6a45 100644 (file)
@@ -1,9 +1,7 @@
 // Verifies that MemorySanitizer track-origins level can be controlled
 // with -Zsanitizer-memory-track-origins option.
 //
-// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-memory
 // revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO
 //
 //[MSAN-0] compile-flags: -Zsanitizer=memory
index d96e76618d32501e33f91ac03276b177563ddf8c..be0547afa4cd5059432123f54ab40db0549d9e94 100644 (file)
@@ -1,11 +1,9 @@
 // Verifies that no_sanitize attribute prevents inlining when
 // given sanitizer is enabled, but has no effect on inlining otherwise.
 //
-// needs-sanitizer-support
-// only-x86_64
-//
+// needs-sanitizer-address
+// needs-sanitizer-leak
 // revisions: ASAN LSAN
-//
 //[ASAN] compile-flags: -Zsanitizer=address -C opt-level=3 -Z mir-opt-level=3
 //[LSAN] compile-flags: -Zsanitizer=leak    -C opt-level=3 -Z mir-opt-level=3
 
@@ -13,7 +11,7 @@
 #![feature(no_sanitize)]
 
 // ASAN-LABEL: define void @test
-// ASAN:         tail call fastcc void @random_inline
+// ASAN:         call {{.*}} @random_inline
 // ASAN:       }
 //
 // LSAN-LABEL: define void @test
index dfceb28c8dd107eaaa01eb5c87021c5241c9fe85..1b2b18822e63e8a8c673166bcb92bd0fdb99ac2f 100644 (file)
@@ -1,7 +1,7 @@
 // Verifies that no_sanitze attribute can be used to
 // selectively disable sanitizer instrumentation.
 //
-// needs-sanitizer-support
+// needs-sanitizer-address
 // compile-flags: -Zsanitizer=address
 
 #![crate_type="lib"]
index 05b4ab5653cc843e897838430312200385829ccb..433d32abd37c65b01de9d76180cce9209b564e1a 100644 (file)
@@ -1,9 +1,8 @@
 // Verifies that AddressSanitizer and MemorySanitizer
 // recovery mode can be enabled with -Zsanitizer-recover.
 //
-// needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-address
+// needs-sanitizer-memory
 // revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO
 // no-prefer-dynamic
 //
 // ASAN:               }
 //
 // MSAN-LABEL: define i32 @penguin(
-// MSAN:         call void @__msan_warning_noreturn()
+// MSAN:         call void @__msan_warning{{(_with_origin_noreturn\(i32 0\)|_noreturn\(\))}}
 // MSAN:         unreachable
 // MSAN:       }
 //
 // MSAN-RECOVER-LABEL: define i32 @penguin(
-// MSAN-RECOVER:         call void @__msan_warning()
+// MSAN-RECOVER:         call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
 // MSAN-RECOVER-NOT:     unreachable
 // MSAN-RECOVER:       }
 //
 // MSAN-RECOVER-LTO-LABEL: define i32 @penguin(
-// MSAN-RECOVER-LTO:          call void @__msan_warning()
+// MSAN-RECOVER-LTO:          call void @__msan_warning{{(_with_origin\(i32 0\)|\(\))}}
 // MSAN-RECOVER-LTO-NOT:      unreachable
 // MSAN-RECOVER-LTO:       }
 //
diff --git a/src/test/codegen/staticlib-external-inline-fns.rs b/src/test/codegen/staticlib-external-inline-fns.rs
new file mode 100644 (file)
index 0000000..8876ab7
--- /dev/null
@@ -0,0 +1,43 @@
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "staticlib"]
+
+// CHECK: define void @a()
+#[no_mangle]
+#[inline]
+pub extern "C" fn a() {}
+
+// CHECK: define void @b()
+#[export_name = "b"]
+#[inline]
+pub extern "C" fn b() {}
+
+// CHECK: define void @c()
+#[no_mangle]
+#[inline]
+extern "C" fn c() {}
+
+// CHECK: define void @d()
+#[export_name = "d"]
+#[inline]
+extern "C" fn d() {}
+
+// CHECK: define void @e()
+#[no_mangle]
+#[inline(always)]
+pub extern "C" fn e() {}
+
+// CHECK: define void @f()
+#[export_name = "f"]
+#[inline(always)]
+pub extern "C" fn f() {}
+
+// CHECK: define void @g()
+#[no_mangle]
+#[inline(always)]
+extern "C" fn g() {}
+
+// CHECK: define void @h()
+#[export_name = "h"]
+#[inline(always)]
+extern "C" fn h() {}
index b9ffce8b0cb3d180d269a2aab8587276bb60a08a..15bfe421e9d35911d8e1f4ad05e3187e4fb644bd 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-debug: the debug assertions get in the way
 // compile-flags: -O
 
 #![crate_type = "lib"]
index ebede0908c6c48d5ac0a01508e07f1d7c6245622..9143fad23408749b278aef4eb428397195a4db1d 100644 (file)
@@ -1,4 +1,3 @@
-//
 // ignore-debug: the debug assertions get in the way
 // no-system-llvm
 // compile-flags: -O
index 9761959335273ec05ac5e1934728e1f7d2562335..21bd6252219035f947e9a010d60743c8ddc8bcce 100644 (file)
@@ -1,15 +1,15 @@
 fn main() {
     [(); & { loop { continue } } ]; //~ ERROR mismatched types
-    //~^ ERROR `loop` is not allowed in a `const`
+
     [(); loop { break }]; //~ ERROR mismatched types
-    //~^ ERROR `loop` is not allowed in a `const`
+
     [(); {while true {break}; 0}];
-    //~^ ERROR `while` is not allowed in a `const`
-    //~| WARN denote infinite loops with
+    //~^ WARN denote infinite loops with
+
     [(); { for _ in 0usize.. {}; 0}];
     //~^ ERROR `for` is not allowed in a `const`
     //~| ERROR calls in constants are limited to constant functions
-    //~| ERROR references in constants may only refer to immutable values
+    //~| ERROR mutable references are not allowed in constants
     //~| ERROR calls in constants are limited to constant functions
     //~| ERROR evaluation of constant value failed
 }
index d9e5280c7e11d1aceed3ab7c7f8f31f78ed93fa5..958f0eb26680194b45bf0c235a10b4a8a6c108c0 100644 (file)
@@ -1,6 +1,6 @@
 // compile-fail
-
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 pub trait Foo {
     fn foo();
index 9742530bd812fef1f0cbf20becfc29cf1153a110..07793b3598f9ead5b07ea7d87856469ade523520 100644 (file)
@@ -12,7 +12,7 @@
 | 8: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
 | 9: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
 | 10: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:18:5: 18:18
-| 11: Canonical { max_universe: U3, variables: [CanonicalVarInfo { kind: Region(U3) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
+| 11: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
 | 12: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
 | 13: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
 | 14: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) } at $DIR/address-of.rs:24:12: 24:28
@@ -22,7 +22,7 @@
 | 18: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
 | 19: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
 | 20: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:28:5: 28:16
-| 21: Canonical { max_universe: U6, variables: [CanonicalVarInfo { kind: Region(U6) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
+| 21: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
 | 22: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
 | 23: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
 | 24: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) } at $DIR/address-of.rs:34:12: 34:26
@@ -128,7 +128,7 @@ fn address_of_reborrow() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/address-of.rs:4:9: 4:10
         StorageLive(_2);                 // scope 0 at $DIR/address-of.rs:4:14: 4:21
-        _2 = [const 0i32; 10];           // scope 0 at $DIR/address-of.rs:4:14: 4:21
+        _2 = [const 0_i32; 10];          // scope 0 at $DIR/address-of.rs:4:14: 4:21
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
@@ -139,7 +139,7 @@ fn address_of_reborrow() -> () {
         FakeRead(ForLet, _1);            // scope 0 at $DIR/address-of.rs:4:9: 4:10
         StorageLive(_3);                 // scope 1 at $DIR/address-of.rs:5:9: 5:14
         StorageLive(_4);                 // scope 1 at $DIR/address-of.rs:5:22: 5:29
-        _4 = [const 0i32; 10];           // scope 1 at $DIR/address-of.rs:5:22: 5:29
+        _4 = [const 0_i32; 10];          // scope 1 at $DIR/address-of.rs:5:22: 5:29
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
index d39b9b8a3b4447bc14b14c822b90d82c99c89f09..2a3a18d6c5b5dbe50f429fb12b81346f550514ee 100644 (file)
@@ -25,7 +25,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14
-        _1 = [const 42u32, const 43u32, const 44u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
+        _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x0000002a))
@@ -45,7 +45,7 @@ fn main() -> () {
                                          // + span: $DIR/array-index-is-temporary.rs:13:26: 13:28
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000002c)) }
         StorageLive(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14
-        _2 = const 1usize;               // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
+        _2 = const 1_usize;              // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000001))
index 381c1ca6f22efc163563e3e052d1bf004ce9ad1e..093c170cf7a3a41ae68187368e7e4801e39579ae 100644 (file)
@@ -25,7 +25,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:13:9: 13:14
-        _1 = [const 42u32, const 43u32, const 44u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
+        _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:13:17: 13:29
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x0000002a))
@@ -45,7 +45,7 @@ fn main() -> () {
                                          // + span: $DIR/array-index-is-temporary.rs:13:26: 13:28
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000002c)) }
         StorageLive(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14
-        _2 = const 1usize;               // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
+        _2 = const 1_usize;              // scope 1 at $DIR/array-index-is-temporary.rs:14:17: 14:18
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000001))
index 88cb09ac15a9cc030a6f4f602e58189605aad2a1..54e01dceb5099967c27e37e63f62f1f99ec60eda 100644 (file)
@@ -21,7 +21,7 @@ fn main() -> () {
                                          // + span: $DIR/byte_slice.rs:5:13: 5:19
                                          // + literal: Const { ty: &[u8; 3], val: Value(Scalar(alloc0)) }
         StorageLive(_2);                 // scope 1 at $DIR/byte_slice.rs:6:9: 6:10
-        _2 = [const 5u8, const 120u8];   // scope 1 at $DIR/byte_slice.rs:6:13: 6:24
+        _2 = [const 5_u8, const 120_u8]; // scope 1 at $DIR/byte_slice.rs:6:13: 6:24
                                          // ty::Const
                                          // + ty: u8
                                          // + val: Value(Scalar(0x05))
index e11619cf0cd0eb14da1cee8ab0fc74bce3faf5e3..65db967fe5f81f81afeb3e4d7777be114e4f2c24 100644 (file)
@@ -28,7 +28,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/combine_array_len.rs:5:9: 5:10
           StorageLive(_3);                 // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
-          _3 = const 0usize;               // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
+          _3 = const 0_usize;              // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000000))
@@ -36,7 +36,7 @@
                                            // + span: $DIR/combine_array_len.rs:5:15: 5:16
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
 -         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
-+         _4 = const 2usize;               // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
++         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x00000002))
@@ -52,7 +52,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/combine_array_len.rs:5:17: 5:18
           StorageLive(_6);                 // scope 1 at $DIR/combine_array_len.rs:6:9: 6:10
           StorageLive(_7);                 // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
-          _7 = const 1usize;               // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
+          _7 = const 1_usize;              // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000001))
@@ -60,7 +60,7 @@
                                            // + span: $DIR/combine_array_len.rs:6:15: 6:16
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
 -         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
-+         _8 = const 2usize;               // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
++         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x00000002))
index 050cfe359a17513e3c9ff7c36353b90f3178b985..712c4eb230c7eef2a522c395d1aae33dca3ca805 100644 (file)
@@ -28,7 +28,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/combine_array_len.rs:5:9: 5:10
           StorageLive(_3);                 // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
-          _3 = const 0usize;               // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
+          _3 = const 0_usize;              // scope 0 at $DIR/combine_array_len.rs:5:15: 5:16
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000000))
@@ -36,7 +36,7 @@
                                            // + span: $DIR/combine_array_len.rs:5:15: 5:16
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
 -         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
-+         _4 = const 2usize;               // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
++         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x0000000000000002))
@@ -52,7 +52,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/combine_array_len.rs:5:17: 5:18
           StorageLive(_6);                 // scope 1 at $DIR/combine_array_len.rs:6:9: 6:10
           StorageLive(_7);                 // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
-          _7 = const 1usize;               // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
+          _7 = const 1_usize;              // scope 1 at $DIR/combine_array_len.rs:6:15: 6:16
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000001))
@@ -60,7 +60,7 @@
                                            // + span: $DIR/combine_array_len.rs:6:15: 6:16
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
 -         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
-+         _8 = const 2usize;               // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
++         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x0000000000000002))
index f4b6c7db444e5a11c52c2a15cbfc5d5919f5cbb2..e84e88b93fcd8a3af3ff39ecef9ec01c3ad04114 100644 (file)
@@ -14,7 +14,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/aggregate.rs:5:9: 5:10
           StorageLive(_2);                 // scope 0 at $DIR/aggregate.rs:5:13: 5:24
           StorageLive(_3);                 // scope 0 at $DIR/aggregate.rs:5:13: 5:22
-          _3 = (const 0i32, const 1i32, const 2i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:22
+          _3 = (const 0_i32, const 1_i32, const 2_i32); // scope 0 at $DIR/aggregate.rs:5:13: 5:22
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
@@ -34,8 +34,8 @@
                                            // + span: $DIR/aggregate.rs:5:20: 5:21
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
 -         _2 = (_3.1: i32);                // scope 0 at $DIR/aggregate.rs:5:13: 5:24
--         _1 = Add(move _2, const 0i32);   // scope 0 at $DIR/aggregate.rs:5:13: 5:28
-+         _2 = const 1i32;                 // scope 0 at $DIR/aggregate.rs:5:13: 5:24
+-         _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/aggregate.rs:5:13: 5:28
++         _2 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:5:13: 5:24
                                            // ty::Const
                                            // + ty: i32
 -                                          // + val: Value(Scalar(0x00000000))
@@ -45,7 +45,7 @@
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
 +                                          // + span: $DIR/aggregate.rs:5:13: 5:24
 +                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-+         _1 = const 1i32;                 // scope 0 at $DIR/aggregate.rs:5:13: 5:28
++         _1 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:5:13: 5:28
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000001))
index d02906132e296a9259dd15a6b36e27e308722f95..48908479935d1e2a2311e5fb627d882360e354a4 100644 (file)
@@ -15,7 +15,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/array_index.rs:5:9: 5:10
           StorageLive(_2);                 // scope 0 at $DIR/array_index.rs:5:18: 5:30
-          _2 = [const 0u32, const 1u32, const 2u32, const 3u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
+          _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x00000000))
                                            // + span: $DIR/array_index.rs:5:28: 5:29
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
           StorageLive(_3);                 // scope 0 at $DIR/array_index.rs:5:31: 5:32
-          _3 = const 2usize;               // scope 0 at $DIR/array_index.rs:5:31: 5:32
+          _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:5:31: 5:32
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
                                            // + span: $DIR/array_index.rs:5:31: 5:32
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
-          _4 = const 4usize;               // scope 0 at $DIR/array_index.rs:5:18: 5:33
+          _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:5:18: 5:33
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000004))
@@ -75,7 +75,7 @@
   
       bb1: {
 -         _1 = _2[_3];                     // scope 0 at $DIR/array_index.rs:5:18: 5:33
-+         _1 = const 2u32;                 // scope 0 at $DIR/array_index.rs:5:18: 5:33
++         _1 = const 2_u32;                // scope 0 at $DIR/array_index.rs:5:18: 5:33
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000002))
index 4fe3f08955894cb2046d41d1a4260801b94e4292..fd662698a0fd431b4003d4156907aeca2e5c15ce 100644 (file)
@@ -15,7 +15,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/array_index.rs:5:9: 5:10
           StorageLive(_2);                 // scope 0 at $DIR/array_index.rs:5:18: 5:30
-          _2 = [const 0u32, const 1u32, const 2u32, const 3u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
+          _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:5:18: 5:30
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x00000000))
                                            // + span: $DIR/array_index.rs:5:28: 5:29
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
           StorageLive(_3);                 // scope 0 at $DIR/array_index.rs:5:31: 5:32
-          _3 = const 2usize;               // scope 0 at $DIR/array_index.rs:5:31: 5:32
+          _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:5:31: 5:32
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000002))
                                            // mir::Constant
                                            // + span: $DIR/array_index.rs:5:31: 5:32
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
-          _4 = const 4usize;               // scope 0 at $DIR/array_index.rs:5:18: 5:33
+          _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:5:18: 5:33
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000004))
@@ -75,7 +75,7 @@
   
       bb1: {
 -         _1 = _2[_3];                     // scope 0 at $DIR/array_index.rs:5:18: 5:33
-+         _1 = const 2u32;                 // scope 0 at $DIR/array_index.rs:5:18: 5:33
++         _1 = const 2_u32;                // scope 0 at $DIR/array_index.rs:5:18: 5:33
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000002))
index de06e5334e0408adda32abc5a4925c9555eba157..ed28678edb30d6aef09522d7760a799d7ba2cd58 100644 (file)
@@ -19,7 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_div_by_zero.rs:4:9: 4:10
-          _1 = const 0i32;                 // scope 0 at $DIR/bad_op_div_by_zero.rs:4:13: 4:14
+          _1 = const 0_i32;                // scope 0 at $DIR/bad_op_div_by_zero.rs:4:13: 4:14
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
@@ -29,8 +29,8 @@
           StorageLive(_2);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:9: 5:11
           StorageLive(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
 -         _3 = _1;                         // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
--         _4 = Eq(_3, const 0i32);         // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
-+         _3 = const 0i32;                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
+-         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
 +                                          // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-          assert(!move _4, "attempt to divide by zero") -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+          assert(!move _4, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
       }
   
       bb1: {
--         _5 = Eq(_3, const -1i32);        // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +         _5 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
                                            // ty::Const
 -                                          // + ty: i32
@@ -59,7 +65,7 @@
                                            // mir::Constant
                                            // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) }
--         _6 = Eq(const 1i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
 +         _6 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
                                            // ty::Const
                                            // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x80000000)) }
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
--         assert(!move _7, "attempt to divide with overflow") -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-         assert(!move _7, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         assert(!const false, "attempt to divide with overflow") -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++         assert(!const false, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +                                          // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
       }
   
       bb2: {
-          _2 = Div(const 1i32, move _3);   // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+          _2 = Div(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
index 7052c8387041b2d1772057268e918c5b7ea0ecb6..8855df95aeab5c5e2590cd81a8aeac12a13b05bd 100644 (file)
@@ -19,7 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:9: 4:10
-          _1 = const 0i32;                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:13: 4:14
+          _1 = const 0_i32;                // scope 0 at $DIR/bad_op_mod_by_zero.rs:4:13: 4:14
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
@@ -29,8 +29,8 @@
           StorageLive(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:9: 5:11
           StorageLive(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
 -         _3 = _1;                         // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
--         _4 = Eq(_3, const 0i32);         // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
-+         _3 = const 0i32;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
+-         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
 +                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-          assert(!move _4, "attempt to calculate the remainder with a divisor of zero") -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+          assert(!move _4, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
       }
   
       bb1: {
--         _5 = Eq(_3, const -1i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +         _5 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
                                            // ty::Const
 -                                          // + ty: i32
@@ -59,7 +65,7 @@
                                            // mir::Constant
                                            // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) }
--         _6 = Eq(const 1i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
 +         _6 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
                                            // ty::Const
                                            // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x80000000)) }
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
--         assert(!move _7, "attempt to calculate the remainder with overflow") -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-         assert(!move _7, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         assert(!const false, "attempt to calculate the remainder with overflow") -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++         assert(!const false, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +                                          // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
       }
   
       bb2: {
-          _2 = Rem(const 1i32, move _3);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+          _2 = Rem(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
index 7071f31dbf104d60324aee2279332ba9825053a7..ee4d4c39f172ca41b76f36e968fa43bfcfce3fa6 100644 (file)
           StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36
           StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
           StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
-          _6 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000003))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
--         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: usize
-+                                          // + val: Value(Scalar(0x00000003))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
-+         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x00))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
           assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
index 15995ab070019842123a9424033798a69999a48d..3626814fa977017b16603db172f6aa0caf13c707 100644 (file)
           StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:35: 5:36
           StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:13: 7:15
           StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
-          _6 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
+          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000003))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
--         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: usize
-+                                          // + val: Value(Scalar(0x0000000000000003))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
-+         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x00))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
           assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
index 16f937f3e7b5efd7fb33f0a787d50fadcb3bc130..f271188ebfdb0bf755e1109248bd88735c7567b3 100644 (file)
@@ -17,7 +17,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/boxes.rs:12:14: 12:22
           StorageLive(_4);                 // scope 0 at $DIR/boxes.rs:12:14: 12:22
           _4 = Box(i32);                   // scope 0 at $DIR/boxes.rs:12:14: 12:22
-          (*_4) = const 42i32;             // scope 0 at $DIR/boxes.rs:12:19: 12:21
+          (*_4) = const 42_i32;            // scope 0 at $DIR/boxes.rs:12:19: 12:21
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
@@ -27,7 +27,7 @@
           _3 = move _4;                    // scope 0 at $DIR/boxes.rs:12:14: 12:22
           StorageDead(_4);                 // scope 0 at $DIR/boxes.rs:12:21: 12:22
           _2 = (*_3);                      // scope 0 at $DIR/boxes.rs:12:13: 12:22
-          _1 = Add(move _2, const 0i32);   // scope 0 at $DIR/boxes.rs:12:13: 12:26
+          _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/boxes.rs:12:13: 12:26
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
index 58c27c5a20f8cfc93b022be478420be10a546fd7..54af804d19b000701291b43b06f2c07ecf087ae2 100644 (file)
@@ -14,8 +14,8 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/cast.rs:4:9: 4:10
--         _1 = const 42u8 as u32 (Misc);   // scope 0 at $DIR/cast.rs:4:13: 4:24
-+         _1 = const 42u32;                // scope 0 at $DIR/cast.rs:4:13: 4:24
+-         _1 = const 42_u8 as u32 (Misc);  // scope 0 at $DIR/cast.rs:4:13: 4:24
++         _1 = const 42_u32;               // scope 0 at $DIR/cast.rs:4:13: 4:24
                                            // ty::Const
 -                                          // + ty: u8
 -                                          // + val: Value(Scalar(0x2a))
@@ -23,7 +23,7 @@
 -                                          // + span: $DIR/cast.rs:4:13: 4:17
 -                                          // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) }
 -         StorageLive(_2);                 // scope 1 at $DIR/cast.rs:6:9: 6:10
--         _2 = const 42u32 as u8 (Misc);   // scope 1 at $DIR/cast.rs:6:13: 6:24
+-         _2 = const 42_u32 as u8 (Misc);  // scope 1 at $DIR/cast.rs:6:13: 6:24
 -                                          // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000002a))
@@ -32,7 +32,7 @@
 +                                          // + span: $DIR/cast.rs:4:13: 4:24
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
 +         StorageLive(_2);                 // scope 1 at $DIR/cast.rs:6:9: 6:10
-+         _2 = const 42u8;                 // scope 1 at $DIR/cast.rs:6:13: 6:24
++         _2 = const 42_u8;                // scope 1 at $DIR/cast.rs:6:13: 6:24
 +                                          // ty::Const
 +                                          // + ty: u8
 +                                          // + val: Value(Scalar(0x2a))
index f9f7d543d21f514153cc1836b7abb1b1d7f8798e..e3690d71294979dc7fb5a04ce5b4a7121015c2a0 100644 (file)
@@ -11,8 +11,8 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/checked_add.rs:5:9: 5:10
--         _2 = CheckedAdd(const 1u32, const 1u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+         _2 = (const 2u32, const false);  // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+-         _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
++         _2 = (const 2_u32, const false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
                                            // ty::Const
                                            // + ty: u32
 -                                          // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
 -                                          // + span: $DIR/checked_add.rs:5:22: 5:23
 -                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
--         assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
 +                                          // + span: $DIR/checked_add.rs:5:18: 5:23
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+                                          // ty::Const
++         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+                                           // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/checked_add.rs:5:18: 5:23
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++                                          // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/checked_add.rs:5:18: 5:19
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+                                           // + span: $DIR/checked_add.rs:5:22: 5:23
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
       }
   
       bb1: {
 -         _1 = move (_2.0: u32);           // scope 0 at $DIR/checked_add.rs:5:18: 5:23
-+         _1 = const 2u32;                 // scope 0 at $DIR/checked_add.rs:5:18: 5:23
++         _1 = const 2_u32;                // scope 0 at $DIR/checked_add.rs:5:18: 5:23
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000002))
index 04541b94ad7801a0e5d466144da1388a84c0b05e..13e8eb3e44e1aeb03471c8e2506a38b054bd7601 100644 (file)
@@ -1,5 +1,10 @@
 // compile-flags: -O
 
+// FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
+// `let x = 42` but that doesn't work because const-prop doesn't support `Operand::Indirect`
+// and `InterpCx::eval_place()` always forces an allocation which creates the `Indirect`.
+// Fixing either of those will allow us to const-prop this away.
+
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR rustc.main.ConstProp.diff
 fn main() {
index 9979ea9549891202df9d3e56b9f8279b497e0fdf..26010b43c922ae80dcefc7c5e579958a9dc7333a 100644 (file)
 + // MIR for `main` after ConstProp
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11
-      let _1: i32;                         // in scope 0 at $DIR/discriminant.rs:6:9: 6:10
-      let mut _2: i32;                     // in scope 0 at $DIR/discriminant.rs:6:13: 6:64
-      let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44
-      let mut _4: isize;                   // in scope 0 at $DIR/discriminant.rs:6:21: 6:31
+      let mut _0: ();                      // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11
+      let _1: i32;                         // in scope 0 at $DIR/discriminant.rs:11:9: 11:10
+      let mut _2: i32;                     // in scope 0 at $DIR/discriminant.rs:11:13: 11:64
+      let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44
+      let mut _4: isize;                   // in scope 0 at $DIR/discriminant.rs:11:21: 11:31
       scope 1 {
-          debug x => _1;                   // in scope 1 at $DIR/discriminant.rs:6:9: 6:10
+          debug x => _1;                   // in scope 1 at $DIR/discriminant.rs:11:9: 11:10
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:6:9: 6:10
-          StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:6:13: 6:64
-          StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:6:34: 6:44
--         _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-+         _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
+          StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:11:9: 11:10
+          StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:11:13: 11:64
+          StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+-         _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
++         _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
                                            // ty::Const
 -                                          // + ty: bool
 +                                          // + ty: std::option::Option<bool>
                                            // + val: Value(Scalar(0x01))
                                            // mir::Constant
--                                          // + span: $DIR/discriminant.rs:6:39: 6:43
+-                                          // + span: $DIR/discriminant.rs:11:39: 11:43
 -                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
--         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:6:21: 6:31
--         switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-+                                          // + span: $DIR/discriminant.rs:6:34: 6:44
+-         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+-         switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
++                                          // + span: $DIR/discriminant.rs:11:34: 11:44
 +                                          // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) }
-+         _4 = const 1isize;               // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++         _4 = const 1_isize;              // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 +                                          // ty::Const
 +                                          // + ty: isize
 +                                          // + val: Value(Scalar(0x00000001))
 +                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:6:21: 6:31
++                                          // + span: $DIR/discriminant.rs:11:21: 11:31
 +                                          // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) }
-+         switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++         switchInt(const 1_isize) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 +                                          // ty::Const
 +                                          // + ty: isize
 +                                          // + val: Value(Scalar(0x00000001))
 +                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:6:21: 6:31
++                                          // + span: $DIR/discriminant.rs:11:21: 11:31
 +                                          // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) }
       }
   
       bb1: {
-          _2 = const 10i32;                // scope 0 at $DIR/discriminant.rs:6:59: 6:61
+          _2 = const 10_i32;               // scope 0 at $DIR/discriminant.rs:11:59: 11:61
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000000a))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:6:59: 6:61
+                                           // + span: $DIR/discriminant.rs:11:59: 11:61
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) }
-          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:11:13: 11:64
       }
   
       bb2: {
--         switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+         switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x01))
-+                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:6:26: 6:30
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
       }
   
       bb3: {
-          _2 = const 42i32;                // scope 0 at $DIR/discriminant.rs:6:47: 6:49
+          _2 = const 42_i32;               // scope 0 at $DIR/discriminant.rs:11:47: 11:49
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:6:47: 6:49
+                                           // + span: $DIR/discriminant.rs:11:47: 11:49
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
-          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:11:13: 11:64
       }
   
       bb4: {
-          _1 = Add(move _2, const 0i32);   // scope 0 at $DIR/discriminant.rs:6:13: 6:68
+          _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/discriminant.rs:11:13: 11:68
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:6:67: 6:68
+                                           // + span: $DIR/discriminant.rs:11:67: 11:68
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
-          StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:6:67: 6:68
-          StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:6:68: 6:69
-          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:5:11: 7:2
+          StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:11:67: 11:68
+          StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:11:68: 11:69
+          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:10:11: 12:2
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:5:11: 7:2
+                                           // + span: $DIR/discriminant.rs:10:11: 12:2
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:7:1: 7:2
-          return;                          // scope 0 at $DIR/discriminant.rs:7:2: 7:2
+          StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:12:1: 12:2
+          return;                          // scope 0 at $DIR/discriminant.rs:12:2: 12:2
       }
   }
   
index ec0341e3de251e9768232f65683a6a604d3ad5d4..b09c9c47661169dd07ec9c7752aa3b3425041eec 100644 (file)
 + // MIR for `main` after ConstProp
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11
-      let _1: i32;                         // in scope 0 at $DIR/discriminant.rs:6:9: 6:10
-      let mut _2: i32;                     // in scope 0 at $DIR/discriminant.rs:6:13: 6:64
-      let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44
-      let mut _4: isize;                   // in scope 0 at $DIR/discriminant.rs:6:21: 6:31
+      let mut _0: ();                      // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11
+      let _1: i32;                         // in scope 0 at $DIR/discriminant.rs:11:9: 11:10
+      let mut _2: i32;                     // in scope 0 at $DIR/discriminant.rs:11:13: 11:64
+      let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44
+      let mut _4: isize;                   // in scope 0 at $DIR/discriminant.rs:11:21: 11:31
       scope 1 {
-          debug x => _1;                   // in scope 1 at $DIR/discriminant.rs:6:9: 6:10
+          debug x => _1;                   // in scope 1 at $DIR/discriminant.rs:11:9: 11:10
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:6:9: 6:10
-          StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:6:13: 6:64
-          StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:6:34: 6:44
--         _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
-+         _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44
+          StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:11:9: 11:10
+          StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:11:13: 11:64
+          StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+-         _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
++         _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44
                                            // ty::Const
 -                                          // + ty: bool
 +                                          // + ty: std::option::Option<bool>
                                            // + val: Value(Scalar(0x01))
                                            // mir::Constant
--                                          // + span: $DIR/discriminant.rs:6:39: 6:43
+-                                          // + span: $DIR/discriminant.rs:11:39: 11:43
 -                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
--         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:6:21: 6:31
--         switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
-+                                          // + span: $DIR/discriminant.rs:6:34: 6:44
+-         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:11:21: 11:31
+-         switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
++                                          // + span: $DIR/discriminant.rs:11:34: 11:44
 +                                          // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) }
-+         _4 = const 1isize;               // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++         _4 = const 1_isize;              // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 +                                          // ty::Const
 +                                          // + ty: isize
 +                                          // + val: Value(Scalar(0x0000000000000001))
 +                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:6:21: 6:31
++                                          // + span: $DIR/discriminant.rs:11:21: 11:31
 +                                          // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) }
-+         switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31
++         switchInt(const 1_isize) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31
 +                                          // ty::Const
 +                                          // + ty: isize
 +                                          // + val: Value(Scalar(0x0000000000000001))
 +                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:6:21: 6:31
++                                          // + span: $DIR/discriminant.rs:11:21: 11:31
 +                                          // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) }
       }
   
       bb1: {
-          _2 = const 10i32;                // scope 0 at $DIR/discriminant.rs:6:59: 6:61
+          _2 = const 10_i32;               // scope 0 at $DIR/discriminant.rs:11:59: 11:61
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000000a))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:6:59: 6:61
+                                           // + span: $DIR/discriminant.rs:11:59: 11:61
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) }
-          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:11:13: 11:64
       }
   
       bb2: {
--         switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+         switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x01))
-+                                          // mir::Constant
-+                                          // + span: $DIR/discriminant.rs:6:26: 6:30
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
       }
   
       bb3: {
-          _2 = const 42i32;                // scope 0 at $DIR/discriminant.rs:6:47: 6:49
+          _2 = const 42_i32;               // scope 0 at $DIR/discriminant.rs:11:47: 11:49
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:6:47: 6:49
+                                           // + span: $DIR/discriminant.rs:11:47: 11:49
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
-          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:6:13: 6:64
+          goto -> bb4;                     // scope 0 at $DIR/discriminant.rs:11:13: 11:64
       }
   
       bb4: {
-          _1 = Add(move _2, const 0i32);   // scope 0 at $DIR/discriminant.rs:6:13: 6:68
+          _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/discriminant.rs:11:13: 11:68
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:6:67: 6:68
+                                           // + span: $DIR/discriminant.rs:11:67: 11:68
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
-          StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:6:67: 6:68
-          StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:6:68: 6:69
-          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:5:11: 7:2
+          StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:11:67: 11:68
+          StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:11:68: 11:69
+          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:10:11: 12:2
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/discriminant.rs:5:11: 7:2
+                                           // + span: $DIR/discriminant.rs:10:11: 12:2
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:7:1: 7:2
-          return;                          // scope 0 at $DIR/discriminant.rs:7:2: 7:2
+          StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:12:1: 12:2
+          return;                          // scope 0 at $DIR/discriminant.rs:12:2: 12:2
       }
   }
   
index 941cde9172a6f5356ec4421e803685d3004ae5c9..71980185fd5cd38bad195ab60f9b20ed7603ea1e 100644 (file)
@@ -13,8 +13,8 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/indirect.rs:5:9: 5:10
           StorageLive(_2);                 // scope 0 at $DIR/indirect.rs:5:13: 5:25
--         _2 = const 2u32 as u8 (Misc);    // scope 0 at $DIR/indirect.rs:5:13: 5:25
-+         _2 = const 2u8;                  // scope 0 at $DIR/indirect.rs:5:13: 5:25
+-         _2 = const 2_u32 as u8 (Misc);   // scope 0 at $DIR/indirect.rs:5:13: 5:25
++         _2 = const 2_u8;                 // scope 0 at $DIR/indirect.rs:5:13: 5:25
                                            // ty::Const
 -                                          // + ty: u32
 -                                          // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
 -                                          // + span: $DIR/indirect.rs:5:14: 5:18
 -                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
--         _3 = CheckedAdd(move _2, const 1u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29
+-         _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29
 +                                          // + span: $DIR/indirect.rs:5:13: 5:25
 +                                          // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
-+         _3 = (const 3u8, const false);   // scope 0 at $DIR/indirect.rs:5:13: 5:29
++         _3 = (const 3_u8, const false);  // scope 0 at $DIR/indirect.rs:5:13: 5:29
                                            // ty::Const
                                            // + ty: u8
 -                                          // + val: Value(Scalar(0x01))
                                            // mir::Constant
 -                                          // + span: $DIR/indirect.rs:5:28: 5:29
 -                                          // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
--         assert(!move (_3.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+-         assert(!move (_3.1: bool), "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
 +                                          // + span: $DIR/indirect.rs:5:13: 5:29
 +                                          // + literal: Const { ty: u8, val: Value(Scalar(0x03)) }
-+                                          // ty::Const
+                                           // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/indirect.rs:5:13: 5:29
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
++         assert(!const false, "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
 +                                          // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/indirect.rs:5:13: 5:29
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++                                          // ty::Const
+                                           // + ty: u8
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/indirect.rs:5:28: 5:29
+                                           // + literal: Const { ty: u8, val: Value(Scalar(0x01)) }
       }
   
       bb1: {
 -         _1 = move (_3.0: u8);            // scope 0 at $DIR/indirect.rs:5:13: 5:29
-+         _1 = const 3u8;                  // scope 0 at $DIR/indirect.rs:5:13: 5:29
++         _1 = const 3_u8;                 // scope 0 at $DIR/indirect.rs:5:13: 5:29
 +                                          // ty::Const
 +                                          // + ty: u8
 +                                          // + val: Value(Scalar(0x03))
index c26494bdc1042959b0905e47d91170cb6d85db3d..242907b5599d8ea45aaeac449fc21cdaebb2887c 100644 (file)
@@ -19,7 +19,7 @@
 +                                          // mir::Constant
 +                                          // + span: $DIR/issue-66971.rs:16:13: 16:15
 +                                          // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          _2 = (move _3, const 0u8, const 0u8); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
+          _2 = (move _3, const 0_u8, const 0_u8); // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x00))
index e328febb407ae4805b9be02c3dbc09821d5183b8..d5c1105d7caff24b15027915085d621fca7c05ba 100644 (file)
@@ -11,7 +11,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/issue-67019.rs:11:5: 11:20
           StorageLive(_2);                 // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
           StorageLive(_3);                 // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
-          _3 = (const 1u8, const 2u8);     // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
+          _3 = (const 1_u8, const 2_u8);   // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x01))
index 187c17454350a05668096496171bd5bcae2bf381..3d4309a8aec547e830778e86417a506ccc615851 100644 (file)
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable.rs:5:9: 5:14
-          _1 = const 42i32;                // scope 0 at $DIR/mutable_variable.rs:5:17: 5:19
+          _1 = const 42_i32;               // scope 0 at $DIR/mutable_variable.rs:5:17: 5:19
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // mir::Constant
                                            // + span: $DIR/mutable_variable.rs:5:17: 5:19
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
-          _1 = const 99i32;                // scope 1 at $DIR/mutable_variable.rs:6:5: 6:11
+          _1 = const 99_i32;               // scope 1 at $DIR/mutable_variable.rs:6:5: 6:11
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000063))
@@ -30,7 +30,7 @@
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10
 -         _2 = _1;                         // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
-+         _2 = const 99i32;                // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
++         _2 = const 99_i32;               // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000063))
index cf432b2acc1c5c86be05afc7f964aad2587b328d..f581b222c83cbc9f59593f0fd092a0d902c3ed5a 100644 (file)
@@ -14,7 +14,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
-          _1 = (const 42i32, const 43i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
+          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
@@ -29,7 +29,7 @@
 -                                          // + span: $DIR/mutable_variable_aggregate.rs:5:22: 5:24
 +                                          // + span: $DIR/mutable_variable_aggregate.rs:5:17: 5:25
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
-          (_1.1: i32) = const 99i32;       // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
+          (_1.1: i32) = const 99_i32;      // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000063))
@@ -38,7 +38,7 @@
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
 -         _2 = _1;                         // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
-+         _2 = (const 42i32, const 99i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
++         _2 = (const 42_i32, const 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x0000002a))
index 44203ac327ab194ce0b1e9e8f345202e8fae4be6..e78bc31b7748022470034a12db776e88d6f94a62 100644 (file)
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
-          _1 = (const 42i32, const 43i32); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+          _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
+-                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
++                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002b))
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
+-                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
++                                          // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
           _2 = &mut _1;                    // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19
-          ((*_2).1: i32) = const 99i32;    // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:7:5: 7:13
+          ((*_2).1: i32) = const 99_i32;   // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:7:5: 7:13
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000063))
index f6bb72baea41990c92a25876c9566b2b5074bab1..b1a0ab88fccd59f708c04b469526bb2a702e7a42 100644 (file)
       }
   
       bb1: {
-          (_1.1: i32) = const 99i32;       // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:6:5: 6:13
+          (_1.1: i32) = const 99_i32;      // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:6:5: 6:13
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000063))
                                            // mir::Constant
                                            // + span: $DIR/mutable_variable_aggregate_partial_read.rs:6:11: 6:13
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
-          (_1.0: i32) = const 42i32;       // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:7:5: 7:13
+          (_1.0: i32) = const 42_i32;      // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:7:5: 7:13
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
@@ -40,7 +40,7 @@
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10
 -         _2 = (_1.1: i32);                // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
-+         _2 = const 99i32;                // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
++         _2 = const 99_i32;               // scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:13: 8:16
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000063))
index b7f1242d8d125de9ebed9cd96fef14a80e119bab..3b72af2d0b9c57341342d7f53c1c88b6a0678270 100644 (file)
@@ -19,7 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_no_prop.rs:7:9: 7:14
-          _1 = const 42u32;                // scope 0 at $DIR/mutable_variable_no_prop.rs:7:17: 7:19
+          _1 = const 42_u32;               // scope 0 at $DIR/mutable_variable_no_prop.rs:7:17: 7:19
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000002a))
index e0b9fbe04c387465bb1d8788040237df30c20eba..b59b180b07d7fd4091ef770e9cd3edfe97a90e23 100644 (file)
@@ -34,7 +34,7 @@
   
       bb1: {
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14
-          _2 = (const 1i32, const 2i32);   // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
+          _2 = (const 1_i32, const 2_i32); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
index 9bd9bfa9f27968d9ab1045d625ff32c8bae367d3..4bfa50e9851f417cbc2946fd8d74e485ae8ec4a4 100644 (file)
@@ -24,8 +24,8 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
--         _2 = CheckedAdd(const 2i32, const 2i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+         _2 = (const 4i32, const false);  // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+-         _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++         _2 = (const 4_i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
                                            // ty::Const
                                            // + ty: i32
 -                                          // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
 -                                          // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
--         assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+                                          // ty::Const
++         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+                                           // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++                                          // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/optimizes_into_variable.rs:12:13: 12:14
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
       }
   
       bb1: {
 -         _1 = move (_2.0: i32);           // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+         _1 = const 4i32;                 // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++         _1 = const 4_i32;                // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000004))
@@ -66,7 +78,7 @@
 +                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
           StorageLive(_3);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
           StorageLive(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
-          _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
+          _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
                                            // + span: $DIR/optimizes_into_variable.rs:13:29: 13:30
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
           StorageLive(_5);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
-          _5 = const 3usize;               // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
+          _5 = const 3_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000003))
                                            // mir::Constant
                                            // + span: $DIR/optimizes_into_variable.rs:13:32: 13:33
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
-          _6 = const 6usize;               // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+          _6 = const 6_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000006))
   
       bb2: {
 -         _3 = _4[_5];                     // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
-+         _3 = const 3i32;                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++         _3 = const 3_i32;                // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000003))
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
           StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
-          _9 = Point { x: const 12u32, y: const 42u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+          _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000000c))
                                            // + span: $DIR/optimizes_into_variable.rs:14:32: 14:34
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
 -         _8 = (_9.1: u32);                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
-+         _8 = const 42u32;                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
++         _8 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x0000002a))
index 8ea9316c7d49b60416b2862244574e9494280e0e..7b74bf81d96fea575bed78ff602ca82f5257068f 100644 (file)
@@ -17,7 +17,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
-        _1 = const 4i32;                 // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+        _1 = const 4_i32;                // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000004))
@@ -25,7 +25,7 @@ fn main() -> () {
                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
         StorageLive(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
-        _2 = const 3i32;                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+        _2 = const 3_i32;                // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -33,7 +33,7 @@ fn main() -> () {
                                          // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
         StorageLive(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
-        _3 = const 42u32;                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
+        _3 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x0000002a))
index 1da763ec9558aac38c46fe15c6750a8fec68e523..2d40567ce8da17d80cb8531d1a9501830651f627 100644 (file)
@@ -24,8 +24,8 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
--         _2 = CheckedAdd(const 2i32, const 2i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+         _2 = (const 4i32, const false);  // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+-         _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++         _2 = (const 4_i32, const false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
                                            // ty::Const
                                            // + ty: i32
 -                                          // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
 -                                          // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
--         assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+                                          // ty::Const
++         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+                                           // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++                                          // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/optimizes_into_variable.rs:12:13: 12:14
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/optimizes_into_variable.rs:12:17: 12:18
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
       }
   
       bb1: {
 -         _1 = move (_2.0: i32);           // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
-+         _1 = const 4i32;                 // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++         _1 = const 4_i32;                // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000004))
@@ -66,7 +78,7 @@
 +                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
           StorageLive(_3);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
           StorageLive(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
-          _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
+          _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
                                            // + span: $DIR/optimizes_into_variable.rs:13:29: 13:30
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
           StorageLive(_5);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
-          _5 = const 3usize;               // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
+          _5 = const 3_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000003))
                                            // mir::Constant
                                            // + span: $DIR/optimizes_into_variable.rs:13:32: 13:33
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
-          _6 = const 6usize;               // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+          _6 = const 6_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000006))
   
       bb2: {
 -         _3 = _4[_5];                     // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
-+         _3 = const 3i32;                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++         _3 = const 3_i32;                // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000003))
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
           StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
-          _9 = Point { x: const 12u32, y: const 42u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+          _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000000c))
                                            // + span: $DIR/optimizes_into_variable.rs:14:32: 14:34
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
 -         _8 = (_9.1: u32);                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
-+         _8 = const 42u32;                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
++         _8 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x0000002a))
index 8ea9316c7d49b60416b2862244574e9494280e0e..7b74bf81d96fea575bed78ff602ca82f5257068f 100644 (file)
@@ -17,7 +17,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
-        _1 = const 4i32;                 // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+        _1 = const 4_i32;                // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000004))
@@ -25,7 +25,7 @@ fn main() -> () {
                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
         StorageLive(_2);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10
-        _2 = const 3i32;                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+        _2 = const 3_i32;                // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -33,7 +33,7 @@ fn main() -> () {
                                          // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
         StorageLive(_3);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
-        _3 = const 42u32;                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
+        _3 = const 42_u32;               // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x0000002a))
index 103444f796ec64c48e6b288cca32217c9d7ebe65..36edfc42b9a76c3168ed0f911ba0cdcdd6a248a0 100644 (file)
@@ -24,7 +24,7 @@
                                            // + span: $DIR/read_immutable_static.rs:7:13: 7:16
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc0)) }
 -         _2 = (*_3);                      // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
-+         _2 = const 2u8;                  // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
++         _2 = const 2_u8;                 // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
 +                                          // ty::Const
 +                                          // + ty: u8
 +                                          // + val: Value(Scalar(0x02))
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc0)) }
 -         _4 = (*_5);                      // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
 -         _1 = Add(move _2, move _4);      // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22
-+         _4 = const 2u8;                  // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
++         _4 = const 2_u8;                 // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
 +                                          // ty::Const
 +                                          // + ty: u8
 +                                          // + val: Value(Scalar(0x02))
 +                                          // mir::Constant
 +                                          // + span: $DIR/read_immutable_static.rs:7:19: 7:22
 +                                          // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
-+         _1 = const 4u8;                  // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22
++         _1 = const 4_u8;                 // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:22
 +                                          // ty::Const
 +                                          // + ty: u8
 +                                          // + val: Value(Scalar(0x04))
index dcd3d4019811ee16f493bcfd9d415df8479231b3..12e3a04d89bf2893eee8f42d25c1165412047a2f 100644 (file)
@@ -20,7 +20,7 @@
                                            // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0])) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 -         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
-+         _1 = const 4i32;                 // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
++         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000004))
index ef696f1ab8052a137f583829b41af9865aff10a2..d56f07e0f57f5430a65d2aed0983befad6156313 100644 (file)
@@ -12,7 +12,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 -         StorageLive(_3);                 // scope 0 at $DIR/ref_deref.rs:5:8: 5:9
--         _3 = const 4i32;                 // scope 0 at $DIR/ref_deref.rs:5:8: 5:9
+-         _3 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:5:8: 5:9
 +         _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
                                            // ty::Const
 -                                          // + ty: i32
index 7f23f5ea7a69a8e456f7feafe86f056bd2e26b2a..0b9c1caa6bdaee2566406b77f375dbb786f4d328 100644 (file)
@@ -12,7 +12,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
 -         StorageLive(_3);                 // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14
--         _3 = (const 4i32, const 5i32);   // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14
+-         _3 = (const 4_i32, const 5_i32); // scope 0 at $DIR/ref_deref_project.rs:5:8: 5:14
 +         _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
                                            // ty::Const
 -                                          // + ty: i32
index b1c9e22913935d2fae793db7b9e56c5fb3fe3aa8..3046b2ca9b8a42b7946a91e51c12cc78624d1517 100644 (file)
@@ -17,7 +17,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/repeat.rs:6:9: 6:10
           StorageLive(_2);                 // scope 0 at $DIR/repeat.rs:6:18: 6:28
           StorageLive(_3);                 // scope 0 at $DIR/repeat.rs:6:18: 6:25
-          _3 = [const 42u32; 8];           // scope 0 at $DIR/repeat.rs:6:18: 6:25
+          _3 = [const 42_u32; 8];          // scope 0 at $DIR/repeat.rs:6:18: 6:25
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000002a))
                                            // + span: $DIR/repeat.rs:6:19: 6:21
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
           StorageLive(_4);                 // scope 0 at $DIR/repeat.rs:6:26: 6:27
-          _4 = const 2usize;               // scope 0 at $DIR/repeat.rs:6:26: 6:27
+          _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:6:26: 6:27
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
                                            // + span: $DIR/repeat.rs:6:26: 6:27
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
-          _5 = const 8usize;               // scope 0 at $DIR/repeat.rs:6:18: 6:28
+          _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:6:18: 6:28
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000008))
@@ -59,8 +59,8 @@
   
       bb1: {
 -         _2 = _3[_4];                     // scope 0 at $DIR/repeat.rs:6:18: 6:28
--         _1 = Add(move _2, const 0u32);   // scope 0 at $DIR/repeat.rs:6:18: 6:32
-+         _2 = const 42u32;                // scope 0 at $DIR/repeat.rs:6:18: 6:28
+-         _1 = Add(move _2, const 0_u32);  // scope 0 at $DIR/repeat.rs:6:18: 6:32
++         _2 = const 42_u32;               // scope 0 at $DIR/repeat.rs:6:18: 6:28
                                            // ty::Const
                                            // + ty: u32
 -                                          // + val: Value(Scalar(0x00000000))
@@ -70,7 +70,7 @@
 -                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // + span: $DIR/repeat.rs:6:18: 6:28
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
-+         _1 = const 42u32;                // scope 0 at $DIR/repeat.rs:6:18: 6:32
++         _1 = const 42_u32;               // scope 0 at $DIR/repeat.rs:6:18: 6:32
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x0000002a))
index 29555b03a8b8e031a94f744df6fcf790168753da..c06ed33df24c1bc052ccdc0d6371e7ccec87f01f 100644 (file)
@@ -17,7 +17,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/repeat.rs:6:9: 6:10
           StorageLive(_2);                 // scope 0 at $DIR/repeat.rs:6:18: 6:28
           StorageLive(_3);                 // scope 0 at $DIR/repeat.rs:6:18: 6:25
-          _3 = [const 42u32; 8];           // scope 0 at $DIR/repeat.rs:6:18: 6:25
+          _3 = [const 42_u32; 8];          // scope 0 at $DIR/repeat.rs:6:18: 6:25
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x0000002a))
                                            // + span: $DIR/repeat.rs:6:19: 6:21
                                            // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
           StorageLive(_4);                 // scope 0 at $DIR/repeat.rs:6:26: 6:27
-          _4 = const 2usize;               // scope 0 at $DIR/repeat.rs:6:26: 6:27
+          _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:6:26: 6:27
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000002))
                                            // mir::Constant
                                            // + span: $DIR/repeat.rs:6:26: 6:27
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
-          _5 = const 8usize;               // scope 0 at $DIR/repeat.rs:6:18: 6:28
+          _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:6:18: 6:28
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000008))
@@ -59,8 +59,8 @@
   
       bb1: {
 -         _2 = _3[_4];                     // scope 0 at $DIR/repeat.rs:6:18: 6:28
--         _1 = Add(move _2, const 0u32);   // scope 0 at $DIR/repeat.rs:6:18: 6:32
-+         _2 = const 42u32;                // scope 0 at $DIR/repeat.rs:6:18: 6:28
+-         _1 = Add(move _2, const 0_u32);  // scope 0 at $DIR/repeat.rs:6:18: 6:32
++         _2 = const 42_u32;               // scope 0 at $DIR/repeat.rs:6:18: 6:28
                                            // ty::Const
                                            // + ty: u32
 -                                          // + val: Value(Scalar(0x00000000))
@@ -70,7 +70,7 @@
 -                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // + span: $DIR/repeat.rs:6:18: 6:28
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) }
-+         _1 = const 42u32;                // scope 0 at $DIR/repeat.rs:6:18: 6:32
++         _1 = const 42_u32;               // scope 0 at $DIR/repeat.rs:6:18: 6:32
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x0000002a))
index fc7d028277bd9ad18a156e596668bf7512db4217..5e39c8e6d523ed4a5563ff3d3293e0fc17bc48ab 100644 (file)
@@ -6,8 +6,8 @@
       let mut _1: (u32, bool);             // in scope 0 at $DIR/return_place.rs:6:5: 6:10
   
       bb0: {
--         _1 = CheckedAdd(const 2u32, const 2u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+         _1 = (const 4u32, const false);  // scope 0 at $DIR/return_place.rs:6:5: 6:10
+-         _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
++         _1 = (const 4_u32, const false); // scope 0 at $DIR/return_place.rs:6:5: 6:10
                                            // ty::Const
                                            // + ty: u32
 -                                          // + val: Value(Scalar(0x00000002))
                                            // mir::Constant
 -                                          // + span: $DIR/return_place.rs:6:9: 6:10
 -                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
--         assert(!move (_1.1: bool), "attempt to add with overflow") -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+-         assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
 +                                          // + span: $DIR/return_place.rs:6:5: 6:10
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+         assert(!const false, "attempt to add with overflow") -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+                                          // ty::Const
++         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+                                           // ty::Const
 +                                          // + ty: bool
 +                                          // + val: Value(Scalar(0x00))
 +                                          // mir::Constant
 +                                          // + span: $DIR/return_place.rs:6:5: 6:10
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
++                                          // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/return_place.rs:6:5: 6:6
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
+                                           // ty::Const
+                                           // + ty: u32
+                                           // + val: Value(Scalar(0x00000002))
+                                           // mir::Constant
+                                           // + span: $DIR/return_place.rs:6:9: 6:10
+                                           // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
       }
   
       bb1: {
 -         _0 = move (_1.0: u32);           // scope 0 at $DIR/return_place.rs:6:5: 6:10
-+         _0 = const 4u32;                 // scope 0 at $DIR/return_place.rs:6:5: 6:10
++         _0 = const 4_u32;                // scope 0 at $DIR/return_place.rs:6:5: 6:10
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000004))
index b741c786fb394321fdeec5c09fabd698638983d6..23ad8d057ba8dbb5cb061b64d11adeebb634c6a4 100644 (file)
@@ -4,7 +4,7 @@ fn add() -> u32 {
     let mut _0: u32;                     // return place in scope 0 at $DIR/return_place.rs:5:13: 5:16
 
     bb0: {
-        _0 = const 4u32;                 // scope 0 at $DIR/return_place.rs:6:5: 6:10
+        _0 = const 4_u32;                // scope 0 at $DIR/return_place.rs:6:5: 6:10
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000004))
index 596ddcb43533ba2360545b5b43f7815a6d4ddf4d..43e0eb09a2e5f2b3c2296177f099c59c4a299741 100644 (file)
@@ -12,7 +12,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:3:9: 3:10
-          _1 = const 1u32;                 // scope 0 at $DIR/scalar_literal_propagation.rs:3:13: 3:14
+          _1 = const 1_u32;                // scope 0 at $DIR/scalar_literal_propagation.rs:3:13: 3:14
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x00000001))
           StorageLive(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
 -         _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
 -         _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
-+         _3 = const 1u32;                 // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
++         _3 = const 1_u32;                // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14
                                            // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000001))
 +                                          // mir::Constant
 +                                          // + span: $DIR/scalar_literal_propagation.rs:4:13: 4:14
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
-+         _2 = const consume(const 1u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
++         _2 = const consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
 +                                          // ty::Const
                                            // + ty: fn(u32) {consume}
                                            // + val: Value(Scalar(<ZST>))
index 9471dbef410d1624347514ec7a355a7ce9d32718..70c415648822308780ad5cdc04109f7d48b0c9b2 100644 (file)
@@ -30,7 +30,7 @@
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           StorageDead(_3);                 // scope 0 at $DIR/slice_len.rs:5:18: 5:19
           StorageLive(_6);                 // scope 0 at $DIR/slice_len.rs:5:31: 5:32
-          _6 = const 1usize;               // scope 0 at $DIR/slice_len.rs:5:31: 5:32
+          _6 = const 1_usize;              // scope 0 at $DIR/slice_len.rs:5:31: 5:32
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x00000001))
@@ -40,7 +40,7 @@
 -         _7 = Len((*_2));                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 -         _8 = Lt(_6, _7);                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 -         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+         _7 = const 3usize;               // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x00000003))
@@ -65,7 +65,7 @@
   
       bb1: {
 -         _1 = (*_2)[_6];                  // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+         _1 = const 2u32;                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++         _1 = const 2_u32;                // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000002))
index 3ae88e0d7986351d7025e7e1dd5fb9d874e4f2b6..885f28124c4b7d4133a2007e52f0cfb10c330367 100644 (file)
@@ -30,7 +30,7 @@
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           StorageDead(_3);                 // scope 0 at $DIR/slice_len.rs:5:18: 5:19
           StorageLive(_6);                 // scope 0 at $DIR/slice_len.rs:5:31: 5:32
-          _6 = const 1usize;               // scope 0 at $DIR/slice_len.rs:5:31: 5:32
+          _6 = const 1_usize;              // scope 0 at $DIR/slice_len.rs:5:31: 5:32
                                            // ty::Const
                                            // + ty: usize
                                            // + val: Value(Scalar(0x0000000000000001))
@@ -40,7 +40,7 @@
 -         _7 = Len((*_2));                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 -         _8 = Lt(_6, _7);                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 -         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+         _7 = const 3usize;               // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x0000000000000003))
@@ -65,7 +65,7 @@
   
       bb1: {
 -         _1 = (*_2)[_6];                  // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+         _1 = const 2u32;                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++         _1 = const 2_u32;                // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000002))
index 8072424729ab043c410a0afa19962287e965612f..9580b99da9e403650378c1c15917aada453fcf92 100644 (file)
@@ -7,15 +7,15 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/switch_int.rs:7:11: 7:12
-          _1 = const 1i32;                 // scope 0 at $DIR/switch_int.rs:7:11: 7:12
+          _1 = const 1_i32;                // scope 0 at $DIR/switch_int.rs:7:11: 7:12
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
                                            // + span: $DIR/switch_int.rs:7:11: 7:12
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
--         switchInt(_1) -> [1i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
-+         switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
+-         switchInt(_1) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
++         switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
 +                                          // ty::Const
 +                                          // + ty: i32
 +                                          // + val: Value(Scalar(0x00000001))
@@ -25,7 +25,7 @@
       }
   
       bb1: {
-          _0 = const foo(const -1i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
+          _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
                                            // ty::Const
                                            // + ty: fn(i32) {foo}
                                            // + val: Value(Scalar(<ZST>))
@@ -41,7 +41,7 @@
       }
   
       bb2: {
-          _0 = const foo(const 0i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
+          _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
                                            // ty::Const
                                            // + ty: fn(i32) {foo}
                                            // + val: Value(Scalar(<ZST>))
index 51f3bf20c1aea36277d07f4f97c9a3e7c11330c3..54f37e609ec1310f87248d9cf81a4786b0970d58 100644 (file)
@@ -7,14 +7,14 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/switch_int.rs:7:11: 7:12
-          _1 = const 1i32;                 // scope 0 at $DIR/switch_int.rs:7:11: 7:12
+          _1 = const 1_i32;                // scope 0 at $DIR/switch_int.rs:7:11: 7:12
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
                                            // mir::Constant
                                            // + span: $DIR/switch_int.rs:7:11: 7:12
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
--         switchInt(const 1i32) -> [1i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
+-         switchInt(const 1_i32) -> [1_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/switch_int.rs:8:9: 8:10
 -                                          // ty::Const
 -                                          // + ty: i32
 -                                          // + val: Value(Scalar(0x00000001))
@@ -25,7 +25,7 @@
       }
   
       bb1: {
-          _0 = const foo(const -1i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
+          _0 = const foo(const -1_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:9:14: 9:21
                                            // ty::Const
                                            // + ty: fn(i32) {foo}
                                            // + val: Value(Scalar(<ZST>))
@@ -41,7 +41,7 @@
       }
   
       bb2: {
-          _0 = const foo(const 0i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
+          _0 = const foo(const 0_i32) -> bb3; // scope 0 at $DIR/switch_int.rs:8:14: 8:20
                                            // ty::Const
                                            // + ty: fn(i32) {foo}
                                            // + val: Value(Scalar(<ZST>))
index 1511b361f587ff0db022d899797cc7dc9a7b6960..941ec64a3cc12561ab93c7729eff97115ed1a623 100644 (file)
@@ -12,7 +12,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10
-          _1 = (const 1u32, const 2u32);   // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
+          _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
                                            // ty::Const
                                            // + ty: u32
                                            // + val: Value(Scalar(0x00000001))
@@ -30,7 +30,7 @@
           StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
           StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
 -         _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
-+         _3 = (const 1u32, const 2u32);   // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
++         _3 = (const 1_u32, const 2_u32); // scope 1 at $DIR/tuple_literal_propagation.rs:5:13: 5:14
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000001))
diff --git a/src/test/mir-opt/const_prop_miscompile.rs b/src/test/mir-opt/const_prop_miscompile.rs
new file mode 100644 (file)
index 0000000..043b228
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(raw_ref_op)]
+
+// EMIT_MIR rustc.foo.ConstProp.diff
+fn foo() {
+    let mut u = (1,);
+    *&mut u.0 = 5;
+    let y = { u.0 } == 5;
+}
+
+// EMIT_MIR rustc.bar.ConstProp.diff
+fn bar() {
+    let mut v = (1,);
+    unsafe {
+        *&raw mut v.0 = 5;
+    }
+    let y = { v.0 } == 5;
+}
+
+fn main() {
+    foo();
+    bar();
+}
diff --git a/src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff
new file mode 100644 (file)
index 0000000..5fe35b4
--- /dev/null
@@ -0,0 +1,75 @@
+- // MIR for `bar` before ConstProp
++ // MIR for `bar` after ConstProp
+  
+  fn bar() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:11:10: 11:10
+      let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+      let _2: ();                          // in scope 0 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+      let mut _3: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+      let mut _5: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+      scope 1 {
+          debug v => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+          let _4: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          scope 2 {
+          }
+          scope 3 {
+              debug y => _4;               // in scope 3 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+-         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
++         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
+                                           // ty::Const
+-                                          // + ty: i32
++                                          // + ty: (i32,)
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+-                                          // + span: $DIR/const_prop_miscompile.rs:12:18: 12:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/const_prop_miscompile.rs:12:17: 12:21
++                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+          StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+          _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+          (*_3) = const 5_i32;             // scope 2 at $DIR/const_prop_miscompile.rs:14:9: 14:26
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:14:25: 14:26
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:26: 14:27
+          _2 = const ();                   // scope 2 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:13:5: 15:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:15:5: 15:6
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          StorageLive(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+          _5 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:16:15: 16:18
+          _4 = Eq(move _5, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:16:24: 16:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:24: 16:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:11:10: 17:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:11:10: 17:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+          StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+          return;                          // scope 0 at $DIR/const_prop_miscompile.rs:17:2: 17:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff
new file mode 100644 (file)
index 0000000..98e9825
--- /dev/null
@@ -0,0 +1,63 @@
+- // MIR for `foo` before ConstProp
++ // MIR for `foo` after ConstProp
+  
+  fn foo() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:4:10: 4:10
+      let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+      let mut _2: &mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+      let mut _4: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+      scope 1 {
+          debug u => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+          let _3: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          scope 2 {
+              debug y => _3;               // in scope 2 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+-         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
++         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
+                                           // ty::Const
+-                                          // + ty: i32
++                                          // + ty: (i32,)
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+-                                          // + span: $DIR/const_prop_miscompile.rs:5:18: 5:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/const_prop_miscompile.rs:5:17: 5:21
++                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+          _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+          (*_2) = const 5_i32;             // scope 1 at $DIR/const_prop_miscompile.rs:6:5: 6:18
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:6:17: 6:18
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:18: 6:19
+          StorageLive(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+          _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:7:15: 7:18
+          _3 = Eq(move _4, const 5_i32);   // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:7:24: 7:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:24: 7:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:4:10: 8:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:4:10: 8:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+          StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/const_prop_miscompile.rs:8:2: 8:2
+      }
+  }
+  
index 1e0271a560f650785d410cfc5edf25cf3ee8f11a..22fbf4e836ba47937a29c5be02db06c3d2202a3a 100644 (file)
@@ -12,7 +12,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
           _2 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
-          _1 = const 123i32;               // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
+          _1 = const 123_i32;              // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000007b))
index b875bbea67bdf0b5bde199b3d5367c959109d2eb..6953a80a5f08aea697866010ab19e8a8f08aec64 100644 (file)
@@ -23,7 +23,7 @@
       bb1: {
           StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:12: 16:13
           StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:13: 16:14
-          _1 = const 5u8;                  // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10
+          _1 = const 5_u8;                 // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x05))
index 3c1c02da42ff8d9cd885b9e12ef497c7892fc73c..b84ca5df9964e01b09a0419569648e2e2fedf0af 100644 (file)
@@ -19,11 +19,11 @@ fn match_tuple(_1: (u32, bool, std::option::Option<i32>, u32)) -> u32 {
 
     bb0: {
         FakeRead(ForMatchedPlace, _1);   // scope 0 at $DIR/exponential-or.rs:7:11: 7:12
-        switchInt((_1.0: u32)) -> [1u32: bb2, 4u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:15: 8:16
+        switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:15: 8:16
     }
 
     bb1: {
-        _0 = const 0u32;                 // scope 0 at $DIR/exponential-or.rs:9:14: 9:15
+        _0 = const 0_u32;                // scope 0 at $DIR/exponential-or.rs:9:14: 9:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -35,15 +35,15 @@ fn match_tuple(_1: (u32, bool, std::option::Option<i32>, u32)) -> u32 {
 
     bb2: {
         _2 = discriminant((_1.2: std::option::Option<i32>)); // scope 0 at $DIR/exponential-or.rs:8:37: 8:48
-        switchInt(move _2) -> [0isize: bb4, 1isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:37: 8:48
+        switchInt(move _2) -> [0_isize: bb4, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:37: 8:48
     }
 
     bb3: {
-        switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1i32: bb4, 8i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:42: 8:43
+        switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1_i32: bb4, 8_i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:8:42: 8:43
     }
 
     bb4: {
-        _5 = Le(const 6u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
+        _5 = Le(const 6_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000006))
@@ -54,7 +54,7 @@ fn match_tuple(_1: (u32, bool, std::option::Option<i32>, u32)) -> u32 {
     }
 
     bb5: {
-        _6 = Le((_1.3: u32), const 9u32); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
+        _6 = Le((_1.3: u32), const 9_u32); // scope 0 at $DIR/exponential-or.rs:8:62: 8:67
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000009))
@@ -65,7 +65,7 @@ fn match_tuple(_1: (u32, bool, std::option::Option<i32>, u32)) -> u32 {
     }
 
     bb6: {
-        _3 = Le(const 13u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
+        _3 = Le(const 13_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x0000000d))
@@ -76,7 +76,7 @@ fn match_tuple(_1: (u32, bool, std::option::Option<i32>, u32)) -> u32 {
     }
 
     bb7: {
-        _4 = Le((_1.3: u32), const 16u32); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
+        _4 = Le((_1.3: u32), const 16_u32); // scope 0 at $DIR/exponential-or.rs:8:70: 8:77
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000010))
diff --git a/src/test/mir-opt/fn-ptr-shim.rs b/src/test/mir-opt/fn-ptr-shim.rs
new file mode 100644 (file)
index 0000000..08413c9
--- /dev/null
@@ -0,0 +1,15 @@
+// compile-flags: -Zmir-opt-level=0 -Zvalidate-mir
+
+// Tests that the `<fn() as Fn>` shim does not create a `Call` terminator with a `Self` callee
+// (as only `FnDef` and `FnPtr` callees are allowed in MIR).
+
+// EMIT_MIR rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
+fn main() {
+    call(noop as fn());
+}
+
+fn noop() {}
+
+fn call<F: Fn()>(f: F) {
+    f();
+}
diff --git a/src/test/mir-opt/fn-ptr-shim/rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/fn-ptr-shim/rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
new file mode 100644 (file)
index 0000000..4ecc331
--- /dev/null
@@ -0,0 +1,13 @@
+// MIR for `std::ops::Fn::call` before AddMovesForPackedDrops
+
+fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> <Self as std::ops::FnOnce<Args>>::Output {
+    let mut _0: <Self as std::ops::FnOnce<Args>>::Output; // return place in scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
+
+    bb0: {
+        _0 = move (*_1)() -> bb1;        // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
+    }
+
+    bb1: {
+        return;                          // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL
+    }
+}
index 3e7083ff62ecd3584a60780c548b791ada20b94e..bd64a31663a6996c7c9c91e307b5ef1dd021c5f7 100644 (file)
@@ -1,5 +1,18 @@
 // MIR for `main::{{closure}}#0` 0 generator_drop
-// generator_layout = GeneratorLayout { field_tys: [std::string::String], variant_fields: [[], [], [], [_0]], storage_conflicts: BitMatrix { num_rows: 1, num_columns: 1, words: [1], marker: PhantomData } }
+/* generator_layout = GeneratorLayout {
+    field_tys: {
+        _0: std::string::String,
+    },
+    variant_fields: {
+        Unresumed(0): [],
+        Returned (1): [],
+        Panicked (2): [],
+        Suspend0 (3): [_0],
+    },
+    storage_conflicts: BitMatrix(1x1) {
+        (_0, _0),
+    },
+} */
 
 fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {std::string::String, ()}]) -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
@@ -21,7 +34,7 @@ fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15:
 
     bb0: {
         _9 = discriminant((*_1));        // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-        switchInt(move _9) -> [0u32: bb7, 3u32: bb11, otherwise: bb12]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        switchInt(move _9) -> [0_u32: bb7, 3_u32: bb11, otherwise: bb12]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 
     bb1 (cleanup): {
index 06645860d842dbcaab8e808ebb65929fa601097e..7dcfda32ca4a2e34436fa647dfee77bcc7deaf50 100644 (file)
@@ -21,7 +21,7 @@ yields ()
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14
-        _3 = Foo(const 5i32);            // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
+        _3 = Foo(const 5_i32);           // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000005))
@@ -29,7 +29,7 @@ yields ()
                                          // + span: $DIR/generator-storage-dead-unwind.rs:23:21: 23:22
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
         StorageLive(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14
-        _4 = Bar(const 6i32);            // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
+        _4 = Bar(const 6_i32);           // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000006))
index c73dea5f8fde691402ba7d1034eb6f36b044028b..8776e5919bd8d1fc9efd06d892ad8ff80403f091 100644 (file)
@@ -1,5 +1,18 @@
 // MIR for `main::{{closure}}#0` 0 generator_resume
-// generator_layout = GeneratorLayout { field_tys: [HasDrop], variant_fields: [[], [], [], [_0]], storage_conflicts: BitMatrix { num_rows: 1, num_columns: 1, words: [1], marker: PhantomData } }
+/* generator_layout = GeneratorLayout {
+    field_tys: {
+        _0: HasDrop,
+    },
+    variant_fields: {
+        Unresumed(0): [],
+        Returned (1): [],
+        Panicked (2): [],
+        Suspend0 (3): [_0],
+    },
+    storage_conflicts: BitMatrix(1x1) {
+        (_0, _0),
+    },
+} */
 
 fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> std::ops::GeneratorState<(), ()> {
     debug _x => _10;                     // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
@@ -19,7 +32,7 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:
 
     bb0: {
         _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        switchInt(move _11) -> [0u32: bb1, 3u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+        switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
     }
 
     bb1: {
index 19748d52ec7e2f2e7e035a2f2b0ce8637fb220d3..c9ff1fe29f5edf96c948c0ede4e65fa02a202429 100644 (file)
@@ -25,14 +25,14 @@ fn bar() -> bool {
                                          // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
         StorageLive(_2);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
         _2 = _1;                         // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
-        _3 = const 1i32;                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        _3 = const 1_i32;                // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
                                          // mir::Constant
                                          // + span: $DIR/inline-any-operand.rs:12:7: 12:8
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
-        _4 = const -1i32;                // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        _4 = const -1_i32;               // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0xffffffff))
index 50913de98b506f8e220c89aa27fb077c9d8c77f8..3b71fbaa5e8a2edb4180f8c0cf12c5ef456090c5 100644 (file)
@@ -19,7 +19,7 @@
           _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
 -         (*_2) = const std::vec::Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
                                            // ty::Const
 -                                          // + ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}
 -                                          // + val: Value(Scalar(<ZST>))
@@ -39,7 +39,7 @@
 +                                          // + span: $SRC_DIR/liballoc/vec.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         ((*_4).1: usize) = const 0usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++         ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x00000000))
index 7a1b6460c5bb3467cf8b043d4417e8639970cd0c..2e7dde39115b7813ef6807261daa595a359c5936 100644 (file)
@@ -19,7 +19,7 @@
           _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
 -         (*_2) = const std::vec::Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: std::ptr::Unique::<u32> { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
                                            // ty::Const
 -                                          // + ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}
 -                                          // + val: Value(Scalar(<ZST>))
@@ -39,7 +39,7 @@
 +                                          // + span: $SRC_DIR/liballoc/vec.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         ((*_4).1: usize) = const 0usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
++         ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/liballoc/vec.rs:LL:COL
 +                                          // ty::Const
 +                                          // + ty: usize
 +                                          // + val: Value(Scalar(0x0000000000000000))
index a3e0d0a57a7c3af60f6127c9708d1326d238fde7..c273c43c4297da7f9731c653de0b626c175c2563 100644 (file)
@@ -13,7 +13,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-specialization.rs:5:9: 5:10
 -         _1 = const <std::vec::Vec<()> as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38
-+         _1 = const 123u32;               // scope 2 at $DIR/inline-specialization.rs:14:31: 14:34
++         _1 = const 123_u32;              // scope 2 at $DIR/inline-specialization.rs:14:31: 14:34
                                            // ty::Const
 -                                          // + ty: fn() -> u32 {<std::vec::Vec<()> as Foo>::bar}
 -                                          // + val: Value(Scalar(<ZST>))
diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs
new file mode 100644 (file)
index 0000000..3fe010e
--- /dev/null
@@ -0,0 +1,20 @@
+// Test that the initial version of Rust coverage injects count_code_region() placeholder calls,
+// at the top of each function. The placeholders are later converted into LLVM instrprof.increment
+// intrinsics, during codegen.
+
+// needs-profiler-support
+// compile-flags: -Zinstrument-coverage
+// EMIT_MIR rustc.main.InstrumentCoverage.diff
+// EMIT_MIR rustc.bar.InstrumentCoverage.diff
+fn main() {
+    loop {
+        if bar() {
+            break;
+        }
+    }
+}
+
+#[inline(never)]
+fn bar() -> bool {
+    true
+}
diff --git a/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff
new file mode 100644 (file)
index 0000000..8a079f0
--- /dev/null
@@ -0,0 +1,41 @@
+- // MIR for `bar` before InstrumentCoverage
++ // MIR for `bar` after InstrumentCoverage
+  
+  fn bar() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
++     let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
+  
+      bb0: {
++         StorageLive(_1);                 // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++         _1 = const std::intrinsics::count_code_region(const 0_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++                                          // ty::Const
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}
++                                          // + val: Value(Scalar(<ZST>))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000000))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:18:1: 18:1
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
++     }
++ 
++     bb1 (cleanup): {
++         resume;                          // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++     }
++ 
++     bb2: {
++         StorageDead(_1);                 // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
+          _0 = const true;                 // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
+                                           // ty::Const
+                                           // + ty: bool
+                                           // + val: Value(Scalar(0x01))
+                                           // mir::Constant
+                                           // + span: $DIR/instrument_coverage.rs:19:5: 19:9
+                                           // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+          return;                          // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff
new file mode 100644 (file)
index 0000000..3c2ec1d
--- /dev/null
@@ -0,0 +1,82 @@
+- // MIR for `main` before InstrumentCoverage
++ // MIR for `main` after InstrumentCoverage
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
+      let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+      let mut _2: bool;                    // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+      let mut _3: !;                       // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
++     let mut _4: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+  
+      bb0: {
+-         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
++         StorageLive(_4);                 // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++         _4 = const std::intrinsics::count_code_region(const 0_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
++                                          // ty::Const
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}
++                                          // + val: Value(Scalar(<ZST>))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000000))
++                                          // mir::Constant
++                                          // + span: $DIR/instrument_coverage.rs:9:1: 9:1
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
+      }
+  
+      bb1: {
+          StorageLive(_2);                 // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+          _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+                                           // ty::Const
+                                           // + ty: fn() -> bool {bar}
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/instrument_coverage.rs:11:12: 11:15
+                                           // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+      }
+  
+      bb3: {
+          FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+          switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+      }
+  
+      bb4: {
+          falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+      }
+  
+      bb5: {
+          _1 = const ();                   // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/instrument_coverage.rs:11:9: 13:10
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
+          goto -> bb0;                     // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+      }
+  
+      bb6: {
+          _0 = const ();                   // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/instrument_coverage.rs:12:13: 12:18
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
+          return;                          // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2
++     }
++ 
++     bb7: {
++         StorageDead(_4);                 // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
++         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+      }
+  }
+  
index d263b2515f17a5267e9b449c814378961751f389..403555964ca15310fabcc122544ecdcf9e615fa7 100644 (file)
@@ -5,7 +5,20 @@
     let mut _1: (usize, bool);           // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22
 
     bb0: {
-        _1 = CheckedAdd(const 1usize, const 1usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+        _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x00000001))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-41697.rs:18:19: 18:20
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x00000001))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-41697.rs:18:21: 18:22
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000001))
@@ -18,7 +31,6 @@
                                          // mir::Constant
                                          // + span: $DIR/issue-41697.rs:18:21: 18:22
                                          // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
-        assert(!move (_1.1: bool), "attempt to add with overflow") -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
     }
 
     bb1 (cleanup): {
index 6c00f49fb75b1590f697e5f8aa88bffcc8d150d9..df933d3ac251f21a8016869ca0d26c7ce1b293b8 100644 (file)
@@ -5,7 +5,20 @@
     let mut _1: (usize, bool);           // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22
 
     bb0: {
-        _1 = CheckedAdd(const 1usize, const 1usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+        _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x0000000000000001))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-41697.rs:18:19: 18:20
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x0000000000000001))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-41697.rs:18:21: 18:22
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000001))
@@ -18,7 +31,6 @@
                                          // mir::Constant
                                          // + span: $DIR/issue-41697.rs:18:21: 18:22
                                          // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
-        assert(!move (_1.1: bool), "attempt to add with overflow") -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
     }
 
     bb1 (cleanup): {
index ce940273c3ef5e1474927133a82a06e06bd84b67..76ad865bcc842ef5e7b3fd91a207d03cefca2303 100644 (file)
@@ -96,7 +96,7 @@ fn main() -> () {
     bb8: {
         StorageDead(_3);                 // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
         _5 = discriminant(_1);           // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
-        switchInt(move _5) -> [0isize: bb10, otherwise: bb9]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
+        switchInt(move _5) -> [0_isize: bb10, otherwise: bb9]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
     }
 
     bb9: {
@@ -250,7 +250,7 @@ fn main() -> () {
 
     bb20: {
         _10 = discriminant(_1);          // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-        switchInt(move _10) -> [0isize: bb15, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        switchInt(move _10) -> [0_isize: bb15, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
     bb21: {
@@ -259,7 +259,7 @@ fn main() -> () {
 
     bb22 (cleanup): {
         _11 = discriminant(_1);          // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-        switchInt(move _11) -> [0isize: bb17, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        switchInt(move _11) -> [0_isize: bb17, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
     bb23 (cleanup): {
index 7299a683a9f0b3ba00acbcff491a974a8ad5924e..f65b93a34da65a918c2e68a3d24ec966fb3181b5 100644 (file)
@@ -58,7 +58,7 @@ fn main() -> () {
     }
 
     bb7: {
-        _2 = const 4i32;                 // scope 0 at $DIR/issue-49232.rs:9:26: 9:27
+        _2 = const 4_i32;                // scope 0 at $DIR/issue-49232.rs:9:26: 9:27
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000004))
index 0b8b03961f2a013e6f5d7edd9e43f22922a079fc..56916d676ed44c0509b8e3e0c9d895e1b6d70008 100644 (file)
@@ -46,7 +46,7 @@ fn test() -> std::option::Option<std::boxed::Box<u32>> {
     bb2: {
         StorageDead(_4);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
         _5 = discriminant(_3);           // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        switchInt(move _5) -> [0isize: bb4, 1isize: bb6, otherwise: bb5]; // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        switchInt(move _5) -> [0_isize: bb4, 1_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
     }
 
     bb3 (cleanup): {
diff --git a/src/test/mir-opt/issue-72181-1.rs b/src/test/mir-opt/issue-72181-1.rs
new file mode 100644 (file)
index 0000000..6d65f84
--- /dev/null
@@ -0,0 +1,21 @@
+// compile-flags: -Z mir-opt-level=1
+// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
+
+#![feature(never_type)]
+#![allow(unused, invalid_value)]
+
+enum Void {}
+
+// EMIT_MIR rustc.f.mir_map.0.mir
+fn f(v: Void) -> ! {
+    match v {}
+}
+
+// EMIT_MIR rustc.main.mir_map.0.mir
+fn main() {
+    let v: Void = unsafe {
+        std::mem::transmute::<(), Void>(())
+    };
+
+    f(v);
+}
diff --git a/src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir b/src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir
new file mode 100644 (file)
index 0000000..1821365
--- /dev/null
@@ -0,0 +1,37 @@
+// MIR for `f` 0 mir_map
+
+fn f(_1: Void) -> ! {
+    debug v => _1;                       // in scope 0 at $DIR/issue-72181-1.rs:10:6: 10:7
+    let mut _0: !;                       // return place in scope 0 at $DIR/issue-72181-1.rs:10:18: 10:19
+    let mut _2: !;                       // in scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
+    let mut _3: !;                       // in scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
+        StorageLive(_3);                 // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
+        FakeRead(ForMatchedPlace, _1);   // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
+        unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181-1.rs:10:1: 12:2
+    }
+
+    bb2: {
+        unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
+    }
+
+    bb3: {
+        StorageDead(_3);                 // scope 0 at $DIR/issue-72181-1.rs:11:14: 11:15
+        unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
+    }
+
+    bb4: {
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181-1.rs:12:1: 12:2
+        goto -> bb5;                     // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
+    }
+
+    bb5: {
+        return;                          // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
+    }
+}
diff --git a/src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir
new file mode 100644 (file)
index 0000000..b87d029
--- /dev/null
@@ -0,0 +1,67 @@
+// MIR for `main` 0 mir_map
+
+| User Type Annotations
+| 0: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16
+| 1: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16
+|
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181-1.rs:15:11: 15:11
+    let mut _1: !;                       // in scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2
+    let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
+    let mut _3: ();                      // in scope 0 at $DIR/issue-72181-1.rs:17:41: 17:43
+    let _4: !;                           // in scope 0 at $DIR/issue-72181-1.rs:20:5: 20:9
+    let mut _5: Void;                    // in scope 0 at $DIR/issue-72181-1.rs:20:7: 20:8
+    scope 1 {
+        debug v => _2;                   // in scope 1 at $DIR/issue-72181-1.rs:16:9: 16:10
+    }
+    scope 2 {
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
+        StorageLive(_3);                 // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
+        _3 = ();                         // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
+        _2 = const std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
+                                         // ty::Const
+                                         // + ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181-1.rs:17:9: 17:40
+                                         // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181-1.rs:15:1: 21:2
+    }
+
+    bb2: {
+        StorageDead(_3);                 // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44
+        FakeRead(ForLet, _2);            // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
+        AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16
+        StorageLive(_4);                 // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
+        StorageLive(_5);                 // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
+        _5 = move _2;                    // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
+        const f(move _5) -> bb1;         // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
+                                         // ty::Const
+                                         // + ty: fn(Void) -> ! {f}
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181-1.rs:20:5: 20:6
+                                         // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb3: {
+        StorageDead(_5);                 // scope 1 at $DIR/issue-72181-1.rs:20:8: 20:9
+        StorageDead(_4);                 // scope 1 at $DIR/issue-72181-1.rs:20:9: 20:10
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181-1.rs:21:1: 21:2
+        unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2
+    }
+
+    bb4: {
+        goto -> bb5;                     // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
+    }
+
+    bb5: {
+        return;                          // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
+    }
+}
diff --git a/src/test/mir-opt/issue-72181.rs b/src/test/mir-opt/issue-72181.rs
new file mode 100644 (file)
index 0000000..9373ce1
--- /dev/null
@@ -0,0 +1,28 @@
+// compile-flags: -Z mir-opt-level=1
+// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
+
+use std::mem;
+
+#[derive(Copy, Clone)]
+enum Never {}
+
+union Foo {
+    a: u64,
+    b: Never
+}
+
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR rustc.foo.mir_map.0.mir
+fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
+
+// EMIT_MIR rustc.bar.mir_map.0.mir
+fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
+
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR rustc.main.mir_map.0.mir
+fn main() {
+    let _ = mem::size_of::<Foo>();
+
+    let f = [Foo { a: 42 }, Foo { a: 10 }];
+    let _ = unsafe { f[0].a };
+}
diff --git a/src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir b/src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir
new file mode 100644 (file)
index 0000000..29654c2
--- /dev/null
@@ -0,0 +1,25 @@
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43
+    let _2: u32;                         // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+    scope 1 {
+        debug x => _2;                   // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+        _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+        _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
+        goto -> bb2;                     // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
+    }
+
+    bb2: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir b/src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir
new file mode 100644 (file)
index 0000000..9f8810e
--- /dev/null
@@ -0,0 +1,37 @@
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+    debug xs => _1;                      // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37
+    let _2: usize;                       // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+    let mut _3: usize;                   // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+    let mut _4: bool;                    // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+        _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x00000000))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:16:43: 16:44
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
+        _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+        _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+        assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
+    }
+
+    bb2: {
+        _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
+        goto -> bb3;                     // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+    }
+
+    bb3: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir
new file mode 100644 (file)
index 0000000..e3fb5eb
--- /dev/null
@@ -0,0 +1,93 @@
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11
+    let mut _1: usize;                   // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+    let mut _3: Foo;                     // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27
+    let mut _4: Foo;                     // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42
+    let mut _5: u64;                     // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30
+    let _6: usize;                       // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25
+    let mut _7: usize;                   // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+    let mut _8: bool;                    // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+    scope 1 {
+        let _2: [Foo; 2];                // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+        scope 2 {
+            debug f => _2;               // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10
+            scope 3 {
+            }
+            scope 4 {
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+        _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+                                         // ty::Const
+                                         // + ty: fn() -> usize {std::mem::size_of::<Foo>}
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:24:13: 24:32
+                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
+    }
+
+    bb2: {
+        StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
+        StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+        StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+        _3 = Foo { a: const 42_u64 };    // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+                                         // ty::Const
+                                         // + ty: u64
+                                         // + val: Value(Scalar(0x000000000000002a))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:26:23: 26:25
+                                         // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
+        StorageLive(_4);                 // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+        _4 = Foo { a: const 10_u64 };    // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+                                         // ty::Const
+                                         // + ty: u64
+                                         // + val: Value(Scalar(0x000000000000000a))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:26:38: 26:40
+                                         // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
+        _2 = [move _3, move _4];         // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
+        StorageDead(_4);                 // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+        StorageDead(_3);                 // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+        FakeRead(ForLet, _2);            // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+        StorageLive(_5);                 // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
+        StorageLive(_6);                 // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+        _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x00000000))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:27:24: 27:25
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) }
+        _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+        _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+        assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+    }
+
+    bb3: {
+        _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
+        StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+        StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+        _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
+                                         // ty::Const
+                                         // + ty: ()
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:23:11: 28:2
+                                         // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+        StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
+        goto -> bb4;                     // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir b/src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir
new file mode 100644 (file)
index 0000000..29654c2
--- /dev/null
@@ -0,0 +1,25 @@
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43
+    let _2: u32;                         // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+    scope 1 {
+        debug x => _2;                   // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+        _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
+        _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
+        goto -> bb2;                     // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
+    }
+
+    bb2: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir b/src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir
new file mode 100644 (file)
index 0000000..aab8efb
--- /dev/null
@@ -0,0 +1,37 @@
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+    debug xs => _1;                      // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37
+    let _2: usize;                       // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+    let mut _3: usize;                   // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+    let mut _4: bool;                    // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+        _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x0000000000000000))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:16:43: 16:44
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+        _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+        _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+        assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
+    }
+
+    bb2: {
+        _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
+        goto -> bb3;                     // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+    }
+
+    bb3: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir
new file mode 100644 (file)
index 0000000..d9e791b
--- /dev/null
@@ -0,0 +1,93 @@
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11
+    let mut _1: usize;                   // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+    let mut _3: Foo;                     // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27
+    let mut _4: Foo;                     // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42
+    let mut _5: u64;                     // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30
+    let _6: usize;                       // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25
+    let mut _7: usize;                   // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+    let mut _8: bool;                    // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26
+    scope 1 {
+        let _2: [Foo; 2];                // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+        scope 2 {
+            debug f => _2;               // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10
+            scope 3 {
+            }
+            scope 4 {
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+        _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+                                         // ty::Const
+                                         // + ty: fn() -> usize {std::mem::size_of::<Foo>}
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:24:13: 24:32
+                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
+    }
+
+    bb2: {
+        StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
+        StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+        StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+        _3 = Foo { a: const 42_u64 };    // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
+                                         // ty::Const
+                                         // + ty: u64
+                                         // + val: Value(Scalar(0x000000000000002a))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:26:23: 26:25
+                                         // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
+        StorageLive(_4);                 // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+        _4 = Foo { a: const 10_u64 };    // scope 1 at $DIR/issue-72181.rs:26:29: 26:42
+                                         // ty::Const
+                                         // + ty: u64
+                                         // + val: Value(Scalar(0x000000000000000a))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:26:38: 26:40
+                                         // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
+        _2 = [move _3, move _4];         // scope 1 at $DIR/issue-72181.rs:26:13: 26:43
+        StorageDead(_4);                 // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+        StorageDead(_3);                 // scope 1 at $DIR/issue-72181.rs:26:42: 26:43
+        FakeRead(ForLet, _2);            // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
+        StorageLive(_5);                 // scope 2 at $DIR/issue-72181.rs:27:13: 27:30
+        StorageLive(_6);                 // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+        _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x0000000000000000))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:27:24: 27:25
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+        _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+        _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+        assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+    }
+
+    bb3: {
+        _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
+        StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+        StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
+        _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
+                                         // ty::Const
+                                         // + ty: ()
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:23:11: 28:2
+                                         // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+        StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
+        goto -> bb4;                     // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir b/src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir
new file mode 100644 (file)
index 0000000..3b6dc46
--- /dev/null
@@ -0,0 +1,25 @@
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:18:40: 18:43
+    let _2: u32;                         // in scope 0 at $DIR/issue-72181.rs:18:13: 18:14
+    scope 1 {
+        debug x => _2;                   // in scope 1 at $DIR/issue-72181.rs:18:13: 18:14
+    }
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:18:13: 18:14
+        _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:18:13: 18:14
+        _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:18:46: 18:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:18:48: 18:49
+        goto -> bb2;                     // scope 0 at $DIR/issue-72181.rs:18:49: 18:49
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:18:1: 18:49
+    }
+
+    bb2: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:18:49: 18:49
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir b/src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir
new file mode 100644 (file)
index 0000000..2941e28
--- /dev/null
@@ -0,0 +1,37 @@
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+    debug xs => _1;                      // in scope 0 at $DIR/issue-72181.rs:15:8: 15:10
+    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:15:34: 15:37
+    let _2: usize;                       // in scope 0 at $DIR/issue-72181.rs:15:43: 15:44
+    let mut _3: usize;                   // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+    let mut _4: bool;                    // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+
+    bb0: {
+        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:15:43: 15:44
+        _2 = const 0usize;               // scope 0 at $DIR/issue-72181.rs:15:43: 15:44
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x0000000000000000))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:15:43: 15:44
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+        _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+        _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+        assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:15:40: 15:45
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:15:1: 15:49
+    }
+
+    bb2: {
+        _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:15:40: 15:47
+        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:15:48: 15:49
+        goto -> bb3;                     // scope 0 at $DIR/issue-72181.rs:15:49: 15:49
+    }
+
+    bb3: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:15:49: 15:49
+    }
+}
diff --git a/src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir
new file mode 100644 (file)
index 0000000..65f4de0
--- /dev/null
@@ -0,0 +1,93 @@
+// MIR for `main` 0 mir_map
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181.rs:21:11: 21:11
+    let mut _1: usize;                   // in scope 0 at $DIR/issue-72181.rs:22:13: 22:34
+    let mut _3: Foo;                     // in scope 0 at $DIR/issue-72181.rs:24:14: 24:27
+    let mut _4: Foo;                     // in scope 0 at $DIR/issue-72181.rs:24:29: 24:42
+    let mut _5: u64;                     // in scope 0 at $DIR/issue-72181.rs:25:13: 25:30
+    let _6: usize;                       // in scope 0 at $DIR/issue-72181.rs:25:24: 25:25
+    let mut _7: usize;                   // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26
+    let mut _8: bool;                    // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26
+    scope 1 {
+        let _2: [Foo; 2];                // in scope 1 at $DIR/issue-72181.rs:24:9: 24:10
+        scope 2 {
+            debug f => _2;               // in scope 2 at $DIR/issue-72181.rs:24:9: 24:10
+            scope 3 {
+            }
+            scope 4 {
+            }
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:22:13: 22:34
+        _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:22:13: 22:34
+                                         // ty::Const
+                                         // + ty: fn() -> usize {std::mem::size_of::<Foo>}
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:22:13: 22:32
+                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb1 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:21:1: 26:2
+    }
+
+    bb2: {
+        StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:22:34: 22:35
+        StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:24:9: 24:10
+        StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:24:14: 24:27
+        _3 = Foo { a: const 42u64 };     // scope 1 at $DIR/issue-72181.rs:24:14: 24:27
+                                         // ty::Const
+                                         // + ty: u64
+                                         // + val: Value(Scalar(0x000000000000002a))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:24:23: 24:25
+                                         // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) }
+        StorageLive(_4);                 // scope 1 at $DIR/issue-72181.rs:24:29: 24:42
+        _4 = Foo { a: const 10u64 };     // scope 1 at $DIR/issue-72181.rs:24:29: 24:42
+                                         // ty::Const
+                                         // + ty: u64
+                                         // + val: Value(Scalar(0x000000000000000a))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:24:38: 24:40
+                                         // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) }
+        _2 = [move _3, move _4];         // scope 1 at $DIR/issue-72181.rs:24:13: 24:43
+        StorageDead(_4);                 // scope 1 at $DIR/issue-72181.rs:24:42: 24:43
+        StorageDead(_3);                 // scope 1 at $DIR/issue-72181.rs:24:42: 24:43
+        FakeRead(ForLet, _2);            // scope 1 at $DIR/issue-72181.rs:24:9: 24:10
+        StorageLive(_5);                 // scope 2 at $DIR/issue-72181.rs:25:13: 25:30
+        StorageLive(_6);                 // scope 4 at $DIR/issue-72181.rs:25:24: 25:25
+        _6 = const 0usize;               // scope 4 at $DIR/issue-72181.rs:25:24: 25:25
+                                         // ty::Const
+                                         // + ty: usize
+                                         // + val: Value(Scalar(0x0000000000000000))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:25:24: 25:25
+                                         // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) }
+        _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
+        _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
+        assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:25:22: 25:26
+    }
+
+    bb3: {
+        _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:25:22: 25:28
+        StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:25:30: 25:31
+        StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:25:30: 25:31
+        _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:21:11: 26:2
+                                         // ty::Const
+                                         // + ty: ()
+                                         // + val: Value(Scalar(<ZST>))
+                                         // mir::Constant
+                                         // + span: $DIR/issue-72181.rs:21:11: 26:2
+                                         // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+        StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:26:1: 26:2
+        goto -> bb4;                     // scope 0 at $DIR/issue-72181.rs:26:2: 26:2
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/issue-72181.rs:26:2: 26:2
+    }
+}
index 7046ebb793466de1503dd8398ebc0e2a1736b09c..e699abf421d6074b08d99b550f1a00e446d1481b 100644 (file)
@@ -67,7 +67,7 @@ fn main() -> () {
 
     bb6: {
         StorageLive(_6);                 // scope 0 at $DIR/loop_test.rs:14:13: 14:14
-        _6 = const 1i32;                 // scope 0 at $DIR/loop_test.rs:14:17: 14:18
+        _6 = const 1_i32;                // scope 0 at $DIR/loop_test.rs:14:17: 14:18
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
index 856248e90d495dac63e2b23d4e4823657cf76fc8..c6832f21208d4d8b86179aa27c1c47b9df04ed23 100644 (file)
@@ -54,7 +54,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb5: {
-        _0 = const 1i32;                 // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
+        _0 = const 1_i32;                // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -82,7 +82,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb8: {
-        _0 = const 3i32;                 // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -142,7 +142,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb16: {
-        _0 = const 3i32;                 // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -181,7 +181,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb20: {
-        _0 = const 2i32;                 // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
+        _0 = const 2_i32;                // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index 1f6b2c982fee0fb5231f8824f663003999fb1180..45f7e91d097c042a195c8a14fc021b44beed98a7 100644 (file)
@@ -67,7 +67,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb8: {
-        _0 = const 1i32;                 // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
+        _0 = const 1_i32;                // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -102,7 +102,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb12: {
-        _0 = const 3i32;                 // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -173,7 +173,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb21: {
-        _0 = const 3i32;                 // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
+        _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -216,7 +216,7 @@ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
     }
 
     bb25: {
-        _0 = const 2i32;                 // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
+        _0 = const 2_i32;                // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index 3e1dec697b76f4ecea869b57a560b2a1941e0dad..d4a2afe2957818b7ebe875b60d93133a5826d23b 100644 (file)
@@ -26,7 +26,7 @@ fn full_tested_match() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
         StorageLive(_2);                 // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
-        _2 = std::option::Option::<i32>::Some(const 42i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
+        _2 = std::option::Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x0000002a))
@@ -35,7 +35,7 @@ fn full_tested_match() -> () {
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         _3 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
-        switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
+        switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
     }
 
     bb1 (cleanup): {
@@ -43,7 +43,7 @@ fn full_tested_match() -> () {
     }
 
     bb2: {
-        _1 = (const 3i32, const 3i32);   // scope 0 at $DIR/match_false_edges.rs:18:17: 18:23
+        _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:18:17: 18:23
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -104,7 +104,7 @@ fn full_tested_match() -> () {
         _5 = ((_2 as Some).0: i32);      // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
         StorageLive(_8);                 // scope 2 at $DIR/match_false_edges.rs:16:35: 16:36
         _8 = _5;                         // scope 2 at $DIR/match_false_edges.rs:16:35: 16:36
-        _1 = (const 1i32, move _8);      // scope 2 at $DIR/match_false_edges.rs:16:31: 16:37
+        _1 = (const 1_i32, move _8);     // scope 2 at $DIR/match_false_edges.rs:16:31: 16:37
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -128,7 +128,7 @@ fn full_tested_match() -> () {
         _9 = ((_2 as Some).0: i32);      // scope 0 at $DIR/match_false_edges.rs:17:14: 17:15
         StorageLive(_10);                // scope 3 at $DIR/match_false_edges.rs:17:24: 17:25
         _10 = _9;                        // scope 3 at $DIR/match_false_edges.rs:17:24: 17:25
-        _1 = (const 2i32, move _10);     // scope 3 at $DIR/match_false_edges.rs:17:20: 17:26
+        _1 = (const 2_i32, move _10);    // scope 3 at $DIR/match_false_edges.rs:17:20: 17:26
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index 4e6dc6e13ff629467e00f863443dbd43687772bd..f1744a94fdc132ca7e8830406831a731a0e9b01c 100644 (file)
@@ -25,7 +25,7 @@ fn full_tested_match2() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
         StorageLive(_2);                 // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
-        _2 = std::option::Option::<i32>::Some(const 42i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
+        _2 = std::option::Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x0000002a))
@@ -34,7 +34,7 @@ fn full_tested_match2() -> () {
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
         _3 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
-        switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
+        switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
     }
 
     bb1 (cleanup): {
@@ -54,7 +54,7 @@ fn full_tested_match2() -> () {
         _9 = ((_2 as Some).0: i32);      // scope 0 at $DIR/match_false_edges.rs:29:14: 29:15
         StorageLive(_10);                // scope 3 at $DIR/match_false_edges.rs:29:24: 29:25
         _10 = _9;                        // scope 3 at $DIR/match_false_edges.rs:29:24: 29:25
-        _1 = (const 2i32, move _10);     // scope 3 at $DIR/match_false_edges.rs:29:20: 29:26
+        _1 = (const 2_i32, move _10);    // scope 3 at $DIR/match_false_edges.rs:29:20: 29:26
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
@@ -96,7 +96,7 @@ fn full_tested_match2() -> () {
         _5 = ((_2 as Some).0: i32);      // scope 0 at $DIR/match_false_edges.rs:27:14: 27:15
         StorageLive(_8);                 // scope 2 at $DIR/match_false_edges.rs:27:35: 27:36
         _8 = _5;                         // scope 2 at $DIR/match_false_edges.rs:27:35: 27:36
-        _1 = (const 1i32, move _8);      // scope 2 at $DIR/match_false_edges.rs:27:31: 27:37
+        _1 = (const 1_i32, move _8);     // scope 2 at $DIR/match_false_edges.rs:27:31: 27:37
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -116,7 +116,7 @@ fn full_tested_match2() -> () {
     }
 
     bb10: {
-        _1 = (const 3i32, const 3i32);   // scope 0 at $DIR/match_false_edges.rs:28:17: 28:23
+        _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:28:17: 28:23
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
index b54058ca73f6f4d5bb38394e673ee6727825380f..4ab4c4d341e2fc3f466fa1dbc674bc55d8bd045a 100644 (file)
@@ -36,7 +36,7 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
         StorageLive(_2);                 // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
-        _2 = std::option::Option::<i32>::Some(const 1i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
+        _2 = std::option::Option::<i32>::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -45,7 +45,7 @@ fn main() -> () {
                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
         _4 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
-        switchInt(move _4) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
+        switchInt(move _4) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
     }
 
     bb1 (cleanup): {
@@ -63,7 +63,7 @@ fn main() -> () {
     bb4: {
         StorageLive(_14);                // scope 0 at $DIR/match_false_edges.rs:39:9: 39:11
         _14 = _2;                        // scope 0 at $DIR/match_false_edges.rs:39:9: 39:11
-        _1 = const 4i32;                 // scope 5 at $DIR/match_false_edges.rs:39:15: 39:16
+        _1 = const 4_i32;                // scope 5 at $DIR/match_false_edges.rs:39:15: 39:16
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000004))
@@ -102,7 +102,7 @@ fn main() -> () {
         FakeRead(ForGuardBinding, _7);   // scope 0 at $DIR/match_false_edges.rs:36:27: 36:28
         StorageLive(_6);                 // scope 0 at $DIR/match_false_edges.rs:36:14: 36:16
         _6 = ((_2 as Some).0: i32);      // scope 0 at $DIR/match_false_edges.rs:36:14: 36:16
-        _1 = const 1i32;                 // scope 2 at $DIR/match_false_edges.rs:36:32: 36:33
+        _1 = const 1_i32;                // scope 2 at $DIR/match_false_edges.rs:36:32: 36:33
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -123,7 +123,7 @@ fn main() -> () {
     bb10: {
         StorageLive(_9);                 // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
         _9 = _2;                         // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
-        _1 = const 2i32;                 // scope 3 at $DIR/match_false_edges.rs:37:15: 37:16
+        _1 = const 2_i32;                // scope 3 at $DIR/match_false_edges.rs:37:15: 37:16
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
@@ -161,7 +161,7 @@ fn main() -> () {
         FakeRead(ForGuardBinding, _11);  // scope 0 at $DIR/match_false_edges.rs:38:28: 38:29
         StorageLive(_10);                // scope 0 at $DIR/match_false_edges.rs:38:14: 38:15
         _10 = ((_2 as Some).0: i32);     // scope 0 at $DIR/match_false_edges.rs:38:14: 38:15
-        _1 = const 3i32;                 // scope 4 at $DIR/match_false_edges.rs:38:33: 38:34
+        _1 = const 3_i32;                // scope 4 at $DIR/match_false_edges.rs:38:33: 38:34
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
index 5996496406a9f8584ca6eaee623001d1fda86fc2..ef6c88d8005b3dbce79565c634cbc8f4d77fbcf9 100644 (file)
@@ -20,7 +20,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/match_test.rs:7:9: 7:10
-        _1 = const 3i32;                 // scope 0 at $DIR/match_test.rs:7:13: 7:14
+        _1 = const 3_i32;                // scope 0 at $DIR/match_test.rs:7:13: 7:14
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -39,7 +39,7 @@ fn main() -> () {
         FakeRead(ForLet, _2);            // scope 1 at $DIR/match_test.rs:8:9: 8:10
         StorageLive(_3);                 // scope 2 at $DIR/match_test.rs:12:5: 17:6
         FakeRead(ForMatchedPlace, _1);   // scope 2 at $DIR/match_test.rs:12:11: 12:12
-        _6 = Le(const 0i32, _1);         // scope 2 at $DIR/match_test.rs:13:9: 13:14
+        _6 = Le(const 0_i32, _1);        // scope 2 at $DIR/match_test.rs:13:9: 13:14
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
@@ -50,7 +50,7 @@ fn main() -> () {
     }
 
     bb1: {
-        _7 = Lt(_1, const 10i32);        // scope 2 at $DIR/match_test.rs:13:9: 13:14
+        _7 = Lt(_1, const 10_i32);       // scope 2 at $DIR/match_test.rs:13:9: 13:14
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x0000000a))
@@ -65,7 +65,7 @@ fn main() -> () {
     }
 
     bb3: {
-        _3 = const 3i32;                 // scope 2 at $DIR/match_test.rs:16:14: 16:15
+        _3 = const 3_i32;                // scope 2 at $DIR/match_test.rs:16:14: 16:15
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000003))
@@ -76,7 +76,7 @@ fn main() -> () {
     }
 
     bb4: {
-        _4 = Le(const 10i32, _1);        // scope 2 at $DIR/match_test.rs:14:9: 14:16
+        _4 = Le(const 10_i32, _1);       // scope 2 at $DIR/match_test.rs:14:9: 14:16
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x0000000a))
@@ -87,7 +87,7 @@ fn main() -> () {
     }
 
     bb5: {
-        _5 = Le(_1, const 20i32);        // scope 2 at $DIR/match_test.rs:14:9: 14:16
+        _5 = Le(_1, const 20_i32);       // scope 2 at $DIR/match_test.rs:14:9: 14:16
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000014))
@@ -102,7 +102,7 @@ fn main() -> () {
     }
 
     bb7: {
-        switchInt(_1) -> [-1i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
+        switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
     }
 
     bb8: {
@@ -119,7 +119,7 @@ fn main() -> () {
     bb10: {
         StorageDead(_9);                 // scope 2 at $DIR/match_test.rs:13:24: 13:25
         FakeRead(ForMatchGuard, _8);     // scope 2 at $DIR/match_test.rs:13:18: 13:19
-        _3 = const 0i32;                 // scope 2 at $DIR/match_test.rs:13:23: 13:24
+        _3 = const 0_i32;                // scope 2 at $DIR/match_test.rs:13:23: 13:24
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
@@ -135,7 +135,7 @@ fn main() -> () {
     }
 
     bb12: {
-        _3 = const 1i32;                 // scope 2 at $DIR/match_test.rs:14:20: 14:21
+        _3 = const 1_i32;                // scope 2 at $DIR/match_test.rs:14:20: 14:21
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -146,7 +146,7 @@ fn main() -> () {
     }
 
     bb13: {
-        _3 = const 2i32;                 // scope 2 at $DIR/match_test.rs:15:15: 15:16
+        _3 = const 2_i32;                // scope 2 at $DIR/match_test.rs:15:15: 15:16
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index eb6911735a59e3d8911453524e70a804f5740fda..ce987a57d5fc7b3854d11bb7ad660633ef48ab64 100644 (file)
@@ -14,7 +14,7 @@ fn unwrap(_1: std::option::Option<T>) -> T {
 
     bb0: {
         _2 = discriminant(_1);           // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
-        switchInt(move _2) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
+        switchInt(move _2) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16
     }
 
     bb1 (cleanup): {
index 4511470f3a50f69fae79bcf6a81834ca48d1be81..18fbffb463067b4fbbce55941619f35e18078bd0 100644 (file)
@@ -17,8 +17,8 @@
   
       bb0: {
 -         StorageLive(_2);                 // scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16
--         _2 = [const 0u8; 1024];          // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
-+         _0 = [const 0u8; 1024];          // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
+-         _2 = [const 0_u8; 1024];         // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
++         _0 = [const 0_u8; 1024];         // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x00))
index 21dab9ab923946c9a7110c7e65e23796d052ee54..075c7647c671fc94e8cc1630809859a5c389e792 100644 (file)
@@ -16,7 +16,7 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14
         StorageLive(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42
         StorageLive(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
-        _3 = Droppy(const 0usize);       // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
+        _3 = Droppy(const 0_usize);      // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000000))
@@ -29,7 +29,7 @@ fn main() -> () {
         StorageDead(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:42: 6:43
         StorageLive(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29
         StorageLive(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
-        _5 = Droppy(const 0usize);       // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
+        _5 = Droppy(const 0_usize);      // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000000))
index cf46f74c16df35b2d999f0cc99c151dc63cc4bac..99a74b6b24f7fd5f4e913c6e245c5c9f88564f42 100644 (file)
@@ -16,7 +16,7 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:9: 6:14
         StorageLive(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:24: 6:42
         StorageLive(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
-        _3 = Droppy(const 0usize);       // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
+        _3 = Droppy(const 0_usize);      // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:32: 6:41
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000000))
@@ -29,7 +29,7 @@ fn main() -> () {
         StorageDead(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:6:42: 6:43
         StorageLive(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:11: 7:29
         StorageLive(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
-        _5 = Droppy(const 0usize);       // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
+        _5 = Droppy(const 0_usize);      // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:19: 7:28
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000000))
index 4e626b1384afc1702da4163730603edcaabd3aa4..7fc209778703eeee0822a7c64c0ac9116e982046 100644 (file)
 -         FakeRead(ForMatchedPlace, _1);   // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12
 +         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:7:11: 7:12
           _3 = discriminant(_1);           // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
-          switchInt(move _3) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
+          switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:9: 8:16
       }
   
       bb1: {
-          _0 = const 1i32;                 // scope 0 at $DIR/remove_fake_borrows.rs:9:14: 9:15
+          _0 = const 1_i32;                // scope 0 at $DIR/remove_fake_borrows.rs:9:14: 9:15
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000001))
@@ -31,7 +31,7 @@
       }
   
       bb2: {
-          switchInt((*(*((_1 as Some).0: &&i32)))) -> [0i32: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:14: 8:15
+          switchInt((*(*((_1 as Some).0: &&i32)))) -> [0_i32: bb3, otherwise: bb1]; // scope 0 at $DIR/remove_fake_borrows.rs:8:14: 8:15
       }
   
       bb3: {
@@ -62,7 +62,7 @@
 +         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21
 +         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21
 +         nop;                             // scope 0 at $DIR/remove_fake_borrows.rs:8:20: 8:21
-          _0 = const 0i32;                 // scope 0 at $DIR/remove_fake_borrows.rs:8:25: 8:26
+          _0 = const 0_i32;                // scope 0 at $DIR/remove_fake_borrows.rs:8:25: 8:26
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000000))
index c8c5da37abe32abf88be8431669a6d8b17195962..14a7f2d500542c6b1e6edd5ae9a95c7d948b95bc 100644 (file)
@@ -56,7 +56,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/retag.rs:30:9: 30:14
-        _1 = const 0i32;                 // scope 0 at $DIR/retag.rs:30:17: 30:18
+        _1 = const 0_i32;                // scope 0 at $DIR/retag.rs:30:17: 30:18
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
@@ -67,7 +67,7 @@ fn main() -> () {
         StorageLive(_3);                 // scope 1 at $DIR/retag.rs:32:13: 32:14
         StorageLive(_4);                 // scope 1 at $DIR/retag.rs:32:17: 32:24
         StorageLive(_5);                 // scope 1 at $DIR/retag.rs:32:17: 32:24
-        _5 = Test(const 0i32);           // scope 1 at $DIR/retag.rs:32:17: 32:24
+        _5 = Test(const 0_i32);          // scope 1 at $DIR/retag.rs:32:17: 32:24
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
@@ -170,7 +170,7 @@ fn main() -> () {
         StorageLive(_19);                // scope 7 at $DIR/retag.rs:47:5: 47:24
         StorageLive(_20);                // scope 7 at $DIR/retag.rs:47:5: 47:12
         StorageLive(_21);                // scope 7 at $DIR/retag.rs:47:5: 47:12
-        _21 = Test(const 0i32);          // scope 7 at $DIR/retag.rs:47:5: 47:12
+        _21 = Test(const 0_i32);         // scope 7 at $DIR/retag.rs:47:5: 47:12
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
index cc2738b5e50a36b00c79f9483f3f5c8dd27d77ef..da3191554f0e067b88069b127875bdcaa1739a63 100644 (file)
@@ -18,7 +18,7 @@ fn match_bool(_1: bool) -> usize {
     }
 
     bb3: {
-        _0 = const 20usize;              // scope 0 at $DIR/simple-match.rs:8:14: 8:16
+        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:8:14: 8:16
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000014))
@@ -29,7 +29,7 @@ fn match_bool(_1: bool) -> usize {
     }
 
     bb4: {
-        _0 = const 10usize;              // scope 0 at $DIR/simple-match.rs:7:17: 7:19
+        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:7:17: 7:19
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000a))
index 309041abef9be180e04cb7613b0405abb39d4c94..55b51a899bc507a33fe996a25a174cd98d66e7a0 100644 (file)
@@ -18,7 +18,7 @@ fn match_bool(_1: bool) -> usize {
     }
 
     bb3: {
-        _0 = const 20usize;              // scope 0 at $DIR/simple-match.rs:8:14: 8:16
+        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:8:14: 8:16
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000014))
@@ -29,7 +29,7 @@ fn match_bool(_1: bool) -> usize {
     }
 
     bb4: {
-        _0 = const 10usize;              // scope 0 at $DIR/simple-match.rs:7:17: 7:19
+        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:7:17: 7:19
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x000000000000000a))
index dfd6d6f0f2ecd270b614f4ddfad3a17c47f5cc8e..33a3403cada92e4524dfb7961f24f4c57f4ae83f 100644 (file)
@@ -19,7 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
-          ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+          ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x00))
@@ -28,7 +28,7 @@
                                            // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
           discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
-          _3 = const 0isize;               // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+          _3 = const 0_isize;              // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
                                            // ty::Const
                                            // + ty: isize
                                            // + val: Value(Scalar(0x00000000))
       }
   
       bb1: {
-          ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+          _2 = const Dst::Foo(0_u8);       // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
                                            // ty::Const
-                                           // + ty: u8
+                                           // + ty: Dst
                                            // + val: Value(Scalar(0x00))
                                            // mir::Constant
-                                           // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
-                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
-          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // + span: $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
           goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
       }
   
index f2bbd195869931ae0d53989d03c705461ae8e5ee..7e4fe1c2dcc4c9633ee1b755ab9f0e16cf8bdd62 100644 (file)
@@ -19,7 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
-          ((_1 as Foo).0: u8) = const 0u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
+          ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x00))
@@ -28,7 +28,7 @@
                                            // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
           discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
-          _3 = const 0isize;               // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
+          _3 = const 0_isize;              // scope 1 at $DIR/simplify-arm-identity.rs:20:9: 20:20
                                            // ty::Const
                                            // + ty: isize
                                            // + val: Value(Scalar(0x0000000000000000))
       }
   
       bb1: {
-          ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+          _2 = const Dst::Foo(0_u8);       // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
                                            // ty::Const
-                                           // + ty: u8
+                                           // + ty: Dst
                                            // + val: Value(Scalar(0x00))
                                            // mir::Constant
-                                           // + span: $DIR/simplify-arm-identity.rs:21:30: 21:31
-                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
-          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // + span: $DIR/simplify-arm-identity.rs:21:21: 21:32
+                                           // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
           goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
       }
   
index b2517cb7012b488869e7f3404f87fd9046292f57..e7373391b79c77f4b8476baaaacd3f48f57b1286 100644 (file)
       }
   
       bb1: {
-          ((_2 as Foo).0: u8) = const 0u8; // scope 1 at $DIR/simplify-arm-identity.rs:20:21: 20:32
+          _2 = const Dst::Foo(0u8);        // bb1[0]: scope 1 at $DIR/simplify-arm-identity.rs:20:21: 20:32
                                            // ty::Const
-                                           // + ty: u8
+                                           // + ty: Dst
                                            // + val: Value(Scalar(0x00))
                                            // mir::Constant
-                                           // + span: $DIR/simplify-arm-identity.rs:20:30: 20:31
-                                           // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
-          discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:20:21: 20:32
-          goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:18:18: 21:6
+                                           // + span: $DIR/simplify-arm-identity.rs:20:21: 20:32
+                                           // + literal: Const { ty: Dst, val: Value(Scalar(0x00)) }
+          goto -> bb4;                     // bb1[1]: scope 1 at $DIR/simplify-arm-identity.rs:18:18: 21:6
       }
   
       bb2: {
index 8bb28206964f1527057ea341faa429ddf78ef583..daae94e87f04461c053039d2a85c16c718c5a998 100644 (file)
@@ -13,7 +13,7 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
-          switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+          switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
       }
   
       bb1: {
index 1226b4feaf41f9ab12adc59e859d0e6aaf7f10d7..15bd5e7c9f0b02e23d2ddfdc4a3c55619a7b86be 100644 (file)
@@ -13,7 +13,7 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
-          switchInt(move _2) -> [0isize: bb1, 1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
+          switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16
       }
   
       bb1: {
index 5a5d67b36d9a54ae5dc012256628cc0e2b88d3e4..37273d1d6517ba07c506201101f2ae1edcc2c1b9 100644 (file)
@@ -18,7 +18,7 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
-          switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
       }
   
       bb1: {
index e82865162615e7498b5dadc0ca325496a76b89cb..f138d637435f8b8e39ef0ff81e8499ce3a88631a 100644 (file)
@@ -18,7 +18,7 @@
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
-          switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
+          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14
       }
   
       bb1: {
index 44f475346e016643fe16733d69af436cf5bec276..b46ca21fb90b3015b5c73f0d9dc990c8e4d04962 100644 (file)
@@ -45,7 +45,7 @@
       bb1: {
           StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
           _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-          switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
       }
   
       bb2: {
index c91c55dfb04c409de2eddbb11effb850e16598bd..93412d1a74f8ab088a611823bb1ce745d0718f8b 100644 (file)
@@ -45,7 +45,7 @@
       bb1: {
           StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
           _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-          switchInt(move _5) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
       }
   
       bb2: {
index f7db14e716526924401a40794ae4a1281e428434..720296a2c66b0c9bcde98f0bd05c876482ee4f94 100644 (file)
@@ -26,7 +26,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69
           StorageDead(_2);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69
           _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
-          switchInt(move _5) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
+          switchInt(move _5) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20
       }
   
       bb1: {
@@ -42,7 +42,7 @@
   
       bb2: {
           _4 = discriminant((_1.1: std::option::Option<T>)); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
-          switchInt(move _4) -> [0isize: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
+          switchInt(move _4) -> [0_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26
       }
   
       bb3: {
@@ -51,7 +51,7 @@
           StorageLive(_7);                 // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
           StorageLive(_8);                 // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
           _8 = _6;                         // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13
-          _7 = Gt(move _8, const 42u8);    // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
+          _7 = Gt(move _8, const 42_u8);   // scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20
                                            // ty::Const
                                            // + ty: u8
                                            // + val: Value(Scalar(0x2a))
index 0bd4ba97b3ca0b6ec6e63cbf892f51f562d36bae..db06b0392df6c3a4133b0393d2dbe6fc21588b0f 100644 (file)
 -         StorageLive(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
 -         StorageLive(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -         StorageLive(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
--         _11 = const Temp { x: 40u8 };    // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
+-         _11 = const Temp { x: 40_u8 };   // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
 +         StorageDead(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23
 +         StorageLive(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
-+         _2 = const use_u8(const 42u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
++         _2 = const use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
                                            // ty::Const
 -                                          // + ty: Temp
 -                                          // + val: Value(Scalar(0x28))
 -                                          // mir::Constant
 -                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
 -                                          // + literal: Const { ty: Temp, val: Value(Scalar(0x28)) }
--         _10 = const 40u8;                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
+-         _10 = const 40_u8;               // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -                                          // ty::Const
 -                                          // + ty: u8
 -                                          // + val: Value(Scalar(0x28))
 -                                          // mir::Constant
 -                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -                                          // + literal: Const { ty: u8, val: Value(Scalar(0x28)) }
--         _9 = const 42u8;                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
+-         _9 = const 42_u8;                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
 -                                          // ty::Const
 -                                          // + ty: u8
 -                                          // + val: Value(Scalar(0x2a))
 -                                          // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
 -                                          // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) }
 -         StorageDead(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34
--         _8 = const use_u8(const 42u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
+-         _8 = const use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
 -                                          // ty::Const
                                            // + ty: fn(u8) {use_u8}
                                            // + val: Value(Scalar(<ZST>))
index 067fa879b40382ca1786220d639c1d95a6de4f72..7047b542aa6077ec88b7a2b9f5d9f88129df3605 100644 (file)
@@ -9,4 +9,5 @@ fn main() {
     map(None);
 }
 
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR rustc.map.SimplifyLocals.diff
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/32bit/rustc.map.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/32bit/rustc.map.SimplifyLocals.diff
new file mode 100644 (file)
index 0000000..f0b6961
--- /dev/null
@@ -0,0 +1,42 @@
+- // MIR for `map` before SimplifyLocals
++ // MIR for `map` after SimplifyLocals
+  
+  fn map(_1: std::option::Option<std::boxed::Box<()>>) -> std::option::Option<std::boxed::Box<()>> {
+      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
+      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+-     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
+-     let mut _5: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+-     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+      }
+  
+      bb1: {
+          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+      }
+  
+      bb2: {
+          _0 = const std::option::Option::<std::boxed::Box<()>>::None; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+                                           // ty::Const
+                                           // + ty: std::option::Option<std::boxed::Box<()>>
+                                           // + val: Value(Scalar(0x00000000))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+                                           // + literal: Const { ty: std::option::Option<std::boxed::Box<()>>, val: Value(Scalar(0x00000000)) }
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+      }
+  
+      bb3: {
+-         _5 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/64bit/rustc.map.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/64bit/rustc.map.SimplifyLocals.diff
new file mode 100644 (file)
index 0000000..1ac6eb8
--- /dev/null
@@ -0,0 +1,42 @@
+- // MIR for `map` before SimplifyLocals
++ // MIR for `map` after SimplifyLocals
+  
+  fn map(_1: std::option::Option<std::boxed::Box<()>>) -> std::option::Option<std::boxed::Box<()>> {
+      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
+      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+-     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
+-     let mut _5: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+-     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+      scope 1 {
+          debug x => _3;                   // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+      }
+  
+      bb0: {
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
+      }
+  
+      bb1: {
+          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+      }
+  
+      bb2: {
+          _0 = const std::option::Option::<std::boxed::Box<()>>::None; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+                                           // ty::Const
+                                           // + ty: std::option::Option<std::boxed::Box<()>>
+                                           // + val: Value(Scalar(0x0000000000000000))
+                                           // mir::Constant
+                                           // + span: $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
+                                           // + literal: Const { ty: std::option::Option<std::boxed::Box<()>>, val: Value(Scalar(0x0000000000000000)) }
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
+      }
+  
+      bb3: {
+-         _5 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/rustc.map.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads/rustc.map.SimplifyLocals.diff
deleted file mode 100644 (file)
index 0ca54af..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-  
-  fn map(_1: std::option::Option<std::boxed::Box<()>>) -> std::option::Option<std::boxed::Box<()>> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
-      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
-      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
--     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
--     let mut _5: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
--     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
-      scope 1 {
-          debug x => _3;                   // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
-      }
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
-          switchInt(move _2) -> [0isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
-      }
-  
-      bb1: {
-          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
-          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
-      }
-  
-      bb2: {
-          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:17: 3:21
-          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:2:5: 5:6
-      }
-  
-      bb3: {
--         _5 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
-          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
-      }
-  }
-  
index 97050122ca96e972a874c2f8a3a6c10be6b77775..7f8366309c0896198a68e6392969bad7366d1bfd 100644 (file)
@@ -46,7 +46,7 @@
           _3 = move _4;                    // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
           StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
           _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
-          switchInt(move _5) -> [0isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
+          switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15
       }
   
       bb1: {
index 7d3537d0943474b8894c8495ffb67e9ffe868333..aa416049f6613e298a2243b576554a19a78b2b00 100644 (file)
@@ -26,7 +26,7 @@
   
       bb0: {
           _3 = discriminant(((*_1).1: std::option::Option<std::ptr::NonNull<Node>>)); // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
-          switchInt(move _3) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
+          switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try_if_let.rs:22:13: 22:17
       }
   
       bb1: {
@@ -62,7 +62,7 @@
       bb4: {
           StorageDead(_6);                 // scope 1 at $DIR/simplify_try_if_let.rs:26:59: 26:60
           _7 = discriminant(_5);           // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
-          switchInt(move _7) -> [1isize: bb6, otherwise: bb5]; // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
+          switchInt(move _7) -> [1_isize: bb6, otherwise: bb5]; // scope 1 at $DIR/simplify_try_if_let.rs:26:24: 26:40
       }
   
       bb5: {
index e79dcba13b00b78424963297f8043abf0557854f..4a13ddb33b5deb498144f9607e2aece017eb060e 100644 (file)
@@ -31,7 +31,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb3 (cleanup): {
         _5 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000001))
@@ -48,7 +48,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb5: {
         _7 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000001))
@@ -64,7 +64,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
     }
 
     bb7: {
-        _4 = const 0usize;               // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _4 = const 0_usize;              // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000000))
@@ -80,7 +80,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb9 (cleanup): {
         _11 = _9;                        // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000001))
@@ -97,7 +97,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb11: {
         _13 = _9;                        // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x00000001))
@@ -126,6 +126,6 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
     bb15: {
         _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
         _3 = Len((*_1));                 // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        switchInt(move _2) -> [0usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
     }
 }
index 604a0228f63cf0e5ffe7fa37afae3014a6f35027..9968c57c237865854579d8fc04ae8af3a66a6931 100644 (file)
@@ -31,7 +31,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb3 (cleanup): {
         _5 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000001))
@@ -48,7 +48,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb5: {
         _7 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _4 = Add(move _4, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000001))
@@ -64,7 +64,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
     }
 
     bb7: {
-        _4 = const 0usize;               // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _4 = const 0_usize;              // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000000))
@@ -80,7 +80,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb9 (cleanup): {
         _11 = _9;                        // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000001))
@@ -97,7 +97,7 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
 
     bb11: {
         _13 = _9;                        // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        _9 = Offset(move _9, const 1usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
                                          // ty::Const
                                          // + ty: usize
                                          // + val: Value(Scalar(0x0000000000000001))
@@ -126,6 +126,6 @@ fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () {
     bb15: {
         _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
         _3 = Len((*_1));                 // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
-        switchInt(move _2) -> [0usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+        switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/libcore/ptr/mod.rs:LL:COL
     }
 }
index 62b7535f2b57565986bec6bbc77839435ac74e6f..d7f73a22c26fd4ad03348d28a0f313a4c861cf0b 100644 (file)
@@ -59,7 +59,7 @@ static XXX: &Foo = {
         StorageLive(_5);                 // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6
         StorageLive(_6);                 // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:12: 22:6
         StorageLive(_7);                 // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15
-        _7 = (const 0u32, const 1u32);   // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15
+        _7 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:9: 8:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -73,7 +73,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:8:13: 8:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_8);                 // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23
-        _8 = (const 0u32, const 2u32);   // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23
+        _8 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:17: 8:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -87,7 +87,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:8:21: 8:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_9);                 // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31
-        _9 = (const 0u32, const 3u32);   // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31
+        _9 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:8:25: 8:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -101,7 +101,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:8:29: 8:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_10);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15
-        _10 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15
+        _10 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:9: 9:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -115,7 +115,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:9:13: 9:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_11);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23
-        _11 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23
+        _11 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:17: 9:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -129,7 +129,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:9:21: 9:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_12);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31
-        _12 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31
+        _12 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:9:25: 9:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -143,7 +143,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:9:29: 9:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_13);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15
-        _13 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15
+        _13 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:9: 10:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -157,7 +157,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:10:13: 10:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_14);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23
-        _14 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23
+        _14 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:17: 10:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -171,7 +171,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:10:21: 10:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_15);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31
-        _15 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31
+        _15 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:10:25: 10:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -185,7 +185,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:10:29: 10:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_16);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15
-        _16 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15
+        _16 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:9: 11:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -199,7 +199,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:11:13: 11:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_17);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23
-        _17 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23
+        _17 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:17: 11:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -213,7 +213,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:11:21: 11:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_18);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31
-        _18 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31
+        _18 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:11:25: 11:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -227,7 +227,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:11:29: 11:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_19);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15
-        _19 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15
+        _19 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:9: 12:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -241,7 +241,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:12:13: 12:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_20);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23
-        _20 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23
+        _20 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:17: 12:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -255,7 +255,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:12:21: 12:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_21);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31
-        _21 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31
+        _21 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:12:25: 12:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -269,7 +269,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:12:29: 12:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_22);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15
-        _22 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15
+        _22 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:9: 13:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -283,7 +283,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:13:13: 13:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_23);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23
-        _23 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23
+        _23 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:17: 13:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -297,7 +297,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:13:21: 13:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_24);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31
-        _24 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31
+        _24 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:13:25: 13:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -311,7 +311,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:13:29: 13:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_25);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15
-        _25 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15
+        _25 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:9: 14:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -325,7 +325,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:14:13: 14:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_26);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23
-        _26 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23
+        _26 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:17: 14:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -339,7 +339,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:14:21: 14:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_27);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31
-        _27 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31
+        _27 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:14:25: 14:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -353,7 +353,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:14:29: 14:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_28);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15
-        _28 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15
+        _28 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:9: 15:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -367,7 +367,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:15:13: 15:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_29);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23
-        _29 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23
+        _29 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:17: 15:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -381,7 +381,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:15:21: 15:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_30);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31
-        _30 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31
+        _30 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:15:25: 15:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -395,7 +395,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:15:29: 15:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_31);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15
-        _31 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15
+        _31 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:9: 16:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -409,7 +409,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:16:13: 16:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_32);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23
-        _32 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23
+        _32 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:17: 16:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -423,7 +423,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:16:21: 16:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_33);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31
-        _33 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31
+        _33 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:16:25: 16:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -437,7 +437,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:16:29: 16:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_34);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15
-        _34 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15
+        _34 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:9: 17:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -451,7 +451,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:17:13: 17:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_35);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23
-        _35 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23
+        _35 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:17: 17:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -465,7 +465,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:17:21: 17:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_36);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31
-        _36 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31
+        _36 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:17:25: 17:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -479,7 +479,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:17:29: 17:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_37);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15
-        _37 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15
+        _37 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:9: 18:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -493,7 +493,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:18:13: 18:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_38);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23
-        _38 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23
+        _38 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:17: 18:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -507,7 +507,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:18:21: 18:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_39);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31
-        _39 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31
+        _39 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:18:25: 18:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -521,7 +521,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:18:29: 18:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_40);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15
-        _40 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15
+        _40 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:9: 19:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -535,7 +535,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:19:13: 19:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_41);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23
-        _41 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23
+        _41 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:17: 19:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -549,7 +549,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:19:21: 19:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_42);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31
-        _42 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31
+        _42 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:19:25: 19:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -563,7 +563,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:19:29: 19:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_43);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15
-        _43 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15
+        _43 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:9: 20:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -577,7 +577,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:20:13: 20:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_44);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23
-        _44 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23
+        _44 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:17: 20:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -591,7 +591,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:20:21: 20:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_45);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31
-        _45 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31
+        _45 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:20:25: 20:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -605,7 +605,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:20:29: 20:30
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000003)) }
         StorageLive(_46);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15
-        _46 = (const 0u32, const 1u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15
+        _46 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:9: 21:15
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -619,7 +619,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:21:13: 21:14
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) }
         StorageLive(_47);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23
-        _47 = (const 0u32, const 2u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23
+        _47 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:17: 21:23
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
@@ -633,7 +633,7 @@ static XXX: &Foo = {
                                          // + span: $DIR/storage_live_dead_in_statics.rs:21:21: 21:22
                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
         StorageLive(_48);                // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
-        _48 = (const 0u32, const 3u32);  // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
+        _48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
                                          // ty::Const
                                          // + ty: u32
                                          // + val: Value(Scalar(0x00000000))
index 7799f20d974bcfbb2bf8235b941c8f8c47357262..099535c0ad279e4a2648d91fae6927288e43dde9 100644 (file)
@@ -38,7 +38,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/storage_ranges.rs:4:9: 4:10
-        _1 = const 0i32;                 // scope 0 at $DIR/storage_ranges.rs:4:13: 4:14
+        _1 = const 0_i32;                // scope 0 at $DIR/storage_ranges.rs:4:13: 4:14
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000000))
@@ -66,7 +66,7 @@ fn main() -> () {
         StorageDead(_3);                 // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6
         StorageDead(_2);                 // scope 1 at $DIR/storage_ranges.rs:7:5: 7:6
         StorageLive(_6);                 // scope 1 at $DIR/storage_ranges.rs:8:9: 8:10
-        _6 = const 1i32;                 // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14
+        _6 = const 1_i32;                // scope 1 at $DIR/storage_ranges.rs:8:13: 8:14
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
index e4798c2e32407bffe826524085c6ce1cacea0f21..5ceca2d091e30fa88ae7c226d5e36ca932878f49 100644 (file)
@@ -18,7 +18,7 @@ fn main() -> () {
         _1 = &(*_2);                     // scope 1 at $DIR/tls-access.rs:8:17: 8:21
         StorageLive(_3);                 // scope 2 at $DIR/tls-access.rs:9:9: 9:12
         _3 = &/*tls*/ mut FOO;           // scope 2 at $DIR/tls-access.rs:9:9: 9:12
-        (*_3) = const 42u8;              // scope 2 at $DIR/tls-access.rs:9:9: 9:17
+        (*_3) = const 42_u8;             // scope 2 at $DIR/tls-access.rs:9:9: 9:17
                                          // ty::Const
                                          // + ty: u8
                                          // + val: Value(Scalar(0x2a))
index de29cd61019f11f6929287f5217f2eddc82cd3dc..eb40baa2000f8cd7aa8025029f43e8f40b46ce6d 100644 (file)
@@ -20,7 +20,7 @@ fn move_out_by_subslice() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
         StorageLive(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
         _3 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-        (*_3) = const 1i32;              // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+        (*_3) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -48,7 +48,7 @@ fn move_out_by_subslice() -> () {
         StorageLive(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
         StorageLive(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
         _5 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
-        (*_5) = const 2i32;              // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+        (*_5) = const 2_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index aeab0e892ae8b8725c6bfa59dcb782fdc0d5f5b4..7beceb66577fe82ce1be0d36d7699ff1ea76794f 100644 (file)
@@ -20,7 +20,7 @@ fn move_out_from_end() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
         StorageLive(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
         _3 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-        (*_3) = const 1i32;              // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+        (*_3) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000001))
@@ -48,7 +48,7 @@ fn move_out_from_end() -> () {
         StorageLive(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
         StorageLive(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
         _5 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
-        (*_5) = const 2i32;              // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+        (*_5) = const 2_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index df6c90fc7fb3757d5284bdceb03a165c518f9d2b..4f4fb7defc3794f0708e84edef625911a9ee86f5 100644 (file)
@@ -33,7 +33,7 @@ fn main() -> () {
         StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
         _7 = Test2::D;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
         _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
-        switchInt(move _8) -> [4isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
+        switchInt(move _8) -> [4_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
     }
 
     bb1: {
index fa1474aa049de9141518e2fe409812f45a2636fc..d262c9432ca833b6ee209844603536218a6055da 100644 (file)
@@ -18,7 +18,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
           _2 = Test1::C;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
           _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
--         switchInt(move _3) -> [0isize: bb2, 1isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
+-         switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
 +         switchInt(move _3) -> bb1;       // scope 0 at $DIR/uninhabited_enum_branching.rs:21:9: 21:20
       }
   
@@ -68,7 +68,7 @@
           StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
           _7 = Test2::D;                   // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
           _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
-          switchInt(move _8) -> [4isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
+          switchInt(move _8) -> [4_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:27:9: 27:17
       }
   
       bb5: {
index ccd9612caddd45f60d0f76b261a8afa1991ca279..e7abf57880047d9a8237c92fe694b8981873d16c 100644 (file)
@@ -30,7 +30,7 @@
   
       bb1: {
           _2 = discriminant(_1);           // scope 0 at $DIR/unreachable.rs:9:12: 9:20
--         switchInt(move _2) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable.rs:9:12: 9:20
+-         switchInt(move _2) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable.rs:9:12: 9:20
 +         goto -> bb2;                     // scope 0 at $DIR/unreachable.rs:9:12: 9:20
       }
   
@@ -63,7 +63,7 @@
 -     }
 - 
 -     bb4: {
--         _4 = const 42i32;                // scope 2 at $DIR/unreachable.rs:15:13: 15:20
+-         _4 = const 42_i32;               // scope 2 at $DIR/unreachable.rs:15:13: 15:20
 -                                          // ty::Const
 -                                          // + ty: i32
 -                                          // + val: Value(Scalar(0x0000002a))
@@ -81,7 +81,7 @@
 -     }
 - 
 -     bb5: {
--         _4 = const 21i32;                // scope 2 at $DIR/unreachable.rs:13:13: 13:20
+-         _4 = const 21_i32;               // scope 2 at $DIR/unreachable.rs:13:13: 13:20
 -                                          // ty::Const
 -                                          // + ty: i32
 -                                          // + val: Value(Scalar(0x00000015))
index 449bea06207d9a43497fccd310099aa7340fc8df..50694900024a081e5da0cacb68a056474b9817f1 100644 (file)
@@ -33,7 +33,7 @@
   
       bb1: {
           _2 = discriminant(_1);           // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
-          switchInt(move _2) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
+          switchInt(move _2) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
       }
   
       bb2: {
@@ -65,7 +65,7 @@
       }
   
       bb4: {
-          _4 = const 42i32;                // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20
+          _4 = const 42_i32;               // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
@@ -83,7 +83,7 @@
       }
   
       bb5: {
-          _4 = const 21i32;                // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20
+          _4 = const 21_i32;               // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000015))
index a152e1dbe892fc18d66007afd11daf7ade3cbb7a..9be05aefcf69e678eeb8782d054bb01ceef8df37 100644 (file)
@@ -36,7 +36,7 @@
   
       bb1: {
           _2 = discriminant(_1);           // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
-          switchInt(move _2) -> [1isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
+          switchInt(move _2) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
       }
   
       bb2: {
@@ -78,7 +78,7 @@
                                            // + span: $DIR/unreachable_asm_2.rs:20:13: 20:41
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
           StorageDead(_8);                 // scope 2 at $DIR/unreachable_asm_2.rs:20:40: 20:41
-          _4 = const 42i32;                // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20
+          _4 = const 42_i32;               // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000002a))
                                            // + span: $DIR/unreachable_asm_2.rs:16:13: 16:41
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
           StorageDead(_7);                 // scope 2 at $DIR/unreachable_asm_2.rs:16:40: 16:41
-          _4 = const 21i32;                // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20
+          _4 = const 21_i32;               // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20
                                            // ty::Const
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000015))
index ff23baf0b4e9ff70cd5057b772aa2f5b26a434de..e7886f683c07e12971935aa33a42203318bdcc03 100644 (file)
@@ -38,7 +38,7 @@
   
       bb1: {
           _3 = discriminant(_2);           // scope 1 at $DIR/unreachable_diverging.rs:14:12: 14:22
-          switchInt(move _3) -> [1isize: bb3, otherwise: bb2]; // scope 1 at $DIR/unreachable_diverging.rs:14:12: 14:22
+          switchInt(move _3) -> [1_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/unreachable_diverging.rs:14:12: 14:22
       }
   
       bb2: {
index c800ccb1ae51f698db8d7a5fcd773be2dfca4672..7f0266d65899231ab90766c6d29dc4b29bc1f5ed 100644 (file)
@@ -4,7 +4,7 @@ E::V::{{constant}}#0: isize = {
     let mut _0: isize;                   // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
 
     bb0: {
-        _0 = const 5isize;               // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
+        _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
                                          // ty::Const
                                          // + ty: isize
                                          // + val: Value(Scalar(0x00000005))
index f4a5cc0b3279a5136106ae8df95aa0dd0939fc0d..4af856c654eedc8ca4bc32eb9f7841078a8fb844 100644 (file)
@@ -4,7 +4,7 @@ const <impl at $DIR/unusual-item-types.rs:9:1: 11:2>::ASSOCIATED_CONSTANT: i32 =
     let mut _0: i32;                     // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35
 
     bb0: {
-        _0 = const 2i32;                 // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
+        _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index e635cd2b01bbd79fb97d6e08f40e69e95fafa81d..f2c1e9c97ddfef10de6dd7ac715e98be5f883abe 100644 (file)
@@ -4,7 +4,7 @@ E::V::{{constant}}#0: isize = {
     let mut _0: isize;                   // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
 
     bb0: {
-        _0 = const 5isize;               // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
+        _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
                                          // ty::Const
                                          // + ty: isize
                                          // + val: Value(Scalar(0x0000000000000005))
index f4a5cc0b3279a5136106ae8df95aa0dd0939fc0d..4af856c654eedc8ca4bc32eb9f7841078a8fb844 100644 (file)
@@ -4,7 +4,7 @@ const <impl at $DIR/unusual-item-types.rs:9:1: 11:2>::ASSOCIATED_CONSTANT: i32 =
     let mut _0: i32;                     // return place in scope 0 at $DIR/unusual-item-types.rs:10:32: 10:35
 
     bb0: {
-        _0 = const 2i32;                 // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
+        _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
                                          // ty::Const
                                          // + ty: i32
                                          // + val: Value(Scalar(0x00000002))
index 4903050e08ed266e9f30b64864822be165d7cc86..b3d188dd708814cf50c3937d59eb7334ef73cb09 100644 (file)
@@ -22,5 +22,13 @@ pub fn main() {
         asm!("{0}", inout(reg) b);
         asm!("{0} {1}", out(reg) _, inlateout(reg) b => _);
         asm!("", out("al") _, lateout("rbx") _);
+        asm!("inst1\ninst2");
+        asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
+        asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b);
+        asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
+        asm!("inst1\ninst2");
+        asm!("inst1\ninst2");
+        asm!("inst1\n\tinst2");
+        asm!("inst1\ninst2\ninst3\ninst4");
     }
 }
index 12c32e6721b334b6e69dd891819cde93989e0ffc..33f25e5216b4eafab08089c2f779fd22ba736544 100644 (file)
@@ -16,5 +16,14 @@ pub fn main() {
         asm!("{name}", name = inout(reg) b);
         asm!("{} {}", out(reg) _, inlateout(reg) b => _);
         asm!("", out("al") _, lateout("rbx") _);
+        asm!("inst1", "inst2");
+        asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
+        asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
+        asm!("inst1 {}, 42", "inst2 {name}, 24", in(reg) a, name = out(reg) b);
+        asm!("inst1
+inst2");
+        asm!("inst1\ninst2");
+        asm!("inst1\n\tinst2");
+        asm!("inst1\ninst2", "inst3\ninst4");
     }
 }
index 5d46be87eac6b2e3da1763e98461a606610ab412..b11d4c4cab7cf54c5f1f5de18a50cf3b15372149 100644 (file)
@@ -1,5 +1,5 @@
 # needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
 # only-linux
 
 -include ../tools.mk
index f62c3a6654ed414d36b74a7128b03555e0bca91a..c2ebd2a6d8cacbf49ad9c02f92ec1f3e8252b448 100644 (file)
@@ -1,5 +1,5 @@
 # needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
 # only-linux
 
 -include ../tools.mk
index f56475b441f1a0aa0731c950f2a7757cc990891e..5ceff16471cee99fde034adabf0d53e8fadd9eeb 100644 (file)
@@ -1,5 +1,5 @@
 # needs-sanitizer-support
-# only-x86_64
+# needs-sanitizer-address
 # only-linux
 
 -include ../tools.mk
diff --git a/src/test/run-make/env-dep-info/Makefile b/src/test/run-make/env-dep-info/Makefile
new file mode 100644 (file)
index 0000000..2be0b4b
--- /dev/null
@@ -0,0 +1,8 @@
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+       EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs
+       $(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d
+       $(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d
+       $(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d
+       $(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d
diff --git a/src/test/run-make/env-dep-info/main.rs b/src/test/run-make/env-dep-info/main.rs
new file mode 100644 (file)
index 0000000..a25246b
--- /dev/null
@@ -0,0 +1,6 @@
+fn main() {
+    env!("EXISTING_ENV");
+    option_env!("EXISTING_OPT_ENV");
+    option_env!("NONEXISTENT_OPT_ENV");
+    option_env!("ESCAPE\nESCAPE\\");
+}
diff --git a/src/test/run-make/static-pie/Makefile b/src/test/run-make/static-pie/Makefile
new file mode 100644 (file)
index 0000000..1d3cc82
--- /dev/null
@@ -0,0 +1,15 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# only-x86_64-unknown-linux-musl
+
+# How to manually run this
+# $ ./x.py test --target x86_64-unknown-linux-musl src/test/run-make/static-pie
+
+all:
+       $(RUSTC) --target $(TARGET) -C target-feature=+crt-static test-aslr.rs
+       # Check that no dynamic interpreter is set
+       ! readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) INTERP
+       # Check that we have a dynamic executable
+       readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) DYNAMIC
+       # Check for address space layout randomization
+       $(call RUN,test-aslr) --test-aslr
diff --git a/src/test/run-make/static-pie/test-aslr.rs b/src/test/run-make/static-pie/test-aslr.rs
new file mode 100644 (file)
index 0000000..f28e00f
--- /dev/null
@@ -0,0 +1,43 @@
+const NUM_RUNS: usize = 10;
+
+fn run_self(exe: &str) -> usize {
+    use std::process::Command;
+    let mut set = std::collections::HashSet::new();
+
+    let mut cmd = Command::new(exe);
+    cmd.arg("--report");
+    (0..NUM_RUNS).for_each(|_| {
+        set.insert(cmd.output().expect("failed to execute process").stdout);
+    });
+    set.len()
+}
+
+fn main() {
+    let mut args = std::env::args();
+    let arg0 = args.next().unwrap();
+    match args.next() {
+        Some(s) if s.eq("--report") => {
+            println!("main = {:#?}", &main as *const _);
+        }
+        Some(s) if s.eq("--test-no-aslr") => {
+            let cnt = run_self(&arg0);
+            if cnt != 1 {
+                eprintln!("FAIL: {} most likely ASLR", arg0);
+                std::process::exit(1);
+            }
+            println!("PASS: {} does no ASLR", arg0);
+        }
+        Some(s) if s.eq("--test-aslr") => {
+            let cnt = run_self(&arg0);
+            if cnt != NUM_RUNS {
+                eprintln!("FAIL: {} most likely no ASLR", arg0);
+                std::process::exit(1);
+            }
+            println!("PASS: {} does ASLR", arg0);
+        }
+        Some(_) | None => {
+            println!("Usage: {} --test-no-aslr | --test-aslr", arg0);
+            std::process::exit(1);
+        }
+    }
+}
diff --git a/src/test/rustdoc-js/doc-alias-filter-out.js b/src/test/rustdoc-js/doc-alias-filter-out.js
new file mode 100644 (file)
index 0000000..46a089d
--- /dev/null
@@ -0,0 +1,9 @@
+// exact-check
+
+const QUERY = 'true';
+
+const FILTER_CRATE = 'some_other_crate';
+
+const EXPECTED = {
+    'others': [],
+};
diff --git a/src/test/rustdoc-js/doc-alias-filter-out.rs b/src/test/rustdoc-js/doc-alias-filter-out.rs
new file mode 100644 (file)
index 0000000..815e8ce
--- /dev/null
@@ -0,0 +1,4 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "true")]
+pub struct Foo;
diff --git a/src/test/rustdoc-js/doc-alias-filter.js b/src/test/rustdoc-js/doc-alias-filter.js
new file mode 100644 (file)
index 0000000..4b1e2e2
--- /dev/null
@@ -0,0 +1,17 @@
+// exact-check
+
+const QUERY = 'true';
+
+const FILTER_CRATE = 'doc_alias_filter';
+
+const EXPECTED = {
+    'others': [
+        {
+            'path': 'doc_alias_filter',
+            'name': 'Foo',
+            'alias': 'true',
+            'href': '../doc_alias_filter/struct.Foo.html',
+            'is_alias': true
+        },
+    ],
+};
diff --git a/src/test/rustdoc-js/doc-alias-filter.rs b/src/test/rustdoc-js/doc-alias-filter.rs
new file mode 100644 (file)
index 0000000..8887f8c
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "true")]
+pub struct Foo;
+
+#[doc(alias = "false")]
+pub struct Bar;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs
new file mode 100644 (file)
index 0000000..2f01099
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "foo")] // ok!
+pub struct Bar;
+
+#[doc(alias)] //~ ERROR
+#[doc(alias = 0)] //~ ERROR
+#[doc(alias("bar"))] //~ ERROR
+pub struct Foo;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
new file mode 100644 (file)
index 0000000..480acc8
--- /dev/null
@@ -0,0 +1,20 @@
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:6:7
+   |
+LL | #[doc(alias)]
+   |       ^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:7:7
+   |
+LL | #[doc(alias = 0)]
+   |       ^^^^^^^^^
+
+error: doc alias attribute expects a string: #[doc(alias = "0")]
+  --> $DIR/check-doc-alias-attr.rs:8:7
+   |
+LL | #[doc(alias("bar"))]
+   |       ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-links-private.public.stderr
new file mode 100644 (file)
index 0000000..0a8dafd
--- /dev/null
@@ -0,0 +1,10 @@
+warning: `[DontDocMe]` public documentation for `DocMe` links to a private item
+  --> $DIR/intra-links-private.rs:6:11
+   |
+LL | /// docs [DontDocMe]
+   |           ^^^^^^^^^ this item is private
+   |
+   = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/intra-links-private.rs b/src/test/rustdoc-ui/intra-links-private.rs
new file mode 100644 (file)
index 0000000..b7906ab
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+// revisions: public private
+// [private]compile-flags: --document-private-items
+#![cfg_attr(private, deny(intra_doc_resolution_failure))]
+
+/// docs [DontDocMe]
+//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
+// FIXME: for [private] we should also make sure the link was actually generated
+pub struct DocMe;
+struct DontDocMe;
diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.rs b/src/test/rustdoc-ui/reference-link-has-one-warning.rs
new file mode 100644 (file)
index 0000000..21cb7eb
--- /dev/null
@@ -0,0 +1,6 @@
+// ignore-test
+// check-pass
+
+/// docs [label][with#anchor#error]
+//~^ WARNING has an issue with the link anchor
+pub struct S;
diff --git a/src/test/rustdoc-ui/reference-link-has-one-warning.stderr b/src/test/rustdoc-ui/reference-link-has-one-warning.stderr
new file mode 100644 (file)
index 0000000..5bbc62b
--- /dev/null
@@ -0,0 +1,10 @@
+warning: `[with#anchor#error]` has an issue with the link anchor.
+  --> $DIR/reference-link-has-one-warning.rs:3:18
+   |
+LL | /// docs [label][with#anchor#error]
+   |                  ^^^^^^^^^^^^^^^^^ only one `#` is allowed in a link
+   |
+   = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+
+warning: 1 warning emitted
+
index 7a2f1815ed8e5ac61ae68b4e9c4466cf52c40033..fab801b3beaeaec049388d3856dbc741c39014f0 100644 (file)
@@ -1,4 +1,4 @@
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
  --> $DIR/test-compile-fail3.rs:3:1
   |
 3 | "fail
@@ -6,3 +6,4 @@ error: unterminated double quote string
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0765`.
index 4ea6455d3aa4cf864a788503d48a83890ba93371..29cb22e2e4b099689f7ff055516d3d5dcca6355d 100644 (file)
@@ -5,7 +5,7 @@ test $DIR/unparseable-doc-test.rs - foo (line 6) ... FAILED
 failures:
 
 ---- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ----
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
   --> $DIR/unparseable-doc-test.rs:8:1
    |
 LL | "unterminated
@@ -13,6 +13,7 @@ LL | "unterminated
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0765`.
 Couldn't compile the test.
 
 failures:
index 2f77929c74e379a4d59edc798cee4acbdca72ec4..b59b21111b009740350b5f5db4a6a1d941a3a231 100644 (file)
@@ -4,6 +4,7 @@
 
 // @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This example deliberately fails to compile"
 // @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "This example is not tested"
+// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]/span' "This example panics"
 
 /// foo
 ///
 /// goo();
 /// ```
 ///
+/// ```should_panic
+/// hoo();
+/// ```
+///
 /// ```
 /// let x = 0;
 /// ```
index 905f958826897833f029bada240c76a9950782a8..85be89719ec395914c6ba9cf6ca0cba54834acb4 100644 (file)
@@ -1,7 +1,6 @@
 // ignore-tidy-linelength
 
 #![feature(const_generics)]
-
 #![crate_name = "foo"]
 
 use std::ops::Add;
@@ -11,7 +10,7 @@ pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
 
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]/h3/code' 'impl Add<Simd<u8, 16usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]/h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
 impl Add for Simd<u8, 16> {
     type Output = Self;
 
index 6af9ed3e33f661e44c0105494b858ec88c3e717a..a79b37ee08210717c27c9f278f7aac0402992e09 100644 (file)
@@ -1,4 +1,5 @@
 // needs-sanitizer-support
+// needs-sanitizer-address
 // compile-flags: --test -Z sanitizer=address
 //
 // #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern
diff --git a/src/test/rustdoc/synthetic_auto/overflow.rs b/src/test/rustdoc/synthetic_auto/overflow.rs
new file mode 100644 (file)
index 0000000..546b3e0
--- /dev/null
@@ -0,0 +1,35 @@
+// Tests that we don't fail with an overflow error for certain
+// strange types
+// See https://github.com/rust-lang/rust/pull/72936#issuecomment-643676915
+
+pub trait Interner {
+    type InternedType;
+}
+
+struct RustInterner<'tcx> {
+    foo: &'tcx ()
+}
+
+impl<'tcx> Interner for RustInterner<'tcx> {
+    type InternedType = Box<TyData<Self>>;
+}
+
+enum TyData<I: Interner> {
+    FnDef(I::InternedType)
+}
+
+struct VariableKind<I: Interner>(I::InternedType);
+
+// @has overflow/struct.BoundVarsCollector.html
+// @has - '//code' "impl<'tcx> Send for BoundVarsCollector<'tcx>"
+pub struct BoundVarsCollector<'tcx> {
+    val: VariableKind<RustInterner<'tcx>>
+}
+
+fn is_send<T: Send>() {}
+
+struct MyInterner<'tcx> {
+    val: &'tcx ()
+}
+
+fn main() {}
index 27fe432e96ded03ca64ece5361602bc91363b0be..973294e985f7a45a65e4c99e946bf31df508dd52 100644 (file)
@@ -37,7 +37,7 @@ fn main() {
         TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Placeholder(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Infer(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
-        TyKind::Error => (), //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Error(_) => (), //~ ERROR usage of `ty::TyKind::<kind>`
     }
 
     if let ty::Int(int_ty) = kind {}
index 0486c90a5a07a4a995601902dfe3c18bc297cb97..d6e4c85c190d5af36da784f4a5ddcb52b7a87394 100644 (file)
@@ -169,7 +169,7 @@ LL |         TyKind::Infer(..) => (),
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:40:9
    |
-LL |         TyKind::Error => (),
+LL |         TyKind::Error(_) => (),
    |         ^^^^^^ help: try using ty::<kind> directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
index fcdff59ffa984cd9b9b58754248715aabd437891..32864dba4587eb20722ba4925734f77e18a3d8d7 100644 (file)
@@ -38,6 +38,7 @@ pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
 
 #[cfg(target_arch = "x86_64")]
 #[inline(never)]
+#[allow(improper_ctypes_definitions)]
 pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct {
     foo.0 *= 1;
     foo.1 *= 2;
index 09abe4fbf7e095f96d245879ecd47a4e4f8d4bb7..f77f40998de012ec0abdf81e11e41e59d453da54 100644 (file)
@@ -10,6 +10,7 @@
 #[repr(align(16))]
 pub struct A(i64);
 
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn foo(x: A) {}
 
 fn main() {
index 4fe8572c2d53130dfc9addddff24c8770e628af8..0ad05b3adeb88faf45c31ec42b49a4770c0c5ce0 100644 (file)
@@ -11,7 +11,7 @@ error[E0308]: mismatched types
   --> $DIR/match_arr_unknown_len.rs:6:9
    |
 LL |         [1, 2] => true,
-   |         ^^^^^^ expected `2usize`, found `N`
+   |         ^^^^^^ expected `2_usize`, found `N`
    |
    = note: expected array `[u32; 2]`
               found array `[u32; N]`
index 69c33921868cfd0a62c2b909a021f14f8b5ebacd..d8a9ae6ca20307363f872a753270fe254d8e4fd9 100644 (file)
@@ -2,7 +2,8 @@
 
 // run-pass
 
-#![feature(const_fn, const_if_match)]
+#![feature(const_fn)]
+
 #[derive(PartialEq, Debug, Clone)]
 struct N(u8);
 
diff --git a/src/test/ui/asm/duplicate-options.fixed b/src/test/ui/asm/duplicate-options.fixed
new file mode 100644 (file)
index 0000000..f4672a5
--- /dev/null
@@ -0,0 +1,26 @@
+// only-x86_64
+// run-rustfix
+
+#![feature(asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, ));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(att_syntax, ));
+        //~^ ERROR the `att_syntax` option was already provided
+        asm!("", options(nostack, att_syntax), options());
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, ), options(), options());
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
+            options( nostack), //~ ERROR the `nomem` option was already provided
+            options(), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs
new file mode 100644 (file)
index 0000000..80292d7
--- /dev/null
@@ -0,0 +1,26 @@
+// only-x86_64
+// run-rustfix
+
+#![feature(asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, nomem));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(att_syntax, att_syntax));
+        //~^ ERROR the `att_syntax` option was already provided
+        asm!("", options(nostack, att_syntax), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, nostack), options(nostack), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
+            options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+            options(noreturn), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr
new file mode 100644 (file)
index 0000000..cd8d743
--- /dev/null
@@ -0,0 +1,56 @@
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:8:33
+   |
+LL |         asm!("", options(nomem, nomem));
+   |                                 ^^^^^ this option was already provided
+
+error: the `att_syntax` option was already provided
+  --> $DIR/duplicate-options.rs:10:38
+   |
+LL |         asm!("", options(att_syntax, att_syntax));
+   |                                      ^^^^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:12:56
+   |
+LL |         asm!("", options(nostack, att_syntax), options(nostack));
+   |                                                        ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:35
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                   ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:53
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                     ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:71
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                                       ^^^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:21:33
+   |
+LL |             options(att_syntax, noreturn),
+   |                                 ^^^^^^^^ this option was already provided
+
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:22:21
+   |
+LL |             options(nomem, nostack),
+   |                     ^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:23:21
+   |
+LL |             options(noreturn),
+   |                     ^^^^^^^^ this option was already provided
+
+error: aborting due to 9 previous errors
+
index 2b1f018f3642eedc253a3cab86e43c924803905f..538a3fde8fdeb6fb525b1a62b8e15e89e1e1e33f 100644 (file)
@@ -13,7 +13,7 @@ fn main() {
         asm!("{}" foo);
         //~^ ERROR expected token: `,`
         asm!("{}", foo);
-        //~^ ERROR expected one of
+        //~^ ERROR expected operand, options, or additional template string
         asm!("{}", in foo);
         //~^ ERROR expected `(`, found `foo`
         asm!("{}", in(reg foo));
@@ -34,11 +34,6 @@ fn main() {
         //~^ ERROR expected one of
         asm!("", options(nomem, foo));
         //~^ ERROR expected one of
-        asm!("", options(), options());
-        //~^ ERROR asm options cannot be specified multiple times
-        asm!("", options(), options(), options());
-        //~^ ERROR asm options cannot be specified multiple times
-        //~^^ ERROR asm options cannot be specified multiple times
         asm!("{}", options(), const foo);
         //~^ ERROR arguments are not allowed after options
         asm!("{a}", a = const foo, a = const bar);
@@ -52,5 +47,13 @@ fn main() {
         //~^ ERROR named arguments cannot follow explicit register arguments
         asm!("{1}", in("eax") foo, const bar);
         //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
+        asm!("", options(), "");
+        //~^ ERROR expected one of
+        asm!("{}", in(reg) foo, "{}", out(reg) foo);
+        //~^ ERROR expected one of
+        asm!(format!("{{{}}}", 0), in(reg) foo);
+        //~^ ERROR asm template must be a string literal
+        asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+        //~^ ERROR asm template must be a string literal
     }
 }
index 583a10570360bf6d0af09b7e21e202db94a549b1..dfbfc0abe3472db706d42858d0227692a90337d4 100644 (file)
@@ -16,11 +16,11 @@ error: expected token: `,`
 LL |         asm!("{}" foo);
    |                   ^^^ expected `,`
 
-error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo`
+error: expected operand, options, or additional template string
   --> $DIR/parse-error.rs:15:20
    |
 LL |         asm!("{}", foo);
-   |                    ^^^ expected one of 8 possible tokens
+   |                    ^^^ expected operand, options, or additional template string
 
 error: expected `(`, found `foo`
   --> $DIR/parse-error.rs:17:23
@@ -82,32 +82,8 @@ error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `prese
 LL |         asm!("", options(nomem, foo));
    |                                 ^^^ expected one of 8 possible tokens
 
-error: asm options cannot be specified multiple times
-  --> $DIR/parse-error.rs:37:29
-   |
-LL |         asm!("", options(), options());
-   |                  ---------  ^^^^^^^^^ duplicate options
-   |                  |
-   |                  previously here
-
-error: asm options cannot be specified multiple times
-  --> $DIR/parse-error.rs:39:29
-   |
-LL |         asm!("", options(), options(), options());
-   |                  ---------  ^^^^^^^^^ duplicate options
-   |                  |
-   |                  previously here
-
-error: asm options cannot be specified multiple times
-  --> $DIR/parse-error.rs:39:40
-   |
-LL |         asm!("", options(), options(), options());
-   |                  ---------             ^^^^^^^^^ duplicate options
-   |                  |
-   |                  previously here
-
 error: arguments are not allowed after options
-  --> $DIR/parse-error.rs:42:31
+  --> $DIR/parse-error.rs:37:31
    |
 LL |         asm!("{}", options(), const foo);
    |                    ---------  ^^^^^^^^^ argument
@@ -115,7 +91,7 @@ LL |         asm!("{}", options(), const foo);
    |                    previous options
 
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:44:36
+  --> $DIR/parse-error.rs:39:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -123,7 +99,7 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |                     previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:44:36
+  --> $DIR/parse-error.rs:39:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                    ^^^^^^^^^^^^^ argument never used
@@ -131,13 +107,13 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
 error: explicit register arguments cannot have names
-  --> $DIR/parse-error.rs:47:18
+  --> $DIR/parse-error.rs:42:18
    |
 LL |         asm!("", a = in("eax") foo);
    |                  ^^^^^^^^^^^^^^^^^
 
 error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:49:36
+  --> $DIR/parse-error.rs:44:36
    |
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ named argument
@@ -145,7 +121,7 @@ LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     explicit register argument
 
 error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:51:36
+  --> $DIR/parse-error.rs:46:36
    |
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ named argument
@@ -153,12 +129,40 @@ LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     explicit register argument
 
 error: positional arguments cannot follow named arguments or explicit register arguments
-  --> $DIR/parse-error.rs:53:36
+  --> $DIR/parse-error.rs:48:36
    |
 LL |         asm!("{1}", in("eax") foo, const bar);
    |                     -------------  ^^^^^^^^^ positional argument
    |                     |
    |                     explicit register argument
 
-error: aborting due to 24 previous errors
+error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
+  --> $DIR/parse-error.rs:50:29
+   |
+LL |         asm!("", options(), "");
+   |                             ^^ expected one of 8 possible tokens
+
+error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
+  --> $DIR/parse-error.rs:52:33
+   |
+LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
+   |                                 ^^^^ expected one of 8 possible tokens
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:54:14
+   |
+LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:56:21
+   |
+LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+   |                     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 25 previous errors
 
index 402adc50d5b44a7935647735b2b6789f4aec34a9..1477e3dd5665ce6230819888ed21c50c8c4824da 100644 (file)
@@ -40,5 +40,85 @@ fn main() {
 
         asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
         //~^ WARN: scale factor without index register is ignored
+
+        asm!(
+            "invalid_instruction",
+        );
+        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            "mov eax, eax",
+            "invalid_instruction",
+            "mov eax, eax",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            "mov eax, eax\n",
+            "invalid_instruction",
+            "mov eax, eax",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            "mov eax, eax",
+            concat!("invalid", "_", "instruction"),
+            "mov eax, eax",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            concat!("mov eax", ", ", "eax"),
+            concat!("invalid", "_", "instruction"),
+            concat!("mov eax", ", ", "eax"),
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        // Make sure template strings get separated
+        asm!(
+            "invalid_instruction1",
+            "invalid_instruction2",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2",
+            ),
+        );
+        //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2",
+            ),
+            concat!(
+                "invalid", "_", "instruction3", "\n",
+                "invalid", "_", "instruction4",
+            ),
+        );
+        //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+        //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+        //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2", "\n",
+            ),
+            concat!(
+                "invalid", "_", "instruction3", "\n",
+                "invalid", "_", "instruction4", "\n",
+            ),
+        );
+        //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+        //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+        //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
     }
 }
index d5d12b004816f56cb1b90650bbaacac4c5e788c9..b62c8948289ddf1bf55575457bdc2e178c99d50c 100644 (file)
@@ -82,5 +82,209 @@ note: instantiated into assembly here
 LL |     movaps %xmm3, (%esi, 2)
    |                          ^
 
-error: aborting due to 6 previous errors; 1 warning emitted
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:45:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:51:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:58:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:65:13
+   |
+LL |             concat!("invalid", "_", "instruction"),
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:72:13
+   |
+LL |             concat!("invalid", "_", "instruction"),
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:79:14
+   |
+LL |             "invalid_instruction1",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:80:14
+   |
+LL |             "invalid_instruction2",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:86:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:86:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:95:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:95:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+  --> $DIR/srcloc.rs:99:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:1
+   |
+LL | invalid_instruction3
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+  --> $DIR/srcloc.rs:99:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:5:1
+   |
+LL | invalid_instruction4
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:110:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:110:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+  --> $DIR/srcloc.rs:114:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:5:1
+   |
+LL | invalid_instruction3
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+  --> $DIR/srcloc.rs:114:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:6:1
+   |
+LL | invalid_instruction4
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 23 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/assoc-lang-items.rs b/src/test/ui/assoc-lang-items.rs
new file mode 100644 (file)
index 0000000..23453d2
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(lang_items)]
+
+trait Foo {
+    #[lang = "dummy_lang_item_1"] //~ ERROR definition
+    fn foo() {}
+
+    #[lang = "dummy_lang_item_2"] //~ ERROR definition
+    fn bar();
+
+    #[lang = "dummy_lang_item_3"] //~ ERROR definition
+    type MyType;
+}
+
+struct Bar;
+
+impl Bar {
+    #[lang = "dummy_lang_item_4"] //~ ERROR definition
+    fn test() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/assoc-lang-items.stderr b/src/test/ui/assoc-lang-items.stderr
new file mode 100644 (file)
index 0000000..040792f
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0522]: definition of an unknown language item: `dummy_lang_item_1`
+  --> $DIR/assoc-lang-items.rs:4:5
+   |
+LL |     #[lang = "dummy_lang_item_1"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_1`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_2`
+  --> $DIR/assoc-lang-items.rs:7:5
+   |
+LL |     #[lang = "dummy_lang_item_2"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_2`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_3`
+  --> $DIR/assoc-lang-items.rs:10:5
+   |
+LL |     #[lang = "dummy_lang_item_3"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_3`
+
+error[E0522]: definition of an unknown language item: `dummy_lang_item_4`
+  --> $DIR/assoc-lang-items.rs:17:5
+   |
+LL |     #[lang = "dummy_lang_item_4"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_4`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0522`.
index fe3721a910922aa7e1df73f14153418732a7d0d9..c1b08010cd5b6396efd829580bd105d66af9e13f 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL |     const B: u8 = Self::A + 1;
    |     --------------^^^^^^^^^^^-
    |                   |
-   |                   attempt to add with overflow
+   |                   attempt to compute `u8::MAX + 1_u8` which would overflow
    |
    = note: `#[deny(const_err)]` on by default
 
index 510a13ea5b1be0348d5be4d4e921043b315f4c92..724823e36405ee5e451015b3cb032ffccb1da711 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
    |
 LL |     const NEG: i32 = -i32::MIN + T::NEG;
-   |                      ^^^^^^^^^ attempt to negate with overflow
+   |                      ^^^^^^^^^ attempt to negate i32::MIN which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,25 +10,25 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
    |
 LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
-   |                                   ^^^^^^^^^^^ attempt to negate with overflow
+   |                                   ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
    |
 LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
-   |                      ^^^^^^^^^^^^ attempt to add with overflow
+   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
    |
 LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
-   |                                    ^^^^^^^^^^^^ attempt to add with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
    |
 LL |     const DIV: i32 = (1/0) + T::DIV;
-   |                      ^^^^^ attempt to divide by zero
+   |                      ^^^^^ attempt to divide 1_i32 by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -36,7 +36,7 @@ error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
    |
 LL |     const DIV_REV: i32 = T::DIV + (1/0);
-   |                                   ^^^^^ attempt to divide by zero
+   |                                   ^^^^^ attempt to divide 1_i32 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
index 510a13ea5b1be0348d5be4d4e921043b315f4c92..724823e36405ee5e451015b3cb032ffccb1da711 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
    |
 LL |     const NEG: i32 = -i32::MIN + T::NEG;
-   |                      ^^^^^^^^^ attempt to negate with overflow
+   |                      ^^^^^^^^^ attempt to negate i32::MIN which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,25 +10,25 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
    |
 LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
-   |                                   ^^^^^^^^^^^ attempt to negate with overflow
+   |                                   ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
    |
 LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
-   |                      ^^^^^^^^^^^^ attempt to add with overflow
+   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
    |
 LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
-   |                                    ^^^^^^^^^^^^ attempt to add with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
    |
 LL |     const DIV: i32 = (1/0) + T::DIV;
-   |                      ^^^^^ attempt to divide by zero
+   |                      ^^^^^ attempt to divide 1_i32 by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -36,7 +36,7 @@ error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
    |
 LL |     const DIV_REV: i32 = T::DIV + (1/0);
-   |                                   ^^^^^ attempt to divide by zero
+   |                                   ^^^^^ attempt to divide 1_i32 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
index 510a13ea5b1be0348d5be4d4e921043b315f4c92..724823e36405ee5e451015b3cb032ffccb1da711 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
    |
 LL |     const NEG: i32 = -i32::MIN + T::NEG;
-   |                      ^^^^^^^^^ attempt to negate with overflow
+   |                      ^^^^^^^^^ attempt to negate i32::MIN which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,25 +10,25 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
    |
 LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
-   |                                   ^^^^^^^^^^^ attempt to negate with overflow
+   |                                   ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
    |
 LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
-   |                      ^^^^^^^^^^^^ attempt to add with overflow
+   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
    |
 LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
-   |                                    ^^^^^^^^^^^^ attempt to add with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
    |
 LL |     const DIV: i32 = (1/0) + T::DIV;
-   |                      ^^^^^ attempt to divide by zero
+   |                      ^^^^^ attempt to divide 1_i32 by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -36,7 +36,7 @@ error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
    |
 LL |     const DIV_REV: i32 = T::DIV + (1/0);
-   |                                   ^^^^^ attempt to divide by zero
+   |                                   ^^^^^ attempt to divide 1_i32 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
index 66c5f34644c016a19c438a22581ccde64037c16f..53a45cf4e4f4db2763635182c1f60372cdfa9bab 100644 (file)
@@ -4,7 +4,16 @@ error[E0412]: cannot find type `A` in this scope
 LL | fn foo2<I: Foo>(x: I) {
    |         - similarly named type parameter `I` defined here
 LL |     let _: A = x.boo();
-   |            ^ help: a type parameter with a similar name exists: `I`
+   |            ^
+   |
+help: a type parameter with a similar name exists
+   |
+LL |     let _: I = x.boo();
+   |            ^
+help: you might be missing a type parameter
+   |
+LL | fn foo2<I: Foo, A>(x: I) {
+   |               ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
new file mode 100644 (file)
index 0000000..25e9f72
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
+  --> $DIR/associated-types-eq-hr.rs:87:5
+   |
+LL | fn foo<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+   |                                    ------------- required by this bound in `foo`
+...
+LL |     foo::<UintStruct>();
+   |     ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
+   |
+   = note: expected reference `&isize`
+              found reference `&usize`
+
+error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
+  --> $DIR/associated-types-eq-hr.rs:91:5
+   |
+LL | fn bar<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+   |                                    ------------- required by this bound in `bar`
+...
+LL |     bar::<IntStruct>();
+   |     ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: expected reference `&usize`
+              found reference `&isize`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
index e6afa3f71c2f047192663b71ac67fa6b58e3110e..fb391913c321ecd0c71384ed633e308f76cabaa7 100644 (file)
@@ -7,7 +7,7 @@ pub trait TheTrait<T> {
 }
 
 struct IntStruct {
-    x: isize
+    x: isize,
 }
 
 impl<'a> TheTrait<&'a isize> for IntStruct {
@@ -19,7 +19,7 @@ fn get(&self, t: &'a isize) -> &'a isize {
 }
 
 struct UintStruct {
-    x: isize
+    x: isize,
 }
 
 impl<'a> TheTrait<&'a isize> for UintStruct {
@@ -30,8 +30,7 @@ fn get(&self, t: &'a isize) -> &'a usize {
     }
 }
 
-struct Tuple {
-}
+struct Tuple {}
 
 impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
     type A = &'a isize;
@@ -42,37 +41,43 @@ fn get(&self, t: (&'a isize, &'a isize)) -> &'a isize {
 }
 
 fn foo<T>()
-    where T : for<'x> TheTrait<&'x isize, A = &'x isize>
+where
+    T: for<'x> TheTrait<&'x isize, A = &'x isize>,
 {
     // ok for IntStruct, but not UintStruct
 }
 
 fn bar<T>()
-    where T : for<'x> TheTrait<&'x isize, A = &'x usize>
+where
+    T: for<'x> TheTrait<&'x isize, A = &'x usize>,
 {
     // ok for UintStruct, but not IntStruct
 }
 
 fn tuple_one<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>,
 {
     // not ok for tuple, two lifetimes and we pick first
 }
 
 fn tuple_two<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>,
 {
     // not ok for tuple, two lifetimes and we pick second
 }
 
 fn tuple_three<T>()
-    where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
+where
+    T: for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>,
 {
     // ok for tuple
 }
 
 fn tuple_four<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>,
 {
     // not ok for tuple, two lifetimes, and lifetime matching is invariant
 }
@@ -89,14 +94,14 @@ pub fn call_bar() {
 
 pub fn call_tuple_one() {
     tuple_one::<Tuple>();
-    //~^ ERROR not satisfied
-    //~| ERROR type mismatch
+    //~^ ERROR implementation of `TheTrait` is not general enough
+    //~| ERROR implementation of `TheTrait` is not general enough
 }
 
 pub fn call_tuple_two() {
     tuple_two::<Tuple>();
-    //~^ ERROR not satisfied
-    //~| ERROR type mismatch
+    //~^ ERROR implementation of `TheTrait` is not general enough
+    //~| ERROR implementation of `TheTrait` is not general enough
 }
 
 pub fn call_tuple_three() {
@@ -105,7 +110,7 @@ pub fn call_tuple_three() {
 
 pub fn call_tuple_four() {
     tuple_four::<Tuple>();
-    //~^ ERROR not satisfied
+    //~^ ERROR implementation of `TheTrait` is not general enough
 }
 
-fn main() { }
+fn main() {}
index 58d72746e76aa3c3c4c4ec7f003b142a52c51af1..127ab8673556d5bf1554ae11d92027176b84fff6 100644 (file)
@@ -1,10 +1,11 @@
 error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
-  --> $DIR/associated-types-eq-hr.rs:82:5
+  --> $DIR/associated-types-eq-hr.rs:87:5
    |
 LL | fn foo<T>()
    |    --- required by a bound in this
-LL |     where T : for<'x> TheTrait<&'x isize, A = &'x isize>
-   |                                           ------------- required by this bound in `foo`
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+   |                                    ------------- required by this bound in `foo`
 ...
 LL |     foo::<UintStruct>();
    |     ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
@@ -13,12 +14,13 @@ LL |     foo::<UintStruct>();
               found reference `&usize`
 
 error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
-  --> $DIR/associated-types-eq-hr.rs:86:5
+  --> $DIR/associated-types-eq-hr.rs:91:5
    |
 LL | fn bar<T>()
    |    --- required by a bound in this
-LL |     where T : for<'x> TheTrait<&'x isize, A = &'x usize>
-   |                                           ------------- required by this bound in `bar`
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+   |                                    ------------- required by this bound in `bar`
 ...
 LL |     bar::<IntStruct>();
    |     ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
@@ -26,71 +28,86 @@ LL |     bar::<IntStruct>();
    = note: expected reference `&usize`
               found reference `&isize`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:91:17
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | fn tuple_one<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
-   |               ---------------------------------------------------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_one::<Tuple>();
-   |                 ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_one::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'x isize`
-  --> $DIR/associated-types-eq-hr.rs:91:5
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | fn tuple_one<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
-   |                                                           ------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_one::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL |       tuple_one::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+   |
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:97:17
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | fn tuple_two<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
-   |               ---------------------------------------------------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_two::<Tuple>();
-   |                 ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_two::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'y isize`
-  --> $DIR/associated-types-eq-hr.rs:97:5
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | fn tuple_two<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
-   |                                                           ------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_two::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL |       tuple_two::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+   |
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:107:18
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:112:5
    |
-LL | fn tuple_four<T>()
-   |    ---------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
-   |               ------------------------------------------- required by this bound in `tuple_four`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_four::<Tuple>();
-   |                  ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_four::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0271`.
index 71a533a36f41820c6d49a9c2aa555d138ecaa1c1..4fc336122fa9dd5c2530cc2bdadc1f4c7efc5963 100644 (file)
@@ -1,26 +1,26 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:55:4
+  --> $DIR/project-fn-ret-invariant.rs:56:5
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |              -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              --  -- lifetime `'b` defined here
    |              |
    |              lifetime `'a` defined here
 ...
-LL |    (a, b)
-   |    ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL |     (a, b)
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:55:4
+  --> $DIR/project-fn-ret-invariant.rs:56:5
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |              -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              --  -- lifetime `'b` defined here
    |              |
    |              lifetime `'a` defined here
 ...
-LL |    (a, b)
-   |    ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+LL |     (a, b)
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
index 5009e0868a7d4f8a8cf673ce3c219c5b87b35e9d..9462121bdf203d44c984ba4b13158a9a3869ca9c 100644 (file)
@@ -1,23 +1,23 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:53:21
+  --> $DIR/project-fn-ret-invariant.rs:54:22
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                                     --------     --------------------
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-LL |    let a = bar(foo, y);
-   |                     ^ ...but data from `x` is returned here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |                                      --------     --------------------
+   |                                      |
+   |                                      this parameter and the return type are declared with different lifetimes...
+LL |     let a = bar(foo, y);
+   |                      ^ ...but data from `x` is returned here
 
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:54:21
+  --> $DIR/project-fn-ret-invariant.rs:56:9
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                        --------                  --------------------
-   |                        |
-   |                        this parameter and the return type are declared with different lifetimes...
-LL |    let a = bar(foo, y);
-LL |    let b = bar(foo, x);
-   |                     ^ ...but data from `y` is returned here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |                                      --------     --------------------
+   |                                      |
+   |                                      this parameter and the return type are declared with different lifetimes...
+...
+LL |     (a, b)
+   |         ^ ...but data from `x` is returned here
 
 error: aborting due to 2 previous errors
 
index 8f445acf2b98cf4fae8b7327221c731c98ecda97..2156ecb17393f2e96bb850086d7ea8552665cb66 100644 (file)
@@ -1,8 +1,8 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/project-fn-ret-invariant.rs:59:1
+  --> $DIR/project-fn-ret-invariant.rs:60:1
    |
-LL | fn main() { }
-   | ^^^^^^^^^^^^^
+LL | fn main() {}
+   | ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index c39030fbed1e1a7f74062425ada2c95680d24bad..44850df7b2f42ce9e0d8c0d011f032a915648453 100644 (file)
@@ -1,26 +1,26 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:38:12
+  --> $DIR/project-fn-ret-invariant.rs:39:13
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |        -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
-LL |    let f = foo; // <-- No consistent type can be inferred for `f` here.
-LL |    let a = bar(f, x);
-   |            ^^^^^^^^^ argument requires that `'a` must outlive `'b`
+LL |     let f = foo; // <-- No consistent type can be inferred for `f` here.
+LL |     let a = bar(f, x);
+   |             ^^^^^^^^^ argument requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:39:12
+  --> $DIR/project-fn-ret-invariant.rs:40:13
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |        -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
 ...
-LL |    let b = bar(f, y);
-   |            ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+LL |     let b = bar(f, y);
+   |             ^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
index 65d16440ac9b04bb8fd324679ef5314c847b8f82..64b5722390858600908dc9444c69a6953c0d3af2 100644 (file)
@@ -1,13 +1,13 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:39:19
+  --> $DIR/project-fn-ret-invariant.rs:40:20
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                               --------     --------------------
-   |                               |
-   |                               this parameter and the return type are declared with different lifetimes...
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |                                --------     --------------------
+   |                                |
+   |                                this parameter and the return type are declared with different lifetimes...
 ...
-LL |    let b = bar(f, y);
-   |                   ^ ...but data from `x` is returned here
+LL |     let b = bar(f, y);
+   |                    ^ ...but data from `x` is returned here
 
 error: aborting due to previous error
 
index 23d873212ed1edbe7741fd67a35e0b1662d13e50..0034d796826de662b16e8aec226e8e3bfcaf8ada 100644 (file)
@@ -1,60 +1,61 @@
 #![feature(unboxed_closures)]
 #![feature(rustc_attrs)]
-
 // Test for projection cache. We should be able to project distinct
 // lifetimes from `foo` as we reinstantiate it multiple times, but not
 // if we do it just once. In this variant, the region `'a` is used in
 // an invariant position, which affects the results.
 
 // revisions: ok oneuse transmute krisskross
-
 #![allow(dead_code, unused_variables)]
 
 use std::marker::PhantomData;
 
 struct Type<'a> {
     // Invariant
-    data: PhantomData<fn(&'a u32) -> &'a u32>
+    data: PhantomData<fn(&'a u32) -> &'a u32>,
 }
 
-fn foo<'a>() -> Type<'a> { loop { } }
+fn foo<'a>() -> Type<'a> {
+    loop {}
+}
 
 fn bar<T>(t: T, x: T::Output) -> T::Output
-    where T: FnOnce<()>
+where
+    T: FnOnce<()>,
 {
     t()
 }
 
 #[cfg(ok)] // two instantiations: OK
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
     let a = bar(foo, x);
     let b = bar(foo, y);
     (a, b)
 }
 
 #[cfg(oneuse)] // one instantiation: BAD
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   let f = foo; // <-- No consistent type can be inferred for `f` here.
-   let a = bar(f, x);
-   let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
-   (a, b)
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+    let f = foo; // <-- No consistent type can be inferred for `f` here.
+    let a = bar(f, x);
+    let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
+    (a, b)
 }
 
 #[cfg(transmute)] // one instantiations: BAD
-fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
-   // Cannot instantiate `foo` with any lifetime other than `'a`,
-   // since it is provided as input.
+fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
+    // Cannot instantiate `foo` with any lifetime other than `'a`,
+    // since it is provided as input.
 
-   bar(foo, x) //[transmute]~ ERROR E0495
+    bar(foo, x) //[transmute]~ ERROR E0495
 }
 
 #[cfg(krisskross)] // two instantiations, mixing and matching: BAD
-fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   let a = bar(foo, y); //[krisskross]~ ERROR E0623
-   let b = bar(foo, x); //[krisskross]~ ERROR E0623
-   (a, b)
+fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+    let a = bar(foo, y); //[krisskross]~ ERROR E0623
+    let b = bar(foo, x);
+    (a, b) //[krisskross]~ ERROR E0623
 }
 
 #[rustc_error]
-fn main() { }
+fn main() {}
 //[ok]~^ ERROR fatal error triggered by #[rustc_error]
index f74d4ba73bf4e34ad32e63636e60cf1a6d1e7c81..db82c9fd43794e359691bcbbf81b7a99aec684f5 100644 (file)
@@ -1,11 +1,11 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+  --> $DIR/project-fn-ret-invariant.rs:49:5
    |
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |        -- lifetime `'a` defined here
 ...
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL |     bar(foo, x)
+   |     ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
    |
    = help: consider replacing `'a` with `'static`
 
index 137cb83ccd32704f6e8b2920e80fb6067e68cd16..ef57f9e0bc480049ba6ed9bfab821693693f1e1f 100644 (file)
@@ -1,27 +1,27 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/project-fn-ret-invariant.rs:48:8
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/project-fn-ret-invariant.rs:49:9
    |
-LL |    bar(foo, x)
-   |        ^^^
+LL |     bar(foo, x)
+   |         ^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8...
-  --> $DIR/project-fn-ret-invariant.rs:44:8
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
+  --> $DIR/project-fn-ret-invariant.rs:45:8
    |
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |        ^^
 note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:48:13
+  --> $DIR/project-fn-ret-invariant.rs:49:14
    |
-LL |    bar(foo, x)
-   |             ^
+LL |     bar(foo, x)
+   |              ^
    = note: expected `Type<'_>`
               found `Type<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+  --> $DIR/project-fn-ret-invariant.rs:49:5
    |
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^
+LL |     bar(foo, x)
+   |     ^^^^^^^^^^^
    = note: expected `Type<'static>`
               found `Type<'_>`
 
index d0ed718b839230c6465a6057f86b090fc29ec179..553705b2a4fab39c944dbae4802093ac3439ff66 100644 (file)
@@ -1,6 +1,7 @@
 //! Tests the interaction of associated type defaults and specialization.
 
 #![feature(associated_type_defaults, specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 trait Tr {
     type Ty = u8;
index 37a4d9b60fdfdc48beab55a685755c2494406f4a..09a8c8f8a88a205e2828f43dad1a86ee527740ec 100644 (file)
@@ -1,5 +1,14 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/defaults-specialization.rs:3:38
+   |
+LL | #![feature(associated_type_defaults, specialization)]
+   |                                      ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0053]: method `make` has an incompatible type for trait
-  --> $DIR/defaults-specialization.rs:18:18
+  --> $DIR/defaults-specialization.rs:19:18
    |
 LL |     fn make() -> Self::Ty {
    |                  -------- type in trait
@@ -11,7 +20,7 @@ LL |     fn make() -> u8 { 0 }
               found fn pointer `fn() -> u8`
 
 error[E0053]: method `make` has an incompatible type for trait
-  --> $DIR/defaults-specialization.rs:34:18
+  --> $DIR/defaults-specialization.rs:35:18
    |
 LL |     fn make() -> Self::Ty {
    |                  -------- type in trait
@@ -26,7 +35,7 @@ LL |     fn make() -> bool { true }
               found fn pointer `fn() -> bool`
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-specialization.rs:9:9
+  --> $DIR/defaults-specialization.rs:10:9
    |
 LL |     type Ty = u8;
    |     ------------- associated type defaults can't be assumed inside the trait defining them
@@ -40,7 +49,7 @@ LL |         0u8
                          found type `u8`
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-specialization.rs:25:29
+  --> $DIR/defaults-specialization.rs:26:29
    |
 LL |     fn make() -> Self::Ty { 0u8 }
    |                  --------   ^^^ expected associated type, found `u8`
@@ -53,7 +62,7 @@ LL |     fn make() -> Self::Ty { 0u8 }
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-specialization.rs:43:29
+  --> $DIR/defaults-specialization.rs:44:29
    |
 LL |     default type Ty = bool;
    |     ----------------------- expected this associated type
@@ -67,7 +76,7 @@ LL |     fn make() -> Self::Ty { true }
                          found type `bool`
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-specialization.rs:86:32
+  --> $DIR/defaults-specialization.rs:87:32
    |
 LL |     let _: <B<()> as Tr>::Ty = 0u8;
    |            -----------------   ^^^ expected associated type, found `u8`
@@ -77,13 +86,13 @@ LL |     let _: <B<()> as Tr>::Ty = 0u8;
    = note: expected associated type `<B<()> as Tr>::Ty`
                          found type `u8`
 help: a method is available that returns `<B<()> as Tr>::Ty`
-  --> $DIR/defaults-specialization.rs:8:5
+  --> $DIR/defaults-specialization.rs:9:5
    |
 LL |     fn make() -> Self::Ty {
    |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-specialization.rs:87:32
+  --> $DIR/defaults-specialization.rs:88:32
    |
 LL |     let _: <B<()> as Tr>::Ty = true;
    |            -----------------   ^^^^ expected associated type, found `bool`
@@ -93,13 +102,13 @@ LL |     let _: <B<()> as Tr>::Ty = true;
    = note: expected associated type `<B<()> as Tr>::Ty`
                          found type `bool`
 help: a method is available that returns `<B<()> as Tr>::Ty`
-  --> $DIR/defaults-specialization.rs:8:5
+  --> $DIR/defaults-specialization.rs:9:5
    |
 LL |     fn make() -> Self::Ty {
    |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-specialization.rs:88:33
+  --> $DIR/defaults-specialization.rs:89:33
    |
 LL |     let _: <B2<()> as Tr>::Ty = 0u8;
    |            ------------------   ^^^ expected associated type, found `u8`
@@ -109,13 +118,13 @@ LL |     let _: <B2<()> as Tr>::Ty = 0u8;
    = note: expected associated type `<B2<()> as Tr>::Ty`
                          found type `u8`
 help: a method is available that returns `<B2<()> as Tr>::Ty`
-  --> $DIR/defaults-specialization.rs:8:5
+  --> $DIR/defaults-specialization.rs:9:5
    |
 LL |     fn make() -> Self::Ty {
    |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
 error[E0308]: mismatched types
-  --> $DIR/defaults-specialization.rs:89:33
+  --> $DIR/defaults-specialization.rs:90:33
    |
 LL |     let _: <B2<()> as Tr>::Ty = true;
    |            ------------------   ^^^^ expected associated type, found `bool`
@@ -125,12 +134,12 @@ LL |     let _: <B2<()> as Tr>::Ty = true;
    = note: expected associated type `<B2<()> as Tr>::Ty`
                          found type `bool`
 help: a method is available that returns `<B2<()> as Tr>::Ty`
-  --> $DIR/defaults-specialization.rs:8:5
+  --> $DIR/defaults-specialization.rs:9:5
    |
 LL |     fn make() -> Self::Ty {
    |     ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make`
 
-error: aborting due to 9 previous errors
+error: aborting due to 9 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0053, E0308.
 For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
new file mode 100644 (file)
index 0000000..2e03986
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/higher-ranked-projection.rs:25:5
+   |
+LL |     foo(());
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
index 3b3e4c3ea117a6211ee32e7c95984f7826787b8c..811c9a8f5e12ba776e6ba237251155550f306c66 100644 (file)
@@ -1,14 +1,12 @@
-error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
+error[E0308]: mismatched types
   --> $DIR/higher-ranked-projection.rs:25:5
    |
-LL | fn foo<U, T>(_t: T)
-   |    --- required by a bound in this
-LL |     where for<'a> &'a T: Mirror<Image=U>
-   |                                 ------- required by this bound in `foo`
-...
 LL |     foo(());
-   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `&'a ()`
+              found type `&()`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
index 5315e21b0f5a9ea2545d15d5e3550374b75c59f4..1b5476d4c364ffcefc7612718741509047cdb59b 100644 (file)
@@ -23,5 +23,5 @@ fn foo<U, T>(_t: T)
 #[rustc_error]
 fn main() { //[good]~ ERROR fatal error triggered by #[rustc_error]
     foo(());
-    //[bad]~^ ERROR type mismatch
+    //[bad]~^ ERROR mismatched types
 }
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-1.rs
new file mode 100644 (file)
index 0000000..497b86e
--- /dev/null
@@ -0,0 +1,18 @@
+trait X<'a>
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(&self, x: &Self::U) {
+        <Self::U>::clone(x);
+    }
+}
+
+impl X<'_> for i32 {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <i32 as X<'b>>::U: std::clone::Clone`
+}
+
+fn main() {
+    1i32.f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr
new file mode 100644 (file)
index 0000000..7ef2fae
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <i32 as X<'b>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-1.rs:12:14
+   |
+LL | trait X<'a>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <Self as X<'b>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<i32 as X<'b>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-2.rs
new file mode 100644 (file)
index 0000000..7ff0fed
--- /dev/null
@@ -0,0 +1,21 @@
+trait X<'a>
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(&self, x: &Self::U) {
+        <Self::U>::clone(x);
+    }
+}
+
+impl X<'_> for u32
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U = str;
+}
+
+fn main() {
+    1u32.f("abc");
+    //~^ ERROR no method named `f` found for type `u32` in the current scope
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr
new file mode 100644 (file)
index 0000000..2a364d3
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0599]: no method named `f` found for type `u32` in the current scope
+  --> $DIR/hr-associated-type-bound-2.rs:19:10
+   |
+LL |     1u32.f("abc");
+   |          ^ method not found in `u32`
+   |
+   = note: the method `f` exists but the following trait bounds were not satisfied:
+           `<u32 as X<'b>>::U: std::clone::Clone`
+           which is required by `u32: X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.rs b/src/test/ui/associated-types/hr-associated-type-bound-object.rs
new file mode 100644 (file)
index 0000000..7c64ae3
--- /dev/null
@@ -0,0 +1,14 @@
+trait X<'a>
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U: ?Sized;
+}
+fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
+    //~^ ERROR the trait bound `for<'b> <T as X<'b>>::U: std::clone::Clone` is not satisfied
+    <<T as X<'_>>::U>::clone(x);
+}
+
+pub fn main() {
+    f::<dyn X<'_, U = str>>("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr
new file mode 100644 (file)
index 0000000..db96687
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <T as X<'b>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-object.rs:7:13
+   |
+LL | trait X<'a>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <Self as X<'b>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL | fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
+   |             ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<T as X<'b>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs
new file mode 100644 (file)
index 0000000..a65f8a8
--- /dev/null
@@ -0,0 +1,20 @@
+trait Y<'a, T: ?Sized>
+where
+    T: Y<'a, Self>,
+    for<'b> <Self as Y<'b, T>>::V: Clone,
+    for<'b> <T as Y<'b, Self>>::V: Clone,
+{
+    type V: ?Sized;
+    fn g(&self, x: &Self::V) {
+        <Self::V>::clone(x);
+    }
+}
+
+impl<'a> Y<'a, u8> for u8 {
+    type V = str;
+    //~^ ERROR the trait bound `for<'b> <u8 as Y<'b, u8>>::V: std::clone::Clone` is not satisfied
+}
+
+fn main() {
+    1u8.g("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr
new file mode 100644 (file)
index 0000000..347a581
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <u8 as Y<'b, u8>>::V: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-1.rs:14:14
+   |
+LL | trait Y<'a, T: ?Sized>
+   |       - required by a bound in this
+...
+LL |     for<'b> <Self as Y<'b, T>>::V: Clone,
+   |                                    ----- required by this bound in `Y`
+...
+LL |     type V = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u8 as Y<'b, u8>>::V`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
new file mode 100644 (file)
index 0000000..9f849b0
--- /dev/null
@@ -0,0 +1,21 @@
+trait Z<'a, T: ?Sized>
+where
+    T: Z<'a, u16>,
+    //~^ the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+    //~| the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+    for<'b> <T as Z<'b, u16>>::W: Clone,
+{
+    type W: ?Sized;
+    fn h(&self, x: &T::W) {
+        <T::W>::clone(x);
+    }
+}
+
+impl<'a> Z<'a, u16> for u16 {
+    type W = str;
+    //~^ ERROR the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone
+}
+
+fn main() {
+    1u16.h("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
new file mode 100644 (file)
index 0000000..e06777e
--- /dev/null
@@ -0,0 +1,51 @@
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+   |
+LL | trait Z<'a, T: ?Sized>
+   |       - required by a bound in this
+LL | where
+LL |     T: Z<'a, u16>,
+   |        ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+...
+LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
+   |                                   ----- required by this bound in `Z`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-2.rs:15:14
+   |
+LL | trait Z<'a, T: ?Sized>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
+   |                                   ----- required by this bound in `Z`
+...
+LL |     type W = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+   |
+LL | trait Z<'a, T: ?Sized>
+   |       - required by a bound in this
+LL | where
+LL |     T: Z<'a, u16>,
+   |        ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+...
+LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
+   |                                   ----- required by this bound in `Z`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs
new file mode 100644 (file)
index 0000000..9aca59f
--- /dev/null
@@ -0,0 +1,21 @@
+// ignore-tidy-linelength
+
+trait X<'a, T>
+where
+    for<'b> T: X<'b, T>,
+    for<'b> <T as X<'b, T>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<T as X<'_, T>>::U) {
+        <<T as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, (T,)> for (S,) {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <(i32,) as X<(i32,)>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr
new file mode 100644 (file)
index 0000000..ff56f60
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-3.rs:15:14
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs
new file mode 100644 (file)
index 0000000..ffe43c6
--- /dev/null
@@ -0,0 +1,19 @@
+trait X<'a, T>
+where
+    for<'b> (T,): X<'b, T>,
+    for<'b> <(T,) as X<'b, T>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<(T,) as X<'_, T>>::U) {
+        <<(T,) as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, T> for (S,) {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <(i32,) as X<i32>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr
new file mode 100644 (file)
index 0000000..c41efb8
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-4.rs:13:14
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+...
+LL |     for<'b> <(T,) as X<'b, T>>::U: Clone,
+   |                                    ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
new file mode 100644 (file)
index 0000000..dcca0b3
--- /dev/null
@@ -0,0 +1,41 @@
+// ignore-tidy-linelength
+
+trait Cycle: Sized {
+    type Next: Cycle<Next = Self>;
+}
+
+impl<T> Cycle for Box<T> {
+    type Next = Vec<T>;
+}
+
+impl<T> Cycle for Vec<T> {
+    type Next = Box<T>;
+}
+
+trait X<'a, T: Cycle + for<'b> X<'b, T>>
+where
+    for<'b> <T as X<'b, T>>::U: Clone,
+    for<'b> T::Next: X<'b, T::Next>,
+    for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<T as X<'_, T>>::U) {
+        <<T as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, Vec<T>> for S {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+    //~| ERROR the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+}
+
+impl<S, T> X<'_, Box<T>> for S {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+    //~| ERROR the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <i32 as X<Box<i32>>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
new file mode 100644 (file)
index 0000000..39c191e
--- /dev/null
@@ -0,0 +1,67 @@
+error[E0277]: the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:28:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+   |                                             ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:28:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:34:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+   |                                             ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:34:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs
new file mode 100644 (file)
index 0000000..4b8018c
--- /dev/null
@@ -0,0 +1,20 @@
+trait X<'a, T>
+where
+    for<'b> T: X<'b, T>,
+    for<'b> <T as X<'b, T>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<T as X<'_, T>>::U) {
+        <<T as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, T> for (S,) {
+    //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <T as X<'b, T>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <(i32,) as X<i32>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr
new file mode 100644 (file)
index 0000000..83845d3
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0277]: the trait bound `for<'b> <T as X<'b, T>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-6.rs:14:14
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<T as X<'b, T>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-6.rs:12:12
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> T: X<'b, T>,
+   |                -------- required by this bound in `X`
+...
+LL | impl<S, T> X<'_, T> for (S,) {
+   |            ^^^^^^^^ the trait `for<'b> X<'b, T>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<S, T: for<'b> X<'b, T>> X<'_, T> for (S,) {
+   |          ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.rs b/src/test/ui/associated-types/hr-associated-type-projection-1.rs
new file mode 100644 (file)
index 0000000..0d4567a
--- /dev/null
@@ -0,0 +1,21 @@
+trait UnsafeCopy<'a, T: Copy>
+where
+    for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
+{
+    type Item;
+
+    fn bug(item: &Self::Item) -> () {
+        let x: T = **item;
+        &x as *const _;
+    }
+}
+
+impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
+    //~^ ERROR the trait bound `<T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+    type Item = T;
+    //~^ ERROR the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref
+}
+
+pub fn main() {
+    <&'static str>::bug(&"");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr
new file mode 100644 (file)
index 0000000..5ab5741
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+  --> $DIR/hr-associated-type-projection-1.rs:15:17
+   |
+LL | trait UnsafeCopy<'a, T: Copy>
+   |       ---------- required by a bound in this
+LL | where
+LL |     for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
+   |                                                --------------------------- required by this bound in `UnsafeCopy`
+...
+LL |     type Item = T;
+   |                 ^ the trait `for<'b> std::ops::Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
+   |
+   = help: the following implementations were found:
+             <&T as std::ops::Deref>
+             <&mut T as std::ops::Deref>
+
+error[E0277]: the trait bound `<T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+  --> $DIR/hr-associated-type-projection-1.rs:13:33
+   |
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
+   |                                 ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
+   |
+help: consider further restricting the associated type
+   |
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T where <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref {
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index cf10ebfeca9399cc7db1dc9b95362339f9f2849f..86d459bf084b1f6827c92525f8dc317f518ac7b9 100644 (file)
@@ -5,7 +5,7 @@
 use std::future::Future;
 
 fn get_future() -> impl Future<Output = ()> {
-//~^ ERROR the trait bound `(): std::future::Future` is not satisfied
+//~^ ERROR `()` is not a future
     panic!()
 }
 
index 4054e739c483d58e0dce7cedd73aa7e913271fa7..9523f040aa8cd91c3526600b6d207913be08228a 100644 (file)
@@ -1,12 +1,13 @@
-error[E0277]: the trait bound `(): std::future::Future` is not satisfied
+error[E0277]: `()` is not a future
   --> $DIR/async-error-span.rs:7:20
    |
 LL | fn get_future() -> impl Future<Output = ()> {
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `()`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
 LL |
 LL |     panic!()
    |     -------- this returned value is of type `!`
    |
+   = help: the trait `std::future::Future` is not implemented for `()`
    = note: the return type of a function must have a statically known size
 
 error[E0698]: type inside `async fn` body must be known in this context
index e78231a68512daf1f306cb1e24f6f19ee5841551..9e7c5847b3b2ee846aff7bea81d414cef29f0725 100644 (file)
@@ -4,9 +4,8 @@ async fn fun() {
     [1; ().await];
     //~^ error: `await` is only allowed inside `async` functions and blocks
     //~| error: `.await` is not allowed in a `const`
-    //~| error: `loop` is not allowed in a `const`
     //~| error: `.await` is not allowed in a `const`
-    //~| error: the trait bound `(): std::future::Future` is not satisfied
+    //~| error: `()` is not a future
 }
 
 fn main() {}
index 496ca506c60f2e2c33c937e7df5f919816cdeb14..badb7ae9f6f6529f407e0d857e8c9c587586c7d4 100644 (file)
@@ -12,30 +12,22 @@ error[E0744]: `.await` is not allowed in a `const`
 LL |     [1; ().await];
    |         ^^^^^^^^
 
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/issue-70594.rs:4:9
-   |
-LL |     [1; ().await];
-   |         ^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
 error[E0744]: `.await` is not allowed in a `const`
   --> $DIR/issue-70594.rs:4:9
    |
 LL |     [1; ().await];
    |         ^^^^^^^^
 
-error[E0277]: the trait bound `(): std::future::Future` is not satisfied
+error[E0277]: `()` is not a future
   --> $DIR/issue-70594.rs:4:9
    |
 LL |     [1; ().await];
-   |         ^^^^^^^^ the trait `std::future::Future` is not implemented for `()`
+   |         ^^^^^^^^ `()` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `()`
    = note: required by `std::future::Future::poll`
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0277, E0658, E0728, E0744.
+Some errors have detailed explanations: E0277, E0728, E0744.
 For more information about an error, try `rustc --explain E0277`.
index ec4e9e397a81e25dbae97822465ec22642a19c1f..e3ba74a03c898c933470709ef1097adb569faad0 100644 (file)
@@ -27,12 +27,13 @@ LL | fn main() {
 LL |     (|_| 2333).await;
    |     ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
-error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]: std::future::Future` is not satisfied
+error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
   --> $DIR/issue-62009-1.rs:12:5
    |
 LL |     (|_| 2333).await;
-   |     ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+   |     ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
    = note: required by `std::future::Future::poll`
 
 error: aborting due to 4 previous errors
index af8fc2cd2ab459d8bc4b3eda43227db55de77e5c..0f58b158904db0a2fb3aa8fdb2e5c935c07e2707 100644 (file)
@@ -1,13 +1,14 @@
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/issue-62097.rs:12:31
    |
 LL |     pub async fn run_dummy_fn(&self) {
    |                               ^^^^^
    |                               |
-   |                               data with this lifetime...
+   |                               this data with an anonymous lifetime `'_`...
    |                               ...is captured here...
 LL |         foo(|| self.bar()).await;
-   |         --- ...and required to be `'static` by this
+   |         --- ...and is required to live as long as `'static` here
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/auto-is-contextual.rs b/src/test/ui/auto-is-contextual.rs
deleted file mode 100644 (file)
index a2ddd53..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// run-pass
-
-#![allow(path_statements)]
-#![allow(dead_code)]
-macro_rules! auto {
-    () => (struct S;)
-}
-
-auto!();
-
-fn auto() {}
-
-fn main() {
-    auto();
-    let auto = 10;
-    auto;
-    auto as u8;
-}
diff --git a/src/test/ui/auto-trait-validation.rs b/src/test/ui/auto-trait-validation.rs
deleted file mode 100644 (file)
index 34d6c3d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(optin_builtin_traits)]
-
-auto trait Generic<T> {}
-//~^ auto traits cannot have generic parameters [E0567]
-auto trait Bound : Copy {}
-//~^ auto traits cannot have super traits [E0568]
-auto trait MyTrait { fn foo() {} }
-//~^ auto traits cannot have methods or associated items [E0380]
-fn main() {}
diff --git a/src/test/ui/auto-trait-validation.stderr b/src/test/ui/auto-trait-validation.stderr
deleted file mode 100644 (file)
index 4040e66..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0567]: auto traits cannot have generic parameters
-  --> $DIR/auto-trait-validation.rs:3:19
-   |
-LL | auto trait Generic<T> {}
-   |            -------^^^ help: remove the parameters
-   |            |
-   |            auto trait cannot have generic parameters
-
-error[E0568]: auto traits cannot have super traits
-  --> $DIR/auto-trait-validation.rs:5:20
-   |
-LL | auto trait Bound : Copy {}
-   |            -----   ^^^^ help: remove the super traits
-   |            |
-   |            auto trait cannot have super traits
-
-error[E0380]: auto traits cannot have methods or associated items
-  --> $DIR/auto-trait-validation.rs:7:25
-   |
-LL | auto trait MyTrait { fn foo() {} }
-   |            -------      ^^^
-   |            |
-   |            auto trait cannot have items
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0380, E0567, E0568.
-For more information about an error, try `rustc --explain E0380`.
diff --git a/src/test/ui/auto-traits/auto-is-contextual.rs b/src/test/ui/auto-traits/auto-is-contextual.rs
new file mode 100644 (file)
index 0000000..a2ddd53
--- /dev/null
@@ -0,0 +1,18 @@
+// run-pass
+
+#![allow(path_statements)]
+#![allow(dead_code)]
+macro_rules! auto {
+    () => (struct S;)
+}
+
+auto!();
+
+fn auto() {}
+
+fn main() {
+    auto();
+    let auto = 10;
+    auto;
+    auto as u8;
+}
diff --git a/src/test/ui/auto-traits/auto-trait-projection-recursion.rs b/src/test/ui/auto-traits/auto-trait-projection-recursion.rs
new file mode 100644 (file)
index 0000000..a36f26f
--- /dev/null
@@ -0,0 +1,34 @@
+// Checking the `Send` bound in `main` requires:
+//
+// checking             <C<'static> as Y>::P: Send
+// which normalizes to  Box<X<C<'?1>>>: Send
+// which needs          X<C<'?1>>: Send
+// which needs          <C<'?1> as Y>::P: Send
+//
+// At this point we used to normalize the predicate to `Box<X<C<'?2>>>: Send`
+// and continue in a loop where we created new region variables to the
+// recursion limit. To avoid this we now "canonicalize" region variables to
+// lowest unified region vid. This means we instead have to prove
+// `Box<X<C<'?1>>>: Send`, which we can because auto traits are coinductive.
+
+// check-pass
+
+// Avoid a really long error message if this regresses.
+#![recursion_limit="20"]
+
+trait Y {
+    type P;
+}
+
+impl<'a> Y for C<'a> {
+    type P = Box<X<C<'a>>>;
+}
+
+struct C<'a>(&'a ());
+struct X<T: Y>(T::P);
+
+fn is_send<S: Send>() {}
+
+fn main() {
+    is_send::<X<C<'static>>>();
+}
diff --git a/src/test/ui/auto-traits/auto-trait-validation.rs b/src/test/ui/auto-traits/auto-trait-validation.rs
new file mode 100644 (file)
index 0000000..34d6c3d
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(optin_builtin_traits)]
+
+auto trait Generic<T> {}
+//~^ auto traits cannot have generic parameters [E0567]
+auto trait Bound : Copy {}
+//~^ auto traits cannot have super traits [E0568]
+auto trait MyTrait { fn foo() {} }
+//~^ auto traits cannot have methods or associated items [E0380]
+fn main() {}
diff --git a/src/test/ui/auto-traits/auto-trait-validation.stderr b/src/test/ui/auto-traits/auto-trait-validation.stderr
new file mode 100644 (file)
index 0000000..4040e66
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0567]: auto traits cannot have generic parameters
+  --> $DIR/auto-trait-validation.rs:3:19
+   |
+LL | auto trait Generic<T> {}
+   |            -------^^^ help: remove the parameters
+   |            |
+   |            auto trait cannot have generic parameters
+
+error[E0568]: auto traits cannot have super traits
+  --> $DIR/auto-trait-validation.rs:5:20
+   |
+LL | auto trait Bound : Copy {}
+   |            -----   ^^^^ help: remove the super traits
+   |            |
+   |            auto trait cannot have super traits
+
+error[E0380]: auto traits cannot have methods or associated items
+  --> $DIR/auto-trait-validation.rs:7:25
+   |
+LL | auto trait MyTrait { fn foo() {} }
+   |            -------      ^^^
+   |            |
+   |            auto trait cannot have items
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0380, E0567, E0568.
+For more information about an error, try `rustc --explain E0380`.
diff --git a/src/test/ui/auto-traits/auto-traits.rs b/src/test/ui/auto-traits/auto-traits.rs
new file mode 100644 (file)
index 0000000..15fdddc
--- /dev/null
@@ -0,0 +1,32 @@
+// run-pass
+#![allow(unused_doc_comments)]
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Auto {}
+unsafe auto trait AutoUnsafe {}
+
+impl !Auto for bool {}
+impl !AutoUnsafe for bool {}
+
+struct AutoBool(bool);
+
+impl Auto for AutoBool {}
+unsafe impl AutoUnsafe for AutoBool {}
+
+fn take_auto<T: Auto>(_: T) {}
+fn take_auto_unsafe<T: AutoUnsafe>(_: T) {}
+
+fn main() {
+    // Parse inside functions.
+    auto trait AutoInner {}
+    unsafe auto trait AutoUnsafeInner {}
+
+    take_auto(0);
+    take_auto(AutoBool(true));
+    take_auto_unsafe(0);
+    take_auto_unsafe(AutoBool(true));
+
+    /// Auto traits are allowed in trait object bounds.
+    let _: &(dyn Send + Auto) = &0;
+}
diff --git a/src/test/ui/auto-traits/issue-23080-2.rs b/src/test/ui/auto-traits/issue-23080-2.rs
new file mode 100644 (file)
index 0000000..7f6b9e3
--- /dev/null
@@ -0,0 +1,15 @@
+//~ ERROR
+
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+unsafe auto trait Trait {
+    type Output; //~ ERROR E0380
+}
+
+fn call_method<T: Trait>(x: T) {}
+
+fn main() {
+    // ICE
+    call_method(());
+}
diff --git a/src/test/ui/auto-traits/issue-23080-2.stderr b/src/test/ui/auto-traits/issue-23080-2.stderr
new file mode 100644 (file)
index 0000000..48ce09a
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0380]: auto traits cannot have methods or associated items
+  --> $DIR/issue-23080-2.rs:7:10
+   |
+LL | unsafe auto trait Trait {
+   |                   ----- auto trait cannot have items
+LL |     type Output;
+   |          ^^^^^^
+
+error[E0275]: overflow evaluating the requirement `<() as Trait>::Output`
+   |
+   = note: required because of the requirements on the impl of `Trait` for `()`
+   = note: required because of the requirements on the impl of `Trait` for `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0275, E0380.
+For more information about an error, try `rustc --explain E0275`.
diff --git a/src/test/ui/auto-traits/issue-23080.rs b/src/test/ui/auto-traits/issue-23080.rs
new file mode 100644 (file)
index 0000000..035db82
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+unsafe auto trait Trait {
+    fn method(&self) { //~ ERROR E0380
+        println!("Hello");
+    }
+}
+
+fn call_method<T: Trait>(x: T) {
+    x.method();
+}
+
+fn main() {
+    // ICE
+    call_method(());
+}
diff --git a/src/test/ui/auto-traits/issue-23080.stderr b/src/test/ui/auto-traits/issue-23080.stderr
new file mode 100644 (file)
index 0000000..73ecb1c
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0380]: auto traits cannot have methods or associated items
+  --> $DIR/issue-23080.rs:5:8
+   |
+LL | unsafe auto trait Trait {
+   |                   ----- auto trait cannot have items
+LL |     fn method(&self) {
+   |        ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0380`.
diff --git a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs
new file mode 100644 (file)
index 0000000..8824a6d
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Magic : Sized where Option<Self> : Magic {} //~ ERROR E0568
+impl<T:Magic> Magic for T {}
+
+fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
+
+#[derive(Debug)]
+struct NoClone;
+
+fn main() {
+    let (a, b) = copy(NoClone);
+    println!("{:?} {:?}", a, b);
+}
diff --git a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr
new file mode 100644 (file)
index 0000000..63b3300
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0568]: auto traits cannot have super traits
+  --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:20
+   |
+LL | auto trait Magic : Sized where Option<Self> : Magic {}
+   |            -----   ^^^^^ help: remove the super traits
+   |            |
+   |            auto trait cannot have super traits
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0568`.
diff --git a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.rs b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.rs
new file mode 100644 (file)
index 0000000..edbca91
--- /dev/null
@@ -0,0 +1,39 @@
+// This test is for #29859, we need to ensure auto traits,
+// (also known previously as default traits), do not have
+// supertraits. Since the compiler synthesizes these
+// instances on demand, we are essentially enabling
+// users to write axioms if we view trait selection,
+// as a proof system.
+//
+// For example the below test allows us to add the rule:
+//  forall (T : Type), T : Copy
+//
+// Providing a copy instance for *any* type, which
+// is most definitely unsound. Imagine copying a
+// type that contains a mutable reference, enabling
+// mutable aliasing.
+//
+// You can imagine an even more dangerous test,
+// which currently compiles on nightly.
+//
+// fn main() {
+//    let mut i = 10;
+//    let (a, b) = copy(&mut i);
+//    println!("{:?} {:?}", a, b);
+// }
+
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Magic: Copy {} //~ ERROR E0568
+impl<T:Magic> Magic for T {}
+
+fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
+
+#[derive(Debug)]
+struct NoClone;
+
+fn main() {
+    let (a, b) = copy(NoClone);
+    println!("{:?} {:?}", a, b);
+}
diff --git a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr
new file mode 100644 (file)
index 0000000..796638f
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0568]: auto traits cannot have super traits
+  --> $DIR/typeck-auto-trait-no-supertraits.rs:28:19
+   |
+LL | auto trait Magic: Copy {}
+   |            -----  ^^^^ help: remove the super traits
+   |            |
+   |            auto trait cannot have super traits
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0568`.
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.rs
new file mode 100644 (file)
index 0000000..71ac2b4
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait MyTrait {}
+
+struct MyS;
+
+struct MyS2;
+
+impl !MyTrait for MyS2 {}
+
+fn is_mytrait<T: MyTrait>() {}
+
+fn main() {
+    is_mytrait::<MyS>();
+
+    is_mytrait::<(MyS2, MyS)>();
+    //~^ ERROR `MyS2: MyTrait` is not satisfied
+}
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr
new file mode 100644 (file)
index 0000000..53ba9b8
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)`
+  --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:5
+   |
+LL | fn is_mytrait<T: MyTrait>() {}
+   |                  ------- required by this bound in `is_mytrait`
+...
+LL |     is_mytrait::<(MyS2, MyS)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`
+   |
+   = help: the following implementations were found:
+             <MyS2 as MyTrait>
+   = note: required because it appears within the type `(MyS2, MyS)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs
new file mode 100644 (file)
index 0000000..6483b92
--- /dev/null
@@ -0,0 +1,23 @@
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait MyTrait {}
+
+impl<T> !MyTrait for *mut T {}
+
+struct MyS;
+
+struct MyS2;
+
+impl !MyTrait for MyS2 {}
+
+struct MyS3;
+
+fn is_mytrait<T: MyTrait>() {}
+
+fn main() {
+    is_mytrait::<MyS>();
+
+    is_mytrait::<MyS2>();
+    //~^ ERROR `MyS2: MyTrait` is not satisfied
+}
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr
new file mode 100644 (file)
index 0000000..bc50000
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied
+  --> $DIR/typeck-default-trait-impl-constituent-types.rs:21:18
+   |
+LL | fn is_mytrait<T: MyTrait>() {}
+   |                  ------- required by this bound in `is_mytrait`
+...
+LL |     is_mytrait::<MyS2>();
+   |                  ^^^^ the trait `MyTrait` is not implemented for `MyS2`
+   |
+   = help: the following implementations were found:
+             <MyS2 as MyTrait>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-negation.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.rs
new file mode 100644 (file)
index 0000000..47cab60
--- /dev/null
@@ -0,0 +1,29 @@
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait MyTrait {}
+
+unsafe auto trait MyUnsafeTrait {}
+
+struct ThisImplsTrait;
+
+impl !MyUnsafeTrait for ThisImplsTrait {}
+
+
+struct ThisImplsUnsafeTrait;
+
+impl !MyTrait for ThisImplsUnsafeTrait {}
+
+fn is_my_trait<T: MyTrait>() {}
+fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
+
+fn main() {
+    is_my_trait::<ThisImplsTrait>();
+    is_my_trait::<ThisImplsUnsafeTrait>();
+    //~^ ERROR `ThisImplsUnsafeTrait: MyTrait` is not satisfied
+
+    is_my_unsafe_trait::<ThisImplsTrait>();
+    //~^ ERROR `ThisImplsTrait: MyUnsafeTrait` is not satisfied
+
+    is_my_unsafe_trait::<ThisImplsUnsafeTrait>();
+}
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr
new file mode 100644 (file)
index 0000000..76a6994
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `ThisImplsUnsafeTrait: MyTrait` is not satisfied
+  --> $DIR/typeck-default-trait-impl-negation.rs:22:19
+   |
+LL | fn is_my_trait<T: MyTrait>() {}
+   |                   ------- required by this bound in `is_my_trait`
+...
+LL |     is_my_trait::<ThisImplsUnsafeTrait>();
+   |                   ^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait`
+   |
+   = help: the following implementations were found:
+             <ThisImplsUnsafeTrait as MyTrait>
+
+error[E0277]: the trait bound `ThisImplsTrait: MyUnsafeTrait` is not satisfied
+  --> $DIR/typeck-default-trait-impl-negation.rs:25:26
+   |
+LL | fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
+   |                          ------------- required by this bound in `is_my_unsafe_trait`
+...
+LL |     is_my_unsafe_trait::<ThisImplsTrait>();
+   |                          ^^^^^^^^^^^^^^ the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait`
+   |
+   = help: the following implementations were found:
+             <ThisImplsTrait as MyUnsafeTrait>
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.rs
new file mode 100644 (file)
index 0000000..614a5ff
--- /dev/null
@@ -0,0 +1,21 @@
+// Test that declaring that `&T` is `Defaulted` if `T:Signed` implies
+// that other `&T` is NOT `Defaulted` if `T:Signed` does not hold. In
+// other words, the auto impl only applies if there are no existing
+// impls whose types unify.
+
+#![feature(optin_builtin_traits)]
+#![feature(negative_impls)]
+
+auto trait Defaulted { }
+impl<'a,T:Signed> Defaulted for &'a T { }
+impl<'a,T:Signed> Defaulted for &'a mut T { }
+fn is_defaulted<T:Defaulted>() { }
+
+trait Signed { }
+impl Signed for i32 { }
+
+fn main() {
+    is_defaulted::<&'static i32>();
+    is_defaulted::<&'static u32>();
+    //~^ ERROR `u32: Signed` is not satisfied
+}
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
new file mode 100644 (file)
index 0000000..5962d19
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `u32: Signed` is not satisfied
+  --> $DIR/typeck-default-trait-impl-precedence.rs:19:5
+   |
+LL | fn is_defaulted<T:Defaulted>() { }
+   |                   --------- required by this bound in `is_defaulted`
+...
+LL |     is_defaulted::<&'static u32>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
+   |
+   = note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/binary-op-on-double-ref.fixed b/src/test/ui/binary-op-on-double-ref.fixed
new file mode 100644 (file)
index 0000000..de9dc19
--- /dev/null
@@ -0,0 +1,9 @@
+// run-rustfix
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
+    let vr = v.iter().filter(|x| {
+        *x % 2 == 0
+        //~^ ERROR cannot mod `&&{integer}` by `{integer}`
+    });
+    println!("{:?}", vr);
+}
index 67e01b9327db1ec904673ca293afe7cfffb6daa3..2616c560cbefb6c320808d9086976a0b65ac570e 100644 (file)
@@ -1,3 +1,4 @@
+// run-rustfix
 fn main() {
     let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
     let vr = v.iter().filter(|x| {
index 6c405333ec681e06f95ca1f7ce65e7bc75cf988b..02b0488488c555154537ef7829870465590c6071 100644 (file)
@@ -1,12 +1,15 @@
 error[E0369]: cannot mod `&&{integer}` by `{integer}`
-  --> $DIR/binary-op-on-double-ref.rs:4:11
+  --> $DIR/binary-op-on-double-ref.rs:5:11
    |
 LL |         x % 2 == 0
    |         - ^ - {integer}
    |         |
    |         &&{integer}
    |
-   = help: `%` can be used on '{integer}', you can dereference `x`: `*x`
+help: `%` can be used on `{integer}`, you can dereference `x`
+   |
+LL |         *x % 2 == 0
+   |         ^
 
 error: aborting due to previous error
 
index 422d1605aa46b78a2b0fff91d8285f6a80c35336..604143b4e7efd232c94267b0e8f410e22a6f7d22 100644 (file)
@@ -5,6 +5,10 @@ LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `maybe.0`
+   |
+LL |         if let Some(ref thing) = maybe {
+   |                     ^^^
 
 error: aborting due to previous error
 
index 8a405edb046550c50a31add622fafe363c658dc9..3e803f3b6d8b2d4901fad28f77964036dfa73d14 100644 (file)
@@ -2,7 +2,8 @@
 struct Value;
 
 static settings_dir: String = format!("");
-//~^ ERROR `match` is not allowed in a `static`
+//~^ ERROR calls in statics are limited to constant functions
+//~| ERROR calls in statics are limited to constant functions
 
 fn from_string(_: String) -> Value {
     Value
@@ -11,6 +12,7 @@ fn set_editor(_: Value) {}
 
 fn main() {
     let settings_data = from_string(settings_dir);
+    //~^ ERROR cannot move out of static item
     let args: i32 = 0;
 
     match args {
index 48859fb676342db23c3c5c8564d7dcb53e321524..081ccd37861cb29df50ca16402882a0b3c37b8a8 100644 (file)
@@ -1,13 +1,26 @@
-error[E0658]: `match` is not allowed in a `static`
+error[E0507]: cannot move out of static item `settings_dir`
+  --> $DIR/issue-64453.rs:14:37
+   |
+LL |     let settings_data = from_string(settings_dir);
+   |                                     ^^^^^^^^^^^^ move occurs because `settings_dir` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-64453.rs:4:31
+   |
+LL | static settings_dir: String = format!("");
+   |                               ^^^^^^^^^^^
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
   --> $DIR/issue-64453.rs:4:31
    |
 LL | static settings_dir: String = format!("");
    |                               ^^^^^^^^^^^
    |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0015, E0507.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/borrowck/move-in-pattern-mut.rs b/src/test/ui/borrowck/move-in-pattern-mut.rs
new file mode 100644 (file)
index 0000000..175eb3b
--- /dev/null
@@ -0,0 +1,23 @@
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+    V {
+        s: S,
+    }
+}
+fn bar(_: E) {}
+
+fn main() {
+    let s = Some(S);
+    if let Some(mut x) = s {
+        x = S;
+    }
+    foo(s); //~ ERROR use of moved value: `s`
+    let mut e = E::V { s: S };
+    let E::V { s: mut x } = e;
+    x = S;
+    bar(e); //~ ERROR use of moved value: `e`
+}
diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr
new file mode 100644 (file)
index 0000000..3916384
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0382]: use of moved value: `s`
+  --> $DIR/move-in-pattern-mut.rs:18:9
+   |
+LL |     if let Some(mut x) = s {
+   |                 ----- value moved here
+...
+LL |     foo(s);
+   |         ^ value used here after partial move
+   |
+   = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `s.0`
+   |
+LL |     if let Some(ref mut x) = s {
+   |                 ^^^
+
+error[E0382]: use of moved value: `e`
+  --> $DIR/move-in-pattern-mut.rs:22:9
+   |
+LL |     let E::V { s: mut x } = e;
+   |                   ----- value moved here
+LL |     x = S;
+LL |     bar(e);
+   |         ^ value used here after partial move
+   |
+   = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `e.s`
+   |
+LL |     let E::V { s: ref mut x } = e;
+   |                   ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/move-in-pattern.fixed b/src/test/ui/borrowck/move-in-pattern.fixed
new file mode 100644 (file)
index 0000000..f55fdcc
--- /dev/null
@@ -0,0 +1,24 @@
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+    V {
+        s: S,
+    }
+}
+fn bar(_: E) {}
+
+fn main() {
+    let s = Some(S);
+    if let Some(ref x) = s {
+        let _ = x;
+    }
+    foo(s); //~ ERROR use of moved value: `s`
+    let e = E::V { s: S };
+    let E::V { s: ref x } = e;
+    let _ = x;
+    bar(e); //~ ERROR use of moved value: `e`
+}
diff --git a/src/test/ui/borrowck/move-in-pattern.rs b/src/test/ui/borrowck/move-in-pattern.rs
new file mode 100644 (file)
index 0000000..7ad04b9
--- /dev/null
@@ -0,0 +1,24 @@
+// run-rustfix
+// Issue #63988
+#[derive(Debug)]
+struct S;
+fn foo(_: Option<S>) {}
+
+enum E {
+    V {
+        s: S,
+    }
+}
+fn bar(_: E) {}
+
+fn main() {
+    let s = Some(S);
+    if let Some(x) = s {
+        let _ = x;
+    }
+    foo(s); //~ ERROR use of moved value: `s`
+    let e = E::V { s: S };
+    let E::V { s: x } = e;
+    let _ = x;
+    bar(e); //~ ERROR use of moved value: `e`
+}
diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr
new file mode 100644 (file)
index 0000000..c5cb244
--- /dev/null
@@ -0,0 +1,33 @@
+error[E0382]: use of moved value: `s`
+  --> $DIR/move-in-pattern.rs:19:9
+   |
+LL |     if let Some(x) = s {
+   |                 - value moved here
+...
+LL |     foo(s);
+   |         ^ value used here after partial move
+   |
+   = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `s.0`
+   |
+LL |     if let Some(ref x) = s {
+   |                 ^^^
+
+error[E0382]: use of moved value: `e`
+  --> $DIR/move-in-pattern.rs:23:9
+   |
+LL |     let E::V { s: x } = e;
+   |                   - value moved here
+LL |     let _ = x;
+LL |     bar(e);
+   |         ^ value used here after partial move
+   |
+   = note: move occurs because value has type `S`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `e.s`
+   |
+LL |     let E::V { s: ref x } = e;
+   |                   ^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.fixed b/src/test/ui/borrowck/mut-borrow-in-loop-2.fixed
new file mode 100644 (file)
index 0000000..ceeba30
--- /dev/null
@@ -0,0 +1,35 @@
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+    fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+    fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+    fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(&mut *value);
+    }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(&mut *value); //~ ERROR use of moved value: `value`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.rs b/src/test/ui/borrowck/mut-borrow-in-loop-2.rs
new file mode 100644 (file)
index 0000000..d13fb7e
--- /dev/null
@@ -0,0 +1,35 @@
+// run-rustfix
+#![allow(dead_code)]
+
+struct Events<R>(R);
+
+struct Other;
+
+pub trait Trait<T> {
+    fn handle(value: T) -> Self;
+}
+
+// Blanket impl. (If you comment this out, compiler figures out that it
+// is passing an `&mut` to a method that must be expecting an `&mut`,
+// and injects an auto-reborrow.)
+impl<T, U> Trait<U> for T where T: From<U> {
+    fn handle(_: U) -> Self { unimplemented!() }
+}
+
+impl<'a, R> Trait<&'a mut Events<R>> for Other {
+    fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() }
+}
+
+fn this_compiles<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(&mut *value);
+    }
+}
+
+fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+    for _ in 0..3 {
+        Other::handle(value); //~ ERROR use of moved value: `value`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr
new file mode 100644 (file)
index 0000000..fa1b741
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0382]: use of moved value: `value`
+  --> $DIR/mut-borrow-in-loop-2.rs:31:23
+   |
+LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) {
+   |                         ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait
+LL |     for _ in 0..3 {
+LL |         Other::handle(value);
+   |                       ^^^^^ value moved here, in previous iteration of loop
+   |
+help: consider creating a fresh reborrow of `value` here
+   |
+LL |         Other::handle(&mut *value);
+   |                       ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
index c8e3628a7ded89ac6e78e68e0b7cf26bc612ab6b..dab133cfb4b673f06c91352c9dc5cfdba9f72992 100644 (file)
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `u32`
   --> $DIR/cast-from-nil.rs:2:21
    |
 LL | fn main() { let u = (assert!(true) as u32); }
-   |                     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                     ^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
index 84933dca929a4f34637fcd397fa7895edf7c6224..d97b0c5f8aadc736c3fdc1c114e1c3c98b34f814 100644 (file)
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `fn(isize) {foo}` as `extern "C" fn() -> isize
   --> $DIR/cast-to-bare-fn.rs:5:13
    |
 LL |     let x = foo as extern "C" fn() -> isize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
 
 error[E0605]: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)`
   --> $DIR/cast-to-bare-fn.rs:7:13
    |
 LL |     let y = v as extern "Rust" fn(isize) -> (isize, isize);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
 
 error: aborting due to 2 previous errors
 
index 478f6b69dafc8c01161d14455c2a15258a9b86e5..29a9baffd71d7592268a801d2fcfd26d730aa78b 100644 (file)
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `u32` as `()`
   --> $DIR/cast-to-nil.rs:2:21
    |
 LL | fn main() { let u = 0u32 as (); }
-   |                     ^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                     ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
index ffa02533d8b66db7869c917abf13b15225b8c4e8..9b86f8d4def86bd04fcb118e7fcfaeac652f21cf 100644 (file)
@@ -12,7 +12,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::ma
 LL |     Box::new(1) as dyn Send;
    |     ^^^^^^^^^^^^^^^--------
    |                    |
-   |                    help: try casting to a `Box` instead: `Box<dyn Send>`
+   |                    help: you can cast to a `Box` instead: `Box<dyn Send>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/cenum_impl_drop_cast.rs b/src/test/ui/cenum_impl_drop_cast.rs
new file mode 100644 (file)
index 0000000..96e3d96
--- /dev/null
@@ -0,0 +1,18 @@
+#![deny(cenum_impl_drop_cast)]
+
+enum E {
+    A = 0,
+}
+
+impl Drop for E {
+    fn drop(&mut self) {
+        println!("Drop");
+    }
+}
+
+fn main() {
+    let e = E::A;
+    let i = e as u32;
+    //~^ ERROR cannot cast enum `E` into integer `u32` because it implements `Drop`
+    //~| WARN this was previously accepted
+}
diff --git a/src/test/ui/cenum_impl_drop_cast.stderr b/src/test/ui/cenum_impl_drop_cast.stderr
new file mode 100644 (file)
index 0000000..8d847a0
--- /dev/null
@@ -0,0 +1,16 @@
+error: cannot cast enum `E` into integer `u32` because it implements `Drop`
+  --> $DIR/cenum_impl_drop_cast.rs:15:13
+   |
+LL |     let i = e as u32;
+   |             ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/cenum_impl_drop_cast.rs:1:9
+   |
+LL | #![deny(cenum_impl_drop_cast)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = 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 #73333 <https://github.com/rust-lang/rust/issues/73333>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/chalkify/closure.rs b/src/test/ui/chalkify/closure.rs
new file mode 100644 (file)
index 0000000..81114d4
--- /dev/null
@@ -0,0 +1,39 @@
+// check-fail
+// compile-flags: -Z chalk
+
+fn main() -> () {
+    let t = || {};
+    t();
+
+    let mut a = 0;
+    let mut b = move || {
+        a = 1;
+    };
+    b();
+
+    let mut c = b;
+
+    c();
+    b();
+
+    let mut a = 0;
+    let mut b = || {
+        a = 1;
+    };
+    b();
+
+    let mut c = b;
+
+    c();
+    b(); //~ ERROR
+
+    // FIXME(chalk): this doesn't quite work
+    /*
+    let b = |c| {
+        c
+    };
+
+    let a = &32;
+    b(a);
+    */
+}
diff --git a/src/test/ui/chalkify/closure.stderr b/src/test/ui/chalkify/closure.stderr
new file mode 100644 (file)
index 0000000..d5a48a7
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0382]: borrow of moved value: `b`
+  --> $DIR/closure.rs:28:5
+   |
+LL |     let mut c = b;
+   |                 - value moved here
+...
+LL |     b();
+   |     ^ value borrowed here after move
+   |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment
+  --> $DIR/closure.rs:21:9
+   |
+LL |         a = 1;
+   |         ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
index 8aa876422924d3e96ff0a38ec2d0e7633c0ac45d..465eb10241ea20d9e38962bdc3474a094f3b9f84 100644 (file)
@@ -8,12 +8,9 @@ trait Bar {
 
 impl Foo for i32 { }
 
-// FIXME(chalk): blocked on better handling of builtin traits for non-struct
-// application types (or a workaround)
-/*
 impl Foo for str { }
-//^ ERROR the size for values of type `str` cannot be known at compilation time
-*/
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+
 
 // Implicit `T: Sized` bound.
 impl<T> Foo for Option<T> { }
@@ -26,15 +23,10 @@ impl<T> Bar for Option<T> {
     type Item = Option<T>;
 }
 
-// FIXME(chalk): the ordering of these two errors differs between CI and local
-// We need to figure out why its non-deterministic
-/*
 impl Bar for f32 {
-//^ ERROR the trait bound `f32: Foo` is not satisfied
     type Item = f32;
-    //^ ERROR the trait bound `f32: Foo` is not satisfied
+    //~^ ERROR the trait bound `f32: Foo` is not satisfied
 }
-*/
 
 trait Baz<U: ?Sized> where U: Foo { }
 
index befd688741c80ca4e77fe8ed684e1ad7da408c4e..e5d7615e43e31f484912f15afa25d02c2457ab3d 100644 (file)
@@ -1,5 +1,28 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/impl_wf.rs:11:6
+   |
+LL | trait Foo: Sized { }
+   |            ----- required by this bound in `Foo`
+...
+LL | impl Foo for str { }
+   |      ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `str`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+
+error[E0277]: the trait bound `f32: Foo` is not satisfied
+  --> $DIR/impl_wf.rs:27:17
+   |
+LL | trait Bar {
+   |       --- required by a bound in this
+LL |     type Item: Foo;
+   |                --- required by this bound in `Bar`
+...
+LL |     type Item = f32;
+   |                 ^^^ the trait `Foo` is not implemented for `f32`
+
 error[E0277]: the trait bound `f32: Foo` is not satisfied
-  --> $DIR/impl_wf.rs:43:6
+  --> $DIR/impl_wf.rs:35:6
    |
 LL | trait Baz<U: ?Sized> where U: Foo { }
    |                               --- required by this bound in `Baz`
@@ -7,6 +30,6 @@ LL | trait Baz<U: ?Sized> where U: Foo { }
 LL | impl Baz<f32> for f32 { }
    |      ^^^^^^^^ the trait `Foo` is not implemented for `f32`
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 44e120c1eebbaabfd4bd162118ff3943199b5303..a2730219fbe2ac0d1a7b70d386ee758961846aa0 100644 (file)
@@ -37,6 +37,6 @@ fn main() {
         x: 5,
     };
 
-    s.dummy_foo();
     s.dummy_bar::<u32>();
+    s.dummy_foo();
 }
index 6ee13f5e7a104da2aab05de447f6074fd4584ab5..87324a5f79bdd760da0e9c63e6b822764bbcb874 100644 (file)
@@ -1,5 +1,5 @@
 // FIXME(chalk): should fail, see comments
-// check-pass
+// check-fail
 // compile-flags: -Z chalk
 
 #![feature(trivial_bounds)]
@@ -10,7 +10,6 @@ trait Bar {
 trait Foo: Bar { }
 
 struct S where S: Foo;
-//~^ WARN Trait bound S: Foo does not depend on any type or lifetime parameters
 
 impl Foo for S {
 }
@@ -26,10 +25,6 @@ fn foo<T: Foo>() {
 fn main() {
     // For some reason, the error is duplicated...
 
-    // FIXME(chalk): this order of this duplicate error seems non-determistic
-    // and causes test to fail
-    /*
-    foo::<S>() // ERROR the type `S` is not well-formed (chalk)
-    //^ ERROR the type `S` is not well-formed (chalk)
-    */
+    foo::<S>() //~ ERROR the type `S` is not well-formed (chalk)
+    //~^ ERROR the type `S` is not well-formed (chalk)
 }
index a5b7ef7fdb2e37b920130c2a875577f2d6a6375c..fddd58959278efb72c4129873cf78306a4e9f911 100644 (file)
@@ -1,10 +1,14 @@
-warning: Trait bound S: Foo does not depend on any type or lifetime parameters
-  --> $DIR/recursive_where_clause_on_type.rs:12:19
+error: the type `S` is not well-formed (chalk)
+  --> $DIR/recursive_where_clause_on_type.rs:28:11
    |
-LL | struct S where S: Foo;
-   |                   ^^^
+LL |     foo::<S>()
+   |           ^
+
+error: the type `S` is not well-formed (chalk)
+  --> $DIR/recursive_where_clause_on_type.rs:28:5
    |
-   = note: `#[warn(trivial_bounds)]` on by default
+LL |     foo::<S>()
+   |     ^^^^^^^^
 
-warning: 1 warning emitted
+error: aborting due to 2 previous errors
 
index 5175c5d062a6e37ffb5e4a0f790da6d5fefd997c..2b62bf18a71ce5ff25da288026142194b82e0413 100644 (file)
@@ -18,11 +18,11 @@ fn main() {
     // is expecting a variable of type `i32`. This behavior differs from the
     // old-style trait solver. I guess this will change, that's why I'm
     // adding that test.
-    // FIXME(chalk): partially blocked on float/int special casing
-    only_foo(x); //~ ERROR the trait bound `f64: Foo` is not satisfied
+    // FIXME(chalk): order of these two errors is non-deterministic,
+    // so let's just hide one for now
+    //only_foo(x); // ERROR the trait bound `f64: Foo` is not satisfied
 
     // Here we have two solutions so we get back the behavior of the old-style
     // trait solver.
-    // FIXME(chalk): blocked on float/int special casing
-    //only_bar(x); // ERROR the trait bound `{float}: Bar` is not satisfied
+    only_bar(x); //~ ERROR the trait bound `f64: Bar` is not satisfied
 }
index ee9e67c6c78849d43095e8efa28ceffeae4ef7d2..5cfb968404df6774a156129b07bcbd0a9d73f952 100644 (file)
@@ -1,11 +1,11 @@
-error[E0277]: the trait bound `f64: Foo` is not satisfied
-  --> $DIR/type_inference.rs:22:5
+error[E0277]: the trait bound `f64: Bar` is not satisfied
+  --> $DIR/type_inference.rs:27:5
    |
-LL | fn only_foo<T: Foo>(_x: T) { }
-   |                --- required by this bound in `only_foo`
+LL | fn only_bar<T: Bar>(_x: T) { }
+   |                --- required by this bound in `only_bar`
 ...
-LL |     only_foo(x);
-   |     ^^^^^^^^ the trait `Foo` is not implemented for `f64`
+LL |     only_bar(x);
+   |     ^^^^^^^^ the trait `Bar` is not implemented for `f64`
 
 error: aborting due to previous error
 
index 396baf814a0b040c5379657fc9671890bf69e4fe..7c469d99c5799c609663ced303e37367e53acfa5 100644 (file)
@@ -1,5 +1,4 @@
-// FIXME(chalk): should have an error, see below
-// check-pass
+// check-fail
 // compile-flags: -Z chalk
 
 trait Foo { }
@@ -16,17 +15,11 @@ fn main() {
        x: 5,
     };
 
-    // FIXME(chalk): blocked on float/int special handling. Needs to know that {float}: !i32
-    /*
-    let s = S { // ERROR the trait bound `{float}: Foo` is not satisfied
+    let s = S { //~ ERROR the trait bound `f64: Foo` is not satisfied
         x: 5.0,
     };
-    */
 
-    // FIXME(chalk): blocked on float/int special handling. Needs to know that {float}: Sized
-    /*
     let s = S {
         x: Some(5.0),
     };
-    */
 }
diff --git a/src/test/ui/chalkify/type_wf.stderr b/src/test/ui/chalkify/type_wf.stderr
new file mode 100644 (file)
index 0000000..ab585a6
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `f64: Foo` is not satisfied
+  --> $DIR/type_wf.rs:18:13
+   |
+LL | struct S<T: Foo> {
+   | ---------------- required by `S`
+...
+LL |     let s = S {
+   |             ^ the trait `Foo` is not implemented for `f64`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index d5e9fb2dede9341255f38bccce90bd67db27475b..3be02f6a0f674cedc3fcca37b8a18647ec439230 100644 (file)
@@ -1,6 +1,6 @@
 // Checks that immutable static items can't have mutable slices
 
 static TEST: &'static mut [isize] = &mut [];
-//~^ ERROR references in statics may only refer to immutable values
+//~^ ERROR mutable references are not allowed in statics
 
 pub fn main() { }
index 66fe8646e1016c53f621c3f490f7a94bd0d02bdd..9ffbb483d139d2e9bd7845e576b76bc105f013ae 100644 (file)
@@ -1,12 +1,9 @@
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/check-static-immutable-mut-slices.rs:3:37
    |
 LL | static TEST: &'static mut [isize] = &mut [];
-   |                                     ^^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                     ^^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0764`.
index 6b5a739899cacb12885d1cdafb9f73e0db23eed6..b00affdca850ae1d0c7b83b392cfe4a75da94c96 100644 (file)
@@ -5,7 +5,9 @@ LL |                                           ..SafeStruct{field1: SafeEnum::Va
    |  ___________________________________________^
 LL | |
 LL | |                                                      field2: SafeEnum::Variant1}};
-   | |________________________________________________________________________________^ statics cannot evaluate destructors
+   | |                                                                                ^- value is dropped here
+   | |________________________________________________________________________________|
+   |                                                                                  statics cannot evaluate destructors
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-static-values-constraints.rs:79:33
index 97fdb76dd11c77b1f6cdf9eeb4015761c3c58360..64a0b52a1fac5c9090717ce98a7f53268e30cf94 100644 (file)
@@ -1,42 +1,43 @@
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:30:5
+error: lifetime may not live long enough
+  --> $DIR/expect-fn-supply-fn.rs:16:49
    |
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
-   |    ------------------------------------------ required by a bound in this
-LL |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
-   |                      ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+   |                                    -- lifetime `'x` defined here
 ...
-LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+   |                                                 ^
+   |                                                 |
+   |                                                 has type `fn(&'1 u32)`
+   |                                                 requires that `'1` must outlive `'x`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:37:5
+error: lifetime may not live long enough
+  --> $DIR/expect-fn-supply-fn.rs:16:49
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+   |                                    -- lifetime `'x` defined here
 ...
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+   |                                                 ^ requires that `'x` must outlive `'static`
+   |
+   = help: consider replacing `'x` with `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:32:49
+   |
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
+   |                                                 ^
+
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:39:50
+   |
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                  ^
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:46:5
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:48:50
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                  ^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0631`.
index a4e43da91baf8d805275a5913d807202a9014c40..c81c40c18b45b2f4f8ac9322a50a55536de567a8 100644 (file)
@@ -1,10 +1,12 @@
 fn with_closure_expecting_fn_with_free_region<F>(_: F)
-    where F: for<'a> FnOnce(fn(&'a u32), &i32)
+where
+    F: for<'a> FnOnce(fn(&'a u32), &i32),
 {
 }
 
 fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-    where F: FnOnce(fn(&u32), &i32)
+where
+    F: FnOnce(fn(&u32), &i32),
 {
 }
 
@@ -28,14 +30,14 @@ fn expect_free_supply_bound() {
     // Here, we are given a function whose region is bound at closure level,
     // but we expect one bound in the argument. Error results.
     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-    //~^ ERROR type mismatch
+    //~^ ERROR mismatched types
 }
 
 fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
     // Here, we are given a `fn(&u32)` but we expect a `fn(&'x
     // u32)`. In principle, this could be ok, but we demand equality.
     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-    //~^ ERROR type mismatch
+    //~^ ERROR mismatched types
 }
 
 fn expect_bound_supply_free_from_closure() {
@@ -44,7 +46,7 @@ fn expect_bound_supply_free_from_closure() {
     // the argument level.
     type Foo<'a> = fn(&'a u32);
     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-    //~^ ERROR type mismatch
+        //~^ ERROR mismatched types
     });
 }
 
@@ -52,8 +54,7 @@ fn expect_bound_supply_bound<'x>(x: &'x u32) {
     // No error in this case. The supplied type supplies the bound
     // regions, and hence we are able to figure out the type of `y`
     // from the expected type
-    with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {
-    });
+    with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {});
 }
 
-fn main() { }
+fn main() {}
index fae41c4114abc49621895e30b76b73d935008ea4..0de15dfa7357d349a99dcc340cc9db6c8548e1e4 100644 (file)
@@ -1,81 +1,68 @@
 error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:14:52
+  --> $DIR/expect-fn-supply-fn.rs:16:52
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                    ^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected fn pointer `fn(&u32)`
               found fn pointer `fn(&'x u32)`
-note: the anonymous lifetime #2 defined on the body at 14:48...
-  --> $DIR/expect-fn-supply-fn.rs:14:48
+note: the anonymous lifetime #2 defined on the body at 16:48...
+  --> $DIR/expect-fn-supply-fn.rs:16:48
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 11:36
-  --> $DIR/expect-fn-supply-fn.rs:11:36
+note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 13:36
+  --> $DIR/expect-fn-supply-fn.rs:13:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
    |                                    ^^
 
 error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:14:52
+  --> $DIR/expect-fn-supply-fn.rs:16:52
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                    ^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected fn pointer `fn(&u32)`
               found fn pointer `fn(&'x u32)`
-note: the lifetime `'x` as defined on the function body at 11:36...
-  --> $DIR/expect-fn-supply-fn.rs:11:36
+note: the lifetime `'x` as defined on the function body at 13:36...
+  --> $DIR/expect-fn-supply-fn.rs:13:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
    |                                    ^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:48
-  --> $DIR/expect-fn-supply-fn.rs:14:48
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 16:48
+  --> $DIR/expect-fn-supply-fn.rs:16:48
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:30:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:32:52
    |
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
-   |    ------------------------------------------ required by a bound in this
-LL |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
-   |                      ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
-...
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
+   |                                                    ^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `fn(&u32)`
+              found fn pointer `for<'r> fn(&'r u32)`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:37:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:39:53
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                     ^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&'x u32)`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:46:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:48:53
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                     ^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&u32)`
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0308, E0631.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
index 2005bd4dd5ca7e7d67e4535238f9409c49d70ee7..0c6d11cd3211d836dc09577f9cafd085225cefb1 100644 (file)
@@ -1,8 +1,8 @@
 error[E0282]: type annotations needed
-  --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27
+  --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:5
    |
 LL |     with_closure(|x: u32, y| {});
-   |                           ^ consider giving this closure parameter a type
+   |     ^^^^^^^^^^^^ cannot infer type for type parameter `B` declared on the function `with_closure`
 
 error: aborting due to previous error
 
index ab6056b65473edd8241d651f6998f010a3ab697d..4b3b4be798fc1e541a2f7b98df22ef6c737b8db3 100644 (file)
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b
   --> $DIR/closure-no-fn-3.rs:6:27
    |
 LL |     let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
 
 error: aborting due to previous error
 
index 5cae0e76d1acbcfa263754ace0d2fc65729b411e..af1e37ba867dee0327622dc1aec9f4c891e7d462 100644 (file)
@@ -7,7 +7,6 @@ impl<'g> T<'g> for u32 {
 }
 
 fn main() {
-    (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+    (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
     //~^ ERROR: type mismatch in closure arguments
-    //~| ERROR: type mismatch resolving
 }
index 2f2871e9f0e90c89e1cfe7a6cbad4d9e544b278f..9c4b7d529ef4dff52555b5edd6b045cda1ae6f00 100644 (file)
@@ -1,23 +1,14 @@
 error[E0631]: type mismatch in closure arguments
   --> $DIR/issue-41366.rs:10:5
    |
-LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
-   |     ^^-----^
+LL |     (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+   |     ^^------^
    |     | |
-   |     | found signature of `fn(_) -> _`
-   |     expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
+   |     | found signature of `fn(u16) -> _`
+   |     expected signature of `fn(<u32 as T<'x>>::V) -> _`
    |
    = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
 
-error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(<u32 as T<'x>>::V,)>>::Output == ()`
-  --> $DIR/issue-41366.rs:10:5
-   |
-LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
-   |     ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
-   |
-   = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
index 634638e1335b327576797cf90a7a99f672d203f6..f79a0bd35486aa388eb91d188bc60cb23dc405f2 100644 (file)
@@ -1,7 +1,6 @@
 fn main() {
     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
     //~^ ERROR: invalid label name `'static`
-    //~| ERROR: `loop` is not allowed in a `const`
     //~| ERROR: type annotations needed
     //~| ERROR mismatched types
 }
index acb59c7b02d1b584c0da3fa2acfed9e95913c3ea..54825cb746d4298cdeacabcc5ec9de61afca6ee8 100644 (file)
@@ -4,15 +4,6 @@ error: invalid label name `'static`
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |             ^^^^^^^
 
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/issue-52437.rs:2:13
-   |
-LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
 error[E0282]: type annotations needed
   --> $DIR/issue-52437.rs:2:30
    |
@@ -27,7 +18,7 @@ LL | fn main() {
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[(); _]`
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0282, E0308, E0658.
+Some errors have detailed explanations: E0282, E0308.
 For more information about an error, try `rustc --explain E0282`.
index 70414bbd953d6447beb3ab308fde4dcd6eef9ef5..0bfdc3ac2651dbccfbe77b8ff007c3b7f82c206f 100644 (file)
@@ -1,4 +1,4 @@
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
   --> $DIR/tab_2.rs:4:7
    |
 LL |                   """;
@@ -8,3 +8,4 @@ LL | | }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0765`.
diff --git a/src/test/ui/coerce/coerce-expect-unsized.rs b/src/test/ui/coerce/coerce-expect-unsized.rs
deleted file mode 100644 (file)
index d486fdf..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// run-pass
-#![allow(unused_braces)]
-#![feature(box_syntax)]
-
-use std::cell::RefCell;
-use std::fmt::Debug;
-use std::rc::Rc;
-
-// Check that coercions apply at the pointer level and don't cause
-// rvalue expressions to be unsized. See #20169 for more information.
-
-pub fn main() {
-    let _: Box<[isize]> = Box::new({ [1, 2, 3] });
-    let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] });
-    let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] });
-    let _: Box<dyn Fn(isize) -> _> = Box::new({ |x| (x as u8) });
-    let _: Box<dyn Debug> = Box::new(if true { false } else { true });
-    let _: Box<dyn Debug> = Box::new(match true { true => 'a', false => 'b' });
-
-    let _: &[isize] = &{ [1, 2, 3] };
-    let _: &[isize] = &if true { [1, 2, 3] } else { [1, 3, 4] };
-    let _: &[isize] = &match true { true => [1, 2, 3], false => [1, 3, 4] };
-    let _: &dyn Fn(isize) -> _ = &{ |x| (x as u8) };
-    let _: &dyn Debug = &if true { false } else { true };
-    let _: &dyn Debug = &match true { true => 'a', false => 'b' };
-
-    let _: &str = &{ String::new() };
-    let _: &str = &if true { String::from("...") } else { 5.to_string() };
-    let _: &str = &match true {
-        true => format!("{}", false),
-        false => ["x", "y"].join("+")
-    };
-
-    let _: Box<[isize]> = Box::new([1, 2, 3]);
-    let _: Box<dyn Fn(isize) -> _> = Box::new(|x| (x as u8));
-
-    let _: Rc<RefCell<[isize]>> = Rc::new(RefCell::new([1, 2, 3]));
-    let _: Rc<RefCell<dyn FnMut(isize) -> _>> = Rc::new(RefCell::new(|x| (x as u8)));
-
-    let _: Vec<Box<dyn Fn(isize) -> _>> = vec![
-        Box::new(|x| (x as u8)),
-        Box::new(|x| (x as i16 as u8)),
-    ];
-}
diff --git a/src/test/ui/coerce/coerce-overloaded-autoderef.rs b/src/test/ui/coerce/coerce-overloaded-autoderef.rs
deleted file mode 100644 (file)
index d548460..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// run-pass
-#![allow(unused_braces)]
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-use std::rc::Rc;
-
-// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
-
-fn use_ref<T>(_: &T) {}
-fn use_mut<T>(_: &mut T) {}
-
-fn use_rc<T>(t: Rc<T>) {
-    use_ref(&*t);  // what you have to write today
-    use_ref(&t);   // what you'd be able to write
-    use_ref(&&&&&&t);
-    use_ref(&mut &&&&&t);
-    use_ref(&&&mut &&&t);
-}
-
-fn use_mut_box<T>(mut t: &mut Box<T>) {
-    use_mut(&mut *t); // what you have to write today
-    use_mut(t);       // what you'd be able to write
-    use_mut(&mut &mut &mut t);
-
-    use_ref(&*t);      // what you have to write today
-    use_ref(t);        // what you'd be able to write
-    use_ref(&&&&&&t);
-    use_ref(&mut &&&&&t);
-    use_ref(&&&mut &&&t);
-}
-
-fn use_nested<T>(t: &Box<T>) {
-    use_ref(&**t);  // what you have to write today
-    use_ref(t);     // what you'd be able to write (note: recursive deref)
-    use_ref(&&&&&&t);
-    use_ref(&mut &&&&&t);
-    use_ref(&&&mut &&&t);
-}
-
-fn use_slice(_: &[u8]) {}
-fn use_slice_mut(_: &mut [u8]) {}
-
-fn use_vec(mut v: Vec<u8>) {
-    use_slice_mut(&mut v[..]); // what you have to write today
-    use_slice_mut(&mut v);     // what you'd be able to write
-    use_slice_mut(&mut &mut &mut v);
-
-    use_slice(&v[..]);  // what you have to write today
-    use_slice(&v);      // what you'd be able to write
-    use_slice(&&&&&&v);
-    use_slice(&mut &&&&&v);
-    use_slice(&&&mut &&&v);
-}
-
-fn use_vec_ref(v: &Vec<u8>) {
-    use_slice(&v[..]);  // what you have to write today
-    use_slice(v);       // what you'd be able to write
-    use_slice(&&&&&&v);
-    use_slice(&mut &&&&&v);
-    use_slice(&&&mut &&&v);
-}
-
-fn use_op_rhs(s: &mut String) {
-    *s += {&String::from(" ")};
-}
-
-pub fn main() {}
diff --git a/src/test/ui/coerce/coerce-reborrow-imm-ptr-arg.rs b/src/test/ui/coerce/coerce-reborrow-imm-ptr-arg.rs
deleted file mode 100644 (file)
index f033e1b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-fn negate(x: &isize) -> isize {
-    -*x
-}
-
-fn negate_mut(y: &mut isize) -> isize {
-    negate(y)
-}
-
-fn negate_imm(y: &isize) -> isize {
-    negate(y)
-}
-
-pub fn main() {}
diff --git a/src/test/ui/coerce/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/ui/coerce/coerce-reborrow-imm-ptr-rcvr.rs
deleted file mode 100644 (file)
index 64a3652..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// run-pass
-
-struct SpeechMaker {
-    speeches: usize
-}
-
-impl SpeechMaker {
-    pub fn how_many(&self) -> usize { self.speeches }
-}
-
-fn foo(speaker: &SpeechMaker) -> usize {
-    speaker.how_many() + 33
-}
-
-pub fn main() {
-    let lincoln = SpeechMaker {speeches: 22};
-    assert_eq!(foo(&lincoln), 55);
-}
diff --git a/src/test/ui/coerce/coerce-reborrow-imm-vec-arg.rs b/src/test/ui/coerce/coerce-reborrow-imm-vec-arg.rs
deleted file mode 100644 (file)
index c2aaae1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-fn sum(x: &[isize]) -> isize {
-    let mut sum = 0;
-    for y in x { sum += *y; }
-    return sum;
-}
-
-fn sum_mut(y: &mut [isize]) -> isize {
-    sum(y)
-}
-
-fn sum_imm(y: &[isize]) -> isize {
-    sum(y)
-}
-
-pub fn main() {}
diff --git a/src/test/ui/coerce/coerce-reborrow-imm-vec-rcvr.rs b/src/test/ui/coerce/coerce-reborrow-imm-vec-rcvr.rs
deleted file mode 100644 (file)
index 9a5652a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// run-pass
-
-
-fn bar(v: &mut [usize]) -> Vec<usize> {
-    v.to_vec()
-}
-
-fn bip(v: &[usize]) -> Vec<usize> {
-    v.to_vec()
-}
-
-pub fn main() {
-    let mut the_vec = vec![1, 2, 3, 100];
-    assert_eq!(the_vec.clone(), bar(&mut the_vec));
-    assert_eq!(the_vec.clone(), bip(&the_vec));
-}
diff --git a/src/test/ui/coerce/coerce-reborrow-mut-ptr-arg.rs b/src/test/ui/coerce/coerce-reborrow-mut-ptr-arg.rs
deleted file mode 100644 (file)
index 76cd679..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// run-pass
-// pretty-expanded FIXME #23616
-
-struct SpeechMaker {
-    speeches: usize
-}
-
-fn talk(x: &mut SpeechMaker) {
-    x.speeches += 1;
-}
-
-fn give_a_few_speeches(speaker: &mut SpeechMaker) {
-
-    // Here speaker is reborrowed for each call, so we don't get errors
-    // about speaker being moved.
-
-    talk(speaker);
-    talk(speaker);
-    talk(speaker);
-}
-
-pub fn main() {
-    let mut lincoln = SpeechMaker {speeches: 22};
-    give_a_few_speeches(&mut lincoln);
-}
diff --git a/src/test/ui/coerce/coerce-reborrow-mut-ptr-rcvr.rs b/src/test/ui/coerce/coerce-reborrow-mut-ptr-rcvr.rs
deleted file mode 100644 (file)
index e6e7c3a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-pass
-// pretty-expanded FIXME #23616
-
-struct SpeechMaker {
-    speeches: usize
-}
-
-impl SpeechMaker {
-    pub fn talk(&mut self) {
-        self.speeches += 1;
-    }
-}
-
-fn give_a_few_speeches(speaker: &mut SpeechMaker) {
-
-    // Here speaker is reborrowed for each call, so we don't get errors
-    // about speaker being moved.
-
-    speaker.talk();
-    speaker.talk();
-    speaker.talk();
-}
-
-pub fn main() {
-    let mut lincoln = SpeechMaker {speeches: 22};
-    give_a_few_speeches(&mut lincoln);
-}
diff --git a/src/test/ui/coerce/coerce-reborrow-mut-vec-arg.rs b/src/test/ui/coerce/coerce-reborrow-mut-vec-arg.rs
deleted file mode 100644 (file)
index 2635754..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// run-pass
-
-
-fn reverse(v: &mut [usize]) {
-    v.reverse();
-}
-
-fn bar(v: &mut [usize]) {
-    reverse(v);
-    reverse(v);
-    reverse(v);
-}
-
-pub fn main() {
-    let mut the_vec = vec![1, 2, 3, 100];
-    bar(&mut the_vec);
-    assert_eq!(the_vec, [100, 3, 2, 1]);
-}
diff --git a/src/test/ui/coerce/coerce-reborrow-mut-vec-rcvr.rs b/src/test/ui/coerce/coerce-reborrow-mut-vec-rcvr.rs
deleted file mode 100644 (file)
index c03336e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// run-pass
-
-
-fn bar(v: &mut [usize]) {
-    v.reverse();
-    v.reverse();
-    v.reverse();
-}
-
-pub fn main() {
-    let mut the_vec = vec![1, 2, 3, 100];
-    bar(&mut the_vec);
-    assert_eq!(the_vec, [100, 3, 2, 1]);
-}
diff --git a/src/test/ui/coerce/coerce-unify-return.rs b/src/test/ui/coerce/coerce-unify-return.rs
deleted file mode 100644 (file)
index 95a7ee8..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-pass
-// Check that coercions unify the expected return type of a polymorphic
-// function call, instead of leaving the type variables as they were.
-
-// pretty-expanded FIXME #23616
-
-struct Foo;
-impl Foo {
-    fn foo<T>(self, x: T) -> Option<T> { Some(x) }
-}
-
-pub fn main() {
-    let _: Option<fn()> = Some(main);
-    let _: Option<fn()> = Foo.foo(main);
-
-    // The same two cases, with implicit type variables made explicit.
-    let _: Option<fn()> = Some::<_>(main);
-    let _: Option<fn()> = Foo.foo::<_>(main);
-}
diff --git a/src/test/ui/coerce/coerce-unify.rs b/src/test/ui/coerce/coerce-unify.rs
deleted file mode 100644 (file)
index f1818f9..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// run-pass
-// Check that coercions can unify if-else, match arms and array elements.
-
-// Try to construct if-else chains, matches and arrays out of given expressions.
-macro_rules! check {
-    ($last:expr $(, $rest:expr)+) => {
-        // Last expression comes first because of whacky ifs and matches.
-        let _ = $(if false { $rest })else+ else { $last };
-
-        let _ = match 0 { $(_ if false => $rest,)+ _ => $last };
-
-        let _ = [$($rest,)+ $last];
-    }
-}
-
-// Check all non-uniform cases of 2 and 3 expressions of 2 types.
-macro_rules! check2 {
-    ($a:expr, $b:expr) => {
-        check!($a, $b);
-        check!($b, $a);
-
-        check!($a, $a, $b);
-        check!($a, $b, $a);
-        check!($a, $b, $b);
-
-        check!($b, $a, $a);
-        check!($b, $a, $b);
-        check!($b, $b, $a);
-    }
-}
-
-// Check all non-uniform cases of 2 and 3 expressions of 3 types.
-macro_rules! check3 {
-    ($a:expr, $b:expr, $c:expr) => {
-        // Delegate to check2 for cases where a type repeats.
-        check2!($a, $b);
-        check2!($b, $c);
-        check2!($a, $c);
-
-        // Check the remaining cases, i.e., permutations of ($a, $b, $c).
-        check!($a, $b, $c);
-        check!($a, $c, $b);
-        check!($b, $a, $c);
-        check!($b, $c, $a);
-        check!($c, $a, $b);
-        check!($c, $b, $a);
-    }
-}
-
-use std::mem::size_of;
-
-fn foo() {}
-fn bar() {}
-
-pub fn main() {
-    check3!(foo, bar, foo as fn());
-    check3!(size_of::<u8>, size_of::<u16>, size_of::<usize> as fn() -> usize);
-
-    let s = String::from("bar");
-    check2!("foo", &s);
-
-    let a = [1, 2, 3];
-    let v = vec![1, 2, 3];
-    check2!(&a[..], &v);
-
-    // Make sure in-array coercion still works.
-    let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)];
-}
diff --git a/src/test/ui/coerce/coerce-unsize-subtype.rs b/src/test/ui/coerce/coerce-unsize-subtype.rs
deleted file mode 100644 (file)
index 45b5330..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-// pretty-expanded FIXME #23616
-
-use std::rc::Rc;
-
-fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
-
-// The two arguments are a subtype of their LUB, after coercion.
-fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
-    lub_short(xs, ys);
-}
-
-// The argument coerces to a subtype of the return type.
-fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
-    xs
-}
-
-// Rc<T> is covariant over T just like &T.
-fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
-    xs
-}
-
-// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
-// to a subtype of the LUB of `xs` and `ys` (i.e., `&'b [&'a T]`),
-// regardless of the order they appear (in if-else/match/array).
-fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
-    let _order1 = [xs, ys];
-    let _order2 = [ys, xs];
-}
-
-// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
-// needs to be coerced, i.e., the resulting type is not &'b [&'static T], but
-// rather the `&'b [&'a T]` LUB.
-fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
-    let _order1 = [xs, ys];
-    let _order2 = [ys, xs];
-}
-
-fn main() {}
diff --git a/src/test/ui/coercion/coerce-expect-unsized.rs b/src/test/ui/coercion/coerce-expect-unsized.rs
new file mode 100644 (file)
index 0000000..d486fdf
--- /dev/null
@@ -0,0 +1,44 @@
+// run-pass
+#![allow(unused_braces)]
+#![feature(box_syntax)]
+
+use std::cell::RefCell;
+use std::fmt::Debug;
+use std::rc::Rc;
+
+// Check that coercions apply at the pointer level and don't cause
+// rvalue expressions to be unsized. See #20169 for more information.
+
+pub fn main() {
+    let _: Box<[isize]> = Box::new({ [1, 2, 3] });
+    let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] });
+    let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] });
+    let _: Box<dyn Fn(isize) -> _> = Box::new({ |x| (x as u8) });
+    let _: Box<dyn Debug> = Box::new(if true { false } else { true });
+    let _: Box<dyn Debug> = Box::new(match true { true => 'a', false => 'b' });
+
+    let _: &[isize] = &{ [1, 2, 3] };
+    let _: &[isize] = &if true { [1, 2, 3] } else { [1, 3, 4] };
+    let _: &[isize] = &match true { true => [1, 2, 3], false => [1, 3, 4] };
+    let _: &dyn Fn(isize) -> _ = &{ |x| (x as u8) };
+    let _: &dyn Debug = &if true { false } else { true };
+    let _: &dyn Debug = &match true { true => 'a', false => 'b' };
+
+    let _: &str = &{ String::new() };
+    let _: &str = &if true { String::from("...") } else { 5.to_string() };
+    let _: &str = &match true {
+        true => format!("{}", false),
+        false => ["x", "y"].join("+")
+    };
+
+    let _: Box<[isize]> = Box::new([1, 2, 3]);
+    let _: Box<dyn Fn(isize) -> _> = Box::new(|x| (x as u8));
+
+    let _: Rc<RefCell<[isize]>> = Rc::new(RefCell::new([1, 2, 3]));
+    let _: Rc<RefCell<dyn FnMut(isize) -> _>> = Rc::new(RefCell::new(|x| (x as u8)));
+
+    let _: Vec<Box<dyn Fn(isize) -> _>> = vec![
+        Box::new(|x| (x as u8)),
+        Box::new(|x| (x as i16 as u8)),
+    ];
+}
diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs
new file mode 100644 (file)
index 0000000..01d9c1e
--- /dev/null
@@ -0,0 +1,32 @@
+fn borrow_mut<T>(x: &mut T) -> &mut T { x }
+fn borrow<T>(x: &T) -> &T { x }
+
+fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
+fn borrow2<T>(_: &mut T, _: &T) {}
+
+fn double_mut_borrow<T>(x: &mut Box<T>) {
+    let y = borrow_mut(x);
+    let z = borrow_mut(x);
+    //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+    drop((y, z));
+}
+
+fn double_imm_borrow(x: &mut Box<i32>) {
+    let y = borrow(x);
+    let z = borrow(x);
+    **x += 1;
+    //~^ ERROR cannot assign to `**x` because it is borrowed
+    drop((y, z));
+}
+
+fn double_mut_borrow2<T>(x: &mut Box<T>) {
+    borrow_mut2(x, x);
+    //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+}
+
+fn double_borrow2<T>(x: &mut Box<T>) {
+    borrow2(x, x);
+    //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable
+}
+
+pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr
new file mode 100644 (file)
index 0000000..d067c3b
--- /dev/null
@@ -0,0 +1,46 @@
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+  --> $DIR/coerce-overloaded-autoderef-fail.rs:9:24
+   |
+LL |     let y = borrow_mut(x);
+   |                        - first mutable borrow occurs here
+LL |     let z = borrow_mut(x);
+   |                        ^ second mutable borrow occurs here
+LL |
+LL |     drop((y, z));
+   |           - first borrow later used here
+
+error[E0506]: cannot assign to `**x` because it is borrowed
+  --> $DIR/coerce-overloaded-autoderef-fail.rs:17:5
+   |
+LL |     let y = borrow(x);
+   |                    - borrow of `**x` occurs here
+LL |     let z = borrow(x);
+LL |     **x += 1;
+   |     ^^^^^^^^ assignment to borrowed `**x` occurs here
+LL |
+LL |     drop((y, z));
+   |           - borrow later used here
+
+error[E0499]: cannot borrow `*x` as mutable more than once at a time
+  --> $DIR/coerce-overloaded-autoderef-fail.rs:23:20
+   |
+LL |     borrow_mut2(x, x);
+   |     ----------- -  ^ second mutable borrow occurs here
+   |     |           |
+   |     |           first mutable borrow occurs here
+   |     first borrow later used by call
+
+error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
+  --> $DIR/coerce-overloaded-autoderef-fail.rs:28:5
+   |
+LL |     borrow2(x, x);
+   |     -------^^^^-^
+   |     |          |
+   |     |          immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     immutable borrow later used by call
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0506.
+For more information about an error, try `rustc --explain E0499`.
index 01d9c1e486a4225e3358bb51f4fd1a4b1362561d..d5484607c8b52021ab31d7b36e7a7b688d904543 100644 (file)
@@ -1,32 +1,68 @@
-fn borrow_mut<T>(x: &mut T) -> &mut T { x }
-fn borrow<T>(x: &T) -> &T { x }
+// run-pass
+#![allow(unused_braces)]
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
 
-fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
-fn borrow2<T>(_: &mut T, _: &T) {}
+use std::rc::Rc;
 
-fn double_mut_borrow<T>(x: &mut Box<T>) {
-    let y = borrow_mut(x);
-    let z = borrow_mut(x);
-    //~^ ERROR cannot borrow `*x` as mutable more than once at a time
-    drop((y, z));
+// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
+
+fn use_ref<T>(_: &T) {}
+fn use_mut<T>(_: &mut T) {}
+
+fn use_rc<T>(t: Rc<T>) {
+    use_ref(&*t);  // what you have to write today
+    use_ref(&t);   // what you'd be able to write
+    use_ref(&&&&&&t);
+    use_ref(&mut &&&&&t);
+    use_ref(&&&mut &&&t);
+}
+
+fn use_mut_box<T>(mut t: &mut Box<T>) {
+    use_mut(&mut *t); // what you have to write today
+    use_mut(t);       // what you'd be able to write
+    use_mut(&mut &mut &mut t);
+
+    use_ref(&*t);      // what you have to write today
+    use_ref(t);        // what you'd be able to write
+    use_ref(&&&&&&t);
+    use_ref(&mut &&&&&t);
+    use_ref(&&&mut &&&t);
 }
 
-fn double_imm_borrow(x: &mut Box<i32>) {
-    let y = borrow(x);
-    let z = borrow(x);
-    **x += 1;
-    //~^ ERROR cannot assign to `**x` because it is borrowed
-    drop((y, z));
+fn use_nested<T>(t: &Box<T>) {
+    use_ref(&**t);  // what you have to write today
+    use_ref(t);     // what you'd be able to write (note: recursive deref)
+    use_ref(&&&&&&t);
+    use_ref(&mut &&&&&t);
+    use_ref(&&&mut &&&t);
+}
+
+fn use_slice(_: &[u8]) {}
+fn use_slice_mut(_: &mut [u8]) {}
+
+fn use_vec(mut v: Vec<u8>) {
+    use_slice_mut(&mut v[..]); // what you have to write today
+    use_slice_mut(&mut v);     // what you'd be able to write
+    use_slice_mut(&mut &mut &mut v);
+
+    use_slice(&v[..]);  // what you have to write today
+    use_slice(&v);      // what you'd be able to write
+    use_slice(&&&&&&v);
+    use_slice(&mut &&&&&v);
+    use_slice(&&&mut &&&v);
 }
 
-fn double_mut_borrow2<T>(x: &mut Box<T>) {
-    borrow_mut2(x, x);
-    //~^ ERROR cannot borrow `*x` as mutable more than once at a time
+fn use_vec_ref(v: &Vec<u8>) {
+    use_slice(&v[..]);  // what you have to write today
+    use_slice(v);       // what you'd be able to write
+    use_slice(&&&&&&v);
+    use_slice(&mut &&&&&v);
+    use_slice(&&&mut &&&v);
 }
 
-fn double_borrow2<T>(x: &mut Box<T>) {
-    borrow2(x, x);
-    //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable
+fn use_op_rhs(s: &mut String) {
+    *s += {&String::from(" ")};
 }
 
 pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef.stderr
deleted file mode 100644 (file)
index 7cdfcb5..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-error[E0499]: cannot borrow `*x` as mutable more than once at a time
-  --> $DIR/coerce-overloaded-autoderef.rs:9:24
-   |
-LL |     let y = borrow_mut(x);
-   |                        - first mutable borrow occurs here
-LL |     let z = borrow_mut(x);
-   |                        ^ second mutable borrow occurs here
-LL |
-LL |     drop((y, z));
-   |           - first borrow later used here
-
-error[E0506]: cannot assign to `**x` because it is borrowed
-  --> $DIR/coerce-overloaded-autoderef.rs:17:5
-   |
-LL |     let y = borrow(x);
-   |                    - borrow of `**x` occurs here
-LL |     let z = borrow(x);
-LL |     **x += 1;
-   |     ^^^^^^^^ assignment to borrowed `**x` occurs here
-LL |
-LL |     drop((y, z));
-   |           - borrow later used here
-
-error[E0499]: cannot borrow `*x` as mutable more than once at a time
-  --> $DIR/coerce-overloaded-autoderef.rs:23:20
-   |
-LL |     borrow_mut2(x, x);
-   |     ----------- -  ^ second mutable borrow occurs here
-   |     |           |
-   |     |           first mutable borrow occurs here
-   |     first borrow later used by call
-
-error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
-  --> $DIR/coerce-overloaded-autoderef.rs:28:5
-   |
-LL |     borrow2(x, x);
-   |     -------^^^^-^
-   |     |          |
-   |     |          immutable borrow occurs here
-   |     mutable borrow occurs here
-   |     immutable borrow later used by call
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0499, E0502, E0506.
-For more information about an error, try `rustc --explain E0499`.
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs b/src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs
new file mode 100644 (file)
index 0000000..f033e1b
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+fn negate(x: &isize) -> isize {
+    -*x
+}
+
+fn negate_mut(y: &mut isize) -> isize {
+    negate(y)
+}
+
+fn negate_imm(y: &isize) -> isize {
+    negate(y)
+}
+
+pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs
new file mode 100644 (file)
index 0000000..64a3652
--- /dev/null
@@ -0,0 +1,18 @@
+// run-pass
+
+struct SpeechMaker {
+    speeches: usize
+}
+
+impl SpeechMaker {
+    pub fn how_many(&self) -> usize { self.speeches }
+}
+
+fn foo(speaker: &SpeechMaker) -> usize {
+    speaker.how_many() + 33
+}
+
+pub fn main() {
+    let lincoln = SpeechMaker {speeches: 22};
+    assert_eq!(foo(&lincoln), 55);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs b/src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs
new file mode 100644 (file)
index 0000000..c2aaae1
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+fn sum(x: &[isize]) -> isize {
+    let mut sum = 0;
+    for y in x { sum += *y; }
+    return sum;
+}
+
+fn sum_mut(y: &mut [isize]) -> isize {
+    sum(y)
+}
+
+fn sum_imm(y: &[isize]) -> isize {
+    sum(y)
+}
+
+pub fn main() {}
diff --git a/src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs
new file mode 100644 (file)
index 0000000..9a5652a
--- /dev/null
@@ -0,0 +1,16 @@
+// run-pass
+
+
+fn bar(v: &mut [usize]) -> Vec<usize> {
+    v.to_vec()
+}
+
+fn bip(v: &[usize]) -> Vec<usize> {
+    v.to_vec()
+}
+
+pub fn main() {
+    let mut the_vec = vec![1, 2, 3, 100];
+    assert_eq!(the_vec.clone(), bar(&mut the_vec));
+    assert_eq!(the_vec.clone(), bip(&the_vec));
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs
new file mode 100644 (file)
index 0000000..48be2d3
--- /dev/null
@@ -0,0 +1,6 @@
+fn test<T>(_a: T, _b: T) {}
+
+fn main() {
+    test(&mut 7, &7);
+    //~^ mismatched types
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
new file mode 100644 (file)
index 0000000..59b0ec4
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
+   |
+LL |     test(&mut 7, &7);
+   |                  ^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg.rs b/src/test/ui/coercion/coerce-reborrow-multi-arg.rs
new file mode 100644 (file)
index 0000000..93cd0bb
--- /dev/null
@@ -0,0 +1,9 @@
+// build-pass
+fn test<T>(_a: T, _b: T) {}
+
+fn main() {
+    test(&7, &7);
+    test(&7, &mut 7);
+    test::<&i32>(&mut 7, &7);
+    test::<&i32>(&mut 7, &mut 7);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs b/src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs
new file mode 100644 (file)
index 0000000..76cd679
--- /dev/null
@@ -0,0 +1,25 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct SpeechMaker {
+    speeches: usize
+}
+
+fn talk(x: &mut SpeechMaker) {
+    x.speeches += 1;
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+    // Here speaker is reborrowed for each call, so we don't get errors
+    // about speaker being moved.
+
+    talk(speaker);
+    talk(speaker);
+    talk(speaker);
+}
+
+pub fn main() {
+    let mut lincoln = SpeechMaker {speeches: 22};
+    give_a_few_speeches(&mut lincoln);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs
new file mode 100644 (file)
index 0000000..e6e7c3a
--- /dev/null
@@ -0,0 +1,27 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct SpeechMaker {
+    speeches: usize
+}
+
+impl SpeechMaker {
+    pub fn talk(&mut self) {
+        self.speeches += 1;
+    }
+}
+
+fn give_a_few_speeches(speaker: &mut SpeechMaker) {
+
+    // Here speaker is reborrowed for each call, so we don't get errors
+    // about speaker being moved.
+
+    speaker.talk();
+    speaker.talk();
+    speaker.talk();
+}
+
+pub fn main() {
+    let mut lincoln = SpeechMaker {speeches: 22};
+    give_a_few_speeches(&mut lincoln);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs b/src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs
new file mode 100644 (file)
index 0000000..2635754
--- /dev/null
@@ -0,0 +1,18 @@
+// run-pass
+
+
+fn reverse(v: &mut [usize]) {
+    v.reverse();
+}
+
+fn bar(v: &mut [usize]) {
+    reverse(v);
+    reverse(v);
+    reverse(v);
+}
+
+pub fn main() {
+    let mut the_vec = vec![1, 2, 3, 100];
+    bar(&mut the_vec);
+    assert_eq!(the_vec, [100, 3, 2, 1]);
+}
diff --git a/src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs
new file mode 100644 (file)
index 0000000..c03336e
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+
+
+fn bar(v: &mut [usize]) {
+    v.reverse();
+    v.reverse();
+    v.reverse();
+}
+
+pub fn main() {
+    let mut the_vec = vec![1, 2, 3, 100];
+    bar(&mut the_vec);
+    assert_eq!(the_vec, [100, 3, 2, 1]);
+}
index 8ef1948084654d9dfa435b43a99d80c91a280e2e..85598a42eccd9bdc26534ab1752ca3987afb1227 100644 (file)
@@ -1,7 +1,5 @@
 #![feature(never_type)]
 
-fn foo(x: usize, y: !, z: usize) { }
-
 fn cast_a() {
     let y = {return; 22} as !;
     //~^ ERROR non-primitive cast
index ff30ebc09c63acf5b43aee6dadee8f8c63160660..50e009aa25bb1085ced0b993f0d548032459714a 100644 (file)
@@ -1,18 +1,14 @@
 error[E0605]: non-primitive cast: `i32` as `!`
-  --> $DIR/coerce-to-bang-cast.rs:6:13
+  --> $DIR/coerce-to-bang-cast.rs:4:13
    |
 LL |     let y = {return; 22} as !;
-   |             ^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `i32` as `!`
-  --> $DIR/coerce-to-bang-cast.rs:11:13
+  --> $DIR/coerce-to-bang-cast.rs:9:13
    |
 LL |     let y = 22 as !;
-   |             ^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/coercion/coerce-unify-return.rs b/src/test/ui/coercion/coerce-unify-return.rs
new file mode 100644 (file)
index 0000000..95a7ee8
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+// Check that coercions unify the expected return type of a polymorphic
+// function call, instead of leaving the type variables as they were.
+
+// pretty-expanded FIXME #23616
+
+struct Foo;
+impl Foo {
+    fn foo<T>(self, x: T) -> Option<T> { Some(x) }
+}
+
+pub fn main() {
+    let _: Option<fn()> = Some(main);
+    let _: Option<fn()> = Foo.foo(main);
+
+    // The same two cases, with implicit type variables made explicit.
+    let _: Option<fn()> = Some::<_>(main);
+    let _: Option<fn()> = Foo.foo::<_>(main);
+}
diff --git a/src/test/ui/coercion/coerce-unify.rs b/src/test/ui/coercion/coerce-unify.rs
new file mode 100644 (file)
index 0000000..f1818f9
--- /dev/null
@@ -0,0 +1,68 @@
+// run-pass
+// Check that coercions can unify if-else, match arms and array elements.
+
+// Try to construct if-else chains, matches and arrays out of given expressions.
+macro_rules! check {
+    ($last:expr $(, $rest:expr)+) => {
+        // Last expression comes first because of whacky ifs and matches.
+        let _ = $(if false { $rest })else+ else { $last };
+
+        let _ = match 0 { $(_ if false => $rest,)+ _ => $last };
+
+        let _ = [$($rest,)+ $last];
+    }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 2 types.
+macro_rules! check2 {
+    ($a:expr, $b:expr) => {
+        check!($a, $b);
+        check!($b, $a);
+
+        check!($a, $a, $b);
+        check!($a, $b, $a);
+        check!($a, $b, $b);
+
+        check!($b, $a, $a);
+        check!($b, $a, $b);
+        check!($b, $b, $a);
+    }
+}
+
+// Check all non-uniform cases of 2 and 3 expressions of 3 types.
+macro_rules! check3 {
+    ($a:expr, $b:expr, $c:expr) => {
+        // Delegate to check2 for cases where a type repeats.
+        check2!($a, $b);
+        check2!($b, $c);
+        check2!($a, $c);
+
+        // Check the remaining cases, i.e., permutations of ($a, $b, $c).
+        check!($a, $b, $c);
+        check!($a, $c, $b);
+        check!($b, $a, $c);
+        check!($b, $c, $a);
+        check!($c, $a, $b);
+        check!($c, $b, $a);
+    }
+}
+
+use std::mem::size_of;
+
+fn foo() {}
+fn bar() {}
+
+pub fn main() {
+    check3!(foo, bar, foo as fn());
+    check3!(size_of::<u8>, size_of::<u16>, size_of::<usize> as fn() -> usize);
+
+    let s = String::from("bar");
+    check2!("foo", &s);
+
+    let a = [1, 2, 3];
+    let v = vec![1, 2, 3];
+    check2!(&a[..], &v);
+
+    // Make sure in-array coercion still works.
+    let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)];
+}
diff --git a/src/test/ui/coercion/coerce-unsize-subtype.rs b/src/test/ui/coercion/coerce-unsize-subtype.rs
new file mode 100644 (file)
index 0000000..45b5330
--- /dev/null
@@ -0,0 +1,40 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+use std::rc::Rc;
+
+fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
+
+// The two arguments are a subtype of their LUB, after coercion.
+fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
+    lub_short(xs, ys);
+}
+
+// The argument coerces to a subtype of the return type.
+fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
+    xs
+}
+
+// Rc<T> is covariant over T just like &T.
+fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
+    xs
+}
+
+// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
+// to a subtype of the LUB of `xs` and `ys` (i.e., `&'b [&'a T]`),
+// regardless of the order they appear (in if-else/match/array).
+fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
+    let _order1 = [xs, ys];
+    let _order2 = [ys, xs];
+}
+
+// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
+// needs to be coerced, i.e., the resulting type is not &'b [&'static T], but
+// rather the `&'b [&'a T]` LUB.
+fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
+    let _order1 = [xs, ys];
+    let _order2 = [ys, xs];
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs
new file mode 100644 (file)
index 0000000..99f805f
--- /dev/null
@@ -0,0 +1,26 @@
+// Test that impls for these two types are considered ovelapping:
+//
+// * `for<'r> fn(fn(&'r u32))`
+// * `fn(fn(&'a u32)` where `'a` is free
+//
+// This is because, for `'a = 'static`, the two types overlap.
+// Effectively for them to be equal to you get:
+//
+// * `for<'r> fn(fn(&'r u32)) <: fn(fn(&'static u32))`
+//   * true if `exists<'r> { 'r: 'static }` (obviously true)
+// * `fn(fn(&'static u32)) <: for<'r> fn(fn(&'r u32))`
+//   * true if `forall<'r> { 'static: 'r }` (also true)
+
+trait Trait {}
+
+impl Trait for for<'r> fn(fn(&'r ())) {}
+impl<'a> Trait for fn(fn(&'a ())) {}
+//~^ ERROR conflicting implementations
+//
+// Note in particular that we do NOT get a future-compatibility warning
+// here. This is because the new leak-check proposed in [MCP 295] does not
+// "error" when these two types are equated.
+//
+// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
new file mode 100644 (file)
index 0000000..49271ed
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`:
+  --> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
+   |
+LL | impl Trait for for<'r> fn(fn(&'r ())) {}
+   | ------------------------------------- first implementation here
+LL | impl<'a> Trait for fn(fn(&'a ())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
+   |
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.rs b/src/test/ui/coherence/coherence-fn-implied-bounds.rs
new file mode 100644 (file)
index 0000000..4539af9
--- /dev/null
@@ -0,0 +1,26 @@
+// Test that our leak-check is not smart enough to take implied bounds
+// into account (yet). Here we have two types that look like they
+// should not be equivalent, but because of the rules on implied
+// bounds we ought to know that, in fact, `'a = 'b` must always hold,
+// and hence they are.
+//
+// Rustc can't figure this out and hence it accepts the impls but
+// gives a future-compatibility warning (because we'd like to make
+// this an error someday).
+//
+// Note that while we would like to make this a hard error, we also
+// give the same warning for `coherence-wasm-bindgen.rs`, which ought
+// to be accepted.
+
+#![deny(coherence_leak_check)]
+
+trait Trait {}
+
+impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+
+impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+    //~^ ERROR conflicting implementations
+    //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.stderr b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr
new file mode 100644 (file)
index 0000000..a3e7f0b
--- /dev/null
@@ -0,0 +1,20 @@
+error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`:
+  --> $DIR/coherence-fn-implied-bounds.rs:21:1
+   |
+LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+   | ------------------------------------------------------------------ first implementation here
+LL | 
+LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-fn-implied-bounds.rs:15:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/coherence/coherence-fn-inputs.rs b/src/test/ui/coherence/coherence-fn-inputs.rs
new file mode 100644 (file)
index 0000000..3afec5c
--- /dev/null
@@ -0,0 +1,25 @@
+// Test that we consider these two types completely equal:
+//
+// * `for<'a, 'b> fn(&'a u32, &'b u32)`
+// * `for<'c> fn(&'c u32, &'c u32)`
+//
+// For a long time we considered these to be distinct types. But in fact they
+// are equivalent, if you work through the implications of subtyping -- this is
+// because:
+//
+// * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection)
+// * `'a` and `'b` can both be equal to `'c`
+
+trait Trait {}
+impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+impl Trait for for<'c> fn(&'c u32, &'c u32) {
+    //~^ ERROR conflicting implementations
+    //
+    // Note in particular that we do NOT get a future-compatibility warning
+    // here. This is because the new leak-check proposed in [MCP 295] does not
+    // "error" when these two types are equated.
+    //
+    // [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-inputs.stderr b/src/test/ui/coherence/coherence-fn-inputs.stderr
new file mode 100644 (file)
index 0000000..56ab873
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`:
+  --> $DIR/coherence-fn-inputs.rs:15:1
+   |
+LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+   | ----------------------------------------------- first implementation here
+LL | impl Trait for for<'c> fn(&'c u32, &'c u32) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)`
+   |
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-free-vs-bound-region.rs b/src/test/ui/coherence/coherence-free-vs-bound-region.rs
new file mode 100644 (file)
index 0000000..2f5c49d
--- /dev/null
@@ -0,0 +1,21 @@
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait TheTrait {}
+
+impl<'a> TheTrait for fn(&'a u8) {}
+
+impl TheTrait for fn(&u8) {
+    //~^ ERROR conflicting implementations of trait
+    //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-free-vs-bound-region.stderr b/src/test/ui/coherence/coherence-free-vs-bound-region.stderr
new file mode 100644 (file)
index 0000000..97aa491
--- /dev/null
@@ -0,0 +1,20 @@
+error: conflicting implementations of trait `TheTrait` for type `fn(&u8)`:
+  --> $DIR/coherence-free-vs-bound-region.rs:16:1
+   |
+LL | impl<'a> TheTrait for fn(&'a u8) {}
+   | -------------------------------- first implementation here
+LL | 
+LL | impl TheTrait for fn(&u8) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-free-vs-bound-region.rs:10:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
index 7f0e5472c3c2ee2772ddf7e8b0d323465cfa9f50..d74d3a2a52351c844e2489224ed9035b1bc2ea1a 100644 (file)
@@ -4,6 +4,7 @@
 //
 // No we expect to run into a more user-friendly cycle error instead.
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 trait Trait<T> { type Assoc; }
 //~^ ERROR E0391
index 71f997c54c6f23441951140f51a9105c1db566fb..7e140480b77d4d0eebe0fc27dbf35e80b3eabd2e 100644 (file)
@@ -1,16 +1,25 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:6:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0391]: cycle detected when building specialization graph of trait `Trait`
-  --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1
+  --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1
    |
 LL | trait Trait<T> { type Assoc; }
    | ^^^^^^^^^^^^^^
    |
    = note: ...which again requires building specialization graph of trait `Trait`, completing the cycle
 note: cycle used when coherence checking all impls of trait `Trait`
-  --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1
+  --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1
    |
 LL | trait Trait<T> { type Assoc; }
    | ^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/coherence/coherence-subtyping.old.stderr b/src/test/ui/coherence/coherence-subtyping.old.stderr
deleted file mode 100644 (file)
index b3c2f45..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-warning: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
-  --> $DIR/coherence-subtyping.rs:16:1
-   |
-LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
-   | ---------------------------------------------------------- first implementation here
-LL | 
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
-   |
-   = note: `#[warn(coherence_leak_check)]` 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
-   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/coherence/coherence-subtyping.re.stderr b/src/test/ui/coherence/coherence-subtyping.re.stderr
deleted file mode 100644 (file)
index b3c2f45..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-warning: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
-  --> $DIR/coherence-subtyping.rs:16:1
-   |
-LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
-   | ---------------------------------------------------------- first implementation here
-LL | 
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
-   |
-   = note: `#[warn(coherence_leak_check)]` 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
-   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
-
-warning: 1 warning emitted
-
index f5c1d92411baafb0dbfa61520298f003ebf15965..b3ed728a81c062c8c81aba2ab9123d2e04f7d3f5 100644 (file)
@@ -4,7 +4,6 @@
 // Note: This scenario is currently accepted, but as part of the
 // universe transition (#56105) may eventually become an error.
 
-// revisions: old re
 // check-pass
 
 trait TheTrait {
@@ -14,10 +13,8 @@ fn foo(&self) {}
 impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
 
 impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-    //[re]~^ WARNING conflicting implementation
-    //[re]~^^ WARNING this was previously accepted by the compiler but is being phased out
-    //[old]~^^^ WARNING conflicting implementation
-    //[old]~^^^^ WARNING this was previously accepted by the compiler but is being phased out
+    //~^ WARNING conflicting implementation
+    //~^^ WARNING this was previously accepted by the compiler but is being phased out
 }
 
 fn main() {}
diff --git a/src/test/ui/coherence/coherence-subtyping.stderr b/src/test/ui/coherence/coherence-subtyping.stderr
new file mode 100644 (file)
index 0000000..7f751a2
--- /dev/null
@@ -0,0 +1,16 @@
+warning: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
+  --> $DIR/coherence-subtyping.rs:15:1
+   |
+LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {}
+   | ---------------------------------------------------------- first implementation here
+LL | 
+LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+   |
+   = note: `#[warn(coherence_leak_check)]` 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.rs b/src/test/ui/coherence/coherence-wasm-bindgen.rs
new file mode 100644 (file)
index 0000000..ee09a72
--- /dev/null
@@ -0,0 +1,37 @@
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait IntoWasmAbi {
+    fn some_method(&self) {}
+}
+
+trait FromWasmAbi {}
+trait RefFromWasmAbi {}
+trait ReturnWasmAbi {}
+
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+where
+    A: FromWasmAbi,
+    R: ReturnWasmAbi,
+{
+}
+
+// Explicitly writing the bound lifetime.
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+where
+    A: RefFromWasmAbi,
+    R: ReturnWasmAbi,
+{
+    //~^^^^^ ERROR conflicting implementation
+    //~| WARNING this was previously accepted
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.stderr b/src/test/ui/coherence/coherence-wasm-bindgen.stderr
new file mode 100644 (file)
index 0000000..c77483b
--- /dev/null
@@ -0,0 +1,32 @@
+error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn std::ops::Fn(&_) -> _`:
+  --> $DIR/coherence-wasm-bindgen.rs:28:1
+   |
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+LL | | where
+LL | |     A: FromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+LL | | {
+LL | | }
+   | |_- first implementation here
+...
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+LL | | where
+LL | |     A: RefFromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+...  |
+LL | |
+LL | | }
+   | |_^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-wasm-bindgen.rs:10:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = 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 #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: downstream crates may implement trait `FromWasmAbi` for type `&_`
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
index b39a160b5298785940b5658298f7e4e3c48583a9..ceda31550ff44b766b8dfbfafc48b6f2a43cafa3 100644 (file)
@@ -13,9 +13,9 @@ LL | pub fn no_iterator() -> impl Iterator<Item = i32> {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
    |
-   = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33usize>`
+   = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33_usize>`
    = note: the return type of a function must have a statically known size
 
 error[E0277]: arrays only have std trait implementations for lengths 0..=32
@@ -33,9 +33,9 @@ LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator {
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
    |
-   = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33usize>`
+   = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33_usize>`
    = note: the return type of a function must have a statically known size
 
 error[E0277]: arrays only have std trait implementations for lengths 0..=32
@@ -53,9 +53,9 @@ LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator {
    |                                    ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
    |
-   = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33usize>`
+   = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33_usize>`
    = note: the return type of a function must have a statically known size
 
 error[E0277]: arrays only have std trait implementations for lengths 0..=32
@@ -73,9 +73,9 @@ LL | pub fn no_fused_iterator() -> impl FusedIterator {
    |                               ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
    |
-   = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33usize>`
+   = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33_usize>`
    = note: the return type of a function must have a statically known size
 
 error[E0277]: arrays only have std trait implementations for lengths 0..=32
@@ -93,9 +93,9 @@ LL | pub fn no_trusted_len() -> impl TrustedLen {
    |                            ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
    |
-   = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33usize>`
+   = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33_usize>`
    = note: the return type of a function must have a statically known size
 
 error[E0277]: arrays only have std trait implementations for lengths 0..=32
@@ -113,9 +113,9 @@ LL | pub fn no_clone() -> impl Clone {
    |                      ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
    |
-   = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33usize>`
+   = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33_usize>`
    = note: the return type of a function must have a statically known size
 
 error[E0277]: arrays only have std trait implementations for lengths 0..=32
@@ -133,9 +133,9 @@ LL | pub fn no_debug() -> impl Debug {
    |                      ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
 LL |
 LL |     IntoIter::new([0i32; 33])
-   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33usize>`
+   |     ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
    |
-   = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33usize>`
+   = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33_usize>`
    = note: the return type of a function must have a statically known size
 
 error: aborting due to 14 previous errors
diff --git a/src/test/ui/const-generics/auxiliary/impl-const.rs b/src/test/ui/const-generics/auxiliary/impl-const.rs
new file mode 100644 (file)
index 0000000..fc993d6
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(const_generics)]
+
+pub struct Num<const N: usize>;
+
+// Braces around const expression causes crash
+impl Num<{5}> {
+    pub fn five(&self) {
+    }
+}
index ad38b632b75f0eac4ba7d1d754bbaec47b7d4b6e..4a6241de1b453658e2e5768ef6043b062f7f496e 100644 (file)
@@ -14,6 +14,7 @@ LL | fn foo<const N: usize>() -> Array<N, ()> {
    |                                   ^
    |
    = note: type arguments must be provided before constant arguments
+   = help: reorder the arguments: types, then consts: `<T, N>`
 
 error: aborting due to previous error; 1 warning emitted
 
index 7eb826b8a36b119a0fc6d4ca7ef261d279be62f9..a3f331ee81155a4ae540b84171e3dad5bf9beff4 100644 (file)
@@ -11,10 +11,10 @@ error[E0308]: mismatched types
   --> $DIR/different_byref.rs:8:9
    |
 LL |     x = Const::<{ [4] }> {};
-   |         ^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `4usize`
+   |         ^^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
    |
-   = note: expected type `[3usize]`
-              found type `[4usize]`
+   = note: expected type `[3_usize]`
+              found type `[4_usize]`
 
 error: aborting due to previous error; 1 warning emitted
 
index afa577fa67ff288f4ac3df0b17d1a587bad9ca0c..90c438b05cb816459e5e4a1b9190e11559ea0a1c 100644 (file)
@@ -1,15 +1,14 @@
-// run-pass
-
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 fn function() -> u32 {
     17
 }
 
-struct Wrapper<const F: fn() -> u32>;
+struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters
 
 impl<const F: fn() -> u32> Wrapper<F> {
+//~^ ERROR: using function pointers as const generic parameters
     fn call() -> u32 {
         F()
     }
index 9c0f7e3ab9b87f82228f3c5bc0ab32f5753ca2c6..b5811243caa8a31b1b3bd97804b832c0ef9c4326 100644 (file)
@@ -1,11 +1,23 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/fn-const-param-call.rs:3:12
+  --> $DIR/fn-const-param-call.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:8:25
+   |
+LL | struct Wrapper<const F: fn() -> u32>;
+   |                         ^^^^^^^^^^^
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-call.rs:10:15
+   |
+LL | impl<const F: fn() -> u32> Wrapper<F> {
+   |               ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
index 08f6e0db31cae41ee6fc4a7d25fc4ce955820b4d..14fa3b494b3fcef1dade36b2d5f66352b3d65945 100644 (file)
@@ -1,7 +1,8 @@
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 struct Checked<const F: fn(usize) -> bool>;
+//~^ ERROR: using function pointers as const generic parameters
 
 fn not_one(val: usize) -> bool { val != 1 }
 fn not_two(val: usize) -> bool { val != 2 }
@@ -13,14 +14,14 @@ fn generic<T>(val: usize) -> bool { val != 1 }
 fn main() {
     let _: Option<Checked<not_one>> = None;
     let _: Checked<not_one> = Checked::<not_one>;
-    let _: Checked<not_one> = Checked::<not_two>; //~ mismatched types
+    let _: Checked<not_one> = Checked::<not_two>;
 
     let _ = Checked::<generic_arg>;
     let _ = Checked::<{generic_arg::<usize>}>;
-    let _ = Checked::<{generic_arg::<u32>}>;  //~ mismatched types
+    let _ = Checked::<{generic_arg::<u32>}>;
 
-    let _ = Checked::<generic>; //~ type annotations needed
+    let _ = Checked::<generic>;
     let _ = Checked::<{generic::<u16>}>;
     let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
-    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
+    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
 }
index de41d2984a655e5f505157a14ca0e0c109ce567a..7aaa41eb7d7b157f462a9af0a4f450b8cd1c7d47 100644 (file)
@@ -1,46 +1,17 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/fn-const-param-infer.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:16:31
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/fn-const-param-infer.rs:4:25
    |
-LL |     let _: Checked<not_one> = Checked::<not_two>;
-   |                               ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
-   |
-   = note: expected type `{not_one as fn(usize) -> bool}`
-              found type `{not_two as fn(usize) -> bool}`
-
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:20:24
-   |
-LL |     let _ = Checked::<{generic_arg::<u32>}>;
-   |                        ^^^^^^^^^^^^^^^^^^ expected `usize`, found `u32`
-   |
-   = note: expected fn pointer `fn(usize) -> _`
-                 found fn item `fn(u32) -> _ {generic_arg::<u32>}`
-
-error[E0282]: type annotations needed
-  --> $DIR/fn-const-param-infer.rs:22:23
-   |
-LL |     let _ = Checked::<generic>;
-   |                       ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic`
-
-error[E0308]: mismatched types
-  --> $DIR/fn-const-param-infer.rs:25:40
-   |
-LL |     let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
-   |
-   = note: expected type `{generic::<u32> as fn(usize) -> bool}`
-              found type `{generic::<u16> as fn(usize) -> bool}`
+LL | struct Checked<const F: fn(usize) -> bool>;
+   |                         ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
 
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs b/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs
new file mode 100644 (file)
index 0000000..bda9ce8
--- /dev/null
@@ -0,0 +1,14 @@
+// aux-build:impl-const.rs
+// run-pass
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+extern crate impl_const;
+
+use impl_const::*;
+
+pub fn main() {
+    let n = Num::<5>;
+    n.five();
+}
diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs
new file mode 100644 (file)
index 0000000..c32bd28
--- /dev/null
@@ -0,0 +1,33 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Test(*const usize);
+
+type PassArg = ();
+
+unsafe extern "C" fn pass(args: PassArg) {
+    println!("Hello, world!");
+}
+
+impl Test {
+    pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
+        //~^ ERROR: using function pointers as const generic parameters is forbidden
+        self.0 = Self::trampiline::<Args, IDX, FN> as _
+    }
+
+    unsafe extern "C" fn trampiline<
+        Args: Sized,
+        const IDX: usize,
+        const FN: unsafe extern "C" fn(Args),
+        //~^ ERROR: using function pointers as const generic parameters is forbidden
+    >(
+        args: Args,
+    ) {
+        FN(args)
+    }
+}
+
+fn main() {
+    let x = Test();
+    x.call_me::<PassArg, 30, pass>()
+}
diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr
new file mode 100644 (file)
index 0000000..6bb776f
--- /dev/null
@@ -0,0 +1,14 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/issue-71381.rs:13:61
+   |
+LL |     pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
+   |                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/issue-71381.rs:21:19
+   |
+LL |         const FN: unsafe extern "C" fn(Args),
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/issues/issue-71382.rs b/src/test/ui/const-generics/issues/issue-71382.rs
new file mode 100644 (file)
index 0000000..e0cf981
--- /dev/null
@@ -0,0 +1,24 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct Test();
+
+fn pass() {
+    println!("Hello, world!");
+}
+
+impl Test {
+    pub fn call_me(&self) {
+        self.test::<pass>();
+    }
+
+    fn test<const FN: fn()>(&self) {
+        //~^ ERROR: using function pointers as const generic parameters is forbidden
+        FN();
+    }
+}
+
+fn main() {
+    let x = Test();
+    x.call_me()
+}
diff --git a/src/test/ui/const-generics/issues/issue-71382.stderr b/src/test/ui/const-generics/issues/issue-71382.stderr
new file mode 100644 (file)
index 0000000..1652b0b
--- /dev/null
@@ -0,0 +1,8 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/issue-71382.rs:15:23
+   |
+LL |     fn test<const FN: fn()>(&self) {
+   |                       ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs
new file mode 100644 (file)
index 0000000..64a049e
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+fn func<A, const F: fn(inner: A)>(outer: A) {
+    //~^ ERROR: using function pointers as const generic parameters is forbidden
+    F(outer);
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr
new file mode 100644 (file)
index 0000000..9a7bf1c
--- /dev/null
@@ -0,0 +1,8 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/issue-71611.rs:4:21
+   |
+LL | fn func<A, const F: fn(inner: A)>(outer: A) {
+   |                     ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-72352.rs b/src/test/ui/const-generics/issues/issue-72352.rs
new file mode 100644 (file)
index 0000000..e977af8
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+use std::ffi::{CStr, CString};
+
+unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
+    //~^ ERROR: using function pointers as const generic parameters is forbidden
+    F(CStr::from_ptr(ptr))
+}
+
+fn safely_do_the_thing(s: &CStr) -> usize {
+    s.to_bytes().len()
+}
+
+fn main() {
+    let baguette = CString::new("baguette").unwrap();
+    let ptr = baguette.as_ptr();
+    println!("{}", unsafe {
+        unsafely_do_the_thing::<safely_do_the_thing>(ptr)
+    });
+}
diff --git a/src/test/ui/const-generics/issues/issue-72352.stderr b/src/test/ui/const-generics/issues/issue-72352.stderr
new file mode 100644 (file)
index 0000000..bc48da1
--- /dev/null
@@ -0,0 +1,8 @@
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/issue-72352.rs:6:42
+   |
+LL | unsafe fn unsafely_do_the_thing<const F: fn(&CStr) -> usize>(ptr: *const i8) -> usize {
+   |                                          ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index c498bfe2e978166a22eca5598cdcdecfc135047b..97ca9d6a44c9e8f38d0527697ad0d3b0a63ea97d 100644 (file)
@@ -1,12 +1,11 @@
-// run-pass
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
 const A: u32 = 3;
 
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
-impl<const P: *const u32> Const<P> {
+impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters
     fn get() -> u32 {
         unsafe {
             *P
index 1ffc63ffdac03577c22d6ad7763590eaa1e39a4e..1ce8bb9c05423a1a421c0da34280e3b032e638a9 100644 (file)
@@ -1,11 +1,23 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-ptr-const-param-deref.rs:2:12
+  --> $DIR/raw-ptr-const-param-deref.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:6:23
+   |
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
+
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param-deref.rs:8:15
+   |
+LL | impl<const P: *const u32> Const<P> {
+   |               ^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
index d7d970e952b656adf6bf0fcbbeb0b73d6ead57a1..237b410e073d6f886b617bfc40f30434b16c7cd7 100644 (file)
@@ -1,9 +1,9 @@
-#![feature(const_generics, const_compare_raw_pointers)]
+#![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
-struct Const<const P: *const u32>;
+struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters
 
 fn main() {
-    let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types
+    let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
     let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>;
 }
index 7a665397c1207fd90c753fc5a21581f9f074f3ca..6e64f8a327fd508241b479fe5f4859eb0a12f1b8 100644 (file)
@@ -1,21 +1,17 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/raw-ptr-const-param.rs:1:12
    |
-LL | #![feature(const_generics, const_compare_raw_pointers)]
+LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-error[E0308]: mismatched types
-  --> $DIR/raw-ptr-const-param.rs:7:40
+error: using raw pointers as const generic parameters is forbidden
+  --> $DIR/raw-ptr-const-param.rs:4:23
    |
-LL |     let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
-   |
-   = note: expected type `{0xf as *const u32}`
-              found type `{0xa as *const u32}`
+LL | struct Const<const P: *const u32>;
+   |                       ^^^^^^^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0308`.
index 53328c2e89bf4ea2c58e6ca737e2fd4bc36ab2c1..49530c9d240b5daeeb04cb1087c04e1370709c6f 100644 (file)
@@ -11,10 +11,10 @@ error[E0308]: mismatched types
   --> $DIR/types-mismatch-const-args.rs:13:41
    |
 LL |     let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32`
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32`
    |
-   = note: expected type `2u32`
-              found type `4u32`
+   = note: expected type `2_u32`
+              found type `4_u32`
 
 error[E0308]: mismatched types
   --> $DIR/types-mismatch-const-args.rs:15:41
index b78ac38d7e7e26673b0222fd4ac63aae56c7a13c..0cb77518197748787ff0cf744a2aab0146bf4e74 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL | pub const A: i8 = -std::i8::MIN;
    | ------------------^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to negate with overflow
+   |                   attempt to negate i8::MIN which would overflow
    |
 note: the lint level is defined here
   --> $DIR/const-err-early.rs:1:9
@@ -18,7 +18,7 @@ error: any use of this value will cause an error
 LL | pub const B: u8 = 200u8 + 200u8;
    | ------------------^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to add with overflow
+   |                   attempt to compute `200_u8 + 200_u8` which would overflow
 
 error: any use of this value will cause an error
   --> $DIR/const-err-early.rs:5:19
@@ -26,7 +26,7 @@ error: any use of this value will cause an error
 LL | pub const C: u8 = 200u8 * 4;
    | ------------------^^^^^^^^^-
    |                   |
-   |                   attempt to multiply with overflow
+   |                   attempt to compute `200_u8 * 4_u8` which would overflow
 
 error: any use of this value will cause an error
   --> $DIR/const-err-early.rs:6:19
@@ -34,7 +34,7 @@ error: any use of this value will cause an error
 LL | pub const D: u8 = 42u8 - (42u8 + 1);
    | ------------------^^^^^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to subtract with overflow
+   |                   attempt to compute `42_u8 - 43_u8` which would overflow
 
 error: any use of this value will cause an error
   --> $DIR/const-err-early.rs:7:19
index 65427b8a1b289b91cffab39fedfb09a849f1a4ec..4ac4a8754d396ed521ffb87e1a4b0916817a58ad 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL | pub const A: i8 = -std::i8::MIN;
    | ------------------^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to negate with overflow
+   |                   attempt to negate i8::MIN which would overflow
    |
 note: the lint level is defined here
   --> $DIR/const-err-multi.rs:1:9
index 5aeeec4bd1435afce765d3fd62d97bd56a64daca..687ffc4c4bf95765f841df37c011b26d3e9ac0d5 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:19:13
    |
 LL |     let a = -std::i8::MIN;
-   |             ^^^^^^^^^^^^^ attempt to negate with overflow
+   |             ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,31 +10,31 @@ error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:21:18
    |
 LL |     let a_i128 = -std::i128::MIN;
-   |                  ^^^^^^^^^^^^^^^ attempt to negate with overflow
+   |                  ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:23:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
-   |             ^^^^^^^^^^^^^ attempt to add with overflow
+   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:25:18
    |
 LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:27:13
    |
 LL |     let c = 200u8 * 4;
-   |             ^^^^^^^^^ attempt to multiply with overflow
+   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:29:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
-   |             ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/const-err2.rs:31:14
index 5aeeec4bd1435afce765d3fd62d97bd56a64daca..687ffc4c4bf95765f841df37c011b26d3e9ac0d5 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:19:13
    |
 LL |     let a = -std::i8::MIN;
-   |             ^^^^^^^^^^^^^ attempt to negate with overflow
+   |             ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,31 +10,31 @@ error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:21:18
    |
 LL |     let a_i128 = -std::i128::MIN;
-   |                  ^^^^^^^^^^^^^^^ attempt to negate with overflow
+   |                  ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:23:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
-   |             ^^^^^^^^^^^^^ attempt to add with overflow
+   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:25:18
    |
 LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:27:13
    |
 LL |     let c = 200u8 * 4;
-   |             ^^^^^^^^^ attempt to multiply with overflow
+   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:29:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
-   |             ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/const-err2.rs:31:14
index 5aeeec4bd1435afce765d3fd62d97bd56a64daca..687ffc4c4bf95765f841df37c011b26d3e9ac0d5 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:19:13
    |
 LL |     let a = -std::i8::MIN;
-   |             ^^^^^^^^^^^^^ attempt to negate with overflow
+   |             ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,31 +10,31 @@ error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:21:18
    |
 LL |     let a_i128 = -std::i128::MIN;
-   |                  ^^^^^^^^^^^^^^^ attempt to negate with overflow
+   |                  ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:23:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
-   |             ^^^^^^^^^^^^^ attempt to add with overflow
+   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:25:18
    |
 LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:27:13
    |
 LL |     let c = 200u8 * 4;
-   |             ^^^^^^^^^ attempt to multiply with overflow
+   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:29:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
-   |             ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/const-err2.rs:31:14
index df8efc44c4966fdb4885b31555d40fb6efc5db36..62f339809e431c0d3eccb9d986dcc207771094c6 100644 (file)
@@ -4,7 +4,7 @@ warning: any use of this value will cause an error
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
    | ------------------^^^^^---------------------------
    |                   |
-   |                   attempt to subtract with overflow
+   |                   attempt to compute `5_u32 - 6_u32` which would overflow
    |
 note: the lint level is defined here
   --> $DIR/conditional_array_execution.rs:3:9
index 2c5b4607aa4d3ca802d13aa78f3f1b69437f46d4..dd79cbd7e5ff72e19a34b2fd2d377a3e0dbbb877 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-eval-overflow-3.rs:20:11
    |
 LL |     = [0; (i8::MAX + 1) as usize];
-   |           ^^^^^^^^^^^^^ attempt to add with overflow
+   |           ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
 
 error: aborting due to previous error
 
index fe7db23dc2e99ccb41d211725c0d1cf3bc43fa7f..30c52a82ea3643e796dcc9b43d28e4f943888d41 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-eval-overflow-4.rs:13:13
    |
 LL |     : [u32; (i8::MAX as i8 + 1i8) as usize]
-   |             ^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow
+   |             ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
 
 error: aborting due to previous error
 
index 5b2c4116c4b1dc9aa7c44b24bb6c207b3235e175..e4d256c0ad19201b93438af57daec0badf1fb1d3 100644 (file)
@@ -16,7 +16,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8`
   --> $DIR/const-eval-overflow-4b.rs:25:13
    |
 LL |     : [u32; 5i8 as char as usize]
-   |             ^^^^^^^^^^^
+   |             ^^^^^^^^^^^ invalid cast
 
 error: aborting due to 3 previous errors
 
index 6f823005572b5de0bbbebae780c03d999d777539..2ad557a71139ee2f2560fd79d5bddbefd7c826b7 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I8: (i8,) =
 LL | |     (
 LL | |      i8::MIN - 1,
-   | |      ^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8` which would overflow
 LL | |      );
    | |_______-
    |
@@ -20,7 +20,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I16: (i16,) =
 LL | |     (
 LL | |      i16::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16` which would overflow
 LL | |      );
    | |_______-
 
@@ -30,7 +30,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I32: (i32,) =
 LL | |     (
 LL | |      i32::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32` which would overflow
 LL | |      );
    | |_______-
 
@@ -40,7 +40,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I64: (i64,) =
 LL | |     (
 LL | |      i64::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64` which would overflow
 LL | |      );
    | |_______-
 
@@ -50,7 +50,7 @@ error: any use of this value will cause an error
 LL | / const VALS_U8: (u8,) =
 LL | |     (
 LL | |      u8::MIN - 1,
-   | |      ^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8` which would overflow
 LL | |      );
    | |_______-
 
@@ -59,7 +59,7 @@ error: any use of this value will cause an error
    |
 LL | / const VALS_U16: (u16,) = (
 LL | |      u16::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16` which would overflow
 LL | |      );
    | |_______-
 
@@ -68,7 +68,7 @@ error: any use of this value will cause an error
    |
 LL | / const VALS_U32: (u32,) = (
 LL | |      u32::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
 LL | |      );
    | |_______-
 
@@ -78,7 +78,7 @@ error: any use of this value will cause an error
 LL | / const VALS_U64: (u64,) =
 LL | |     (
 LL | |      u64::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to subtract with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64` which would overflow
 LL | |      );
    | |_______-
 
index f9a4e5aa96801328137cc325ed10d86fbdf45302..fce616b296c291d3a5090600cadf2d586ef32e3a 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I8: (i8,) =
 LL | |     (
 LL | |      i8::MAX + 1,
-   | |      ^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
 LL | |      );
    | |_______-
    |
@@ -20,7 +20,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I16: (i16,) =
 LL | |     (
 LL | |      i16::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16` which would overflow
 LL | |      );
    | |_______-
 
@@ -30,7 +30,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I32: (i32,) =
 LL | |     (
 LL | |      i32::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
 LL | |      );
    | |_______-
 
@@ -40,7 +40,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I64: (i64,) =
 LL | |     (
 LL | |      i64::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64` which would overflow
 LL | |      );
    | |_______-
 
@@ -50,7 +50,7 @@ error: any use of this value will cause an error
 LL | / const VALS_U8: (u8,) =
 LL | |     (
 LL | |      u8::MAX + 1,
-   | |      ^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8` which would overflow
 LL | |      );
    | |_______-
 
@@ -59,7 +59,7 @@ error: any use of this value will cause an error
    |
 LL | / const VALS_U16: (u16,) = (
 LL | |      u16::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16` which would overflow
 LL | |      );
    | |_______-
 
@@ -68,7 +68,7 @@ error: any use of this value will cause an error
    |
 LL | / const VALS_U32: (u32,) = (
 LL | |      u32::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32` which would overflow
 LL | |      );
    | |_______-
 
@@ -78,7 +78,7 @@ error: any use of this value will cause an error
 LL | / const VALS_U64: (u64,) =
 LL | |     (
 LL | |      u64::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to add with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64` which would overflow
 LL | |      );
    | |_______-
 
index 6b906178026292ee1b51b0d166cb025a0b2a65bf..76201524d32bcaffea76c886cf4bdb540db41162 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I8: (i8,) =
 LL | |     (
 LL | |      i8::MIN * 2,
-   | |      ^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8` which would overflow
 LL | |      );
    | |_______-
    |
@@ -20,7 +20,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I16: (i16,) =
 LL | |     (
 LL | |      i16::MIN * 2,
-   | |      ^^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16` which would overflow
 LL | |      );
    | |_______-
 
@@ -30,7 +30,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I32: (i32,) =
 LL | |     (
 LL | |      i32::MIN * 2,
-   | |      ^^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32` which would overflow
 LL | |      );
    | |_______-
 
@@ -40,7 +40,7 @@ error: any use of this value will cause an error
 LL | / const VALS_I64: (i64,) =
 LL | |     (
 LL | |      i64::MIN * 2,
-   | |      ^^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64` which would overflow
 LL | |      );
    | |_______-
 
@@ -50,7 +50,7 @@ error: any use of this value will cause an error
 LL | / const VALS_U8: (u8,) =
 LL | |     (
 LL | |      u8::MAX * 2,
-   | |      ^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8` which would overflow
 LL | |      );
    | |_______-
 
@@ -59,7 +59,7 @@ error: any use of this value will cause an error
    |
 LL | / const VALS_U16: (u16,) = (
 LL | |      u16::MAX * 2,
-   | |      ^^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16` which would overflow
 LL | |      );
    | |_______-
 
@@ -68,7 +68,7 @@ error: any use of this value will cause an error
    |
 LL | / const VALS_U32: (u32,) = (
 LL | |      u32::MAX * 2,
-   | |      ^^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32` which would overflow
 LL | |      );
    | |_______-
 
@@ -78,7 +78,7 @@ error: any use of this value will cause an error
 LL | / const VALS_U64: (u64,) =
 LL | |     (
 LL | |      u64::MAX * 2,
-   | |      ^^^^^^^^^^^^ attempt to multiply with overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64` which would overflow
 LL | |      );
    | |_______-
 
index 4753222a7c07d816fb5f49190e58dcdb891b02fb..47f39b703e46095b28e8de9672dbc117a829c144 100644 (file)
@@ -2,25 +2,33 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:16:32
    |
 LL | const Y: FakeNeedsDrop = { let mut x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-   |                                ^^^^^ constants cannot evaluate destructors
+   |                                ^^^^^                  - value is dropped here
+   |                                |
+   |                                constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:20:33
    |
 LL | const Y2: FakeNeedsDrop = { let mut x; x = FakeNeedsDrop; x = FakeNeedsDrop; x };
-   |                                 ^^^^^ constants cannot evaluate destructors
+   |                                 ^^^^^                     - value is dropped here
+   |                                 |
+   |                                 constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:24:21
    |
 LL | const Z: () = { let mut x = None; x = Some(FakeNeedsDrop); };
-   |                     ^^^^^ constants cannot evaluate destructors
+   |                     ^^^^^                                  - value is dropped here
+   |                     |
+   |                     constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/const_let.rs:28:22
    |
 LL | const Z2: () = { let mut x; x = None; x = Some(FakeNeedsDrop); };
-   |                      ^^^^^ constants cannot evaluate destructors
+   |                      ^^^^^                                     - value is dropped here
+   |                      |
+   |                      constants cannot evaluate destructors
 
 error: aborting due to 4 previous errors
 
index 9be1374f85d99af66d4c126e0e9034b2f3793525..e238e13b8e2da46fff8542ce21a634f011144655 100644 (file)
@@ -1,17 +1,6 @@
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
-
 fn main() {}
 
 // unconst and bad, will thus error in miri
-const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
-// unconst and bad, will thus error in miri
-const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR any use of this
-// unconst and fine
-const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
-// unconst and bad, will thus error in miri
-const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
-// unconst and fine
-const Z: i32 = unsafe { *(&1 as *const i32) };
+const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
 // unconst and bad, will thus error in miri
-const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
-const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
+const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably
index cc40728e6b574afa577f8f59cead2455a48782ee..21d3f5e7e853651c48fdb33b532c68d8e6543288 100644 (file)
@@ -1,44 +1,18 @@
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:6:26
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/const_raw_ptr_ops.rs:4:26
    |
 LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
-   | -------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[deny(const_err)]` on by default
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:8:27
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/const_raw_ptr_ops.rs:6:27
    |
 LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
-   | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
-   |                           |
-   |                           "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:12:28
-   |
-LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
-   | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
-   |                            |
-   |                            "pointer-to-integer cast" needs an rfc before being allowed inside constants
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:16:26
-   |
-LL | const Z2: i32 = unsafe { *(42 as *const i32) };
-   | -------------------------^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          unable to turn bytes into a pointer
-
-error: any use of this value will cause an error
-  --> $DIR/const_raw_ptr_ops.rs:17:26
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | const Z3: i32 = unsafe { *(44 as *const i32) };
-   | -------------------------^^^^^^^^^^^^^^^^^^^---
-   |                          |
-   |                          unable to turn bytes into a pointer
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
new file mode 100644 (file)
index 0000000..d2a7623
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
+
+fn main() {}
+
+// unconst and fine
+const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
+// unconst and bad, will thus error in miri
+const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
+// unconst and fine
+const Z: i32 = unsafe { *(&1 as *const i32) };
+// unconst and bad, will thus error in miri
+const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR any use of this value will cause
+const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR any use of this value will cause
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
new file mode 100644 (file)
index 0000000..93f2261
--- /dev/null
@@ -0,0 +1,28 @@
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:8:28
+   |
+LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 };
+   | ---------------------------^^^^^^^^^^^^^^^^^^^^^^^^^-------
+   |                            |
+   |                            "pointer-to-integer cast" needs an rfc before being allowed inside constants
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:12:26
+   |
+LL | const Z2: i32 = unsafe { *(42 as *const i32) };
+   | -------------------------^^^^^^^^^^^^^^^^^^^---
+   |                          |
+   |                          unable to turn bytes into a pointer
+
+error: any use of this value will cause an error
+  --> $DIR/const_raw_ptr_ops2.rs:13:26
+   |
+LL | const Z3: i32 = unsafe { *(44 as *const i32) };
+   | -------------------------^^^^^^^^^^^^^^^^^^^---
+   |                          |
+   |                          unable to turn bytes into a pointer
+
+error: aborting due to 3 previous errors
+
index 81fa5c0df13f6f626bccf3f6edc64b3f82ed4a8c..93dd9a53ec99f95c3595d875e208dc49bf181652 100644 (file)
@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {(
 LL | |     Union { u8: &BAR }.foo,
 LL | |     Union { u8: &BAR }.bar,
 LL | | )};
-   | |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum discriminant
+   | |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
index c8de259354eac03f0d79f73d45b5a4a2bbe79238..14a573ccf5ac635149b5be2842b0b77506e5d62e 100644 (file)
@@ -4,10 +4,8 @@ fn main() {
     let _ = [(); {
         let mut n = 113383; // #20 in https://oeis.org/A006884
         while n != 0 {
-        //~^ ERROR `while` is not allowed in a `const`
             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
             //~^ ERROR evaluation of constant value failed
-            //~| ERROR `if` is not allowed in a `const`
         }
         n
     }];
index 3386e6e588e7120105e272edf2fb7131ec97c52e..d01376e595945f8cb0fbb65254dff3687cd12e8b 100644 (file)
@@ -1,34 +1,9 @@
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/infinite_loop.rs:6:9
-   |
-LL | /         while n != 0 {
-LL | |
-LL | |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
-LL | |
-LL | |
-LL | |         }
-   | |_________^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/infinite_loop.rs:8:17
-   |
-LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
 error[E0080]: evaluation of constant value failed
-  --> $DIR/infinite_loop.rs:8:17
+  --> $DIR/infinite_loop.rs:7:17
    |
 LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0080, E0658.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0080`.
index 8aaae9fe6a7d168da9468dae63167beb0c02927c..b3e1f496ae3e3e501552715923334734efe456e8 100644 (file)
@@ -4,7 +4,7 @@ warning: any use of this value will cause an error
 LL |     const X: u32 = 0 - 1;
    |     ---------------^^^^^-
    |                    |
-   |                    attempt to subtract with overflow
+   |                    attempt to compute `0_u32 - 1_u32` which would overflow
    |
 note: the lint level is defined here
   --> $DIR/issue-43197.rs:3:9
@@ -18,7 +18,7 @@ warning: any use of this value will cause an error
 LL |     const Y: u32 = foo(0 - 1);
    |     -------------------^^^^^--
    |                        |
-   |                        attempt to subtract with overflow
+   |                        attempt to compute `0_u32 - 1_u32` which would overflow
 
 error[E0080]: evaluation of constant expression failed
   --> $DIR/issue-43197.rs:14:23
index 2e5167a99a2c638abe4d04709be5a72760e3e8d6..4be84f8d1843cf8dd1e79f2eef5330fae06af7b3 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL |     const MAX: u8 = A::MAX + B::MAX;
    |     ----------------^^^^^^^^^^^^^^^-
    |                     |
-   |                     attempt to add with overflow
+   |                     attempt to compute `u8::MAX + u8::MAX` which would overflow
    |
    = note: `#[deny(const_err)]` on by default
 
index 07fb491015a853c184acda4426dff1e36928bfd2..ea24578c7dd0cfd28f6937987db69918d647e143 100644 (file)
@@ -1,6 +1,5 @@
 fn main() {
     [();  { &loop { break } as *const _ as usize } ];
-    //~^ ERROR `loop` is not allowed in a `const`
-    //~| ERROR casting pointers to integers in constants is unstable
+    //~^ ERROR casting pointers to integers in constants is unstable
     //~| ERROR evaluation of constant value failed
 }
index eda2dbf0b6b1569ff8f412bf2436b78b325f2106..53a87837e16e3881cf80f74e9eb0c4ba5cb3d04d 100644 (file)
@@ -1,12 +1,3 @@
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/issue-52442.rs:2:14
-   |
-LL |     [();  { &loop { break } as *const _ as usize } ];
-   |              ^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
 error[E0658]: casting pointers to integers in constants is unstable
   --> $DIR/issue-52442.rs:2:13
    |
@@ -22,7 +13,7 @@ error[E0080]: evaluation of constant value failed
 LL |     [();  { &loop { break } as *const _ as usize } ];
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0080, E0658.
 For more information about an error, try `rustc --explain E0080`.
index 869f0b981af7d881e4dce06fc6f4cd9fe531b727..ce65407bbab0b5d928795c8b4fdc82297aac8625 100644 (file)
@@ -3,7 +3,6 @@ fn main() {
         let mut x = &0;
         let mut n = 0;
         while n < 5 {
-        //~^ ERROR `while` is not allowed in a `const`
             n = (n + 1) % 5; //~ ERROR evaluation of constant value failed
             x = &0; // Materialize a new AllocId
         }
index b069537ead9637a63df6bf2bb80b8dcfe92a601e..8536ff02c6dae89b96403ba90c8fd15b61f58a3b 100644 (file)
@@ -1,24 +1,9 @@
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/issue-52475.rs:5:9
-   |
-LL | /         while n < 5 {
-LL | |
-LL | |             n = (n + 1) % 5;
-LL | |             x = &0; // Materialize a new AllocId
-LL | |         }
-   | |_________^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-52475.rs:7:17
+  --> $DIR/issue-52475.rs:6:17
    |
 LL |             n = (n + 1) % 5;
    |                 ^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0080, E0658.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-62272.rs b/src/test/ui/consts/const-eval/issue-62272.rs
deleted file mode 100644 (file)
index 19abd91..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// `loop`s unconditionally-broken-from used to be allowed in constants, but are now forbidden by
-// the HIR const-checker.
-//
-// See https://github.com/rust-lang/rust/pull/66170 and
-// https://github.com/rust-lang/rust/issues/62272.
-
-const FOO: () = loop { break; }; //~ ERROR `loop` is not allowed in a `const`
-
-fn main() {
-    [FOO; { let x; loop { x = 5; break; } x }]; //~ ERROR `loop` is not allowed in a `const`
-}
diff --git a/src/test/ui/consts/const-eval/issue-62272.stderr b/src/test/ui/consts/const-eval/issue-62272.stderr
deleted file mode 100644 (file)
index 380f68b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/issue-62272.rs:7:17
-   |
-LL | const FOO: () = loop { break; };
-   |                 ^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/issue-62272.rs:10:20
-   |
-LL |     [FOO; { let x; loop { x = 5; break; } x }];
-   |                    ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index b1c058eac9e4bfc213d0c38553bdb9c1dc64dfc8..2518e4ed40b30bf161644840f9e77736f8a6d857 100644 (file)
@@ -5,7 +5,7 @@
 
 const _: Vec<i32> = {
     let mut x = Vec::<i32>::new(); //~ ERROR destructors cannot be evaluated at compile-time
-    let r = &mut x; //~ ERROR references in constants may only refer to immutable values
+    let r = &mut x; //~ ERROR mutable references are not allowed in constants
     let y = x;
     y
 };
index d85a1a1a3c32bff0d0c93d33b8dad06710b354dc..771d368d7839104de25363732e5248515a75ab38 100644 (file)
@@ -1,19 +1,19 @@
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/issue-65394.rs:8:13
    |
 LL |     let r = &mut x;
-   |             ^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |             ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/issue-65394.rs:7:9
    |
 LL |     let mut x = Vec::<i32>::new();
    |         ^^^^^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0493, E0658.
+Some errors have detailed explanations: E0493, E0764.
 For more information about an error, try `rustc --explain E0493`.
index 8b79d5d53c5c2740a30d8568f7a12aff2daf978b..3c81afa67a69fc046938b16d013c4c3f3b23511f 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_loop)]
-
 static _X: () = loop {}; //~ ERROR could not evaluate static initializer
 
 fn main() {}
index 687d6565a7163d7c8b3a16b1fef1a5b30ad5270b..09fb3e060dc4c367dae3e9153225d393378a9225 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: could not evaluate static initializer
-  --> $DIR/issue-70723.rs:3:17
+  --> $DIR/issue-70723.rs:1:17
    |
 LL | static _X: () = loop {};
    |                 ^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
diff --git a/src/test/ui/consts/const-eval/livedrop.rs b/src/test/ui/consts/const-eval/livedrop.rs
new file mode 100644 (file)
index 0000000..66b7d05
--- /dev/null
@@ -0,0 +1,17 @@
+const _: Option<Vec<i32>> = {
+    let mut never_returned = Some(Vec::new());
+    let mut always_returned = None; //~ ERROR destructors cannot be evaluated at compile-time
+
+    let mut i = 0;
+    loop {
+        always_returned = never_returned;
+        never_returned = None;
+
+        i += 1;
+        if i == 10 {
+            break always_returned;
+        }
+    }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/livedrop.stderr b/src/test/ui/consts/const-eval/livedrop.stderr
new file mode 100644 (file)
index 0000000..1e8b423
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/livedrop.rs:3:9
+   |
+LL |     let mut always_returned = None;
+   |         ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+...
+LL |         always_returned = never_returned;
+   |         --------------- value is dropped here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
index 80494d1662987e98efbf5bf12896aeafe35a5887..f6b5ad005a8841430515c5129a46883de2f094e1 100644 (file)
@@ -5,7 +5,6 @@ fn main() {
     let _: [u8; 0] = [4; {
         match &1 as *const i32 as usize {
             //~^ ERROR casting pointers to integers in constants
-            //~| ERROR `match` is not allowed in a `const`
             //~| ERROR evaluation of constant value failed
             0 => 42,
             n => n,
index b47f6d5f845feeab0e81fbd237a557ebbfbf939f..48dbe661492d408f87dd327aa37acad435e92df4 100644 (file)
@@ -1,18 +1,3 @@
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/match-test-ptr-null.rs:6:9
-   |
-LL | /         match &1 as *const i32 as usize {
-LL | |
-LL | |
-LL | |
-LL | |             0 => 42,
-LL | |             n => n,
-LL | |         }
-   | |_________^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
 error[E0658]: casting pointers to integers in constants is unstable
   --> $DIR/match-test-ptr-null.rs:6:15
    |
@@ -28,7 +13,7 @@ error[E0080]: evaluation of constant value failed
 LL |         match &1 as *const i32 as usize {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0080, E0658.
 For more information about an error, try `rustc --explain E0080`.
index a545503ce8955a3385b521f6ffab45d3ce974cc6..52313205dc80bff826cb0c05d97cf3eaa80bebd1 100644 (file)
@@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow
   --> $DIR/promoted_errors.rs:12:20
    |
 LL |     println!("{}", 0u32 - 1);
-   |                    ^^^^^^^^ attempt to subtract with overflow
+   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:20
@@ -14,13 +14,13 @@ warning: this arithmetic operation will overflow
   --> $DIR/promoted_errors.rs:14:14
    |
 LL |     let _x = 0u32 - 1;
-   |              ^^^^^^^^ attempt to subtract with overflow
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1 / (1 - 1));
-   |                    ^^^^^^^^^^^ attempt to divide by zero
+   |                    ^^^^^^^^^^^ attempt to divide 1_i32 by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:41
@@ -50,13 +50,13 @@ warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:20:14
    |
 LL |     let _x = 1 / (1 - 1);
-   |              ^^^^^^^^^^^ attempt to divide by zero
+   |              ^^^^^^^^^^^ attempt to divide 1_i32 by zero
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:22:20
    |
 LL |     println!("{}", 1 / (false as u32));
-   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
 
 warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:22:20
@@ -74,7 +74,7 @@ warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1 / (false as u32);
-   |              ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
 
 warning: 10 warnings emitted
 
index 48878261782446854b568d17080c5d698b9a2641..b411bb2e7fe2005b0c6bab92cf194c0788a34294 100644 (file)
@@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow
   --> $DIR/promoted_errors.rs:14:14
    |
 LL |     let _x = 0u32 - 1;
-   |              ^^^^^^^^ attempt to subtract with overflow
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:20
@@ -14,7 +14,7 @@ warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1 / (1 - 1));
-   |                    ^^^^^^^^^^^ attempt to divide by zero
+   |                    ^^^^^^^^^^^ attempt to divide 1_i32 by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:41
@@ -44,13 +44,13 @@ warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:20:14
    |
 LL |     let _x = 1 / (1 - 1);
-   |              ^^^^^^^^^^^ attempt to divide by zero
+   |              ^^^^^^^^^^^ attempt to divide 1_i32 by zero
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:22:20
    |
 LL |     println!("{}", 1 / (false as u32));
-   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
 
 warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:22:20
@@ -68,7 +68,7 @@ warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1 / (false as u32);
-   |              ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
 
 warning: 9 warnings emitted
 
index a545503ce8955a3385b521f6ffab45d3ce974cc6..52313205dc80bff826cb0c05d97cf3eaa80bebd1 100644 (file)
@@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow
   --> $DIR/promoted_errors.rs:12:20
    |
 LL |     println!("{}", 0u32 - 1);
-   |                    ^^^^^^^^ attempt to subtract with overflow
+   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:20
@@ -14,13 +14,13 @@ warning: this arithmetic operation will overflow
   --> $DIR/promoted_errors.rs:14:14
    |
 LL |     let _x = 0u32 - 1;
-   |              ^^^^^^^^ attempt to subtract with overflow
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1 / (1 - 1));
-   |                    ^^^^^^^^^^^ attempt to divide by zero
+   |                    ^^^^^^^^^^^ attempt to divide 1_i32 by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:41
@@ -50,13 +50,13 @@ warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:20:14
    |
 LL |     let _x = 1 / (1 - 1);
-   |              ^^^^^^^^^^^ attempt to divide by zero
+   |              ^^^^^^^^^^^ attempt to divide 1_i32 by zero
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:22:20
    |
 LL |     println!("{}", 1 / (false as u32));
-   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
 
 warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:22:20
@@ -74,7 +74,7 @@ warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1 / (false as u32);
-   |              ^^^^^^^^^^^^^^^^^^ attempt to divide by zero
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
 
 warning: 10 warnings emitted
 
index c6fb5eeab5aec27816d7ebd66233bb5891ad45fd..d724fe3060b21b748998189dd2e68a9c14f30d75 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_raw_ptr_to_usize_cast, const_compare_raw_pointers, const_raw_ptr_deref)]
+#![feature(const_raw_ptr_to_usize_cast, const_raw_ptr_deref)]
 
 fn main() {
     let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
index 1f1dd203a640186dfe3c503c370e5fa313932e7a..ecdba2f1c506d60cccdb3980ce4fda8a37505b13 100644 (file)
@@ -4,7 +4,7 @@ warning: any use of this value will cause an error
 LL | pub const Z: u32 = 0 - 1;
    | -------------------^^^^^-
    |                    |
-   |                    attempt to subtract with overflow
+   |                    attempt to compute `0_u32 - 1_u32` which would overflow
    |
 note: the lint level is defined here
   --> $DIR/pub_const_err.rs:2:9
index 3ae0a11026f38bfcbf40794422134a18812d55a7..b2b65767dc05964ad7bb5439d830feb591d8d861 100644 (file)
@@ -4,7 +4,7 @@ warning: any use of this value will cause an error
 LL | pub const Z: u32 = 0 - 1;
    | -------------------^^^^^-
    |                    |
-   |                    attempt to subtract with overflow
+   |                    attempt to compute `0_u32 - 1_u32` which would overflow
    |
 note: the lint level is defined here
   --> $DIR/pub_const_err_bin.rs:2:9
index f4840e9ac96bd7235cf2f7dd4bf80f094857b614..478769ca9ffe1dc62dfa6aba0c93785c5451fd85 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/shift_overflow.rs:3:9
    |
 LL |     X = 1 << ((u32::MAX as u64) + 1),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left with overflow
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by 4294967296_u64 which would overflow
 
 error: aborting due to previous error
 
index e49fd3e0b970bd4ed7d2b5a92a57c3b0ceb44bf2..1f7593c6db9b6b25f66bd958265cf92a7ff1ff12 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:24:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum discriminant
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
@@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:42:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum discriminant
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
index 45e3cf438888e64344cd353c8e17054d09416e9d..6864f7247ad5f4e35840b29b37fd0290b2572255 100644 (file)
@@ -1,12 +1,11 @@
+// run-pass
+
 // Using labeled break in a while loop has caused an illegal instruction being
 // generated, and an ICE later.
 //
 // See https://github.com/rust-lang/rust/issues/51350 for more information.
-//
-// It is now forbidden by the HIR const-checker.
-//
-// See https://github.com/rust-lang/rust/pull/66170.
 
-const CRASH: () = 'a: while break 'a {}; //~ ERROR `while` is not allowed in a `const`
+#[allow(unreachable_code)]
+const _: () = 'a: while break 'a {};
 
 fn main() {}
diff --git a/src/test/ui/consts/const-labeled-break.stderr b/src/test/ui/consts/const-labeled-break.stderr
deleted file mode 100644 (file)
index ac845df..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/const-labeled-break.rs:10:19
-   |
-LL | const CRASH: () = 'a: while break 'a {};
-   |                   ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 150d3eb525d5ebebf9aacdf6dde28f92b9f8c8de..eff50587ca3411887fb34cd3c4a426be75cf5116 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL | const LEN: usize = ONE - TWO;
    | -------------------^^^^^^^^^-
    |                    |
-   |                    attempt to subtract with overflow
+   |                    attempt to compute `1_usize - 2_usize` which would overflow
    |
    = note: `#[deny(const_err)]` on by default
 
index 37f6ef1bd9d7e95207a8bc57e872f31905d7fe88..8ef8ef9625c81c7303cbcc49d4ff2dad485ca0ec 100644 (file)
@@ -7,5 +7,5 @@
 fn main() {
     let a: [i8; ONE - TWO] = unimplemented!();
     //~^ ERROR evaluation of constant value failed
-    //~| attempt to subtract with overflow
+    //~| attempt to compute `1_usize - 2_usize` which would overflow
 }
index 63bce1e2c831f1e3a85f1c73e7a0fdc88ea00f78..e52e64b25b6de3f838fa7406f79821e58f318ba4 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const-len-underflow-subspans.rs:8:17
    |
 LL |     let a: [i8; ONE - TWO] = unimplemented!();
-   |                 ^^^^^^^^^ attempt to subtract with overflow
+   |                 ^^^^^^^^^ attempt to compute `1_usize - 2_usize` which would overflow
 
 error: aborting due to previous error
 
index 12ba9cacabf7c333bd5e184b754134cb326f9cda..eb6b0774e152c42462ddf076226a6c1e482e2e51 100644 (file)
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:25:15
    |
 LL |     A = { let 0 = 0; 0 },
-   |               ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+   |               ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
index 2eed7abdc65701c99658a7c8aaf919e4eecd8b12..756426d84a47990faa5eb01cdfd9653bafdc4dff 100644 (file)
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:31:24
    |
 LL |     let x: [i32; { let 0 = 0; 0 }] = [];
-   |                        ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+   |                        ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
index 1fa0cb17fe66e6a8b53a5e0e5e78e5f039620a4f..84600bb1b8aadebb9a089ac090b5c66b85c76862 100644 (file)
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:4:22
    |
 LL | const X: i32 = { let 0 = 0; 0 };
-   |                      ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+   |                      ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL | const X: i32 = { if let 0 = 0 { /* */ } 0 };
    |                  ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:8:23
    |
 LL | static Y: i32 = { let 0 = 0; 0 };
-   |                       ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+   |                       ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -26,11 +26,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 };
    |                   ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:13:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
-   |                          ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+   |                          ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -40,11 +40,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL |     const X: i32 = { if let 0 = 0 { /* */ } 0 };
    |                      ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
   --> $DIR/const-match-check.rs:19:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
-   |                          ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered
+   |                          ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
index 0482f7f7daeab9db9b0df82c46961b40f9f638d5..90680c0194c554735b1cfd9043d5c7c7e020e96a 100644 (file)
@@ -1,12 +1,12 @@
-#![allow(warnings)]
+// check-pass
 
-const x: bool = match Some(true) { //~ ERROR `match` is not allowed in a `const`
+const _: bool = match Some(true) {
     Some(value) => true,
     _ => false
 };
 
-const y: bool = {
-    match Some(true) { //~ ERROR `match` is not allowed in a `const`
+const _: bool = {
+    match Some(true) {
         Some(value) => true,
         _ => false
     }
diff --git a/src/test/ui/consts/const-match-pattern-arm.stderr b/src/test/ui/consts/const-match-pattern-arm.stderr
deleted file mode 100644 (file)
index 412e160..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/const-match-pattern-arm.rs:3:17
-   |
-LL |   const x: bool = match Some(true) {
-   |  _________________^
-LL | |     Some(value) => true,
-LL | |     _ => false
-LL | | };
-   | |_^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/const-match-pattern-arm.rs:9:5
-   |
-LL | /     match Some(true) {
-LL | |         Some(value) => true,
-LL | |         _ => false
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index 5e2be0d4f3f02ee73be0731b934390bdbc4de1d2..18645efc8871505c7292ec1b4ad8ecab8dd1ac9a 100644 (file)
@@ -3,7 +3,7 @@
 
 const _: i32 = {
     let mut a = 5;
-    let p = &mut a; //~ ERROR references in constants may only refer to immutable values
+    let p = &mut a; //~ ERROR mutable references are not allowed in constants
 
     let reborrow = {p};
     let pp = &reborrow;
index e01dd4e574738c119dad431d325423da226d2c65..9a7914b458874a748167ebb0528fe2e14525539a 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/const-multi-ref.rs:6:13
    |
 LL |     let p = &mut a;
-   |             ^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |             ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
   --> $DIR/const-multi-ref.rs:16:13
@@ -15,5 +12,5 @@ LL |     let p = &a;
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0492, E0658.
+Some errors have detailed explanations: E0492, E0764.
 For more information about an error, try `rustc --explain E0492`.
index 130ba9283b1d97b9bfd2d65393779f4d3b40990b..5819daa817af04cce4c45d3f3991fb868072031d 100644 (file)
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(const_mut_refs)]
 #![feature(const_fn)]
 #![feature(raw_ref_op)]
@@ -24,7 +22,9 @@ const fn baz(foo: &mut Foo)-> *mut usize {
 
 const _: () = {
     foo().bar();
+    //~^ ERROR mutable references are not allowed in constants
     baz(&mut foo());
+    //~^ ERROR mutable references are not allowed in constants
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr b/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr
new file mode 100644 (file)
index 0000000..2214ce6
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_address_of.rs:24:5
+   |
+LL |     foo().bar();
+   |     ^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_address_of.rs:26:9
+   |
+LL |     baz(&mut foo());
+   |         ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0764`.
index 99006a20b1bcba56dfe6275b847724ea47185cc1..9099d5a1b8ea642367d3f713984c5013268ed8ab 100644 (file)
@@ -1,5 +1,3 @@
-// run-pass
-
 #![feature(const_mut_refs)]
 
 struct Foo {
@@ -31,6 +29,9 @@ const fn bazz(foo: &mut Foo) -> usize {
 
 fn main() {
     let _: [(); foo().bar()] = [(); 1];
+    //~^ ERROR mutable references are not allowed in constants
     let _: [(); baz(&mut foo())] = [(); 2];
+    //~^ ERROR mutable references are not allowed in constants
     let _: [(); bazz(&mut foo())] = [(); 3];
+    //~^ ERROR mutable references are not allowed in constants
 }
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr
new file mode 100644 (file)
index 0000000..4ca7b12
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_refs.rs:31:17
+   |
+LL |     let _: [(); foo().bar()] = [(); 1];
+   |                 ^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_refs.rs:33:21
+   |
+LL |     let _: [(); baz(&mut foo())] = [(); 2];
+   |                     ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_refs.rs:35:22
+   |
+LL |     let _: [(); bazz(&mut foo())] = [(); 3];
+   |                      ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0764`.
index 65f09eb80098c73c260f53aa75026a6bf35af121..2105c12a1680a7bbf49ddb55b3ffece7a2f196fd 100644 (file)
@@ -9,8 +9,8 @@ mod foo {
 const a: u8 = 2;
 
 fn main() {
-    let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX
-    let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX
-    let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX
+    let a = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
+    let c = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
+    let d = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
index bb2fdec72ba0dd6638b15ca2f9a92f39b2abe266..3e3bc1979a2e0e4c762965956d088172d0971318 100644 (file)
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:12:9
    |
 LL | const a: u8 = 2;
@@ -12,7 +12,7 @@ LL |     let a = 4;
    |
    = note: the matched value is of type `u8`
 
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:13:9
    |
 LL |     pub const b: u8 = 2;
@@ -26,7 +26,7 @@ LL |     let c = 4;
    |
    = note: the matched value is of type `u8`
 
-error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
   --> $DIR/const-pattern-irrefutable.rs:14:9
    |
 LL |     pub const d: u8 = 2;
diff --git a/src/test/ui/consts/const-variant-count.rs b/src/test/ui/consts/const-variant-count.rs
new file mode 100644 (file)
index 0000000..455419d
--- /dev/null
@@ -0,0 +1,47 @@
+// run-pass
+#![allow(dead_code)]
+#![feature(variant_count)]
+#![feature(never_type)]
+
+use std::mem::variant_count;
+
+enum Void {}
+
+enum Foo {
+    A,
+    B,
+    C,
+}
+
+enum Bar {
+    A,
+    B,
+    C,
+    D(usize),
+    E { field_1: usize, field_2: Foo },
+}
+
+struct Baz {
+    a: u32,
+    b: *const u8,
+}
+
+const TEST_VOID: usize = variant_count::<Void>();
+const TEST_FOO: usize = variant_count::<Foo>();
+const TEST_BAR: usize = variant_count::<Bar>();
+
+const NO_ICE_STRUCT: usize = variant_count::<Baz>();
+const NO_ICE_BOOL: usize = variant_count::<bool>();
+const NO_ICE_PRIM: usize = variant_count::<*const u8>();
+
+fn main() {
+    assert_eq!(TEST_VOID, 0);
+    assert_eq!(TEST_FOO, 3);
+    assert_eq!(TEST_BAR, 5);
+    assert_eq!(variant_count::<Void>(), 0);
+    assert_eq!(variant_count::<Foo>(), 3);
+    assert_eq!(variant_count::<Bar>(), 5);
+    assert_eq!(variant_count::<Option<char>>(), 2);
+    assert_eq!(variant_count::<Option<!>>(), 2);
+    assert_eq!(variant_count::<Result<!, !>>(), 2);
+}
index 81a2024a81b7bc5a07f75db8e17fc0f9e7d4988a..a38731ceb8a860995727c9ef926454e75410b905 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(const_if_match)]
 #![warn(indirect_structural_match)]
 
 struct CustomEq;
index 21c4de6fbb1f1d9f57bbb0393f92e84c0a715f6c..a1f9838ca088573ba7c595c2e7ac0512cdfacbfc 100644 (file)
@@ -1,6 +1,5 @@
 // check-pass
 
-#![feature(const_if_match)]
 #![warn(indirect_structural_match)]
 //~^ NOTE lint level is defined here
 
index 06ec2a7fdd35c963e453cb22baa3f18f4fcb0789..0be1cca806ed1bedcbbe6794a7c4e42796063501 100644 (file)
@@ -1,11 +1,11 @@
 warning: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/custom-eq-branch-warn.rs:33:9
+  --> $DIR/custom-eq-branch-warn.rs:32:9
    |
 LL |         BAR_BAZ => panic!(),
    |         ^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/custom-eq-branch-warn.rs:4:9
+  --> $DIR/custom-eq-branch-warn.rs:3:9
    |
 LL | #![warn(indirect_structural_match)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/const_in_pattern/issue-73431.rs b/src/test/ui/consts/const_in_pattern/issue-73431.rs
new file mode 100644 (file)
index 0000000..fa18a3a
--- /dev/null
@@ -0,0 +1,29 @@
+// run-pass
+
+// Regression test for https://github.com/rust-lang/rust/issues/73431.
+
+pub trait Zero {
+    const ZERO: Self;
+}
+
+impl Zero for usize {
+    const ZERO: Self = 0;
+}
+
+impl<T: Zero> Zero for Wrapper<T> {
+    const ZERO: Self = Wrapper(T::ZERO);
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct Wrapper<T>(T);
+
+fn is_zero(x: Wrapper<usize>) -> bool {
+    match x {
+        Zero::ZERO => true,
+        _ => false,
+    }
+}
+
+fn main() {
+    let _ = is_zero(Wrapper(42));
+}
index 28b3fbb952563fc5168999c067ebfd64eaf3a2e1..c7f02c615a02a75bff67836a40bed0a5e0309fff 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_if_match)]
 #![warn(indirect_structural_match)]
 
 struct NoEq;
index cb870ec7dbcf2738013ecd9d8886442811f676df..ee78c6f5c3e9f9206b603857e0372ed5d104027d 100644 (file)
@@ -1,11 +1,11 @@
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/no-eq-branch-fail.rs:22:9
+  --> $DIR/no-eq-branch-fail.rs:21:9
    |
 LL |         BAR_BAZ => panic!(),
    |         ^^^^^^^
 
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/no-eq-branch-fail.rs:22:9
+  --> $DIR/no-eq-branch-fail.rs:21:9
    |
 LL |         BAR_BAZ => panic!(),
    |         ^^^^^^^
index cbe73923e9c424b961abec029bb092733899827f..f993a427b4899dbf591ac718ace8bd7553f3ae79 100644 (file)
@@ -13,14 +13,14 @@ const fn foo(&mut self, x: u32) {
 
 const FOO: S = {
     let mut s = S { state: 42 };
-    s.foo(3); //~ ERROR references in constants may only refer to immutable values
+    s.foo(3); //~ ERROR mutable references are not allowed in constants
     s
 };
 
 type Array = [u32; {
     let mut x = 2;
     let y = &mut x;
-//~^ ERROR references in constants may only refer to immutable values
+//~^ ERROR mutable references are not allowed in constants
     *y = 42;
 //~^ ERROR constant contains unimplemented expression type
     *y
index 62fd04ea522c3326e626b90b399a248e9b1b4f3d..dd05a4c0bb069c9ff3184829fb0aea8990fb3954 100644 (file)
@@ -6,23 +6,17 @@ LL |         self.state = x;
    |
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/const_let_assign3.rs:16:5
    |
 LL |     s.foo(3);
-   |     ^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |     ^ `&mut` is only allowed in `const fn`
 
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/const_let_assign3.rs:22:13
    |
 LL |     let y = &mut x;
-   |             ^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |             ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0019]: constant contains unimplemented expression type
   --> $DIR/const_let_assign3.rs:24:5
@@ -34,5 +28,5 @@ LL |     *y = 42;
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0019, E0658.
+Some errors have detailed explanations: E0019, E0764.
 For more information about an error, try `rustc --explain E0019`.
index e49d47673912a29c8f678d936ecfb5f85f78ae26..efb134d2eef1ad5049c235ca0ff318bd26e65eb5 100644 (file)
@@ -2,6 +2,5 @@ fn main() {}
 
 const fn slice(&[a, b]: &[i32]) -> i32 {
     //~^ ERROR refutable pattern in function argument
-    //~| ERROR loops and conditional expressions are not stable in const fn
     a + b
 }
index 02296e6de75fcced3c8760c439f45a82ec7cde18..d7e8c048f7dcce7ae8ad7c4b4a7f10f1707ee29e 100644 (file)
@@ -6,16 +6,6 @@ LL | const fn slice(&[a, b]: &[i32]) -> i32 {
    |
    = note: the matched value is of type `&[i32]`
 
-error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/const_let_refutable.rs:3:17
-   |
-LL | const fn slice(&[a, b]: &[i32]) -> i32 {
-   |                 ^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0005, E0723.
-For more information about an error, try `rustc --explain E0005`.
+For more information about this error, try `rustc --explain E0005`.
index 34abcdf08dae0e2cf6159f5a3af2e04ae2b8b79a..629d1f02a30f3d88f4db73470e3b0289a80fe3a4 100644 (file)
@@ -1,7 +1,6 @@
 // check-pass
 
 #![feature(const_eval_limit)]
-#![feature(const_loop, const_if_match)]
 
 // This needs to be higher than the number of loop iterations since each pass through the loop may
 // hit more than one terminator.
index b45aca0b13e42f51a1f2f7299555cfdb76530cab..069dac00c9ace7c1b605e0433037e8e4fc41adeb 100644 (file)
@@ -1,7 +1,5 @@
 #![feature(const_eval_limit)]
-#![feature(const_loop, const_if_match)]
-
-#![const_eval_limit="500"]
+#![const_eval_limit = "500"]
 
 const X: usize = {
     let mut x = 0;
index 8c2190b4e591f87624bbed87cd95288ffe9bfba9..8785c9e54b9bfef14162fd8f2693a08c3f28dc0e 100644 (file)
@@ -1,5 +1,5 @@
 error: any use of this value will cause an error
-  --> $DIR/const_eval_limit_reached.rs:8:5
+  --> $DIR/const_eval_limit_reached.rs:6:5
    |
 LL |  / const X: usize = {
 LL |  |     let mut x = 0;
index 87b14a1117805a6f985eef716664e959219fc86a..6403fbb17dd58ded8f5781992effcee065ba970a 100644 (file)
@@ -1,13 +1,13 @@
+// check-pass
+
 const _: bool = false && false;
 const _: bool = true && false;
 const _: bool = {
     let mut x = true && false;
-    //~^ ERROR new features like let bindings are not permitted
     x
 };
 const _: bool = {
     let x = true && false;
-    //~^ ERROR new features like let bindings are not permitted
     x
 };
 
diff --git a/src/test/ui/consts/const_short_circuit.stderr b/src/test/ui/consts/const_short_circuit.stderr
deleted file mode 100644 (file)
index b020382..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-error: new features like let bindings are not permitted in constants which also use short circuiting operators
-  --> $DIR/const_short_circuit.rs:4:9
-   |
-LL |     let mut x = true && false;
-   |         ^^^^^
-   |
-note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information.
-  --> $DIR/const_short_circuit.rs:4:22
-   |
-LL |     let mut x = true && false;
-   |                      ^^
-
-error: new features like let bindings are not permitted in constants which also use short circuiting operators
-  --> $DIR/const_short_circuit.rs:9:9
-   |
-LL |     let x = true && false;
-   |         ^
-   |
-note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information.
-  --> $DIR/const_short_circuit.rs:9:18
-   |
-LL |     let x = true && false;
-   |                  ^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/consts/control-flow/assert.both.stderr b/src/test/ui/consts/control-flow/assert.both.stderr
deleted file mode 100644 (file)
index 7dd60cf..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/assert.rs:12:15
-   |
-LL | const _: () = assert!(false);
-   | --------------^^^^^^^^^^^^^^-
-   |               |
-   |               the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:12:15
-   |
-   = note: `#[deny(const_err)]` on by default
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/consts/control-flow/assert.if_match.stderr b/src/test/ui/consts/control-flow/assert.if_match.stderr
deleted file mode 100644 (file)
index 466fb7c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: panicking in constants is unstable
-  --> $DIR/assert.rs:8:15
-   |
-LL | const _: () = assert!(true);
-   |               ^^^^^^^^^^^^^
-   |
-   = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
-   = help: add `#![feature(const_panic)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: panicking in constants is unstable
-  --> $DIR/assert.rs:12:15
-   |
-LL | const _: () = assert!(false);
-   |               ^^^^^^^^^^^^^^
-   |
-   = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
-   = help: add `#![feature(const_panic)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index eafbdd84cc86ca0f0d8a98d305d04223696e8c5e..03662a352090927a1e25d7504c08c43e7bcfd029 100644 (file)
@@ -1,23 +1,13 @@
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/assert.rs:8:15
-   |
-LL | const _: () = assert!(true);
-   |               ^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/assert.rs:12:15
+error: any use of this value will cause an error
+  --> $DIR/assert.rs:10:15
    |
 LL | const _: () = assert!(false);
-   |               ^^^^^^^^^^^^^^
+   | --------------^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15
    |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: `#[deny(const_err)]` on by default
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
index 2da42d5084bc1737473c533fb5e2057cb56a2c2f..30cd31ee8a734bcb9eea457e8f8d6c7be06d61d7 100644 (file)
@@ -1,17 +1,14 @@
-// Test that `assert` works only when both `const_if_match` and `const_panic` are enabled.
+// Test that `assert` works when `const_panic` is enabled.
 
-// revisions: stock if_match panic both
+// revisions: stock panic
 
-#![cfg_attr(any(both, if_match), feature(const_if_match))]
-#![cfg_attr(any(both, panic), feature(const_panic))]
+#![cfg_attr(panic, feature(const_panic))]
 
 const _: () = assert!(true);
-//[stock,panic]~^ ERROR `if` is not allowed in a `const`
-//[if_match]~^^ ERROR panicking in constants is unstable
+//[stock]~^ ERROR panicking in constants is unstable
 
 const _: () = assert!(false);
-//[stock,panic]~^ ERROR `if` is not allowed in a `const`
-//[if_match]~^^ ERROR panicking in constants is unstable
-//[both]~^^^ ERROR any use of this value will cause an error
+//[stock]~^ ERROR panicking in constants is unstable
+//[panic]~^^ ERROR any use of this value will cause an error
 
 fn main() {}
index eafbdd84cc86ca0f0d8a98d305d04223696e8c5e..fd344533ce10fe4f19677982f9d81fd0de0897ba 100644 (file)
@@ -1,21 +1,21 @@
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/assert.rs:8:15
+error[E0658]: panicking in constants is unstable
+  --> $DIR/assert.rs:7:15
    |
 LL | const _: () = assert!(true);
    |               ^^^^^^^^^^^^^
    |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
+   = help: add `#![feature(const_panic)]` to the crate attributes to enable
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/assert.rs:12:15
+error[E0658]: panicking in constants is unstable
+  --> $DIR/assert.rs:10:15
    |
 LL | const _: () = assert!(false);
    |               ^^^^^^^^^^^^^^
    |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: see issue #51999 <https://github.com/rust-lang/rust/issues/51999> for more information
+   = help: add `#![feature(const_panic)]` to the crate attributes to enable
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
index a53293743d522d1ed72336ab91b11881773ffcb6..6dd6192941d384dba861e54fd0c76f9a22410a9e 100644 (file)
@@ -3,8 +3,6 @@
 // run-pass
 
 #![feature(const_panic)]
-#![feature(const_if_match)]
-#![feature(const_loop)]
 #![feature(const_fn)]
 
 const X: u32 = 4;
index b4b6be8a1e5f0c9ff37c94d45897f0259939ca7b..0b0b2443a4a464a3d2c43b64de9b70377b7d3461 100644 (file)
@@ -1,11 +1,11 @@
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-fail.rs:10:9
+  --> $DIR/drop-fail.rs:8:9
    |
 LL |     let x = Some(Vec::new());
    |         ^ constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-fail.rs:41:9
+  --> $DIR/drop-fail.rs:39:9
    |
 LL |     let mut tmp = None;
    |         ^^^^^^^ constants cannot evaluate destructors
index 7bd36726cead54238f57dc37ab308bc80765242b..efa5a11c941e9158f20242450fc66386a4dd31e4 100644 (file)
@@ -1,7 +1,5 @@
 // revisions: stock precise
 
-#![feature(const_if_match)]
-#![feature(const_loop)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
 
 // `x` is *not* always moved into the final value and may be dropped inside the initializer.
index 77cded5c438b5896b0bf4636bce6747da3b8a0bf..72ca4fa08bc4ee8f0e5d097c655865f961a6c1ad 100644 (file)
@@ -1,26 +1,38 @@
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-fail.rs:10:9
+  --> $DIR/drop-fail.rs:8:9
    |
 LL |     let x = Some(Vec::new());
    |         ^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-fail.rs:23:9
+  --> $DIR/drop-fail.rs:21:9
    |
 LL |     let vec_tuple = (Vec::new(),);
    |         ^^^^^^^^^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-fail.rs:31:9
+  --> $DIR/drop-fail.rs:29:9
    |
 LL |     let x: Result<_, Vec<i32>> = Ok(Vec::new());
    |         ^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-fail.rs:41:9
+  --> $DIR/drop-fail.rs:39:9
    |
 LL |     let mut tmp = None;
    |         ^^^^^^^ constants cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
 
 error: aborting due to 4 previous errors
 
index b0afd76c4e6ef9aae0eb15661543d014c5eda31d..95f954a59a8ddf3a2303d04e0a016deb2347725e 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // revisions: stock precise
 
-#![feature(const_if_match)]
-#![feature(const_loop)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
 
 // `x` is always moved into the final value and is not dropped inside the initializer.
index 95df76d9905546bf81f703cfdc61871c3cb960cc..4ecc5ef78dd5ccbd8d2aac5c492e01e7f457b613 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // gate-test-const_precise_live_drops
 
-#![feature(const_if_match)]
-#![feature(const_loop)]
 #![feature(const_precise_live_drops)]
 
 const _: Vec<i32> = {
index 6bbbdd972a26c102b243a275b71352ed823d4815..4320133dfdbcc8a4709dcc8de70f6071fd32054d 100644 (file)
@@ -2,8 +2,6 @@
 
 // check-pass
 
-#![feature(const_if_match)]
-
 enum E {
     A,
     B,
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
deleted file mode 100644 (file)
index 21e3f2a..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate-const-if-match.rs:108:1
-   |
-LL | / fn main() {
-LL | |     let _ = [0; {
-LL | |         let x = if false { 0 } else { 1 };
-LL | |
-...  |
-LL | |     }];
-LL | | }
-   | |_^
-
-error: aborting due to previous error
-
index c49dd830a12e87b04c12f37fa56ed9d13388a448..cb66bc75309b63447612744c4a239e29380f01e0 100644 (file)
@@ -1,25 +1,10 @@
-// Ensure that `if`, `if let` and `match` are only allowed in the various const contexts when
-// `#![feature(const_if_match)]` is enabled. When the feature gate is removed, the `#[rustc_error]`
-// on `main` should be removed and this test converted to `check-pass`.
+// check-pass
 
-// revisions: stock if_match
+const _: i32 = if true { 5 } else { 6 };
 
-#![feature(rustc_attrs)]
-#![cfg_attr(if_match, feature(const_if_match))]
+const _: i32 = if let Some(true) = Some(false) { 0 } else { 1 };
 
-const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
-    5
-} else {
-    6
-};
-
-const _: i32 = if let Some(true) = Some(false) { //[stock]~ ERROR `if` is not allowed in a `const`
-    0
-} else {
-    1
-};
-
-const _: i32 = match 1 { //[stock]~ ERROR `match` is not allowed in a `const`
+const _: i32 = match 1 {
     2 => 3,
     4 => 5,
     _ => 0,
 
 static FOO: i32 = {
     let x = if true { 0 } else { 1 };
-    //[stock]~^ ERROR `if` is not allowed in a `static`
-    let x = match x { 0 => 1, _ => 0 };
-    //[stock]~^ ERROR `match` is not allowed in a `static`
+    let x = match x {
+        0 => 1,
+        _ => 0,
+    };
     if let Some(x) = Some(x) { x } else { 1 }
-    //[stock]~^ ERROR `if` is not allowed in a `static`
 };
 
 static mut BAR: i32 = {
     let x = if true { 0 } else { 1 };
-    //[stock]~^ ERROR `if` is not allowed in a `static mut`
-    let x = match x { 0 => 1, _ => 0 };
-    //[stock]~^ ERROR `match` is not allowed in a `static mut`
+    let x = match x {
+        0 => 1,
+        _ => 0,
+    };
     if let Some(x) = Some(x) { x } else { 1 }
-    //[stock]~^ ERROR `if` is not allowed in a `static mut`
 };
 
 const fn if_() -> i32 {
-    if true { 5 } else { 6 } //[stock]~ ERROR `if` is not allowed in a `const fn`
+    if true { 5 } else { 6 }
 }
 
 const fn if_let(a: Option<bool>) -> i32 {
-    if let Some(true) = a { //[stock]~ ERROR `if` is not allowed in a `const fn`
-        0
-    } else {
-        1
-    }
+    if let Some(true) = a { 0 } else { 1 }
 }
 
 const fn match_(i: i32) -> i32 {
-    match i { //[stock]~ ERROR `match` is not allowed in a `const fn`
+    match i {
         i if i > 10 => i,
         1 => 2,
-        _ => 0
+        _ => 0,
     }
 }
 
 pub trait Foo {
     const IF: i32 = if true { 5 } else { 6 };
-    //[stock]~^ ERROR `if` is not allowed in a `const`
-
     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
-    //[stock]~^ ERROR `if` is not allowed in a `const`
-
-    const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
-    //[stock]~^ ERROR `match` is not allowed in a `const`
+    const MATCH: i32 = match 0 {
+        1 => 2,
+        _ => 0,
+    };
 }
 
 impl Foo for () {
     const IF: i32 = if true { 5 } else { 6 };
-    //[stock]~^ ERROR `if` is not allowed in a `const`
-
     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
-    //[stock]~^ ERROR `if` is not allowed in a `const`
-
-    const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
-    //[stock]~^ ERROR `match` is not allowed in a `const`
+    const MATCH: i32 = match 0 {
+        1 => 2,
+        _ => 0,
+    };
 }
 
 fn non_const_outside() {
     const fn const_inside(y: bool) -> i32 {
         let x = if y { 0 } else { 1 };
-        //[stock]~^ ERROR `if` is not allowed in a `const fn`
-        let x = match x { 0 => 1, _ => 0 };
-        //[stock]~^ ERROR `match` is not allowed in a `const fn`
+        let x = match x {
+            0 => 1,
+            _ => 0,
+        };
         if let Some(x) = Some(x) { x } else { 1 }
-        //[stock]~^ ERROR `if` is not allowed in a `const fn`
     }
 }
 
 const fn const_outside() {
     fn non_const_inside(y: bool) -> i32 {
         let x = if y { 0 } else { 1 };
-        let x = match x { 0 => 1, _ => 0 };
+        let x = match x {
+            0 => 1,
+            _ => 0,
+        };
         if let Some(x) = Some(x) { x } else { 1 }
     }
 }
 
-#[rustc_error]
-fn main() { //[if_match]~ ERROR fatal error triggered by #[rustc_error]
+fn main() {
     let _ = [0; {
         let x = if false { 0 } else { 1 };
-        //[stock]~^ ERROR `if` is not allowed in a `const`
-        let x = match x { 0 => 1, _ => 0 };
-        //[stock]~^ ERROR `match` is not allowed in a `const`
+        let x = match x {
+            0 => 1,
+            _ => 0,
+        };
         if let Some(x) = Some(x) { x } else { 1 }
-        //[stock]~^ ERROR `if` is not allowed in a `const`
     }];
 }
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
deleted file mode 100644 (file)
index b27971d..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:10:16
-   |
-LL |   const _: i32 = if true {
-   |  ________________^
-LL | |     5
-LL | | } else {
-LL | |     6
-LL | | };
-   | |_^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:16:16
-   |
-LL |   const _: i32 = if let Some(true) = Some(false) {
-   |  ________________^
-LL | |     0
-LL | | } else {
-LL | |     1
-LL | | };
-   | |_^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:22:16
-   |
-LL |   const _: i32 = match 1 {
-   |  ________________^
-LL | |     2 => 3,
-LL | |     4 => 5,
-LL | |     _ => 0,
-LL | | };
-   | |_^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:29:13
-   |
-LL |     let x = if true { 0 } else { 1 };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:31:13
-   |
-LL |     let x = match x { 0 => 1, _ => 0 };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:33:5
-   |
-LL |     if let Some(x) = Some(x) { x } else { 1 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:38:13
-   |
-LL |     let x = if true { 0 } else { 1 };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:40:13
-   |
-LL |     let x = match x { 0 => 1, _ => 0 };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:42:5
-   |
-LL |     if let Some(x) = Some(x) { x } else { 1 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:47:5
-   |
-LL |     if true { 5 } else { 6 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:51:5
-   |
-LL | /     if let Some(true) = a {
-LL | |         0
-LL | |     } else {
-LL | |         1
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:59:5
-   |
-LL | /     match i {
-LL | |         i if i > 10 => i,
-LL | |         1 => 2,
-LL | |         _ => 0
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:90:17
-   |
-LL |         let x = if y { 0 } else { 1 };
-   |                 ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:92:17
-   |
-LL |         let x = match x { 0 => 1, _ => 0 };
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:94:9
-   |
-LL |         if let Some(x) = Some(x) { x } else { 1 }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:110:17
-   |
-LL |         let x = if false { 0 } else { 1 };
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:112:17
-   |
-LL |         let x = match x { 0 => 1, _ => 0 };
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:114:9
-   |
-LL |         if let Some(x) = Some(x) { x } else { 1 }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:67:21
-   |
-LL |     const IF: i32 = if true { 5 } else { 6 };
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:70:25
-   |
-LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:73:24
-   |
-LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:78:21
-   |
-LL |     const IF: i32 = if true { 5 } else { 6 };
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:81:25
-   |
-LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = 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:84:24
-   |
-LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to 24 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index c2439f4a7bff31c697b132fca970c463038dc823..a6d44237b0d98436e580426b0922470e961eb42e 100644 (file)
@@ -1,9 +1,6 @@
 // Ensure that *any* assignment to the return place of a value with interior mutability
 // disqualifies it from promotion.
 
-#![feature(const_if_match)]
-#![feature(const_loop)]
-
 use std::cell::Cell;
 
 const X: Option<Cell<i32>> = {
@@ -39,7 +36,6 @@
     z
 };
 
-
 fn main() {
     let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed
     let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed
index 0977c84d12d8a7505f222ae6dad0eeeabfeacd50..4f9c7d34c35f4fc5db581d76698446d4bdc99a28 100644 (file)
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/interior-mutability.rs:44:26
+  --> $DIR/interior-mutability.rs:40:26
    |
 LL |     let x: &'static _ = &X;
    |            ----------    ^ creates a temporary which is freed while still in use
@@ -10,7 +10,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/interior-mutability.rs:45:26
+  --> $DIR/interior-mutability.rs:41:26
    |
 LL |     let y: &'static _ = &Y;
    |            ----------    ^ creates a temporary which is freed while still in use
@@ -21,7 +21,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/interior-mutability.rs:46:26
+  --> $DIR/interior-mutability.rs:42:26
    |
 LL |     let z: &'static _ = &Z;
    |            ----------    ^ creates a temporary which is freed while still in use
diff --git a/src/test/ui/consts/control-flow/issue-46843.if_match.stderr b/src/test/ui/consts/control-flow/issue-46843.if_match.stderr
deleted file mode 100644 (file)
index 4c64d7d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/issue-46843.rs:11:26
-   |
-LL | pub const Q: i32 = match non_const() {
-   |                          ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0015`.
index 1fc91015ffa702351cd0e8eb345c3f17236e88cf..edf62f23266193b667da1d761005cd65908943de 100644 (file)
@@ -1,16 +1,14 @@
-// revisions: stock if_match
-
-#![cfg_attr(if_match, feature(const_if_match))]
-
-enum Thing { This, That }
+enum Thing {
+    This,
+    That,
+}
 
 fn non_const() -> Thing {
     Thing::This
 }
 
 pub const Q: i32 = match non_const() {
-    //[stock]~^ ERROR `match` is not allowed in a `const`
-    //[if_match]~^^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR calls in constants are limited to constant functions
     Thing::This => 1,
     Thing::That => 0
 };
diff --git a/src/test/ui/consts/control-flow/issue-46843.stderr b/src/test/ui/consts/control-flow/issue-46843.stderr
new file mode 100644 (file)
index 0000000..ea9ea25
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-46843.rs:10:26
+   |
+LL | pub const Q: i32 = match non_const() {
+   |                          ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/control-flow/issue-46843.stock.stderr b/src/test/ui/consts/control-flow/issue-46843.stock.stderr
deleted file mode 100644 (file)
index e4650da..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/issue-46843.rs:11:20
-   |
-LL |   pub const Q: i32 = match non_const() {
-   |  ____________________^
-LL | |
-LL | |
-LL | |     Thing::This => 1,
-LL | |     Thing::That => 0
-LL | | };
-   | |_^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/issue-50577.if_match.stderr b/src/test/ui/consts/control-flow/issue-50577.if_match.stderr
deleted file mode 100644 (file)
index 831360d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0317]: `if` may be missing an `else` clause
-  --> $DIR/issue-50577.rs:7:16
-   |
-LL |         Drop = assert_eq!(1, 1)
-   |                ^^^^^^^^^^^^^^^^
-   |                |
-   |                expected `()`, found `isize`
-   |                found here
-   |
-   = note: `if` expressions without `else` evaluate to `()`
-   = help: consider adding an `else` block that evaluates to the expected type
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0317`.
index 9600f8b6aeeab8fda71d7cb3a21d2a922b164717..beb9a44fca52d28b49094cc850e5ce57dc1f67ff 100644 (file)
@@ -1,13 +1,6 @@
-// revisions: stock if_match
-
-#![cfg_attr(if_match, feature(const_if_match))]
-
 fn main() {
     enum Foo {
-        Drop = assert_eq!(1, 1)
-        //[stock,if_match]~^ ERROR `if` may be missing an `else` clause
-        //[stock]~^^ ERROR `match` is not allowed in a `const`
-        //[stock]~| ERROR `match` is not allowed in a `const`
-        //[stock]~| ERROR `if` is not allowed in a `const`
+        Drop = assert_eq!(1, 1),
+        //~^ ERROR `if` may be missing an `else` clause
     }
 }
diff --git a/src/test/ui/consts/control-flow/issue-50577.stderr b/src/test/ui/consts/control-flow/issue-50577.stderr
new file mode 100644 (file)
index 0000000..b7b4c3a
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0317]: `if` may be missing an `else` clause
+  --> $DIR/issue-50577.rs:3:16
+   |
+LL |         Drop = assert_eq!(1, 1),
+   |                ^^^^^^^^^^^^^^^^
+   |                |
+   |                expected `()`, found `isize`
+   |                found here
+   |
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0317`.
diff --git a/src/test/ui/consts/control-flow/issue-50577.stock.stderr b/src/test/ui/consts/control-flow/issue-50577.stock.stderr
deleted file mode 100644 (file)
index 9d0d283..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/issue-50577.rs:7:16
-   |
-LL |         Drop = assert_eq!(1, 1)
-   |                ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/issue-50577.rs:7:16
-   |
-LL |         Drop = assert_eq!(1, 1)
-   |                ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/issue-50577.rs:7:16
-   |
-LL |         Drop = assert_eq!(1, 1)
-   |                ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0317]: `if` may be missing an `else` clause
-  --> $DIR/issue-50577.rs:7:16
-   |
-LL |         Drop = assert_eq!(1, 1)
-   |                ^^^^^^^^^^^^^^^^
-   |                |
-   |                expected `()`, found `isize`
-   |                found here
-   |
-   = note: `if` expressions without `else` evaluate to `()`
-   = help: consider adding an `else` block that evaluates to the expected type
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0317, E0658.
-For more information about an error, try `rustc --explain E0317`.
diff --git a/src/test/ui/consts/control-flow/loop.both.stderr b/src/test/ui/consts/control-flow/loop.both.stderr
deleted file mode 100644 (file)
index 71d96b2..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:63:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:67:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/control-flow/loop.if_match.stderr b/src/test/ui/consts/control-flow/loop.if_match.stderr
deleted file mode 100644 (file)
index e8ff362..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:10:15
-   |
-LL | const _: () = loop {};
-   |               ^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `static`
-  --> $DIR/loop.rs:12:19
-   |
-LL | static FOO: i32 = loop { break 4; };
-   |                   ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:15:5
-   |
-LL |     loop {}
-   |     ^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:28:9
-   |
-LL |         loop {}
-   |         ^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:40:9
-   |
-LL |         while false {}
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:49:5
-   |
-LL | /     while x < 4 {
-LL | |         x += 1;
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:53:5
-   |
-LL | /     while x < 8 {
-LL | |         x += 1;
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:63:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:67:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:77:5
-   |
-LL | /     loop {
-LL | |         x += 1;
-LL | |         if x == 4 {
-LL | |             break;
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:84:5
-   |
-LL | /     loop {
-LL | |         x += 1;
-LL | |         if x == 8 {
-LL | |             break;
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:96:5
-   |
-LL |     while let None = Some(x) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:97:5
-   |
-LL |     while let None = Some(x) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:19:22
-   |
-LL |     const BAR: i32 = loop { break 4; };
-   |                      ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:23:22
-   |
-LL |     const BAR: i32 = loop { break 4; };
-   |                      ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to 15 previous errors
-
-Some errors have detailed explanations: E0658, E0744.
-For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/loop.loop_.stderr b/src/test/ui/consts/control-flow/loop.loop_.stderr
deleted file mode 100644 (file)
index 3d739f4..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:40:9
-   |
-LL |         while false {}
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:49:5
-   |
-LL | /     while x < 4 {
-LL | |         x += 1;
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:53:5
-   |
-LL | /     while x < 8 {
-LL | |         x += 1;
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:63:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:67:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:79:9
-   |
-LL | /         if x == 4 {
-LL | |             break;
-LL | |         }
-   | |_________^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:86:9
-   |
-LL | /         if x == 8 {
-LL | |             break;
-LL | |         }
-   | |_________^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:96:5
-   |
-LL |     while let None = Some(x) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:97:5
-   |
-LL |     while let None = Some(x) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
-
-error: aborting due to 9 previous errors
-
-Some errors have detailed explanations: E0658, E0744.
-For more information about an error, try `rustc --explain E0658`.
index bc57f7568a70aca5fc18598221df853e7cbafa51..2b8561a2644888486e4cf3648bd54b2405e3d3cc 100644 (file)
@@ -1,31 +1,22 @@
-// Ensure that loops are forbidden in a const context unless `#![feature(const_loop)]` is enabled.
-// `while` loops require `#![feature(const_if_match)]` to be enabled as well.
+const _: () = loop { break (); };
 
-// gate-test-const_loop
-// revisions: stock if_match loop_ both
-
-#![cfg_attr(any(both, if_match), feature(const_if_match))]
-#![cfg_attr(any(both, loop_), feature(const_loop))]
-
-const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
-
-static FOO: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `static`
+static FOO: i32 = loop { break 4; };
 
 const fn foo() {
-    loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
+    loop {}
 }
 
 pub trait Foo {
-    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+    const BAR: i32 = loop { break 4; };
 }
 
 impl Foo for () {
-    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+    const BAR: i32 = loop { break 4; };
 }
 
 fn non_const_outside() {
     const fn const_inside() {
-        loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
+        loop {}
     }
 }
 
@@ -38,7 +29,6 @@ fn non_const_inside() {
 fn main() {
     let x = [0; {
         while false {}
-        //[stock,if_match,loop_]~^ ERROR `while` is not allowed in a `const`
         4
     }];
 }
@@ -46,11 +36,11 @@ fn main() {
 const _: i32 = {
     let mut x = 0;
 
-    while x < 4 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+    while x < 4 {
         x += 1;
     }
 
-    while x < 8 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+    while x < 8 {
         x += 1;
     }
 
@@ -60,11 +50,11 @@ fn main() {
 const _: i32 = {
     let mut x = 0;
 
-    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
+    for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
         x += i;
     }
 
-    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
+    for i in 0..4 { //~ ERROR `for` is not allowed in a `const`
         x += i;
     }
 
@@ -74,16 +64,16 @@ fn main() {
 const _: i32 = {
     let mut x = 0;
 
-    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+    loop {
         x += 1;
-        if x == 4 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
+        if x == 4 {
             break;
         }
     }
 
-    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
+    loop {
         x += 1;
-        if x == 8 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
+        if x == 8 {
             break;
         }
     }
@@ -93,7 +83,7 @@ fn main() {
 
 const _: i32 = {
     let mut x = 0;
-    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
-    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+    while let None = Some(x) { }
+    while let None = Some(x) { }
     x
 };
diff --git a/src/test/ui/consts/control-flow/loop.stderr b/src/test/ui/consts/control-flow/loop.stderr
new file mode 100644 (file)
index 0000000..7b99fa4
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:53:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:57:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/control-flow/loop.stock.stderr b/src/test/ui/consts/control-flow/loop.stock.stderr
deleted file mode 100644 (file)
index 987ced9..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:10:15
-   |
-LL | const _: () = loop {};
-   |               ^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `static`
-  --> $DIR/loop.rs:12:19
-   |
-LL | static FOO: i32 = loop { break 4; };
-   |                   ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:15:5
-   |
-LL |     loop {}
-   |     ^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:28:9
-   |
-LL |         loop {}
-   |         ^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:40:9
-   |
-LL |         while false {}
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:49:5
-   |
-LL | /     while x < 4 {
-LL | |         x += 1;
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:53:5
-   |
-LL | /     while x < 8 {
-LL | |         x += 1;
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:63:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:67:5
-   |
-LL | /     for i in 0..4 {
-LL | |         x += i;
-LL | |     }
-   | |_____^
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:77:5
-   |
-LL | /     loop {
-LL | |         x += 1;
-LL | |         if x == 4 {
-LL | |             break;
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:79:9
-   |
-LL | /         if x == 4 {
-LL | |             break;
-LL | |         }
-   | |_________^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:84:5
-   |
-LL | /     loop {
-LL | |         x += 1;
-LL | |         if x == 8 {
-LL | |             break;
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:86:9
-   |
-LL | /         if x == 8 {
-LL | |             break;
-LL | |         }
-   | |_________^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:96:5
-   |
-LL |     while let None = Some(x) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:97:5
-   |
-LL |     while let None = Some(x) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:19:22
-   |
-LL |     const BAR: i32 = loop { break 4; };
-   |                      ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error[E0658]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:23:22
-   |
-LL |     const BAR: i32 = loop { break 4; };
-   |                      ^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to 17 previous errors
-
-Some errors have detailed explanations: E0658, E0744.
-For more information about an error, try `rustc --explain E0658`.
index 8cee2a54f56d3e4c08b1aeeeb272a068e9364959..4dfa22b8ebaf6310da8333e30a337114288604cd 100644 (file)
@@ -2,7 +2,6 @@
 
 // run-pass
 
-#![feature(const_if_match)]
 #![feature(const_panic)]
 
 const X: i32 = {
diff --git a/src/test/ui/consts/control-flow/short-circuit.if_match.stderr b/src/test/ui/consts/control-flow/short-circuit.if_match.stderr
deleted file mode 100644 (file)
index f6ba28e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/short-circuit.rs:14:1
-   |
-LL | fn main() {}
-   | ^^^^^^^^^^^^
-
-error: aborting due to previous error
-
index f5e54a69d4a6f72e52a9924a162b86dc3a000966..f6a0f03a4a6b89905560524f34200ae98d03e86f 100644 (file)
@@ -1,14 +1,14 @@
-// Test that both `&&` and `||` actually short-circuit when the `const_if_match` feature flag is
-// enabled. Without the feature flag, both sides are evaluated unconditionally.
+// run-pass
 
-// revisions: stock if_match
+// Test that both `&&` and `||` actually short-circuit.
+// Formerly, both sides were evaluated unconditionally
 
-#![feature(rustc_attrs)]
 #![feature(const_panic)]
-#![cfg_attr(if_match, feature(const_if_match))]
 
-const _: bool = true || panic!();  //[stock]~ ERROR any use of this value will cause an error
-const _: bool = false && panic!(); //[stock]~ ERROR any use of this value will cause an error
+const TRUE: bool = true || panic!();
+const FALSE: bool = false && panic!();
 
-#[rustc_error]
-fn main() {} //[if_match]~ ERROR fatal error triggered by #[rustc_error]
+fn main() {
+    assert!(TRUE);
+    assert!(!FALSE);
+}
diff --git a/src/test/ui/consts/control-flow/short-circuit.stock.stderr b/src/test/ui/consts/control-flow/short-circuit.stock.stderr
deleted file mode 100644 (file)
index f32f248..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/short-circuit.rs:10:25
-   |
-LL | const _: bool = true || panic!();
-   | ------------------------^^^^^^^^-
-   |                         |
-   |                         the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:10:25
-   |
-   = note: `#[deny(const_err)]` on by default
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: any use of this value will cause an error
-  --> $DIR/short-circuit.rs:11:26
-   |
-LL | const _: bool = false && panic!();
-   | -------------------------^^^^^^^^-
-   |                          |
-   |                          the evaluated program panicked at 'explicit panic', $DIR/short-circuit.rs:11:26
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
index 823605ff034f10c8ca1c25bb2b53c6da78c021c8..b59be00ffb7885943f8be3574fd0de511461c5ce 100644 (file)
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(const_if_match)]
-
 enum Foo {
     Prob,
 }
index 31fe09d4f69624e3885bbf32f25277b284ac4d9d..7d85a412b47226a3015444f6f6bb9b58632de40d 100644 (file)
@@ -1,8 +1,6 @@
 // The `?` operator is still not const-evaluatable because it calls `From::from` on the error
 // variant.
 
-#![feature(const_if_match)]
-
 const fn opt() -> Option<i32> {
     let x = Some(2);
     x?; //~ ERROR `?` is not allowed in a `const fn`
index 60a386ef6c870fc7bf9d4c8d9f5d4da306206856..35075a3e60b98d3cba64200099064eecf64cbe6e 100644 (file)
@@ -1,5 +1,5 @@
 error[E0744]: `?` is not allowed in a `const fn`
-  --> $DIR/try.rs:8:5
+  --> $DIR/try.rs:6:5
    |
 LL |     x?;
    |     ^^
diff --git a/src/test/ui/consts/min_const_fn/loop_ice.rs b/src/test/ui/consts/min_const_fn/loop_ice.rs
deleted file mode 100644 (file)
index 754a1d7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-const fn foo() {
-    loop {} //~ ERROR `loop` is not allowed in a `const fn`
-}
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/loop_ice.stderr b/src/test/ui/consts/min_const_fn/loop_ice.stderr
deleted file mode 100644 (file)
index f48b739..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop_ice.rs:2:5
-   |
-LL |     loop {}
-   |     ^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 557439f394953ed460f11012a6e57e641be84479..2ebd9dd10c5123014b2b3b4c6d1c4a72971d8098 100644 (file)
@@ -98,13 +98,13 @@ const fn foo30_2(x: *mut u32) -> usize { x as usize }
 const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
 //~^ ERROR casting pointers to ints is unstable
 const fn foo30_6() -> bool { let x = true; x }
-const fn foo36(a: bool, b: bool) -> bool { a && b }
-//~^ ERROR loops and conditional expressions are not stable in const fn
-const fn foo37(a: bool, b: bool) -> bool { a || b }
-//~^ ERROR loops and conditional expressions are not stable in const fn
 const fn inc(x: &mut i32) { *x += 1 }
 //~^ ERROR mutable references in const fn are unstable
 
+// ok
+const fn foo36(a: bool, b: bool) -> bool { a && b }
+const fn foo37(a: bool, b: bool) -> bool { a || b }
+
 fn main() {}
 
 impl<T: std::fmt::Debug> Foo<T> {
index 512b343011b40c8a6030d5f76dabbba90faa7837..9b55b6c6f3bbc97bad469192d7230db86eb9093f 100644 (file)
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:37:25
    |
 LL |     const fn into_inner(self) -> T { self.0 }
-   |                         ^^^^ constant functions cannot evaluate destructors
+   |                         ^^^^                - value is dropped here
+   |                         |
+   |                         constant functions cannot evaluate destructors
 
 error[E0723]: mutable references in const fn are unstable
   --> $DIR/min_const_fn.rs:39:36
@@ -17,7 +19,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:44:28
    |
 LL |     const fn into_inner_lt(self) -> T { self.0 }
-   |                            ^^^^ constant functions cannot evaluate destructors
+   |                            ^^^^                - value is dropped here
+   |                            |
+   |                            constant functions cannot evaluate destructors
 
 error[E0723]: mutable references in const fn are unstable
   --> $DIR/min_const_fn.rs:46:42
@@ -32,7 +36,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/min_const_fn.rs:51:27
    |
 LL |     const fn into_inner_s(self) -> T { self.0 }
-   |                           ^^^^ constant functions cannot evaluate destructors
+   |                           ^^^^                - value is dropped here
+   |                           |
+   |                           constant functions cannot evaluate destructors
 
 error[E0723]: mutable references in const fn are unstable
   --> $DIR/min_const_fn.rs:53:38
@@ -160,26 +166,8 @@ LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:101:44
-   |
-LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
-   |                                            ^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
-error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/min_const_fn.rs:103:44
-   |
-LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
-   |                                            ^^^^^^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
-
 error[E0723]: mutable references in const fn are unstable
-  --> $DIR/min_const_fn.rs:105:14
+  --> $DIR/min_const_fn.rs:101:14
    |
 LL | const fn inc(x: &mut i32) { *x += 1 }
    |              ^
@@ -277,7 +265,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error: aborting due to 32 previous errors
+error: aborting due to 30 previous errors
 
 Some errors have detailed explanations: E0493, E0723.
 For more information about an error, try `rustc --explain E0493`.
index 52f6536b5ea67c545be92817aafe36e75fcfbce8..08d68b039bead295625a4d615868b5ad71cde644 100644 (file)
@@ -2,8 +2,7 @@
 // aux-build:static_cross_crate.rs
 #![allow(const_err)]
 
-// `const_if_match` is a HIR check and thus needed even when unleashed.
-#![feature(exclusive_range_pattern, half_open_range_patterns, const_if_match)]
+#![feature(exclusive_range_pattern, half_open_range_patterns)]
 
 extern crate static_cross_crate;
 
index 9d1e88a811f2f4267e0ca9b98ec06406bfe1d740..52662ef9eaf5a0ec1a2aacc78bc0d68149e1f379 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/const_refers_to_static_cross_crate.rs:12:1
+  --> $DIR/const_refers_to_static_cross_crate.rs:11:1
    |
 LL | / const SLICE_MUT: &[u8; 1] = {
 LL | |
@@ -11,13 +11,13 @@ LL | | };
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:40:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:39:9
    |
 LL |         SLICE_MUT => true,
    |         ^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/const_refers_to_static_cross_crate.rs:18:1
+  --> $DIR/const_refers_to_static_cross_crate.rs:17:1
    |
 LL | / const U8_MUT: &u8 = {
 LL | |
@@ -29,13 +29,13 @@ LL | | };
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:49:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:48:9
    |
 LL |         U8_MUT => true,
    |         ^^^^^^
 
 warning: any use of this value will cause an error
-  --> $DIR/const_refers_to_static_cross_crate.rs:27:14
+  --> $DIR/const_refers_to_static_cross_crate.rs:26:14
    |
 LL | / const U8_MUT2: &u8 = {
 LL | |     unsafe { &(*static_cross_crate::ZERO_REF)[0] }
@@ -46,19 +46,19 @@ LL | | };
    | |__-
    |
 note: the lint level is defined here
-  --> $DIR/const_refers_to_static_cross_crate.rs:25:8
+  --> $DIR/const_refers_to_static_cross_crate.rs:24:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:60:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:59:9
    |
 LL |         U8_MUT2 => true,
    |         ^^^^^^^
 
 warning: any use of this value will cause an error
-  --> $DIR/const_refers_to_static_cross_crate.rs:33:51
+  --> $DIR/const_refers_to_static_cross_crate.rs:32:51
    |
 LL | / const U8_MUT3: &u8 = {
 LL | |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
@@ -69,37 +69,37 @@ LL | | };
    | |__-
    |
 note: the lint level is defined here
-  --> $DIR/const_refers_to_static_cross_crate.rs:31:8
+  --> $DIR/const_refers_to_static_cross_crate.rs:30:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:68:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:67:9
    |
 LL |         U8_MUT3 => true,
    |         ^^^^^^^
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:40:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:39:9
    |
 LL |         SLICE_MUT => true,
    |         ^^^^^^^^^
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:49:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:48:9
    |
 LL |         U8_MUT => true,
    |         ^^^^^^
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:60:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:59:9
    |
 LL |         U8_MUT2 => true,
    |         ^^^^^^^
 
 error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:68:9
+  --> $DIR/const_refers_to_static_cross_crate.rs:67:9
    |
 LL |         U8_MUT3 => true,
    |         ^^^^^^^
@@ -107,57 +107,52 @@ LL |         U8_MUT3 => true,
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:15:15
+  --> $DIR/const_refers_to_static_cross_crate.rs:14:15
    |
 LL |     unsafe { &static_cross_crate::ZERO }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:15:15
+  --> $DIR/const_refers_to_static_cross_crate.rs:14:15
    |
 LL |     unsafe { &static_cross_crate::ZERO }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:21:15
+  --> $DIR/const_refers_to_static_cross_crate.rs:20:15
    |
 LL |     unsafe { &static_cross_crate::ZERO[0] }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:21:15
+  --> $DIR/const_refers_to_static_cross_crate.rs:20:15
    |
 LL |     unsafe { &static_cross_crate::ZERO[0] }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:21:15
+  --> $DIR/const_refers_to_static_cross_crate.rs:20:15
    |
 LL |     unsafe { &static_cross_crate::ZERO[0] }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:27:17
+  --> $DIR/const_refers_to_static_cross_crate.rs:26:17
    |
 LL |     unsafe { &(*static_cross_crate::ZERO_REF)[0] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:33:20
+  --> $DIR/const_refers_to_static_cross_crate.rs:32:20
    |
 LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:33:20
-   |
-LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:33:20
+  --> $DIR/const_refers_to_static_cross_crate.rs:32:20
    |
 LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_panic` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:33:77
+  --> $DIR/const_refers_to_static_cross_crate.rs:32:77
    |
 LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
    |                                                                             ^^^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_refers_to_static_cross_crate.rs:33:20
+  --> $DIR/const_refers_to_static_cross_crate.rs:32:20
    |
 LL |     unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 37016664ac58f38c913b3d1dbd36cf8ddd243c99..0b6cb2fab46f1cb06462205c3dabac2bb7688019 100644 (file)
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/feature-gate-unleash_the_miri_inside_of_you.rs:11:20
    |
 LL |     const F: u32 = (U::X, 42).1;
-   |                    ^^^^^^^^^^ constants cannot evaluate destructors
+   |                    ^^^^^^^^^^ - value is dropped here
+   |                    |
+   |                    constants cannot evaluate destructors
 
 error: aborting due to previous error
 
index 064dc6c262c88462e64b6ce6ecfb36b5ff4a5e7e..65fc49c0b27a6b44a8bb1c765c23b3aca130e1dd 100644 (file)
@@ -6,15 +6,14 @@
 
 static CMP: () = {
     let x = &0 as *const _;
-    let _v = x == x; //~ NOTE in this
+    let _v = x == x;
     //~^ ERROR could not evaluate static initializer
     //~| NOTE pointer arithmetic or comparison
-    //~| NOTE in this
 };
 
 static INT_PTR_ARITH: () = unsafe {
     let x: usize = std::mem::transmute(&0);
-    let _v = x + 0; //~ NOTE in this
+    let _v = x + 0;
     //~^ ERROR could not evaluate static initializer
     //~| NOTE pointer-to-integer cast
 };
index 4b3fe9957002e8f359116f6029328841ef67ae79..21f11dda5a66729a3339ae446018454657f52417 100644 (file)
@@ -5,20 +5,20 @@ LL |     let _v = x == x;
    |              ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:17:14
+  --> $DIR/ptr_arith.rs:16:14
    |
 LL |     let _v = x + 0;
    |              ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
 
 warning: skipping const checks
    |
-help: skipping check for `const_compare_raw_pointers` feature
+help: skipping check that does not even have a feature gate
   --> $DIR/ptr_arith.rs:9:14
    |
 LL |     let _v = x == x;
    |              ^^^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/ptr_arith.rs:16:20
+  --> $DIR/ptr_arith.rs:15:20
    |
 LL |     let x: usize = std::mem::transmute(&0);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/miri_unleashed/slice_eq.rs b/src/test/ui/consts/miri_unleashed/slice_eq.rs
new file mode 100644 (file)
index 0000000..fd84310
--- /dev/null
@@ -0,0 +1,17 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+// run-pass
+
+#![feature(const_raw_ptr_comparison)]
+
+const EMPTY_SLICE: &[i32] = &[];
+const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
+const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
+const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
+const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
+
+fn main() {
+    assert!(!EMPTY_EQ);
+    assert!(!EMPTY_EQ2);
+    assert!(!EMPTY_NE);
+    assert!(!EMPTY_NE2);
+}
index 92ecea5fdacddb8f46cf44b7126f33c22b269ae4..cde2fe32626922d8b8c5275c0c1d82d43c93cf57 100644 (file)
@@ -45,7 +45,7 @@ error: any use of this value will cause an error
 LL |           intrinsics::ptr_offset_from(self, origin)
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |           |
-   |           exact_div: 1isize cannot be divided by 2isize without remainder
+   |           exact_div: 1_isize cannot be divided by 2_isize without remainder
    |           inside `std::ptr::const_ptr::<impl *const u16>::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
    |           inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:31:14
    | 
index 0945a23f3b123fc9b83c532c70f7c4690d34f4a1..fad8f011f75f55ba17f3926d9408a4641f05f4fb 100644 (file)
@@ -1,3 +1,9 @@
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/projection_qualif.rs:10:27
+   |
+LL |         let b: *mut u32 = &mut a;
+   |                           ^^^^^^ `&mut` is only allowed in `const fn`
+
 error[E0658]: dereferencing raw pointers in constants is unstable
   --> $DIR/projection_qualif.rs:11:18
    |
@@ -7,6 +13,7 @@ LL |         unsafe { *b = 5; }
    = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
    = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
index cfe8e7f03d5e45e8445ff79094bf79610b71de1d..7db970cf1379f4aebc0e9ea9e6cd43fc27feb05d 100644 (file)
@@ -7,7 +7,7 @@
 const FOO: &u32 = {
     let mut a = 42;
     {
-        let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values
+        let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants
         unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
         //[stock]~^ contains unimplemented expression
     }
index cfa48d947c992894f07d487676b5eebea57a122f..212f12286455f44a53a48f23df2aa48e419a9a99 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/projection_qualif.rs:10:27
    |
 LL |         let b: *mut u32 = &mut a;
-   |                           ^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                           ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0658]: dereferencing raw pointers in constants is unstable
   --> $DIR/projection_qualif.rs:11:18
@@ -26,5 +23,5 @@ LL |         unsafe { *b = 5; }
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0019, E0658.
+Some errors have detailed explanations: E0019, E0658, E0764.
 For more information about an error, try `rustc --explain E0019`.
index c18227e0f5515bedfc98402003ad8d47a90789c1..5faa983ab09f71cc0e9ebabcea6f6d0df7daf80f 100644 (file)
@@ -1,10 +1,9 @@
-// run-pass
+// We are keeping this test in case we decide to allow mutable references in statics again
 #![feature(const_mut_refs)]
 #![allow(const_err)]
 
-static OH_YES: &mut i32 = &mut 42;
-
+static OH_NO: &mut i32 = &mut 42;
+//~^ ERROR mutable references are not allowed in statics
 fn main() {
-    // Make sure `OH_YES` can be read.
-    assert_eq!(*OH_YES, 42);
+    assert_eq!(*OH_NO, 42);
 }
diff --git a/src/test/ui/consts/read_from_static_mut_ref.stderr b/src/test/ui/consts/read_from_static_mut_ref.stderr
new file mode 100644 (file)
index 0000000..c936ac0
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0764]: mutable references are not allowed in statics
+  --> $DIR/read_from_static_mut_ref.rs:5:26
+   |
+LL | static OH_NO: &mut i32 = &mut 42;
+   |                          ^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0764`.
index 8db75dd63cf2a0e5357f7e65bf3ee69bd4d52a98..36c280ca5c607bc33c5f1dbb9f00c67b9900ec10 100644 (file)
@@ -1,9 +1,9 @@
-error[E0080]: could not evaluate static initializer
-  --> $DIR/static_mut_containing_mut_ref2.rs:7:45
+error[E0764]: mutable references are not allowed in statics
+  --> $DIR/static_mut_containing_mut_ref2.rs:7:46
    |
 LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0764`.
index 74162fbd54b046537817eeb17a99b8e716632077..a6bbe8d6ec24c1b15c1312f30a51f433aedd2b6d 100644 (file)
@@ -5,8 +5,7 @@
 static mut STDERR_BUFFER_SPACE: u8 = 0;
 
 pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-//[mut_refs]~^ ERROR could not evaluate static initializer
-//[stock]~^^ ERROR references in statics may only refer to immutable values
+//~^ ERROR  mutable references are not allowed in statics
 //[stock]~| ERROR static contains unimplemented expression type
 
 fn main() {}
index cc169351bf268c14dd63c5cc689a65808f02c576..57fb27e642e6f00aa30cd95a338f1825814deed7 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/static_mut_containing_mut_ref2.rs:7:46
    |
 LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0019]: static contains unimplemented expression type
   --> $DIR/static_mut_containing_mut_ref2.rs:7:45
@@ -17,5 +14,5 @@ LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 4
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0019, E0658.
+Some errors have detailed explanations: E0019, E0764.
 For more information about an error, try `rustc --explain E0019`.
index 8010d2fe1aee933983eb901a15c14c686385e70a..3adbbb53046340abf7193be415f7eda66ffcad23 100644 (file)
@@ -5,7 +5,7 @@
 // Tests that specialization does not cause optimizations running on polymorphic MIR to resolve
 // to a `default` implementation.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Marker {}
 
diff --git a/src/test/ui/consts/trait_specialization.stderr b/src/test/ui/consts/trait_specialization.stderr
new file mode 100644 (file)
index 0000000..03da7d5
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/trait_specialization.rs:8:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 0b64786ccce5447826859841aaf8bf1a7764f4fe..29d3dc18fa7cc06bdfd1ca168d78073850b9e70b 100644 (file)
@@ -4,7 +4,6 @@
 // gate was not enabled in libcore.
 
 #![stable(feature = "core", since = "1.6.0")]
-#![feature(const_if_match)]
 #![feature(rustc_const_unstable)]
 #![feature(staged_api)]
 
index a8455cefd01cf94a8d45caaae57d0c5b42dcf64e..be797cae7ca97cfc65320645c77be589f834461c 100644 (file)
@@ -1,20 +1,26 @@
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/unstable-const-fn-in-libcore.rs:24:26
+  --> $DIR/unstable-const-fn-in-libcore.rs:23:26
    |
 LL |             Opt::None => f(),
    |                          ^^^
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:19:53
+  --> $DIR/unstable-const-fn-in-libcore.rs:18:53
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                                     ^ constant functions cannot evaluate destructors
+...
+LL |     }
+   |     - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/unstable-const-fn-in-libcore.rs:19:47
+  --> $DIR/unstable-const-fn-in-libcore.rs:18:47
    |
 LL |     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
    |                                               ^^^^ constant functions cannot evaluate destructors
+...
+LL |     }
+   |     - value is dropped here
 
 error: aborting due to 3 previous errors
 
index 749d569b9aedc46d487c3ab5a54284133a5ae0a0..006a334021b1419428d1f9813cfd2f85318e382d 100644 (file)
@@ -9,6 +9,10 @@ LL | impl Foo<[isize]> for usize { }
    |
    = help: the trait `std::marker::Sized` is not implemented for `[isize]`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized
+   |            ^^^^^^^^
 
 error[E0277]: the size for values of type `[usize]` cannot be known at compilation time
   --> $DIR/dst-sized-trait-param.rs:10:6
index 8d2cdf34f373e83e317330cbe6751a833932ce87..b3694bb4216c67eee40e259acab2db9e9e803879 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(const_panic)]
-#![feature(const_if_match)]
 
 //! Make sure that we read and write enum discriminants correctly for corner cases caused
 //! by layout optimizations.
index 64be41170d0c897156211e5d7fc5c1b8b4f9959c..818dec1207b961c621d459b2c72104e001f2d1ef 100644 (file)
@@ -2,10 +2,10 @@
 const C: i32 = 2;
 static mut M: i32 = 3;
 
-const CR: &'static mut i32 = &mut C; //~ ERROR E0658
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
+const CR: &'static mut i32 = &mut C; //~ ERROR E0764
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764
                                               //~| ERROR E0019
                                               //~| ERROR cannot borrow
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
-static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0658
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
+static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764
 fn main() {}
index f959ad0d00887af3de083347a7084a513c472d7c..c1d96de1dca7c94346e98e3d4f85804fc3fe6c18 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/E0017.rs:5:30
    |
 LL | const CR: &'static mut i32 = &mut C;
-   |                              ^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                              ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0019]: static contains unimplemented expression type
   --> $DIR/E0017.rs:6:39
@@ -15,14 +12,11 @@ LL | static STATIC_REF: &'static mut i32 = &mut X;
    |
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0017.rs:6:39
    |
 LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                       ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0596]: cannot borrow immutable static item `X` as mutable
   --> $DIR/E0017.rs:6:39
@@ -30,25 +24,19 @@ error[E0596]: cannot borrow immutable static item `X` as mutable
 LL | static STATIC_REF: &'static mut i32 = &mut X;
    |                                       ^^^^^^ cannot borrow as mutable
 
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0017.rs:9:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C;
-   |                                      ^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                      ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0017.rs:10:52
    |
 LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
-   |                                                    ^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                                    ^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0019, E0596, E0658.
+Some errors have detailed explanations: E0019, E0596, E0764.
 For more information about an error, try `rustc --explain E0019`.
index ac0e7737f43fcdb20d16fb8ec87a7b41e731b673..b31cf2ec447e7108796b61f24bb90ae9c11d4703 100644 (file)
@@ -1,6 +1,6 @@
 enum Enum {
     X = (1 << 500), //~ ERROR E0080
-    //~| shift left with overflow
+    //~| attempt to shift left by 500_i32 which would overflow
     Y = (1 / 0) //~ ERROR E0080
 }
 
index 3113fd2189b4c8493604972d34c0bf0768c19c96..3acd15ff6bc9ecb6c7930a3db3e405a735bb787f 100644 (file)
@@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/E0080.rs:2:9
    |
 LL |     X = (1 << 500),
-   |         ^^^^^^^^^^ attempt to shift left with overflow
+   |         ^^^^^^^^^^ attempt to shift left by 500_i32 which would overflow
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/E0080.rs:4:9
    |
 LL |     Y = (1 / 0)
-   |         ^^^^^^^ attempt to divide by zero
+   |         ^^^^^^^ attempt to divide 1_isize by zero
 
 error: aborting due to 2 previous errors
 
index 5954e3490b06c770766b596604225d9798b05d14..13131017c2e07df2e87dd9da1cebd72dea8fd39b 100644 (file)
@@ -1,10 +1,10 @@
 static X: i32 = 1;
 const C: i32 = 2;
 
-const CR: &'static mut i32 = &mut C; //~ ERROR E0658
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
+const CR: &'static mut i32 = &mut C; //~ ERROR E0764
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019
                                               //~| ERROR cannot borrow
-                                              //~| ERROR E0019
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
+                                              //~| ERROR E0764
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
 
 fn main() {}
index 8bdfbac36816b9869718c64df2ef1a080d436ac3..f09100bac43ce2c9c29a795dbb5d07f15161daa2 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/E0388.rs:4:30
    |
 LL | const CR: &'static mut i32 = &mut C;
-   |                              ^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                              ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0019]: static contains unimplemented expression type
   --> $DIR/E0388.rs:5:39
@@ -15,14 +12,11 @@ LL | static STATIC_REF: &'static mut i32 = &mut X;
    |
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0388.rs:5:39
    |
 LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                       ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0596]: cannot borrow immutable static item `X` as mutable
   --> $DIR/E0388.rs:5:39
@@ -30,16 +24,13 @@ error[E0596]: cannot borrow immutable static item `X` as mutable
 LL | static STATIC_REF: &'static mut i32 = &mut X;
    |                                       ^^^^^^ cannot borrow as mutable
 
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0388.rs:8:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C;
-   |                                      ^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                      ^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0019, E0596, E0658.
+Some errors have detailed explanations: E0019, E0596, E0764.
 For more information about an error, try `rustc --explain E0019`.
index bbefff27d7f683873ed1421c9b707cf02a1c7276..d2edd97efb232e6bd2a34d6053ea5a79f5a4672b 100644 (file)
@@ -1,10 +1,8 @@
-// gate-test-const_compare_raw_pointers
-
 static FOO: i32 = 42;
 static BAR: i32 = 42;
 
 static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
-//~^ ERROR comparing raw pointers inside static
+//~^ ERROR pointers cannot be reliably compared during const eval
 
 fn main() {
 }
index 20c8622f33726c5cb7aac8a6fecf54247b403c25..674cc696450290625d5366140775b41f698da39e 100644 (file)
@@ -1,12 +1,10 @@
-error[E0658]: comparing raw pointers inside static
-  --> $DIR/E0395.rs:6:29
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/E0395.rs:4:29
    |
 LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
index b746ca63590ec80c2734ca8d81f0b7e55598b2dd..ead78b7ffa2c40005838c27da367f1b4bea92c20 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 trait SpaceLlama {
     fn fly(&self);
index 72fc85ab1e74badfa19fcbe8e1c40c6d3b6eb8b1..1041ccee937042726a1296b22fdbdb2b49ddbf52 100644 (file)
@@ -1,5 +1,14 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/E0520.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default`
-  --> $DIR/E0520.rs:16:5
+  --> $DIR/E0520.rs:17:5
    |
 LL | / impl<T: Clone> SpaceLlama for T {
 LL | |     fn fly(&self) {}
@@ -11,6 +20,6 @@ LL |       default fn fly(&self) {}
    |
    = note: to specialize, `fly` in the parent `impl` must be marked `default`
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0520`.
index 5861bdcb7a953c7cc07fd36b9bc491159991c87b..18835310bd5e87ec6541fa49df36540a60be1c64 100644 (file)
@@ -2,7 +2,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/E0604.rs:2:5
    |
 LL |     1u32 as char;
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ invalid cast
 
 error: aborting due to previous error
 
index 95e899db8b7e94db190ec8016beb412ea848e979..f23d2008e0b5f2c4cd38904b074ac9c48bc5747c 100644 (file)
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `u8` as `std::vec::Vec<u8>`
   --> $DIR/E0605.rs:3:5
    |
 LL |     x as Vec<u8>;
-   |     ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/E0605.rs:6:5
    |
 LL |     v as &u8;
-   |     ^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
index 7f524230ef00633a7ecc45a9a0273a596744be5c..905195d4ad963fe4b963a1dc31e03a1b9a115a27 100644 (file)
@@ -42,15 +42,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/error-festival.rs:25:5
    |
 LL |     0u32 as char;
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ invalid cast
 
 error[E0605]: non-primitive cast: `u8` as `std::vec::Vec<u8>`
   --> $DIR/error-festival.rs:29:5
    |
 LL |     x as Vec<u8>;
-   |     ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0054]: cannot cast as `bool`
   --> $DIR/error-festival.rs:33:24
index cf49b9614381788f4b9c6de30b04010fb4cc3ab6..4ef06c78069f2f86901e4b1b0b5f73b2c0c0470c 100644 (file)
@@ -1,9 +1,9 @@
 enum Test {
     DivZero = 1/0,
-    //~^ attempt to divide by zero
+    //~^ attempt to divide 1_isize by zero
     //~| ERROR evaluation of constant value failed
     RemZero = 1%0,
-    //~^ attempt to calculate the remainder with a divisor of zero
+    //~^ attempt to calculate the remainder of 1_isize with a divisor of zero
     //~| ERROR evaluation of constant value failed
 }
 
index 195eaddb71b37974415601e06cdbfdd1644599c3..dd89a2d7c3bfc740566980e244c9adceda9803c5 100644 (file)
@@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/eval-enum.rs:2:15
    |
 LL |     DivZero = 1/0,
-   |               ^^^ attempt to divide by zero
+   |               ^^^ attempt to divide 1_isize by zero
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/eval-enum.rs:5:15
    |
 LL |     RemZero = 1%0,
-   |               ^^^ attempt to calculate the remainder with a divisor of zero
+   |               ^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
 
 error: aborting due to 2 previous errors
 
index 9ed52511fa399256c23b4805282c4868ce3ffc72..0c7995fde3273f838194afc92f360afe2fa229f0 100644 (file)
@@ -26,6 +26,10 @@ LL |     assert_sized::<Foo>();
    = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Foo`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn assert_sized<T: ?Sized>() { }
+   |                  ^^^^^^^^
 
 error[E0277]: the size for values of type `A` cannot be known at compilation time
   --> $DIR/extern-types-unsized.rs:28:5
@@ -39,6 +43,10 @@ LL |     assert_sized::<Bar<A>>();
    = help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn assert_sized<T: ?Sized>() { }
+   |                  ^^^^^^^^
 
 error[E0277]: the size for values of type `A` cannot be known at compilation time
   --> $DIR/extern-types-unsized.rs:31:5
@@ -53,6 +61,10 @@ LL |     assert_sized::<Bar<Bar<A>>>();
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `Bar<A>`
    = note: required because it appears within the type `Bar<Bar<A>>`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn assert_sized<T: ?Sized>() { }
+   |                  ^^^^^^^^
 
 error: aborting due to 4 previous errors
 
index 93e1471838f72acdf8d97aa1bc05924c15275d52..56d5a26beb04ee0d37e823799155373569c068a4 100644 (file)
@@ -34,9 +34,7 @@ error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize`
   --> $DIR/fat-ptr-cast.rs:14:5
    |
 LL |     b as usize;
-   |     ^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0606]: casting `*const [i32]` as `usize` is invalid
   --> $DIR/fat-ptr-cast.rs:15:5
index 1ab11ce3b4423458705cc5bcc69f5489ff0d13fb..dc602ba7e6f2138d5e3d0321a80dd0eb384d63ba 100644 (file)
@@ -1,9 +1,9 @@
 struct ConstFn<const F: fn()>;
 //~^ ERROR const generics are unstable
-//~^^ ERROR using function pointers as const generic parameters is unstable
+//~^^ ERROR using function pointers as const generic parameters is forbidden
 
 struct ConstPtr<const P: *const u32>;
 //~^ ERROR const generics are unstable
-//~^^ ERROR using raw pointers as const generic parameters is unstable
+//~^^ ERROR using raw pointers as const generic parameters is forbidden
 
 fn main() {}
index dc7ef55e7ab997db81a8e954a027fd0a8b67f6ee..b2c96d3810f980fae1e4543247b354ebfc5bc33e 100644 (file)
@@ -16,23 +16,17 @@ LL | struct ConstPtr<const P: *const u32>;
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
-error[E0658]: using function pointers as const generic parameters is unstable
+error: using function pointers as const generic parameters is forbidden
   --> $DIR/feature-gate-const_generics-ptr.rs:1:25
    |
 LL | struct ConstFn<const F: fn()>;
    |                         ^^^^
-   |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
-error[E0658]: using raw pointers as const generic parameters is unstable
+error: using raw pointers as const generic parameters is forbidden
   --> $DIR/feature-gate-const_generics-ptr.rs:5:26
    |
 LL | struct ConstPtr<const P: *const u32>;
    |                          ^^^^^^^^^^
-   |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to 4 previous errors
 
index 7ff348aca7cc1e37349a952c89a3a9936e10dca6..17548d7b9e88c5551bf7a8b49b2cd132146c7eab 100644 (file)
@@ -3,11 +3,9 @@
 trait PointerFamily<U> {
     type Pointer<T>: Deref<Target = T>;
     //~^ ERROR generic associated types are unstable
-    //~| ERROR type-generic associated types are not yet implemented
     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
     //~^ ERROR generic associated types are unstable
     //~| ERROR where clauses on associated types are unstable
-    //~| ERROR type-generic associated types are not yet implemented
 }
 
 struct Foo;
index a0e06cb2b679530c8a88483c451b6e754cf5fa7c..8499b1ab70f5d02a4bcbf7bef7d713ac5083064a 100644 (file)
@@ -8,7 +8,7 @@ LL |     type Pointer<T>: Deref<Target = T>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:7:5
+  --> $DIR/feature-gate-generic_associated_types.rs:6:5
    |
 LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:7:5
+  --> $DIR/feature-gate-generic_associated_types.rs:6:5
    |
 LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:16:5
+  --> $DIR/feature-gate-generic_associated_types.rs:14:5
    |
 LL |     type Pointer<Usize> = Box<Usize>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -35,7 +35,7 @@ LL |     type Pointer<Usize> = Box<Usize>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:18:5
+  --> $DIR/feature-gate-generic_associated_types.rs:16:5
    |
 LL |     type Pointer2<U32> = Box<U32>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     type Pointer2<U32> = Box<U32>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:23:5
+  --> $DIR/feature-gate-generic_associated_types.rs:21:5
    |
 LL |     type Assoc where Self: Sized;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ LL |     type Assoc where Self: Sized;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:28:5
+  --> $DIR/feature-gate-generic_associated_types.rs:26:5
    |
 LL |     type Assoc where Self: Sized = Foo;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,22 +61,6 @@ LL |     type Assoc where Self: Sized = Foo;
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/feature-gate-generic_associated_types.rs:4:5
-   |
-LL |     type Pointer<T>: Deref<Target = T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/feature-gate-generic_associated_types.rs:7:5
-   |
-LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 68b75c18a43dc52769978449b88d3496156599fc..abae40162a0fcacdfc6f58397fc0fa8622f60204 100644 (file)
@@ -12,22 +12,44 @@ impl<T> Foo for T { /* `foo` is still default here */ }
 fn main() {
     eq(foo::<u8>, bar::<u8>);
     //~^ ERROR mismatched types
-    //~|  expected fn item `fn(_) -> _ {foo::<u8>}`
-    //~|  found fn item `fn(_) -> _ {bar::<u8>}`
-    //~|  expected fn item, found a different fn item
+    //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+    //~| found fn item `fn(_) -> _ {bar::<u8>}`
+    //~| expected fn item, found a different fn item
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
 
     eq(foo::<u8>, foo::<i8>);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `i8`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
 
     eq(bar::<String>, bar::<Vec<u8>>);
     //~^ ERROR mismatched types
-    //~|  expected fn item `fn(_) -> _ {bar::<std::string::String>}`
-    //~|  found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
-    //~|  expected struct `std::string::String`, found struct `std::vec::Vec`
+    //~| expected fn item `fn(_) -> _ {bar::<std::string::String>}`
+    //~| found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+    //~| expected struct `std::string::String`, found struct `std::vec::Vec`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
 
     // Make sure we distinguish between trait methods correctly.
     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
     //~^ ERROR mismatched types
     //~| expected `u8`, found `u16`
+    //~| different `fn` items always have unique types, even if their signatures are the same
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+
+    eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+    //~^ ERROR mismatched types
+    //~| expected fn item `fn(_) -> _ {foo::<u8>}`
+    //~| found fn pointer `fn(_) -> _`
+    //~| expected fn item, found fn pointer
+    //~| change the expected type to be function pointer
+    //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer
+
+    eq(foo::<u8> as fn(isize) -> isize, bar::<u8>); // ok!
 }
index 4cce25c43c485b31eb8e73bedbc392db400c8a74..bfa9efa219f4c8aa71c2df4a1a00e8e0820f74d8 100644 (file)
@@ -6,34 +6,57 @@ LL |     eq(foo::<u8>, bar::<u8>);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {bar::<u8>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:19:19
+  --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
    |                   ^^^^^^^^^ expected `u8`, found `i8`
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
               found fn item `fn(_) -> _ {foo::<i8>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:23:23
+  --> $DIR/fn-item-type.rs:29:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
    |                       ^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
    |
    = note: expected fn item `fn(_) -> _ {bar::<std::string::String>}`
               found fn item `fn(_) -> _ {bar::<std::vec::Vec<u8>>}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar::<std::string::String> as fn(isize) -> isize`
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:30:26
+  --> $DIR/fn-item-type.rs:39:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
    |                          ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
               found fn item `fn() {<u16 as Foo>::foo}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `fn()`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`
 
-error: aborting due to 4 previous errors
+error[E0308]: mismatched types
+  --> $DIR/fn-item-type.rs:46:19
+   |
+LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+   |
+   = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+           found fn pointer `fn(_) -> _`
+   = help: change the expected type to be function pointer `fn(isize) -> isize`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index e32005e21a8e1b63df9ce58f44c08a209185bf51..20b689aa5e0afc8273843335c3e5bc97edb8c6b4 100644 (file)
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0i32` and `&2i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered
   --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9
    |
 LL |     for &1 in [1].iter() {}
-   |         ^^ patterns `&i32::MIN..=0i32` and `&2i32..=i32::MAX` not covered
+   |         ^^ patterns `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered
    |
    = note: the matched value is of type `&i32`
 
diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
new file mode 100644 (file)
index 0000000..7d71219
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/resume-arg-late-bound.rs:15:5
+   |
+LL |     test(gen);
+   |     ^^^^^^^^^
+
+error: aborting due to previous error
+
index 87b1f1a065bc8c3099b34410267256398fb84765..a8f657eaabe47b8ba69ffeaea6f4cb5b70becdcd 100644 (file)
@@ -13,5 +13,6 @@ fn main() {
         *arg = true;
     };
     test(gen);
-    //~^ ERROR type mismatch in function arguments
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
 }
index ffa440daed8c45088be819f24f8e4bb8e9a12c60..c379d9eae8ecdc375dba5d70bd3e247eb0b7140a 100644 (file)
@@ -1,15 +1,21 @@
-error[E0631]: type mismatch in function arguments
-  --> $DIR/resume-arg-late-bound.rs:15:10
+error[E0308]: mismatched types
+  --> $DIR/resume-arg-late-bound.rs:15:5
    |
-LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
-   |                 ------------------------------- required by this bound in `test`
-...
 LL |     test(gen);
-   |          ^^^
-   |          |
-   |          expected signature of `for<'a> fn(&'a mut bool) -> _`
-   |          found signature of `fn(&mut bool) -> _`
+   |     ^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+              found type `std::ops::Generator<&mut bool>`
+
+error[E0308]: mismatched types
+  --> $DIR/resume-arg-late-bound.rs:15:5
+   |
+LL |     test(gen);
+   |     ^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+              found type `std::ops::Generator<&mut bool>`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0631`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs
new file mode 100644 (file)
index 0000000..5fbae02
--- /dev/null
@@ -0,0 +1,72 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+// A Collection trait and collection families. Based on
+// http://smallcultfollowing.com/babysteps/blog/2016/11/03/
+// associated-type-constructors-part-2-family-traits/
+
+// check that we don't normalize with trait defaults.
+
+trait Collection<T> {
+    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
+    type Family: CollectionFamily;
+    // Test associated type defaults with parameters
+    type Sibling<U>: Collection<U> =
+        <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
+
+    fn empty() -> Self;
+
+    fn add(&mut self, value: T);
+
+    fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
+}
+
+trait CollectionFamily {
+    type Member<T>: Collection<T, Family = Self>;
+}
+
+struct VecFamily;
+
+impl CollectionFamily for VecFamily {
+    type Member<T> = Vec<T>;
+}
+
+impl<T> Collection<T> for Vec<T> {
+    type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
+    type Family = VecFamily;
+
+    fn empty() -> Self {
+        Vec::new()
+    }
+
+    fn add(&mut self, value: T) {
+        self.push(value)
+    }
+
+    fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
+        self.iter()
+    }
+}
+
+fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+where
+    C: Collection<i32>,
+{
+    let mut res = <C::Family as CollectionFamily>::Member::<f32>::empty();
+    for &v in ints.iterate() {
+        res.add(v as f32);
+    }
+    res
+    //~^ ERROR mismatched types
+}
+
+fn use_floatify() {
+    let a = vec![1i32, 2, 3];
+    let c = floatify_sibling(&a);
+    assert_eq!(Some(&1.0), c.iterate().next());
+}
+
+fn main() {
+    use_floatify();
+}
diff --git a/src/test/ui/generic-associated-types/collections-project-default.stderr b/src/test/ui/generic-associated-types/collections-project-default.stderr
new file mode 100644 (file)
index 0000000..ca02b26
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/collections-project-default.rs:60:5
+   |
+LL | fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+   |                                     ------------------------------------ expected `<C as Collection<i32>>::Sibling<f32>` because of return type
+...
+LL |     res
+   |     ^^^ expected Collection::Sibling, found CollectionFamily::Member
+   |
+   = note: expected associated type `<C as Collection<i32>>::Sibling<f32>`
+              found associated type `<<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 6f018f04018630912848cf1d5ddca3f6da5abb03..1b5b9c181fb612ea83926eee74f460b1d9f4a7ea 100644 (file)
@@ -6,13 +6,14 @@
 // http://smallcultfollowing.com/babysteps/blog/2016/11/03/
 // associated-type-constructors-part-2-family-traits/
 
+// run-pass
+
 trait Collection<T> {
-    type Iter<'iter>: Iterator<Item=&'iter T>;
+    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
     type Family: CollectionFamily;
     // Test associated type defaults with parameters
     type Sibling<U>: Collection<U> =
         <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
-    //~^^ ERROR type-generic associated types are not yet implemented
 
     fn empty() -> Self;
 
@@ -23,7 +24,6 @@ trait Collection<T> {
 
 trait CollectionFamily {
     type Member<T>: Collection<T, Family = Self>;
-    //~^ ERROR type-generic associated types are not yet implemented
 }
 
 struct VecFamily;
@@ -33,7 +33,7 @@ impl CollectionFamily for VecFamily {
 }
 
 impl<T> Collection<T> for Vec<T> {
-    type Iter<'iter> = std::slice::Iter<'iter, T>;
+    type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
     type Family = VecFamily;
 
     fn empty() -> Self {
@@ -53,18 +53,7 @@ fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>
 where
     C: Collection<i32>,
 {
-    let mut res = C::Family::Member::<f32>::empty();
-    for &v in ints.iterate() {
-        res.add(v as f32);
-    }
-    res
-}
-
-fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
-where
-    C: Collection<i32>,
-{
-    let mut res = C::Family::Member::<f32>::empty();
+    let mut res = <C::Family as CollectionFamily>::Member::<f32>::empty();
     for &v in ints.iterate() {
         res.add(v as f32);
     }
@@ -72,11 +61,11 @@ fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
 }
 
 fn use_floatify() {
-    let a = vec![1i32, 2, 3];
-    let b = floatify(a);
-    println!("{}", b.iterate().next());
-    let c = floatify_sibling(a);
-    println!("{}", c.iterate().next());
+    let a = vec![1, 2, 3];
+    let b = floatify(&a);
+    assert_eq!(Some(&1.0), b.iterate().next());
 }
 
-fn main() {}
+fn main() {
+    use_floatify();
+}
diff --git a/src/test/ui/generic-associated-types/collections.stderr b/src/test/ui/generic-associated-types/collections.stderr
deleted file mode 100644 (file)
index fb06d5e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/collections.rs:13:5
-   |
-LL | /     type Sibling<U>: Collection<U> =
-LL | |         <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
-   | |_________________________________________________________________________^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/collections.rs:25:5
-   |
-LL |     type Member<T>: Collection<T, Family = Self>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 2 previous errors
-
index 2198b99db25c1d985f76bd27df24a21300f19ac6..ff9d61658f4eb2a1da4aad9ebad725cb0ce66881 100644 (file)
@@ -1,7 +1,7 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(#30472) normalize enough to handle this.
+// check-pass
 
 use std::ops::Deref;
 
@@ -17,7 +17,6 @@ trait Baz {
 }
 
 impl<T> Baz for T where T: Foo {
-//~^ ERROR type mismatch resolving
     type Quux<'a> where T: 'a = T;
 
     type Baa<'a> where T: 'a = &'a <T as Foo>::Bar<'a, 'static>;
diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.stderr b/src/test/ui/generic-associated-types/construct_with_other_type.stderr
deleted file mode 100644 (file)
index b9468b3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0271]: type mismatch resolving `for<'a> <<T as Baz>::Baa<'a> as std::ops::Deref>::Target == <<T as Baz>::Quux<'a> as Foo>::Bar<'a, 'static>`
-  --> $DIR/construct_with_other_type.rs:19:9
-   |
-LL | impl<T> Baz for T where T: Foo {
-   |      -  ^^^ expected type parameter `T`, found associated type
-   |      |
-   |      this type parameter
-   |
-   = note: expected associated type `<T as Foo>::Bar<'_, 'static>`
-              found associated type `<<T as Baz>::Quux<'_> as Foo>::Bar<'_, 'static>`
-help: consider further restricting this bound
-   |
-LL | impl<T> Baz for T where T: Foo + Baz<Quux = T> {
-   |                                ^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0271`.
index f88df6a608aa33c0e70d53987199071abd53ef64..c1d68812e9356e269a24e2f06a1b16d790522d7b 100644 (file)
@@ -6,7 +6,6 @@
 trait MyTrait {
     type Item<T>;
     //~^ ERROR generic associated types are unstable [E0658]
-    //~| ERROR type-generic associated types are not yet implemented
 }
 
 impl MyTrait for Foo {
index f3da27775adcf18de435375bb9e26c7ebc5f6ec0..34f536dbe8f647b3a96aa8fa9506e0d4325e5561 100644 (file)
@@ -8,7 +8,7 @@ LL |     type Item<T>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/gat-dont-ice-on-absent-feature-2.rs:13:5
+  --> $DIR/gat-dont-ice-on-absent-feature-2.rs:12:5
    |
 LL |     type Item<T> = T;
    |     ^^^^^^^^^^^^^^^^^
@@ -16,14 +16,6 @@ LL |     type Item<T> = T;
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/gat-dont-ice-on-absent-feature-2.rs:7:5
-   |
-LL |     type Item<T>;
-   |     ^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
index 589024e162166821a06597534970444c568fc1e3..1a94796535c14b1f444097f7c8cca8a624e9aada 100644 (file)
@@ -9,11 +9,8 @@
 trait Foo {
     type Assoc where Self: Sized;
     type Assoc2<T> where T: Display;
-    //~^ ERROR type-generic associated types are not yet implemented
     type Assoc3<T>;
-    //~^ ERROR type-generic associated types are not yet implemented
-    type WithDefault<'a, T: Debug + 'a> = dyn Iterator<Item=T>;
-    //~^ ERROR type-generic associated types are not yet implemented
+    type WithDefault<'a, T: Debug + 'a>: ?Sized = dyn Iterator<Item=T>;
     type NoGenerics;
 }
 
@@ -23,6 +20,7 @@ impl Foo for Bar {
     type Assoc = usize;
     type Assoc2<T> = Vec<T>;
     type Assoc3<T> where T: Iterator = Vec<T>;
+    //~^ impl has stricter requirements than trait
     type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator<Item=T>;
     type NoGenerics = ::std::cell::Cell<i32>;
 }
index fb29b377a16e3bd77c6ab73887dfb5736daec953..4d02f2c46a6d062af9f07e308c9f106d6274ddc1 100644 (file)
@@ -1,26 +1,12 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/generic-associated-types-where.rs:11:5
-   |
-LL |     type Assoc2<T> where T: Display;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/generic-associated-types-where.rs:13:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/generic-associated-types-where.rs:22:5
    |
 LL |     type Assoc3<T>;
-   |     ^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/generic-associated-types-where.rs:15:5
-   |
-LL |     type WithDefault<'a, T: Debug + 'a> = dyn Iterator<Item=T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+   |     --------------- definition of `Assoc3` from trait
+...
+LL |     type Assoc3<T> where T: Iterator = Vec<T>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator`
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0276`.
index 53e350aacf88e35448c8c1c9e9c0618917fe4625..de2b978460f7f19020cc78d6e99384733d0dd405 100644 (file)
@@ -5,13 +5,13 @@
 
 trait Foo {
     type Assoc3<T>;
-    //~^ type-generic associated types are not yet implemented
 }
 
 struct Bar;
 
 impl Foo for Bar {
     type Assoc3<T> where T: Iterator = Vec<T>;
+    //~^ ERROR impl has stricter requirements than trait
 }
 
 fn main() {}
index c9c1a4753b0dd4131b00addf78f7d70a10d1a057..bc5c40ff029f9d3c8cf71e51c875a48d73675c6d 100644 (file)
@@ -1,10 +1,12 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/issue-47206-where-clause.rs:7:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/issue-47206-where-clause.rs:13:5
    |
 LL |     type Assoc3<T>;
-   |     ^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+   |     --------------- definition of `Assoc3` from trait
+...
+LL |     type Assoc3<T> where T: Iterator = Vec<T>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0276`.
index 1a79dbf2279a0250f9e8922996b82610d5b142d5..404be59a36d9258b2da2fb91976e7ba41a0c8c64 100644 (file)
@@ -1,11 +1,14 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(generic-associated-types) Investigate why this doesn't compile.
+// check-pass
 
 trait Iterator {
     type Item<'a>: 'a;
-    //~^ ERROR the requirement `for<'a> <Self as Iterator>::Item<'a>: 'a` is not satisfied
+}
+
+impl Iterator for () {
+    type Item<'a> = &'a ();
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr
deleted file mode 100644 (file)
index 4b06baa..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error[E0280]: the requirement `for<'a> <Self as Iterator>::Item<'a>: 'a` is not satisfied
-  --> $DIR/issue-62326-parameter-out-of-range.rs:7:20
-   |
-LL | trait Iterator {
-   |       -------- required by a bound in this
-LL |     type Item<'a>: 'a;
-   |                    ^^ required by this bound in `Iterator`
-
-error: aborting due to previous error
-
index 9b616b8abc2eec2257d0012303c3095124a980c8..fa35a3e8b04d1f609078d4aa5a47944d34d7d0d2 100644 (file)
@@ -7,7 +7,6 @@ trait Trait1 {
 trait Trait2 {
     type Type1<B>: Trait1<A=B>;
     //~^ ERROR: generic associated types are unstable
-    //~| ERROR: type-generic associated types are not yet implemented
 }
 
 fn main() {}
index 8b08c71759bb998c630999935fd8e1b0059b3bfe..bbb7d56f5928e071a8e82d8e628f7bb7e89424fc 100644 (file)
@@ -7,14 +7,6 @@ LL |     type Type1<B>: Trait1<A=B>;
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/issue-67424.rs:8:5
-   |
-LL |     type Type1<B>: Trait1<A=B>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs
new file mode 100644 (file)
index 0000000..71f9b29
--- /dev/null
@@ -0,0 +1,32 @@
+// Regression test for #68641
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait UnsafeCopy {
+    type Item<'a>: Copy;
+
+    fn copy<'a>(item: &Self::Item<'a>) -> Self::Item<'a> {
+        *item
+    }
+}
+
+impl<T> UnsafeCopy for T {
+    type Item<'a> = T;
+    //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied
+}
+
+fn main() {
+    let mut s = String::from("Hello world!");
+
+    let copy = String::copy(&s);
+
+    // Do we indeed point to the samme memory?
+    assert!(s.as_ptr() == copy.as_ptr());
+
+    // Any use of `copy` is certeinly UB after this
+    drop(s);
+
+    // UB UB UB UB UB!!
+    println!("{}", copy);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
new file mode 100644 (file)
index 0000000..834bc3b
--- /dev/null
@@ -0,0 +1,26 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68641-check-gat-bounds.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-68641-check-gat-bounds.rs:15:5
+   |
+LL |     type Item<'a>: Copy;
+   |     -------------------- required by `UnsafeCopy::Item`
+...
+LL |     type Item<'a> = T;
+   |     ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::marker::Copy> UnsafeCopy for T {
+   |       ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs
new file mode 100644 (file)
index 0000000..c99073c
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for #68642
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+    <fn() -> usize>::callme(|| 1);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
new file mode 100644 (file)
index 0000000..89cc5df
--- /dev/null
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68642-broken-llvm-ir.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68642-broken-llvm-ir.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs
new file mode 100644 (file)
index 0000000..24133e7
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for #68643
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+pub fn main() {
+    <fn()>::callme(|| {});
+}
diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
new file mode 100644 (file)
index 0000000..efd3287
--- /dev/null
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68643-broken-mir.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68643-broken-mir.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs
new file mode 100644 (file)
index 0000000..22620c6
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for #68644
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+    <u8>::callme(0);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
new file mode 100644 (file)
index 0000000..5da924a
--- /dev/null
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68644-codegen-selection.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68644-codegen-selection.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs
new file mode 100644 (file)
index 0000000..423b80e
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for #68645
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+    <&dyn Iterator<Item = u8>>::callme(&std::iter::once(1));
+}
diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
new file mode 100644 (file)
index 0000000..12d84ab
--- /dev/null
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68645-codegen-fulfillment.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68645-codegen-fulfillment.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs
new file mode 100644 (file)
index 0000000..4ccd42b
--- /dev/null
@@ -0,0 +1,22 @@
+// Regression test for #68656
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait UnsafeCopy<T: Copy> {
+    type Item<'a>: std::ops::Deref<Target = T>;
+
+    fn bug<'a>(item: &Self::Item<'a>) -> () {
+        let x: T = **item;
+        &x as *const _;
+    }
+}
+
+impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
+    type Item<'a> = T;
+    //~^ ERROR type mismatch resolving `<T as std::ops::Deref>::Target == T`
+}
+
+fn main() {
+    <&'static str>::bug(&"");
+}
diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
new file mode 100644 (file)
index 0000000..e1ceeac
--- /dev/null
@@ -0,0 +1,30 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68656-unsized-values.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0271]: type mismatch resolving `<T as std::ops::Deref>::Target == T`
+  --> $DIR/issue-68656-unsized-values.rs:16:5
+   |
+LL |     type Item<'a>: std::ops::Deref<Target = T>;
+   |     ------------------------------------------- required by `UnsafeCopy::Item`
+...
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
+   |      - this type parameter
+LL |     type Item<'a> = T;
+   |     ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type
+   |
+   = note: expected type parameter `T`
+             found associated type `<T as std::ops::Deref>::Target`
+help: consider further restricting this bound
+   |
+LL | impl<T: Copy + std::ops::Deref + std::ops::Deref<Target = T>> UnsafeCopy<T> for T {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
index 105ab4a8adc380b3cc140552176f36c4ae1e52ec..600a69006c1ea6184a008166e2796f4777a7993f 100644 (file)
@@ -1,7 +1,7 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(#30472) normalize enough to handle this.
+// run-pass
 
 trait Iterable {
     type Item<'a> where Self: 'a;
@@ -13,39 +13,35 @@ trait Iterable {
 // Impl for struct type
 impl<T> Iterable for Vec<T> {
     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-    //~^ ERROR type mismatch resolving
     type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
 
     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-    //~^ ERROR type mismatch resolving
-        self.iter()
+        self[..].iter()
     }
 }
 
 // Impl for a primitive type
 impl<T> Iterable for [T] {
     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-    //~^ ERROR type mismatch resolving
     type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
 
     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-    //~^ ERROR type mismatch resolving
         self.iter()
     }
 }
 
-fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
+fn make_iter<'a, I: Iterable + ?Sized>(it: &'a I) -> I::Iter<'a> {
     it.iter()
 }
 
-fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
+fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option<I::Item<'a>> {
     it.iter().next()
 }
 
 fn main() {
     let v = vec![1, 2, 3];
-    assert_eq!(v, make_iter(&v).copied().collect());
-    assert_eq!(v, make_iter(&*v).copied().collect());
-    assert_eq!(1, get_first(&v));
-    assert_eq!(1, get_first(&*v));
+    assert_eq!(v, make_iter(&v).copied().collect::<Vec<_>>());
+    assert_eq!(v, make_iter(&*v).copied().collect::<Vec<_>>());
+    assert_eq!(Some(&1), get_first(&v));
+    assert_eq!(Some(&1), get_first(&*v));
 }
diff --git a/src/test/ui/generic-associated-types/iterable.stderr b/src/test/ui/generic-associated-types/iterable.stderr
deleted file mode 100644 (file)
index 6e75462..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:15:33
-   |
-LL |     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type
-   |
-   = note:    expected reference `&T`
-           found associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
-   = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:27:33
-   |
-LL |     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type
-   |
-   = note:    expected reference `&T`
-           found associated type `<[T] as Iterable>::Item<'_>`
-   = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:19:30
-   |
-LL | trait Iterable {
-   |       -------- required by a bound in this
-LL |     type Item<'a> where Self: 'a;
-LL |     type Iter<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
-   |                             --------------------- required by this bound in `Iterable`
-...
-LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-   |                              ^^^^^^^^^^^^^^ expected associated type, found reference
-   |
-   = note: expected associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
-                    found reference `&T`
-   = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` or calling a method that returns `<std::vec::Vec<T> as Iterable>::Item<'_>`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:31:30
-   |
-LL | trait Iterable {
-   |       -------- required by a bound in this
-LL |     type Item<'a> where Self: 'a;
-LL |     type Iter<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
-   |                             --------------------- required by this bound in `Iterable`
-...
-LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-   |                              ^^^^^^^^^^^^^^ expected associated type, found reference
-   |
-   = note: expected associated type `<[T] as Iterable>::Item<'_>`
-                    found reference `&T`
-   = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0271`.
index 364d2388741b0e9664970e9a17bd4ba6a94a3136..3ba7d043d0759a636d402cea317b26ee3c6a2b9a 100644 (file)
@@ -34,12 +34,11 @@ impl<B: std::ops::Add<Output = B>> Add for D<B> {
 
 struct E<B>(B);
 
-impl<B: Add> Add for E<B> where B: Add<Output = B>, B: std::ops::Add<Output = B> {
-    //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
+        Self(self.0 + rhs.0)
     }
 }
 
index ffafff5e9f586d2543061aaaa616eec501040f8a..962d2db9476bd73a0b690c940831ec83d567d308 100644 (file)
@@ -34,12 +34,11 @@ fn add(self, rhs: Self) -> Self {
 
 struct E<B>(B);
 
-impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-    //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
+        Self(self.0 + rhs.0)
     }
 }
 
index 50536fdaca96e25d04359a9ac5bf05d8c5ee4194..630ceac093ef29764728918fdc1b96b2b78362ee 100644 (file)
@@ -1,15 +1,3 @@
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/missing-bounds.rs:37:33
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
-   |                                 ^^^^^^^^^^^^^^^^^^
-
 error[E0308]: mismatched types
   --> $DIR/missing-bounds.rs:11:11
    |
@@ -55,23 +43,7 @@ help: consider restricting type parameter `B`
 LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:42:14
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-   |      - this type parameter
-...
-LL |         Self(self.0 + rhs.0)
-   |              ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
-   |
-   = note: expected type parameter `B`
-             found associated type `<B as std::ops::Add>::Output`
-help: consider further restricting type parameter `B`
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: std::ops::Add<Output = B> {
-   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0308, E0369.
 For more information about an error, try `rustc --explain E0308`.
index 0edc5c48c01af48773a97edc1c94b5540f755ae3..f4d09fc1539da658835677719c8b349770930930 100644 (file)
@@ -7,18 +7,14 @@ trait Foo {
     type B<'a, 'b>;
     type C;
     type D<T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     type E<'a, T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     // Test parameters in default values
     type FOk<T> = Self::E<'static, T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     type FErr1 = Self::E<'static, 'static>;
     //~^ ERROR wrong number of lifetime arguments: expected 1, found 2
     //~| ERROR wrong number of type arguments: expected 1, found 0
     type FErr2<T> = Self::E<'static, T, u32>;
-    //~^ ERROR type-generic associated types are not yet implemented
-    //~| ERROR wrong number of type arguments: expected 1, found 2
+    //~^ ERROR wrong number of type arguments: expected 1, found 2
 }
 
 fn main() {}
index 028ab72f48812cdb66c6f52bf1e5524b7120895b..ed090e302cefacb513de11b64e4b8f82e1af296e 100644 (file)
@@ -1,53 +1,21 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:9:5
-   |
-LL |     type D<T>;
-   |     ^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:11:5
-   |
-LL |     type E<'a, T>;
-   |     ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:14:5
-   |
-LL |     type FOk<T> = Self::E<'static, T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:19:5
-   |
-LL |     type FErr2<T> = Self::E<'static, T, u32>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
 error[E0107]: wrong number of lifetime arguments: expected 1, found 2
-  --> $DIR/parameter_number_and_kind.rs:16:35
+  --> $DIR/parameter_number_and_kind.rs:13:35
    |
 LL |     type FErr1 = Self::E<'static, 'static>;
    |                                   ^^^^^^^ unexpected lifetime argument
 
 error[E0107]: wrong number of type arguments: expected 1, found 0
-  --> $DIR/parameter_number_and_kind.rs:16:18
+  --> $DIR/parameter_number_and_kind.rs:13:18
    |
 LL |     type FErr1 = Self::E<'static, 'static>;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument
 
 error[E0107]: wrong number of type arguments: expected 1, found 2
-  --> $DIR/parameter_number_and_kind.rs:19:41
+  --> $DIR/parameter_number_and_kind.rs:16:41
    |
 LL |     type FErr2<T> = Self::E<'static, T, u32>;
    |                                         ^^^ unexpected type argument
 
-error: aborting due to 7 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
index 1668759b4e39c00ec9db1b4b9d654796ca819114..b322b752a156738a349bb866f9ef1a837fdb678c 100644 (file)
@@ -1,7 +1,7 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(#44265): allow type-generic associated types.
+// check-pass
 
 use std::rc::Rc;
 use std::sync::Arc;
@@ -9,7 +9,6 @@
 
 trait PointerFamily {
     type Pointer<T>: Deref<Target = T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     fn new<T>(value: T) -> Self::Pointer<T>;
 }
 
diff --git a/src/test/ui/generic-associated-types/pointer_family.stderr b/src/test/ui/generic-associated-types/pointer_family.stderr
deleted file mode 100644 (file)
index 83fe992..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/pointer_family.rs:11:5
-   |
-LL |     type Pointer<T>: Deref<Target = T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to previous error
-
index 5c308948bd3f87d2574713b0a53362618442172a..44528ca1da36e40f37c198167f0b2d087b3c24d2 100644 (file)
@@ -18,12 +18,10 @@ impl<'a> NoShadow<'a> for &'a u32 {
 trait ShadowT<T> {
     type Bar<T>;
     //~^ ERROR the name `T` is already used
-    //~| ERROR type-generic associated types are not yet implemented
 }
 
 trait NoShadowT<T> {
     type Bar<U>; // OK
-    //~^ ERROR type-generic associated types are not yet implemented
 }
 
 impl<T> NoShadowT<T> for Option<T> {
index 2d9a0d6fceb2dbaf6754faa28268dae58531980f..d51c29080a0c9f662836e24671b1763ea6820bd0 100644 (file)
@@ -7,7 +7,7 @@ LL |     type Bar<T>;
    |              ^ already used
 
 error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/shadowing.rs:30:14
+  --> $DIR/shadowing.rs:28:14
    |
 LL | impl<T> NoShadowT<T> for Option<T> {
    |      - first use of `T`
@@ -30,23 +30,7 @@ LL | impl<'a> NoShadow<'a> for &'a u32 {
 LL |     type Bar<'a> = i32;
    |              ^^ lifetime 'a already in scope
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/shadowing.rs:19:5
-   |
-LL |     type Bar<T>;
-   |     ^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/shadowing.rs:25:5
-   |
-LL |     type Bar<U>; // OK
-   |     ^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0403, E0496.
 For more information about an error, try `rustc --explain E0403`.
diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs
new file mode 100644 (file)
index 0000000..7510c58
--- /dev/null
@@ -0,0 +1,22 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+trait ATy {
+    type Item<'a>: 'a;
+}
+
+impl<'b> ATy for &'b () {
+    type Item<'a> = &'b ();
+    //~^ ERROR does not fulfill the required lifetime
+}
+
+trait StaticTy {
+    type Item<'a>: 'static;
+}
+
+impl StaticTy for () {
+    type Item<'a> = &'a ();
+    //~^ ERROR does not fulfill the required lifetime
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr
new file mode 100644 (file)
index 0000000..5d61228
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0477]: the type `&'b ()` does not fulfill the required lifetime
+  --> $DIR/unsatisfied-outlives-bound.rs:9:5
+   |
+LL |     type Item<'a> = &'b ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must outlive the lifetime `'a` as defined on the associated item at 9:15
+  --> $DIR/unsatisfied-outlives-bound.rs:9:15
+   |
+LL |     type Item<'a> = &'b ();
+   |               ^^
+
+error[E0477]: the type `&'a ()` does not fulfill the required lifetime
+  --> $DIR/unsatisfied-outlives-bound.rs:18:5
+   |
+LL |     type Item<'a> = &'a ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type must satisfy the static lifetime
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0477`.
index 63c435cc20641268f130505e19e93e44ca463749..32660fdb41876158f95f34860e837cefd8c052cc 100644 (file)
@@ -29,3 +29,7 @@ fn main() {
     foo::<C>(); //~ ERROR: cannot find type `C` in this scope
     foo::<D>(); //~ ERROR: cannot find type `D` in this scope
 }
+
+mod other {
+    pub fn import() {}
+}
index 995da6cc1f97591ed07fcd348edd2865d8082f9b..3c818f3ae48ea4634db7720946b065247e97b3a5 100644 (file)
@@ -42,6 +42,11 @@ error[E0425]: cannot find function `import` in this scope
    |
 LL |     import();
    |     ^^^^^^ not found in this scope
+   |
+help: consider importing this function
+   |
+LL | use other::import;
+   |
 
 error[E0412]: cannot find type `A` in this scope
   --> $DIR/glob-resolve1.rs:28:11
index 028bfb89312fc7174760aa9925efc48e4200ec87..5744232235dd151e8c777702759a2fa3c56ef5f4 100644 (file)
@@ -79,20 +79,20 @@ LL |         m!(0, ..core::u8::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `254u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `254u8..=u8::MAX` not covered
+   |            ^ pattern `254_u8..=u8::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `0u8` not covered
+error[E0004]: non-exhaustive patterns: `0_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
    |
 LL |         m!(0, ALMOST_MIN..);
-   |            ^ pattern `0u8` not covered
+   |            ^ pattern `0_u8` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
@@ -106,20 +106,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `43u8` not covered
+error[E0004]: non-exhaustive patterns: `43_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43u8` not covered
+   |            ^ pattern `43_u8` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `43u8` not covered
+error[E0004]: non-exhaustive patterns: `43_u8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:46:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43u8` not covered
+   |            ^ pattern `43_u8` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
@@ -133,20 +133,20 @@ LL |         m!(0, ..core::u16::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
 
-error[E0004]: non-exhaustive patterns: `65534u16..=u16::MAX` not covered
+error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `65534u16..=u16::MAX` not covered
+   |            ^ pattern `65534_u16..=u16::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
 
-error[E0004]: non-exhaustive patterns: `0u16` not covered
+error[E0004]: non-exhaustive patterns: `0_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
    |
 LL |         m!(0, ALMOST_MIN..);
-   |            ^ pattern `0u16` not covered
+   |            ^ pattern `0_u16` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
@@ -160,20 +160,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
 
-error[E0004]: non-exhaustive patterns: `43u16` not covered
+error[E0004]: non-exhaustive patterns: `43_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43u16` not covered
+   |            ^ pattern `43_u16` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
 
-error[E0004]: non-exhaustive patterns: `43u16` not covered
+error[E0004]: non-exhaustive patterns: `43_u16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:59:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43u16` not covered
+   |            ^ pattern `43_u16` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u16`
@@ -187,20 +187,20 @@ LL |         m!(0, ..core::u32::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
 
-error[E0004]: non-exhaustive patterns: `4294967294u32..=u32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `4294967294u32..=u32::MAX` not covered
+   |            ^ pattern `4294967294_u32..=u32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
 
-error[E0004]: non-exhaustive patterns: `0u32` not covered
+error[E0004]: non-exhaustive patterns: `0_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
    |
 LL |         m!(0, ALMOST_MIN..);
-   |            ^ pattern `0u32` not covered
+   |            ^ pattern `0_u32` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
@@ -214,20 +214,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
 
-error[E0004]: non-exhaustive patterns: `43u32` not covered
+error[E0004]: non-exhaustive patterns: `43_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43u32` not covered
+   |            ^ pattern `43_u32` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
 
-error[E0004]: non-exhaustive patterns: `43u32` not covered
+error[E0004]: non-exhaustive patterns: `43_u32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:72:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43u32` not covered
+   |            ^ pattern `43_u32` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u32`
@@ -241,20 +241,20 @@ LL |         m!(0, ..core::u64::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
 
-error[E0004]: non-exhaustive patterns: `18446744073709551614u64..=u64::MAX` not covered
+error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `18446744073709551614u64..=u64::MAX` not covered
+   |            ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
 
-error[E0004]: non-exhaustive patterns: `0u64` not covered
+error[E0004]: non-exhaustive patterns: `0_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
    |
 LL |         m!(0, ALMOST_MIN..);
-   |            ^ pattern `0u64` not covered
+   |            ^ pattern `0_u64` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
@@ -268,20 +268,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
 
-error[E0004]: non-exhaustive patterns: `43u64` not covered
+error[E0004]: non-exhaustive patterns: `43_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43u64` not covered
+   |            ^ pattern `43_u64` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
 
-error[E0004]: non-exhaustive patterns: `43u64` not covered
+error[E0004]: non-exhaustive patterns: `43_u64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:85:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43u64` not covered
+   |            ^ pattern `43_u64` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u64`
@@ -295,20 +295,20 @@ LL |         m!(0, ..core::u128::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `340282366920938463463374607431768211454u128..=u128::MAX` not covered
+   |            ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `0u128` not covered
+error[E0004]: non-exhaustive patterns: `0_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
    |
 LL |         m!(0, ALMOST_MIN..);
-   |            ^ pattern `0u128` not covered
+   |            ^ pattern `0_u128` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
@@ -322,20 +322,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `43u128` not covered
+error[E0004]: non-exhaustive patterns: `43_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43u128` not covered
+   |            ^ pattern `43_u128` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `43u128` not covered
+error[E0004]: non-exhaustive patterns: `43_u128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:98:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43u128` not covered
+   |            ^ pattern `43_u128` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
@@ -349,11 +349,11 @@ LL |         m!(0, ..core::i8::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
 
-error[E0004]: non-exhaustive patterns: `126i8..=i8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `126i8..=i8::MAX` not covered
+   |            ^ pattern `126_i8..=i8::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
@@ -376,20 +376,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
 
-error[E0004]: non-exhaustive patterns: `43i8` not covered
+error[E0004]: non-exhaustive patterns: `43_i8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43i8` not covered
+   |            ^ pattern `43_i8` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
 
-error[E0004]: non-exhaustive patterns: `43i8` not covered
+error[E0004]: non-exhaustive patterns: `43_i8` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:114:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43i8` not covered
+   |            ^ pattern `43_i8` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
@@ -403,11 +403,11 @@ LL |         m!(0, ..core::i16::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
 
-error[E0004]: non-exhaustive patterns: `32766i16..=i16::MAX` not covered
+error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `32766i16..=i16::MAX` not covered
+   |            ^ pattern `32766_i16..=i16::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
@@ -430,20 +430,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
 
-error[E0004]: non-exhaustive patterns: `43i16` not covered
+error[E0004]: non-exhaustive patterns: `43_i16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43i16` not covered
+   |            ^ pattern `43_i16` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
 
-error[E0004]: non-exhaustive patterns: `43i16` not covered
+error[E0004]: non-exhaustive patterns: `43_i16` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:127:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43i16` not covered
+   |            ^ pattern `43_i16` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
@@ -457,11 +457,11 @@ LL |         m!(0, ..core::i32::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
 
-error[E0004]: non-exhaustive patterns: `2147483646i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `2147483646i32..=i32::MAX` not covered
+   |            ^ pattern `2147483646_i32..=i32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
@@ -484,20 +484,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
 
-error[E0004]: non-exhaustive patterns: `43i32` not covered
+error[E0004]: non-exhaustive patterns: `43_i32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43i32` not covered
+   |            ^ pattern `43_i32` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
 
-error[E0004]: non-exhaustive patterns: `43i32` not covered
+error[E0004]: non-exhaustive patterns: `43_i32` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:140:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43i32` not covered
+   |            ^ pattern `43_i32` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
@@ -511,11 +511,11 @@ LL |         m!(0, ..core::i64::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
 
-error[E0004]: non-exhaustive patterns: `9223372036854775806i64..=i64::MAX` not covered
+error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `9223372036854775806i64..=i64::MAX` not covered
+   |            ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
@@ -538,20 +538,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
 
-error[E0004]: non-exhaustive patterns: `43i64` not covered
+error[E0004]: non-exhaustive patterns: `43_i64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43i64` not covered
+   |            ^ pattern `43_i64` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
 
-error[E0004]: non-exhaustive patterns: `43i64` not covered
+error[E0004]: non-exhaustive patterns: `43_i64` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:153:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43i64` not covered
+   |            ^ pattern `43_i64` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i64`
@@ -565,11 +565,11 @@ LL |         m!(0, ..core::i128::MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
 
-error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726i128..=i128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
    |
 LL |         m!(0, ..ALMOST_MAX);
-   |            ^ pattern `170141183460469231731687303715884105726i128..=i128::MAX` not covered
+   |            ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
@@ -592,20 +592,20 @@ LL |         m!(0, ..=ALMOST_MAX);
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
 
-error[E0004]: non-exhaustive patterns: `43i128` not covered
+error[E0004]: non-exhaustive patterns: `43_i128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
    |
 LL |         m!(0, ..=VAL | VAL_2..);
-   |            ^ pattern `43i128` not covered
+   |            ^ pattern `43_i128` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
 
-error[E0004]: non-exhaustive patterns: `43i128` not covered
+error[E0004]: non-exhaustive patterns: `43_i128` not covered
   --> $DIR/half-open-range-pats-exhaustive-fail.rs:166:12
    |
 LL |         m!(0, ..VAL_1 | VAL_2..);
-   |            ^ pattern `43i128` not covered
+   |            ^ pattern `43_i128` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i128`
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr
new file mode 100644 (file)
index 0000000..d534356
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
+LL | | for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+   | |_____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
index b91798fa1237913a168ea43df13fb5f4eebd4c95..92a85825030c27bf80e890c9b4ce3125c777f2bf 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-LL | |                                             for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
-   | |_________________________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+   | |_____________________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
               found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32) -> &'a u32>`
index 45f53d4fe99db100ec221ad503ca80717c510b44..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-LL | |                                 for<'a>    fn(&'a u32, &'a u32)) }
-   | |__________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
-              found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr
new file mode 100644 (file)
index 0000000..f115609
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
index c3e4f6d2ed0c1c91e348822f324bcacb0e28f386..98f5bff732762e808b1b6f20bd0e82d67ab286cf 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-LL | |                              fn(&'x u32)) }
-   | |___________________________________________- in this macro invocation
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a> fn(&'a u32)>`
               found enum `std::option::Option<fn(&'x u32)>`
index 4d7b86027f56463d68b380b4bd73d51b354d1f93..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-LL | |                                       for<'a>    fn(Co<'a>, Co<'a>)) }
-   | |______________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
index 7f0a4197dd7fe412d5602ba145b5a0c8970e48bc..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-LL | |                                         for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
-   | |______________________________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index c12e543a44e79e29a8cd21449e220cbfd0a96864..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-LL | |                                             for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
-   | |______________________________________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
-              found enum `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr
new file mode 100644 (file)
index 0000000..4541c46
--- /dev/null
@@ -0,0 +1,26 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
index 460356856bd562cd9f229b1f832c5cb04982635d..100ba6ac27e2530f11ce2d8c3e1e192852b1efef 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-LL | |                                         for<'a>    fn(Inv<'a>, Inv<'a>)) }
-   | |__________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
               found enum `std::option::Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index 6b5e7a5a6345a5ecf515af8b60aca007e25054a3..af5cf41be0a48f279b49f81e9961cd5cbf91785c 100644 (file)
@@ -1,33 +1,33 @@
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:33:13
+  --> $DIR/hr-subtype.rs:39:13
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
-   |                      -- -- lifetime `'y` defined here
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
+   |                      --  -- lifetime `'y` defined here
    |                      |
    |                      lifetime `'x` defined here
 LL |               gimme::<$t2>(None::<$t1>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:39:13
+  --> $DIR/hr-subtype.rs:45:13
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                        -- -- lifetime `'y` defined here
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                        --  -- lifetime `'y` defined here
    |                        |
    |                        lifetime `'x` defined here
 LL |               gimme::<$t1>(None::<$t2>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
index fc3643306e628cf0a1cb0185a1a674f495df2557..3c8af20e50cef383296b4663c454839320917791 100644 (file)
@@ -1,65 +1,65 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:33:26
+  --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t2>(None::<$t1>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'y>)>`
               found enum `std::option::Option<fn(Inv<'x>)>`
-note: the lifetime `'x` as defined on the function body at 32:20...
-  --> $DIR/hr-subtype.rs:32:20
+note: the lifetime `'x` as defined on the function body at 38:20...
+  --> $DIR/hr-subtype.rs:38:20
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
    |                      ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 32:23
-  --> $DIR/hr-subtype.rs:32:23
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:24
+  --> $DIR/hr-subtype.rs:38:24
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
-   |                         ^^
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
+   |                          ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'x>)>`
               found enum `std::option::Option<fn(Inv<'y>)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..948375566104becb71af12379dc710934c685e3c 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index 7c0770924daaac4c54807f3824e57b3b24c45e92..75d7e0e46b72a75d25055944a0af69b368d81a7f 100644 (file)
@@ -1,16 +1,16 @@
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:39:13
+  --> $DIR/hr-subtype.rs:45:13
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                        -- -- lifetime `'y` defined here
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                        --  -- lifetime `'y` defined here
    |                        |
    |                        lifetime `'x` defined here
 LL |               gimme::<$t1>(None::<$t2>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
index 0dde27788f6296212d46f897aa762803c7ea0fcc..7b4cdd4a419b4f4856e7f7409f71e5f5766a5af8 100644 (file)
@@ -1,33 +1,33 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(&'x u32)>`
               found enum `std::option::Option<fn(&'y u32)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index b31f198bd97bf8cee87182f5f2efae6780ce8870..ad9500eedca935efa09aa76beb3ba29d6b30897b 100644 (file)
 // revisions: bound_inv_a_b_vs_bound_inv_a
 // revisions: bound_a_b_ret_a_vs_bound_a_ret_a
 
-fn gimme<T>(_: Option<T>) { }
+fn gimme<T>(_: Option<T>) {}
 
-struct Inv<'a> { x: *mut &'a u32 }
+struct Inv<'a> {
+    x: *mut &'a u32,
+}
 
-struct Co<'a> { x: fn(&'a u32) }
+struct Co<'a> {
+    x: fn(&'a u32),
+}
 
-struct Contra<'a> { x: &'a u32 }
+struct Contra<'a> {
+    x: &'a u32,
+}
 
 macro_rules! check {
     ($rev:ident: ($t1:ty, $t2:ty)) => {
         #[cfg($rev)]
-        fn subtype<'x,'y:'x,'z:'y>() {
+        fn subtype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t2>(None::<$t1>);
             //[free_inv_x_vs_free_inv_y]~^ ERROR
         }
 
         #[cfg($rev)]
-        fn supertype<'x,'y:'x,'z:'y>() {
+        fn supertype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t1>(None::<$t2>);
             //[bound_a_vs_free_x]~^ ERROR
             //[free_x_vs_free_y]~^^ ERROR
             //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR
             //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR
             //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR
-            //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types
-            //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
-            //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR
-            //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR
         }
-    }
+    };
 }
 
 // If both have bound regions, they are equivalent, regardless of
 // variant.
 check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32),
-                              for<'a> fn(&'a u32)) }
+for<'a> fn(&'a u32)) }
 check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32),
-                              for<'b> fn(&'b u32)) }
+for<'b> fn(&'b u32)) }
 check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>),
-                                      for<'b> fn(Inv<'b>)) }
+for<'b> fn(Inv<'b>)) }
 check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>),
-                                    for<'b> fn(Co<'b>)) }
+for<'b> fn(Co<'b>)) }
 
 // Bound is a subtype of free.
 check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-                             fn(&'x u32)) }
+fn(&'x u32)) }
 
 // Two free regions are relatable if subtyping holds.
 check! { free_x_vs_free_x: (fn(&'x u32),
-                            fn(&'x u32)) }
+fn(&'x u32)) }
 check! { free_x_vs_free_y: (fn(&'x u32),
-                            fn(&'y u32)) }
+fn(&'y u32)) }
 check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-                                    fn(Inv<'y>)) }
+fn(Inv<'y>)) }
 
 // Somewhat surprisingly, a fn taking two distinct bound lifetimes and
 // a fn taking one bound lifetime can be interchangeable, but only if
@@ -82,25 +84,29 @@ fn supertype<'x,'y:'x,'z:'y>() {
 //   intersection;
 // - if we are contravariant, then 'a can be inferred to 'static.
 check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-                                for<'a>    fn(&'a u32, &'a u32)) }
+for<'a>    fn(&'a u32, &'a u32)) }
 check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-                                      for<'a>    fn(Co<'a>, Co<'a>)) }
+for<'a>    fn(Co<'a>, Co<'a>)) }
 check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-                                            for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
 check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-                                        for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
+for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
 
 // If we make those lifetimes invariant, then the two types are not interchangeable.
 check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-                                        for<'a>    fn(Inv<'a>, Inv<'a>)) }
+for<'a>    fn(Inv<'a>, Inv<'a>)) }
 check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-                                            for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
 
 #[rustc_error]
 fn main() {
-//[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
-//[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
-//[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_b_vs_bound_co_a]~^^^^^^ ERROR
+    //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
+    //[bound_a_b_vs_bound_a]~^^^^^^^^ ERROR
+    //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR
 }
diff --git a/src/test/ui/hr-subtype/return-static.rs b/src/test/ui/hr-subtype/return-static.rs
new file mode 100644 (file)
index 0000000..6455854
--- /dev/null
@@ -0,0 +1,13 @@
+// check-pass
+
+fn make<T>() -> T {
+    panic!()
+}
+
+fn take<T>(x: T) {}
+
+fn main() {
+    let x: for<'a> fn(&'a u32) -> _ = make();
+    let y: &'static u32 = x(&22);
+    take::<for<'b> fn(&'b u32) -> &'b u32>(x);
+}
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
new file mode 100644 (file)
index 0000000..f290a93
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
index 7250935ea296b067fb44fd8798154d9dd631adca..45573814d13c0945f2577dd3843a8e13da15fb06 100644 (file)
@@ -1,17 +1,16 @@
-error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied
-  --> $DIR/hrtb-conflate-regions.rs:27:22
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-conflate-regions.rs:27:10
    |
-LL | fn want_foo2<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
-   |               -------------------------------------- required by this bound in `want_foo2`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL | fn b() { want_foo2::<SomeStruct>(); }
-   |                      ^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct`
+LL |   fn b() { want_foo2::<SomeStruct>(); }
+   |            ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <SomeStruct as Foo<(&'a isize, &'a isize)>>
+   = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr
new file mode 100644 (file)
index 0000000..11390d9
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-fn.rs:17:12
+   |
+LL |     let _: for<'b> fn(&'b u32) = foo();
+   |            ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 328e98657effb179aa1f90cc61ec76274c533b00..9914783d9767d5d99ecd0790eae8597cc1714265 100644 (file)
@@ -2,9 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hrtb-exists-forall-fn.rs:17:34
    |
 LL |     let _: for<'b> fn(&'b u32) = foo();
-   |            -------------------   ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b
-   |            |
-   |            expected due to this
+   |                                  ^^^^^ one type is more general than the other
    |
    = note: expected fn pointer `for<'b> fn(&'b u32)`
               found fn pointer `fn(&u32)`
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
new file mode 100644 (file)
index 0000000..a4c3ffd
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 4c1d4d28a09b01eace9d5efbd5a2596ea8632f14..921061916fc95b7d46c891db83d39cfae29499a5 100644 (file)
@@ -32,5 +32,5 @@ fn main() {
     // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
-    //~^ ERROR not satisfied
+    //~^ ERROR implementation of `Trait` is not general enough
 }
index 7a7285d3d76e051dbc23c8ee082448a4be4fe33e..fe8209d054c8ad641044ddda3eda030241b2ec80 100644 (file)
@@ -1,18 +1,14 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(&'b u32)>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:11
+error: implementation of `Trait` is not general enough
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
    |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(&'b u32)>,
-   |        -------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+   | ----------------- trait `Trait` defined here
 ...
 LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(&'b u32)>` is not implemented for `()`
+   |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = help: the following implementations were found:
-             <() as Trait<fn(&'a u32)>>
+   = note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
+   = note: ...but `()` actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index 95b57d6c5bb5ed2998209f67667575d0ff262c6a..f95496a6c3cc0dc5845f83dfede498241dd2632f 100644 (file)
@@ -2,6 +2,8 @@
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
+//
+// check-pass
 
 trait Trait<T> {}
 
@@ -30,9 +32,6 @@ fn main() {
     //         - `?b: ?a` -- solveable if `?b` is inferred to `'static`
     // - So the subtyping check succeeds, somewhat surprisingly.
     //   This is because we can use `'static`.
-    //
-    // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
-    //~^ ERROR not satisfied
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
deleted file mode 100644 (file)
index 1e335f9..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(fn(&'b u32))>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:11
-   |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(fn(&'b u32))>,
-   |        ------------------------------ required by this bound in `foo`
-...
-LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(fn(&'b u32))>` is not implemented for `()`
-   |
-   = help: the following implementations were found:
-             <() as Trait<fn(fn(&'a u32))>>
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
new file mode 100644 (file)
index 0000000..e2a399b
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 827a68beee8bd67e6f356c6a5e39dbfca494ce40..b1b7ec6bcf1a5803b80ee3f6b0a8bc1225d90f30 100644 (file)
@@ -25,5 +25,5 @@ fn main() {
     //     yielding `fn(&!b u32)`, in a fresh universe U1
     //   - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`.
 
-    foo::<()>(); //~ ERROR not satisfied
+    foo::<()>(); //~ ERROR implementation of `Trait` is not general enough
 }
index 9174ea4d8419d208f087468ffe879240533ee88a..720e2276d5343705292569e851f3dc6815dad7f3 100644 (file)
@@ -1,18 +1,14 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:11
+error: implementation of `Trait` is not general enough
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
    |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(Cell<&'b u32>)>,
-   |        -------------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+   | ----------------- trait `Trait` defined here
 ...
 LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not implemented for `()`
+   |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = help: the following implementations were found:
-             <() as Trait<fn(std::cell::Cell<&'a u32>)>>
+   = note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
+   = note: ...but `()` actually implements `Trait<fn(std::cell::Cell<&'0 u32>)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
new file mode 100644 (file)
index 0000000..8901a1b
--- /dev/null
@@ -0,0 +1,24 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:24:5
+   |
+LL |     want_hrtb::<StaticInt>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL | fn give_some<'a>() {
+   |              -- lifetime `'a` defined here
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index 4fa404624775b731bba309d7034687fefba4fd1d..5e3014317f5bc7025c8eddaeee4a217aee17639f 100644 (file)
@@ -1,31 +1,30 @@
-error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
-  --> $DIR/hrtb-just-for-static.rs:24:17
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-just-for-static.rs:24:5
    |
-LL | fn want_hrtb<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a> Foo<&'a isize>
-   |               ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL |     want_hrtb::<StaticInt>()
-   |                 ^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt`
+LL |       want_hrtb::<StaticInt>()
+   |       ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <StaticInt as Foo<&'static isize>>
+   = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
+   = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
 
-error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied
-  --> $DIR/hrtb-just-for-static.rs:30:17
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-just-for-static.rs:30:5
    |
-LL | fn want_hrtb<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a> Foo<&'a isize>
-   |               ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL |     want_hrtb::<&'a u32>()
-   |                 ^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32`
+LL |       want_hrtb::<&'a u32>()
+   |       ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <&'a u32 as Foo<&'a isize>>
+   = note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`...
+   = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
index c0e3fd3cf4679dc3d8d9b70943d1cfd8f2a7e1c1..90a7cadca41b7e43336a55b4674122aa0313e725 100644 (file)
@@ -1,17 +1,43 @@
-error: implementation of `Stream` is not general enough
-  --> $DIR/issue-30786.rs:108:22
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+  --> $DIR/issue-30786.rs:128:22
    |
-LL | / pub trait Stream {
-LL | |     type Item;
-LL | |     fn next(self) -> Option<Self::Item>;
-LL | | }
-   | |_- trait `Stream` defined here
+LL | pub struct Map<S, F> {
+   | --------------------
+   | |
+   | method `filterx` not found for this
+   | doesn't satisfy `_: StreamExt`
 ...
-LL |       let map = source.map(|x: &_| x);
-   |                        ^^^ implementation of `Stream` is not general enough
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
    |
-   = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`...
-   = note: ...but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
+   = note: the method `filterx` exists but the following trait bounds were not satisfied:
+           `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
 
-error: aborting due to previous error
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+  --> $DIR/issue-30786.rs:141:24
+   |
+LL | pub struct Filter<S, F> {
+   | -----------------------
+   | |
+   | method `countx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+   |
+   = note: the method `countx` exists but the following trait bounds were not satisfied:
+           `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0599`.
index c736c5479f848a47a0b9cd05927477795f280dc6..90a7cadca41b7e43336a55b4674122aa0313e725 100644 (file)
@@ -1,56 +1,43 @@
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:108:15
-   |
-LL |     let map = source.map(|x: &_| x);
-   |               ^^^^^^^^^^^^^^^^^^^^^
-
-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: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 9 previous errors
-
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+  --> $DIR/issue-30786.rs:128:22
+   |
+LL | pub struct Map<S, F> {
+   | --------------------
+   | |
+   | method `filterx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
+   |
+   = note: the method `filterx` exists but the following trait bounds were not satisfied:
+           `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+  --> $DIR/issue-30786.rs:141:24
+   |
+LL | pub struct Filter<S, F> {
+   | -----------------------
+   | |
+   | method `countx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+   |
+   = note: the method `countx` exists but the following trait bounds were not satisfied:
+           `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
index c656f8430653629be8124a5b4114d9276921454a..8ce5c090b543edcd646a7c3d65809e8323ab9b53 100644 (file)
@@ -16,7 +16,7 @@
 
 //[nll]compile-flags: -Z borrowck=mir
 
-pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here
+pub trait Stream {
     type Item;
     fn next(self) -> Option<Self::Item>;
 }
@@ -37,8 +37,9 @@ pub struct Map<S, F> {
 }
 
 impl<'a, A, F, T> Stream for &'a mut Map<A, F>
-where &'a mut A: Stream,
-      F: FnMut(<&'a mut A as Stream>::Item) -> T,
+where
+    &'a mut A: Stream,
+    F: FnMut(<&'a mut A as Stream>::Item) -> T,
 {
     type Item = T;
     fn next(self) -> Option<T> {
@@ -55,8 +56,9 @@ pub struct Filter<S, F> {
 }
 
 impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
-where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
-      F: FnMut(&T) -> bool,
+where
+    for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
+    F: FnMut(&T) -> bool,
 {
     type Item = <&'a mut A as Stream>::Item;
     fn next(self) -> Option<Self::Item> {
@@ -69,29 +71,29 @@ fn next(self) -> Option<Self::Item> {
     }
 }
 
-pub trait StreamExt where for<'b> &'b mut Self: Stream {
-    fn map<F>(self, func: F) -> Map<Self, F>
-    where Self: Sized,
-    for<'a> &'a mut Map<Self, F>: Stream,
+pub trait StreamExt
+where
+    for<'b> &'b mut Self: Stream,
+{
+    fn mapx<F>(self, func: F) -> Map<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Map<Self, F>: Stream,
     {
-        Map {
-            func: func,
-            stream: self,
-        }
+        Map { func: func, stream: self }
     }
 
-    fn filter<F>(self, func: F) -> Filter<Self, F>
-    where Self: Sized,
-    for<'a> &'a mut Filter<Self, F>: Stream,
+    fn filterx<F>(self, func: F) -> Filter<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Filter<Self, F>: Stream,
     {
-        Filter {
-            func: func,
-            stream: self,
-        }
+        Filter { func: func, stream: self }
     }
 
-    fn count(mut self) -> usize
-    where Self: Sized,
+    fn countx(mut self) -> usize
+    where
+        Self: Sized,
     {
         let mut count = 0;
         while let Some(_) = self.next() {
@@ -101,24 +103,44 @@ fn count(mut self) -> usize
     }
 }
 
-impl<T> StreamExt for T where for<'a> &'a mut T: Stream { }
+impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
 
-fn main() {
+fn identity<T>(x: &T) -> &T {
+    x
+}
+
+fn variant1() {
     let source = Repeat(10);
-    let map = source.map(|x: &_| x);
-    //[nll]~^ ERROR higher-ranked subtype error
-    //[migrate]~^^ ERROR implementation of `Stream` is not general enough
-    //[migrate]~| NOTE  `Stream` would have to be implemented for the type `&'0 mut Map
-    //[migrate]~| NOTE  but `Stream` is actually implemented for the type `&'1
-    //[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
+
+    // Here, the call to `mapx` returns a type `T` to which `StreamExt`
+    // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold.
+    //
+    // More concretely, the type `T` is `Map<Repeat, Closure>`, and
+    // the where clause doesn't hold because the signature of the
+    // closure gets inferred to a signature like `|&'_ Stream| -> &'_`
+    // for some specific `'_`, rather than a more generic
+    // signature.
+    //
+    // Why *exactly* we opt for this signature is a bit unclear to me,
+    // we deduce it somehow from a reuqirement that `Map: Stream` I
+    // guess.
+    let map = source.mapx(|x: &_| x);
+    let filter = map.filterx(|x: &_| true);
+    //[migrate]~^ ERROR no method named `filterx`
+    //[nll]~^^ ERROR no method named `filterx`
 }
+
+fn variant2() {
+    let source = Repeat(10);
+
+    // Here, we use a function, which is not subject to the vagaries
+    // of closure signature inference. In this case, we get the error
+    // on `countx` as, I think, the test originally expected.
+    let map = source.mapx(identity);
+    let filter = map.filterx(|x: &_| true);
+    let count = filter.countx();
+    //[migrate]~^ ERROR no method named `countx`
+    //[nll]~^^ ERROR no method named `countx`
+}
+
+fn main() {}
diff --git a/src/test/ui/hrtb/issue-46989.nll.stderr b/src/test/ui/hrtb/issue-46989.nll.stderr
new file mode 100644 (file)
index 0000000..6c127b9
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-46989.rs:38:5
+   |
+LL |     assert_foo::<fn(&i32)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 2c8590554580719201b873c12e6a9afdbeb89d39..4a09f4be156e2bb60a879883cf640004796c28d1 100644 (file)
 //
 // holds because 'a can be instantiated to 'empty.
 
-trait Foo {
+trait Foo {}
 
-}
-
-impl<A> Foo for fn(A) { }
+impl<A> Foo for fn(A) {}
 
 fn assert_foo<T: Foo>() {}
 
 fn main() {
     assert_foo::<fn(&i32)>();
-    //~^ ERROR the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
+    //~^ ERROR implementation of `Foo` is not general enough
 }
index 0a7382c4dd818305ed5794882f83123b7d8ccbe6..c85c37ff9239e3a3a6d78870395c7c0789843cd9 100644 (file)
@@ -1,15 +1,14 @@
-error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
-  --> $DIR/issue-46989.rs:40:18
+error: implementation of `Foo` is not general enough
+  --> $DIR/issue-46989.rs:38:5
    |
-LL | fn assert_foo<T: Foo>() {}
-   |                  --- required by this bound in `assert_foo`
+LL | trait Foo {}
+   | ------------ trait `Foo` defined here
 ...
 LL |     assert_foo::<fn(&i32)>();
-   |                  ^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <fn(A) as Foo>
+   = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)`
+   = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index 8f6b7aca8fda8048e3b5892253e78a03d0c2fa7a..6dcbf055a8bb78fbc0f968c83b6c146e253b2189 100644 (file)
@@ -23,14 +23,10 @@ LL | |     }
    | |_____- in this macro invocation
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider importing one of these items
+help: consider importing this function
    |
 LL | use bar::g;
    |
-LL | use foo::test2::test::g;
-   |
-LL | use foo::test::g;
-   |
 
 error[E0425]: cannot find function `f` in this scope
   --> $DIR/globs.rs:61:12
index fc5ed724e3c67ff03139865769833af7cbfd68f6..acd852103cae3d0b5219b7f1c50c5a60cd31778a 100644 (file)
@@ -18,12 +18,8 @@ fn y /* 0#0 */() { }
 Expansions:
 0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root
 1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, "foo")
-2: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
-3: parent: ExpnId(0), call_site_ctxt: #1, kind: Desugaring(Operator)
 
 SyntaxContexts:
 #0: parent: #0, outer_mark: (ExpnId(0), Opaque)
 #1: parent: #0, outer_mark: (ExpnId(1), SemiTransparent)
-#2: parent: #1, outer_mark: (ExpnId(2), Transparent)
-#3: parent: #1, outer_mark: (ExpnId(3), Transparent)
 */
diff --git a/src/test/ui/impl-trait/binding-without-value.rs b/src/test/ui/impl-trait/binding-without-value.rs
new file mode 100644 (file)
index 0000000..6a97f28
--- /dev/null
@@ -0,0 +1,9 @@
+#![allow(incomplete_features)]
+#![feature(impl_trait_in_bindings)]
+
+fn foo() {
+    let _ : impl Copy;
+    //~^ ERROR cannot resolve opaque type
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/binding-without-value.stderr b/src/test/ui/impl-trait/binding-without-value.stderr
new file mode 100644 (file)
index 0000000..0d2faea
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0720]: cannot resolve opaque type
+  --> $DIR/binding-without-value.rs:5:13
+   |
+LL |     let _ : impl Copy;
+   |         -   ^^^^^^^^^ cannot resolve opaque type
+   |         |
+   |         this binding might not have a concrete type
+   |
+help: set the binding to a value for a concrete type to be resolved
+   |
+LL |     let _ : impl Copy = /* value */;
+   |                       ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.
index 05c9e4173b0e4d51d6948f3f37c2bfa8392bff9e..607b4a49661cc6cb8014cbb565f3dd748d860b2e 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo: std::fmt::Debug + Eq {}
 
diff --git a/src/test/ui/impl-trait/equality-rpass.stderr b/src/test/ui/impl-trait/equality-rpass.stderr
new file mode 100644 (file)
index 0000000..1abf05d
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/equality-rpass.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 14b0eeb739ae5b0a4359d8e3f832b077388ae5b4..828b5aac896beff3d71fb276d3dc3b0785502dfd 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo: Copy + ToString {}
 
index 9178358b60a9c140a8f19870d3ac1f5225898865..628dfb13d4ca8834bc6c32f2ffbbf282a00dce3e 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/equality.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0308]: mismatched types
   --> $DIR/equality.rs:15:5
    |
@@ -24,7 +33,7 @@ LL |         n + sum_to(n - 1)
    |
    = help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
index abce8c8c204bd2d8d1f06363883a55565fe0bf7f..2e325867da86ee999dcfd87719630c995a3a2857 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo: Copy + ToString {}
 
index 2454c218ffc8ba4e6805dbe60971998f655b97bc..1780931efc5415790de6efab2b5c47be4694e680 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/equality2.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0308]: mismatched types
   --> $DIR/equality2.rs:25:18
    |
@@ -58,6 +67,6 @@ LL |          x.0);
    = note: expected opaque type `impl Foo` (`i32`)
               found opaque type `impl Foo` (`u32`)
 
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/issue-69840.rs b/src/test/ui/impl-trait/issue-69840.rs
new file mode 100644 (file)
index 0000000..b270f88
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(impl_trait_in_bindings)]
+#![allow(incomplete_features)]
+
+struct A<'a>(&'a ());
+
+trait Trait<T> {}
+
+impl<T> Trait<T> for () {}
+
+pub fn foo<'a>() {
+    let _x: impl Trait<A<'a>> = ();
+}
+
+fn main() {}
index 150a8015cbc756190e7c25e9799cf166327e5c3c..451ddb3cce0e01c1bd9bc6d6034f055c5901f2d1 100644 (file)
@@ -5,13 +5,13 @@
 
 trait Quux {}
 
-fn foo() -> impl Quux { //~ opaque type expands to a recursive type
+fn foo() -> impl Quux { //~ ERROR cannot resolve opaque type
     struct Foo<T>(T);
     impl<T> Quux for Foo<T> {}
     Foo(bar())
 }
 
-fn bar() -> impl Quux { //~ opaque type expands to a recursive type
+fn bar() -> impl Quux { //~ ERROR cannot resolve opaque type
     struct Bar<T>(T);
     impl<T> Quux for Bar<T> {}
     Bar(foo())
index d10001e8a8e53429225f2d0e7ae64a69cc0ca0cd..c538b77098a2d23a133667a96d30897926a1c4f5 100644 (file)
@@ -1,18 +1,26 @@
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/infinite-impl-trait-issue-38064.rs:8:13
    |
 LL | fn foo() -> impl Quux {
-   |             ^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `foo::Foo<bar::Bar<impl Quux>>`
+   |             ^^^^^^^^^ recursive opaque type
+...
+LL |     Foo(bar())
+   |     ---------- returning here with type `foo::Foo<impl Quux>`
+...
+LL | fn bar() -> impl Quux {
+   |             --------- returning this opaque type `foo::Foo<impl Quux>`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/infinite-impl-trait-issue-38064.rs:14:13
    |
+LL | fn foo() -> impl Quux {
+   |             --------- returning this opaque type `bar::Bar<impl Quux>`
+...
 LL | fn bar() -> impl Quux {
-   |             ^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `bar::Bar<foo::Foo<impl Quux>>`
+   |             ^^^^^^^^^ recursive opaque type
+...
+LL |     Bar(foo())
+   |     ---------- returning here with type `bar::Bar<impl Quux>`
 
 error: aborting due to 2 previous errors
 
index 1806d2607a3ac8c288ffd7874318b91e57897c55..3b339c5c3d7fc69a75c6a1f00338b8b8a748f2f2 100644 (file)
@@ -26,7 +26,42 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                ^^^^^^^^^^^^^^
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:12:69
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+   |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+   |               -                              ^ returning this value requires that `'1` must outlive `'static`
+   |               |
+   |               let's call the lifetime of this reference `'1`
+   |
+   = help: consider replacing `'1` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+   |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+   |              -- lifetime `'a` defined here            ^ returning this value requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+   = help: consider replacing `'a` with `'static`
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/must_outlive_least_region_or_bound.rs:15:41
+   |
+LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+   |               ----                      ^ lifetime `'a` required
+   |               |
+   |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:24
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               -        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |               |
+   |               let's call the lifetime of this reference `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
@@ -35,7 +70,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:17:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                          --  -- lifetime `'b` defined here  ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
@@ -45,13 +80,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    = help: consider adding the following bound: `'b: 'a`
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:22:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                                   ^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
 
-error: aborting due to 5 previous errors
+error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0310`.
+Some errors have detailed explanations: E0310, E0621.
+For more information about an error, try `rustc --explain E0310`.
index 00f3490991b5235771fb2362207cb00f53f09fa8..9bf86fa66cdeda4c7ccd2cd6a55d18a2fbdc570a 100644 (file)
@@ -6,6 +6,31 @@ fn elided(x: &i32) -> impl Copy { x }
 fn explicit<'a>(x: &'a i32) -> impl Copy { x }
 //~^ ERROR cannot infer an appropriate lifetime
 
+fn elided2(x: &i32) -> impl Copy + 'static { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+//~^ ERROR explicit lifetime required in the type of `x`
+
+fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+//~^ ERROR cannot infer an appropriate lifetime
+
+fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+//~^ ERROR cannot infer an appropriate lifetime
+//~| ERROR cannot infer an appropriate lifetime
+
 trait LifetimeTrait<'a> {}
 impl<'a> LifetimeTrait<'a> for &'a i32 {}
 
index d7dae6a08a7b94b9d17514e79198245d1ee7fa17..ffadcaae08e05ed165636b369249098c140a5f37 100644 (file)
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/must_outlive_least_region_or_bound.rs:3:35
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
-   |              ----     ---------   ^ ...and is captured here
-   |              |        |
-   |              |        ...is required to be `'static` by this...
-   |              data with this lifetime...
+   |              ----                 ^ ...is captured here...
+   |              |
+   |              this data with an anonymous lifetime `'_`...
    |
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+   |
+LL | fn elided(x: &i32) -> impl Copy { x }
+   |                       ^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
    |
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ^^^^
 
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/must_outlive_least_region_or_bound.rs:6:44
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-   |                    -------     ---------   ^ ...and is captured here
-   |                    |           |
-   |                    |           ...is required to be `'static` by this...
-   |                    data with this lifetime...
+   |                    -------                 ^ ...is captured here...
+   |                    |
+   |                    this data with lifetime `'a`...
    |
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 6:13
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+   |
+LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
+   |                                ^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'a` lifetime bound
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                          ^^^^
 
-error: cannot infer an appropriate lifetime
-  --> $DIR/must_outlive_least_region_or_bound.rs:12:69
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+   |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+   |               ----                           ^ ...is captured here...
+   |               |
+   |               this data with an anonymous lifetime `'_`...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:9:24
+   |
+LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
+   |                        ^^^^^^^^^^^^^^^^^^^
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn elided2(x: &i32) -> impl Copy + '_ { x }
+   |                                    ^^
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
+   |               ^^^^^^^^^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+   |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+   |                     -------                           ^ ...is captured here...
+   |                     |
+   |                     this data with lifetime `'a`...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:12:33
+   |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
+   |                                 ^^^^^^^^^^^^^^^^^^^
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x }
+   |                                             ^^
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x }
+   |                     ^^^^^^^^^^^^
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/must_outlive_least_region_or_bound.rs:15:24
+   |
+LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
+   |               ----     ^^^^^^^^^^^^^^ lifetime `'a` required
+   |               |
+   |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:65
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
+   |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+   |                                       ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+   |                                                    ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:69
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |               ---- this data with an anonymous lifetime `'_`...     ^ ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:30:41
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
+   |                                         ^^^^^^^^^^
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
+   |                                       ^^^^
+help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
+   |                                                    ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+   |
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
+   |                      ------- this data with lifetime `'a`...        ^ ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/must_outlive_least_region_or_bound.rs:37:34
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
-   |                      -------     --------------------------------   ^ ...and is captured here
-   |                      |           |
-   |                      |           ...is required to be `'static` by this...
-   |                      data with this lifetime...
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x`
    |
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x }
+   |                                                           ^^
+help: alternatively, add an explicit `'static` bound to this reference
    |
-LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
-   |                                                                   ^^^^
+LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
+   |                      ^^^^^^^^^^^^
 
 error[E0623]: lifetime mismatch
-  --> $DIR/must_outlive_least_region_or_bound.rs:17:61
+  --> $DIR/must_outlive_least_region_or_bound.rs:42:61
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
    |                                                 -------     ^^^^^^^^^^^^^^^^
@@ -50,14 +151,72 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
    |                                                 this parameter and the return type are declared with different lifetimes...
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/must_outlive_least_region_or_bound.rs:22:51
+  --> $DIR/must_outlive_least_region_or_bound.rs:47:51
    |
 LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
    |                                 --                ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |                                 |
    |                                 help: consider adding an explicit lifetime bound...: `T: 'static +`
 
-error: aborting due to 5 previous errors
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+   |
+LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+   |               ----                               ^ ...is captured here, requiring it to live as long as `'static`
+   |               |
+   |               this data with an anonymous lifetime `'_`...
+   |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
+   |                                      ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:21:59
+   |
+LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
+   |                     -------                               ^ ...is captured here, requiring it to live as long as `'static`
+   |                     |
+   |                     this data with lifetime `'a`...
+   |
+help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
+   |
+LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
+   |                                               ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:24:60
+   |
+LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+   |               ----                                         ^ ...is captured here, requiring it to live as long as `'static`
+   |               |
+   |               this data with an anonymous lifetime `'_`...
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn elided4(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
+   |                                        ^^
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+   |               ^^^^^^^^^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+   |
+LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+   |                     ------- this data with lifetime `'a`...         ^ ...is captured here, requiring it to live as long as `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
+   |                                                 ^^
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+   |                     ^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
 
-Some errors have detailed explanations: E0310, E0623.
+Some errors have detailed explanations: E0310, E0621, E0623, E0759.
 For more information about an error, try `rustc --explain E0310`.
index b5135b53e18905852274a53c42caccbab77c6173..3cd4d0dd391af41490eebebb5b97cb4274cc60cc 100644 (file)
@@ -49,14 +49,6 @@ LL | use foo::Bar;
 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) {}
-   |            ------
-   |            |
-   |            the method is available for `std::boxed::Box<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
-   |            the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
-   |            the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
-   |            the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here
-...
 LL |     std::rc::Rc::new(&mut Box::new(&'a')).method();
    |                                           ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>`
    |
@@ -83,16 +75,6 @@ error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::b
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method();
    |                                            ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>`
-   | 
-  ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12
-   |
-LL |         fn method(&self) {}
-   |            ------
-   |            |
-   |            the method is available for `std::boxed::Box<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
-   |            the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
-   |            the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
-   |            the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
index 5a95e2969d1b0aa0e36cdac5b1498ba52959d2e8..5a3027ec751a91126268ddd7bc3eb8691c248246 100644 (file)
@@ -1,10 +1,11 @@
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-direct.rs:5:14
    |
 LL | fn test() -> impl Sized {
-   |              ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
+   |              ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     test()
+   |     ------ returning here with type `impl Sized`
 
 error: aborting due to previous error
 
index 6573b00870c5bcc8c2cd2bd9c0a38e9de566113b..75ff9e078cc2ca7fe96b51e61d66bb1c25d8ad22 100644 (file)
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:7:22
    |
 LL | fn option(i: i32) -> impl Sized {
-   |                      ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `std::option::Option<(impl Sized, i32)>`
+   |                      ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     if i < 0 { None } else { Some((option(i - 1), i)) }
+   |                ----          ------------------------ returning here with type `std::option::Option<(impl Sized, i32)>`
+   |                |
+   |                returning here with type `std::option::Option<(impl Sized, i32)>`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:12:15
    |
 LL | fn tuple() -> impl Sized {
-   |               ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `(impl Sized,)`
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (tuple(),)
+   |     ---------- returning here with type `(impl Sized,)`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:17:15
    |
 LL | fn array() -> impl Sized {
-   |               ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[impl Sized; 1]`
+   |               ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     [array()]
+   |     --------- returning here with type `[impl Sized; 1]`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:22:13
    |
 LL | fn ptr() -> impl Sized {
-   |             ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `*const impl Sized`
+   |             ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     &ptr() as *const _
+   |     ------------------ returning here with type `*const impl Sized`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:27:16
    |
 LL | fn fn_ptr() -> impl Sized {
-   |                ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `fn() -> impl Sized`
+   |                ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     fn_ptr as fn() -> _
+   |     ------------------- returning here with type `fn() -> impl Sized`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:32:25
    |
-LL | fn closure_capture() -> impl Sized {
-   |                         ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]`
+LL |   fn closure_capture() -> impl Sized {
+   |                           ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         x;
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:40:29
    |
-LL | fn closure_ref_capture() -> impl Sized {
-   |                             ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]`
+LL |   fn closure_ref_capture() -> impl Sized {
+   |                               ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         &x;
+LL | |     }
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:48:21
    |
 LL | fn closure_sig() -> impl Sized {
-   |                     ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]`
+   |                     ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || closure_sig()
+   |     ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:53:23
    |
 LL | fn generator_sig() -> impl Sized {
-   |                       ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]`
+   |                       ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     || generator_sig()
+   |     ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:58:27
    |
-LL | fn generator_capture() -> impl Sized {
-   |                           ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]`
+LL |   fn generator_capture() -> impl Sized {
+   |                             ^^^^^^^^^^ recursive opaque type
+...
+LL | /     move || {
+LL | |         yield;
+LL | |         x;
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:67:35
    |
 LL | fn substs_change<T: 'static>() -> impl Sized {
-   |                                   ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `(impl Sized,)`
+   |                                   ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     (substs_change::<&T>(),)
+   |     ------------------------ returning here with type `(impl Sized,)`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:72:24
    |
-LL | fn generator_hold() -> impl Sized {
-   |                        ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]`
+LL |   fn generator_hold() -> impl Sized {
+   |                          ^^^^^^^^^^ recursive opaque type
+LL |
+LL | /     move || {
+LL | |         let x = generator_hold();
+LL | |         yield;
+LL | |         x;
+LL | |     }
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:86:26
    |
 LL | fn mutual_recursion() -> impl Sync {
-   |                          ^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
+   |                          ^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion_b()
+   |     -------------------- returning here with type `impl Sized`
+...
+LL | fn mutual_recursion_b() -> impl Sized {
+   |                            ---------- returning this opaque type `impl Sized`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:91:28
    |
+LL | fn mutual_recursion() -> impl Sync {
+   |                          --------- returning this opaque type `impl std::marker::Sync`
+...
 LL | fn mutual_recursion_b() -> impl Sized {
-   |                            ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
+   |                            ^^^^^^^^^^ recursive opaque type
+LL |
+LL |     mutual_recursion()
+   |     ------------------ returning here with type `impl std::marker::Sync`
 
 error: aborting due to 14 previous errors
 
index cfd9c0ec5b45bab47c0813922f7ec11902452e3a..818e40365394dea65b44fe652d41be64aae4071e 100644 (file)
@@ -4,21 +4,21 @@
 
 fn id<T>(t: T) -> impl Sized { t }
 
-fn recursive_id() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_id() -> impl Sized { //~ ERROR cannot resolve opaque type
     id(recursive_id2())
 }
 
-fn recursive_id2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_id2() -> impl Sized { //~ ERROR cannot resolve opaque type
     id(recursive_id())
 }
 
 fn wrap<T>(t: T) -> impl Sized { (t,) }
 
-fn recursive_wrap() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_wrap() -> impl Sized { //~ ERROR cannot resolve opaque type
     wrap(recursive_wrap2())
 }
 
-fn recursive_wrap2() -> impl Sized { //~ ERROR opaque type expands to a recursive type
+fn recursive_wrap2() -> impl Sized { //~ ERROR cannot resolve opaque type
     wrap(recursive_wrap())
 }
 
index 73c12f6137d24bad6697f1b97d1fcc1ba5733a10..fbc58837a8e946dc45cd62490a2dc6442c83f4ae 100644 (file)
@@ -1,34 +1,46 @@
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:7:22
    |
+LL | fn id<T>(t: T) -> impl Sized { t }
+   |                   ---------- returning this opaque type `impl Sized`
+LL | 
 LL | fn recursive_id() -> impl Sized {
-   |                      ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
+   |                      ^^^^^^^^^^ recursive opaque type
+LL |     id(recursive_id2())
+   |     ------------------- returning here with type `impl Sized`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:11:23
    |
+LL | fn id<T>(t: T) -> impl Sized { t }
+   |                   ---------- returning this opaque type `impl Sized`
+...
 LL | fn recursive_id2() -> impl Sized {
-   |                       ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: type resolves to itself
+   |                       ^^^^^^^^^^ recursive opaque type
+LL |     id(recursive_id())
+   |     ------------------ returning here with type `impl Sized`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:17:24
    |
+LL | fn wrap<T>(t: T) -> impl Sized { (t,) }
+   |                     ---------- returning this opaque type `impl Sized`
+LL | 
 LL | fn recursive_wrap() -> impl Sized {
-   |                        ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `((impl Sized,),)`
+   |                        ^^^^^^^^^^ recursive opaque type
+LL |     wrap(recursive_wrap2())
+   |     ----------------------- returning here with type `impl Sized`
 
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:21:25
    |
+LL | fn wrap<T>(t: T) -> impl Sized { (t,) }
+   |                     ---------- returning this opaque type `impl Sized`
+...
 LL | fn recursive_wrap2() -> impl Sized {
-   |                         ^^^^^^^^^^ expands to a recursive type
-   |
-   = note: expanded type is `((impl Sized,),)`
+   |                         ^^^^^^^^^^ recursive opaque type
+LL |     wrap(recursive_wrap())
+   |     ---------------------- returning here with type `impl Sized`
 
 error: aborting due to 4 previous errors
 
index 1c3a5979ee55bc74c7038c31c2fcd532996f7e77..df0db6e4fc6df927297d9793d271390de5bc21dd 100644 (file)
@@ -1,36 +1,43 @@
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/static-return-lifetime-infered.rs:7:16
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         -----     ----------------------- ...is required to be `'static` by this...
-   |                         |
-   |                         data with this lifetime...
+   |                         ----- this data with an anonymous lifetime `'_`...
 LL |         self.x.iter().map(|a| a.0)
    |         ------ ^^^^
    |         |
-   |         ...and is captured here
+   |         ...is captured here...
    |
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5
+note: ...and is required to live as long as `'static` here
+  --> $DIR/static-return-lifetime-infered.rs:6:35
+   |
+LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ^^^^
 
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/static-return-lifetime-infered.rs:11:16
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                        --------     ----------------------- ...is required to be `'static` by this...
-   |                        |
-   |                        data with this lifetime...
+   |                        -------- this data with lifetime `'a`...
 LL |         self.x.iter().map(|a| a.0)
    |         ------ ^^^^
    |         |
-   |         ...and is captured here
+   |         ...is captured here...
    |
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the method body at 10:20
+note: ...and is required to live as long as `'static` here
+  --> $DIR/static-return-lifetime-infered.rs:10:37
+   |
+LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                                             ^^^^
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0759`.
index f7744ef1b3eaeb0da606b0e3625755b39090bca1..462508f306ef34f4b1f3de692f996a79a3d894e8 100644 (file)
@@ -3,7 +3,6 @@
 use std::fmt::Debug;
 
 // Disallowed
-fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
-//~^ ERROR opaque type expands to a recursive type
+fn in_adt_in_return() -> Vec<impl Debug> { panic!() } //~ ERROR cannot resolve opaque type
 
 fn main() {}
index 1de15014c1f8dd3cd46ce46f92d597eaffd3fc71..b8e06725cbcdd6493683dc2ca34fd4d775d5cc27 100644 (file)
@@ -1,10 +1,12 @@
-error[E0720]: opaque type expands to a recursive type
+error[E0720]: cannot resolve opaque type
   --> $DIR/where-allowed-2.rs:6:30
    |
 LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
-   |                              ^^^^^^^^^^ expands to a recursive type
+   |                              ^^^^^^^^^^    -------- this returned value is of `!` type
+   |                              |
+   |                              cannot resolve opaque type
    |
-   = note: type resolves to itself
+   = help: this error will resolve once the item's body returns a concrete type
 
 error: aborting due to previous error
 
index 6f53680f7c81dc4e1261c9e1c853b87d9f7f7b89..9fee01c1ba62329789f91af0e17a8c080203df7d 100644 (file)
@@ -1,9 +1,3 @@
-//
-// We get an error message at the top of file (dummy span).
-// This is not helpful, but also kind of annoying to prevent,
-// so for now just live with it.
-// This test case was originally for issue #2258.
-
 // build-fail
 
 trait ToOpt: Sized {
@@ -23,11 +17,9 @@ fn to_option(&self) -> Option<Option<T>> {
 }
 
 fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-//~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
     if counter > 0 {
         function(counter - 1, t.to_option());
-        // FIXME(#4287) Error message should be here. It should be
-        // a type error to instantiate `test` at a type other than T.
+        //~^ ERROR reached the recursion limit while instantiating `function::<std::option::Option<
     }
 }
 
index ae81c680a7b65f3e2853690e9e67e9d0c601692f..7b22393ee7c0f7a7ee856a87c1dbd9d35fd83fca 100644 (file)
@@ -1,11 +1,16 @@
 error: reached the recursion limit while instantiating `function::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<usize>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
-  --> $DIR/infinite-instantiation.rs:25:1
+  --> $DIR/infinite-instantiation.rs:21:9
+   |
+LL |         function(counter - 1, t.to_option());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `function` defined here
+  --> $DIR/infinite-instantiation.rs:19:1
    |
 LL | / fn function<T:ToOpt + Clone>(counter: usize, t: T) {
-LL | |
 LL | |     if counter > 0 {
 LL | |         function(counter - 1, t.to_option());
-...  |
+LL | |
 LL | |     }
 LL | | }
    | |_^
index ce306c845175af061075edcc003316362fb70775..3b3a2950942d0bb8640e986c7a4f9292a5b72489 100644 (file)
@@ -1,10 +1,14 @@
+// Don't allow unstable features in stable functions without `allow_internal_unstable`.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
 #![feature(staged_api)]
-#![feature(const_if_match)]
+#![feature(const_transmute, const_fn)]
 
 #[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
+pub const fn foo() -> i32 {
+    unsafe { std::mem::transmute(4u32) } //~ ERROR is not stable as `const fn`
 }
 
 fn main() {}
index b2d97b981ba5dce9d3d6714f914641122bc3ea51..5a2c58f3928dc34d0d754afe9b518cd44c9120d9 100644 (file)
@@ -1,8 +1,8 @@
-error[E0723]: loops and conditional expressions are not stable in const fn
-  --> $DIR/internal-unstable-const.rs:7:5
+error[E0723]: can only call other `const fn` within a `const fn`, but `const std::intrinsics::transmute::<u32, i32>` is not stable as `const fn`
+  --> $DIR/internal-unstable-const.rs:11:14
    |
-LL |     if true { 4 } else { 5 }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { std::mem::transmute(4u32) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
index 08b10463d3927699119461181943f93513654960..fecba721ac9fdeb101053fd43ce0b7e2789ee00e 100644 (file)
@@ -1,5 +1,5 @@
 fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
-    *x //~^ ERROR the trait bound `u32: std::future::Future` is not satisfied
+    *x //~^ ERROR `u32` is not a future
 }
 
 fn main() {
index 85da87914e768405e59bdb8bff42fdb53f122def..b3b29a726413156e284f85931100cdb5e688fba3 100644 (file)
@@ -4,14 +4,15 @@ error[E0425]: cannot find value `u` in this scope
 LL |     let _ = test_ref & u;
    |                        ^ not found in this scope
 
-error[E0277]: the trait bound `u32: std::future::Future` is not satisfied
+error[E0277]: `u32` is not a future
   --> $DIR/issues-71798.rs:1:25
    |
 LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `u32`
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
 LL |     *x
    |     -- this returned value is of type `u32`
    |
+   = help: the trait `std::future::Future` is not implemented for `u32`
    = note: the return type of a function must have a statically known size
 
 error: aborting due to 2 previous errors
index 888576c43365f912ab2f2c4b307def62e05476e1..d7a4bf4f21f18dc946084e62b64fa2ce0796d2f8 100644 (file)
@@ -57,6 +57,10 @@ LL | impl<'self> Serializable<str> for &'self str {
    |
    = help: the trait `std::marker::Sized` is not implemented for `str`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait Serializable<'self, T: ?Sized> {
+   |                            ^^^^^^^^
 
 error: aborting due to 9 previous errors
 
index f12539b47cf44c15b9a23201f77215e9f1efcc38..5b8a1823386936929c5200ea19a420515be3608e 100644 (file)
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `usize`
   --> $DIR/issue-10991.rs:3:14
    |
 LL |     let _t = nil as usize;
-   |              ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |              ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
index 7d24f3a40a742e2669664ff54553ceae0d400e69..eaf6acff26bf35cf92b704ebca96c4c0bdaaebb0 100644 (file)
@@ -18,12 +18,12 @@ fn new(buf: &'a mut [u8]) -> Foo<'a> {
 }
 
 impl<'a> NoLifetime for Foo<'a> {
-    fn get<'p, T : Test<'a>>(&self) -> T {
+    fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T {
     //~^ ERROR E0195
     //~| NOTE lifetimes do not match method in trait
         return *self as T;
         //~^ ERROR non-primitive cast: `Foo<'a>` as `T`
-        //~| NOTE an `as` expression can only be used to convert between primitive types.
+        //~| NOTE an `as` expression can only be used to convert between primitive types
     }
 }
 
index a137bcdf1915edd39ec053786aa664e5bc76a514..73610942d7a7ed358ded73169f73004ff5bfac24 100644 (file)
@@ -4,16 +4,16 @@ error[E0195]: lifetime parameters or bounds on method `get` do not match the tra
 LL |     fn get<'p, T : Test<'p>>(&self) -> T;
    |           ------------------ lifetimes in impl do not match this method in trait
 ...
-LL |     fn get<'p, T : Test<'a>>(&self) -> T {
-   |           ^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+LL |     fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
 
 error[E0605]: non-primitive cast: `Foo<'a>` as `T`
   --> $DIR/issue-16048.rs:24:16
    |
 LL |         return *self as T;
-   |                ^^^^^^^^^^
+   |                ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)`
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
index bae3813f9da951b01997de7073d3c21c9837d694..bafa204e06b252eb709c8cd936b12b3ab9cc1e80 100644 (file)
@@ -5,6 +5,7 @@
 struct Empty;
 
 // This used to cause an ICE
+#[allow(improper_ctypes_definitions)]
 extern "C" fn ice(_a: Empty) {}
 
 fn main() {
index 02d33aae023ff27f5c31f28e7b6edfd267523943..919594fc9af4b434967d1975e1a23b41346c5f6e 100644 (file)
@@ -1,18 +1,16 @@
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/issue-16922.rs:4:14
    |
 LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
-   |                       -- data with this lifetime...
+   |                       -- this data with an anonymous lifetime `'_`...
 LL |     Box::new(value) as Box<dyn Any>
-   |     ---------^^^^^-
-   |     |        |
-   |     |        ...and is captured here
-   |     ...is required to be `'static` by this...
+   |              ^^^^^ ...is captured here, requiring it to live as long as `'static`
    |
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1
+help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
    |
 LL | fn foo<T: Any>(value: &T) -> Box<dyn Any + '_> {
    |                                          ^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0759`.
index 0ab035515a0515220d72b1824996c69d6641681c..b63a3995d255dd523a3518f7e891845f57bd5069 100644 (file)
@@ -16,7 +16,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<usize>` as `dyn std::fmt::D
 LL |     let _bar = Box::new(1_usize) as dyn std::fmt::Debug;
    |                ^^^^^^^^^^^^^^^^^^^^^-------------------
    |                                     |
-   |                                     help: try casting to a `Box` instead: `Box<dyn std::fmt::Debug>`
+   |                                     help: you can cast to a `Box` instead: `Box<dyn std::fmt::Debug>`
 
 error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug`
   --> $DIR/issue-17441.rs:8:16
index 9355c8ab15256f7e993d81e57b4a7ea1e77b3faa..49023f18ddbfbfb35c1f75e90228604001b2c219 100644 (file)
@@ -1,10 +1,10 @@
 const C1: &'static mut [usize] = &mut [];
-//~^ ERROR: references in constants may only refer to immutable values
+//~^ ERROR: mutable references are not allowed in constants
 
 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
+//~| ERROR: mutable references are not allowed in constants
 
 fn main() {}
index 688efcdd022eb57bc3a89e541b51b6accb99245b..7c50978d4ebb83932e167818a6cf94cd9194b5cf 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: references in constants may only refer to immutable values
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/issue-17718-const-bad-values.rs:1:34
    |
 LL | const C1: &'static mut [usize] = &mut [];
-   |                                  ^^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                  ^^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0013]: constants cannot refer to statics
   --> $DIR/issue-17718-const-bad-values.rs:5:46
@@ -23,16 +20,13 @@ 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
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/issue-17718-const-bad-values.rs:5:41
    |
 LL | const C2: &'static mut usize = unsafe { &mut S };
-   |                                         ^^^^^^ constants require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                         ^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0013, E0658.
+Some errors have detailed explanations: E0013, E0764.
 For more information about an error, try `rustc --explain E0013`.
index e4fe26800eff347c9b148be74474cc8a2c3cee6c..9f8a3a82624446cc259bf3b237f28c22917ce553 100644 (file)
@@ -1,6 +1,7 @@
 // build-pass
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
+#![warn(clashing_extern_declarations)]
 
 // pretty-expanded FIXME #23616
 
@@ -20,6 +21,7 @@ pub mod rustrt {
         use super::rust_task;
         extern {
             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+            //~^ WARN `rust_task_is_unwinding` redeclared with a different signature
         }
     }
 }
diff --git a/src/test/ui/issues/issue-1866.stderr b/src/test/ui/issues/issue-1866.stderr
new file mode 100644 (file)
index 0000000..5edae48
--- /dev/null
@@ -0,0 +1,19 @@
+warning: `rust_task_is_unwinding` redeclared with a different signature
+  --> $DIR/issue-1866.rs:23:13
+   |
+LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+   |             ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
+...
+LL |             pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+note: the lint level is defined here
+  --> $DIR/issue-1866.rs:4:9
+   |
+LL | #![warn(clashing_extern_declarations)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected `unsafe extern "C" fn(*const usize) -> bool`
+              found `unsafe extern "C" fn(*const bool) -> bool`
+
+warning: 1 warning emitted
+
index 1ea40d0728ed13343c4e8594c8f935c87e9451c3..383cdd4979ad9ad46007915e25745e81e3b2d847 100644 (file)
@@ -9,6 +9,13 @@ LL | enum Option<T> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/issue-18919.rs:7:13
+   |
+LL | enum Option<T> {
+   |             ^ this could be changed to `T: ?Sized`...
+LL |     Some(T),
+   |          - ...if indirection was used here: `Box<T>`
 
 error: aborting due to previous error
 
index cc7ace30cabef108eff333f1c6b428fa847a885c..4c35deb1fbe4e0b566c14fc9026d09f5883cfff3 100644 (file)
@@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)`
   --> $DIR/issue-22289.rs:2:5
    |
 LL |     0 as &dyn std::any::Any;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+   |
+LL |     &0 as &dyn std::any::Any;
+   |     ^
 
 error: aborting due to previous error
 
index 250fec2588702c0e94ec3155b40e36e2a86f2202..4e359b3412a71e8400aca880fea2c4cadf9f93f6 100644 (file)
@@ -1,6 +1,6 @@
 use std::ops::Index;
 
-pub trait Array2D: Index<usize> {
+pub trait Array2D: Index<usize> + Sized {
     fn rows(&self) -> usize;
     fn columns(&self) -> usize;
     fn get<'a>(&'a self, y: usize, x: usize) -> Option<&'a <Self as Index<usize>>::Output> {
index fc32fd376b75a9eb023d3fc8b5e54dc184bc19fc..28564b074633bf2fd402729008e8f39644b90f7d 100644 (file)
@@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index<usize, Output
   --> $DIR/issue-22312.rs:11:24
    |
 LL |         let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+   |
+LL |         let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
+   |                         ^
 
 error: aborting due to previous error
 
index a68369616d8b62a32b84bfc9a0e5b2994eae5bc8..75be4a11efd22dab804500b0d60b17bdf48468df 100644 (file)
@@ -14,7 +14,7 @@ pub fn let_<'var, VAR, F: for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
 }
 
 fn main() {
-    let ex = |x| { //~ ERROR type annotations needed
-        let_(add(x,x), |y| {
+    let ex = |x| {
+        let_(add(x,x), |y| { //~ ERROR type annotations needed
             let_(add(x, x), |x|x)})};
 }
index 12b2eb48e7eaa2987d341590f80595f040d88ba6..77555fce7c460bbff07b074bb9884dca84521ce2 100644 (file)
@@ -1,8 +1,13 @@
-error[E0282]: type annotations needed for `Expr<'_, VAR>`
-  --> $DIR/issue-23046.rs:17:15
+error[E0282]: type annotations needed for the closure `fn(Expr<'_, _>) -> Expr<'_, _>`
+  --> $DIR/issue-23046.rs:18:9
    |
-LL |     let ex = |x| {
-   |               ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
+LL |         let_(add(x,x), |y| {
+   |         ^^^^ cannot infer type for type parameter `VAR` declared on the function `let_`
+   |
+help: give this closure an explicit return type without `_` placeholders
+   |
+LL |             let_(add(x, x), |x|-> Expr<'_, _> { x })})};
+   |                                ^^^^^^^^^^^^^^^^   ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23080-2.rs b/src/test/ui/issues/issue-23080-2.rs
deleted file mode 100644 (file)
index 7f6b9e3..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-//~ ERROR
-
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-unsafe auto trait Trait {
-    type Output; //~ ERROR E0380
-}
-
-fn call_method<T: Trait>(x: T) {}
-
-fn main() {
-    // ICE
-    call_method(());
-}
diff --git a/src/test/ui/issues/issue-23080-2.stderr b/src/test/ui/issues/issue-23080-2.stderr
deleted file mode 100644 (file)
index 48ce09a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0380]: auto traits cannot have methods or associated items
-  --> $DIR/issue-23080-2.rs:7:10
-   |
-LL | unsafe auto trait Trait {
-   |                   ----- auto trait cannot have items
-LL |     type Output;
-   |          ^^^^^^
-
-error[E0275]: overflow evaluating the requirement `<() as Trait>::Output`
-   |
-   = note: required because of the requirements on the impl of `Trait` for `()`
-   = note: required because of the requirements on the impl of `Trait` for `()`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0275, E0380.
-For more information about an error, try `rustc --explain E0275`.
diff --git a/src/test/ui/issues/issue-23080.rs b/src/test/ui/issues/issue-23080.rs
deleted file mode 100644 (file)
index 035db82..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-unsafe auto trait Trait {
-    fn method(&self) { //~ ERROR E0380
-        println!("Hello");
-    }
-}
-
-fn call_method<T: Trait>(x: T) {
-    x.method();
-}
-
-fn main() {
-    // ICE
-    call_method(());
-}
diff --git a/src/test/ui/issues/issue-23080.stderr b/src/test/ui/issues/issue-23080.stderr
deleted file mode 100644 (file)
index 73ecb1c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0380]: auto traits cannot have methods or associated items
-  --> $DIR/issue-23080.rs:5:8
-   |
-LL | unsafe auto trait Trait {
-   |                   ----- auto trait cannot have items
-LL |     fn method(&self) {
-   |        ^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0380`.
index 3b4b8997a70095e43ec2cff2dd8c8ef2da864450..cffa52361696c93c21c41727c3a2befab1c64466 100644 (file)
@@ -9,6 +9,13 @@ LL | struct Vec<T> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/issue-23281.rs:8:12
+   |
+LL | struct Vec<T> {
+   |            ^ this could be changed to `T: ?Sized`...
+LL |     t: T,
+   |        - ...if indirection was used here: `Box<T>`
 
 error: aborting due to previous error
 
index 36a69cf4c22ff9895bc476983be8d0be4c29e592..d1093c205798a0b8875111e57d65d23625d0e74b 100644 (file)
@@ -1,6 +1,6 @@
 fn id<T>(t: T) -> T { t }
 fn main() {
     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
-    //~^ ERROR comparing raw pointers inside constant
+    //~^ ERROR pointers cannot be reliably compared during const eval
     println!("{}", A);
 }
index 3a5a6b509ba9dd05c6013503ade00cb794211458..67d1b3ab9bed60589b671ed483f99bf91666f6ff 100644 (file)
@@ -1,12 +1,10 @@
-error[E0658]: comparing raw pointers inside constant
+error: pointers cannot be reliably compared during const eval.
   --> $DIR/issue-25826.rs:3:30
    |
 LL |     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-   = help: add `#![feature(const_compare_raw_pointers)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-26545.rs b/src/test/ui/issues/issue-26545.rs
new file mode 100644 (file)
index 0000000..5652ee7
--- /dev/null
@@ -0,0 +1,12 @@
+mod foo {
+    pub struct B(pub ());
+}
+
+mod baz {
+    fn foo() {
+        B(());
+        //~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-26545.stderr b/src/test/ui/issues/issue-26545.stderr
new file mode 100644 (file)
index 0000000..d3c8669
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
+  --> $DIR/issue-26545.rs:7:9
+   |
+LL |         B(());
+   |         ^ not found in this scope
+   |
+help: consider importing this tuple struct
+   |
+LL |     use foo::B;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
index f6d349a38f52338729d6880a785d64298c3f5720..fcabd1d84557c70abe60cf8b02cd55ac5e228e4e 100644 (file)
@@ -6,6 +6,7 @@ pub struct Foo {
 }
 
 impl Foo {
+    #[allow(improper_ctypes_definitions)]
     pub extern fn foo_new() -> Foo {
         Foo { x: 21, y: 33 }
     }
index 3bbe4ae29bdd69a45bf47919d3978eda55096291..297519b9a79e2b633384523a7db36b868f24315c 100644 (file)
@@ -6,6 +6,7 @@
 impl Test {
     #[allow(dead_code)]
     #[allow(unused_variables)]
+    #[allow(improper_ctypes_definitions)]
     pub extern fn test(val: &str) {
 
     }
index c316780d5f6a5c972bed74f0a84254b6dbeea847..9f5968399a37d8a730bced19a959071fba7e0bf9 100644 (file)
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize`
   --> $DIR/issue-2995.rs:2:22
    |
 LL |     let _q: &isize = p as &isize;
-   |                      ^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                      ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
index eb139ec4d7f433f9b48f5372bdef3c97d6cf3931..cc35213b93d686aec69d958fe88c640ac3c5972e 100644 (file)
@@ -1,5 +1,6 @@
 // check-pass
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 fn main() {}
 
diff --git a/src/test/ui/issues/issue-35376.stderr b/src/test/ui/issues/issue-35376.stderr
new file mode 100644 (file)
index 0000000..06c31f3
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-35376.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 98e8e6366b99b0e00d553a758fc09a50ddd747dd..600cacc23aef5d1f24a51fba65c278f40722c621 100644 (file)
@@ -5,6 +5,11 @@ LL |     a.iter().map(|a| a*a)
    |                      -^- &T
    |                      |
    |                      &T
+   |
+help: consider restricting type parameter `T`
+   |
+LL | fn func<'a, T: std::ops::Mul<Output = &T>>(a: &'a [T]) -> impl Iterator<Item=&'a T> {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 7876811a9ac39703facfee392a43b5de5f789673..683761667d40aee2077f5d6463b311fb9dab5065 100644 (file)
@@ -33,7 +33,7 @@ fn qux() -> Some {
 fn main() {}
 
 mod x {
-    enum Enum {
+    pub enum Enum {
         Variant1,
         Variant2(),
         Variant3(usize),
index 00aa810f8308c743fce889c679c74f399ac33838..a84391b94d1de3fd60eac77f439330c959cb8539 100644 (file)
@@ -1,5 +1,5 @@
-// run-pass
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 trait Iterate<'a> {
     type Ty: Valid;
@@ -7,6 +7,7 @@ trait Iterate<'a> {
 }
 impl<'a, T> Iterate<'a> for T where T: Check {
     default type Ty = ();
+    //~^ ERROR the trait bound `(): Valid` is not satisfied
     default fn iterate(self) {}
 }
 
diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr
new file mode 100644 (file)
index 0000000..81beec8
--- /dev/null
@@ -0,0 +1,21 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-38091.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: the trait bound `(): Valid` is not satisfied
+  --> $DIR/issue-38091.rs:9:5
+   |
+LL |     type Ty: Valid;
+   |     --------------- required by `Iterate::Ty`
+...
+LL |     default type Ty = ();
+   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
index 6e6de09225f571f8391b37ab45e191c4f813411f..a966cf217e1655cc6f0a66ca1ea121647f23901f 100644 (file)
@@ -5,6 +5,7 @@
 pub struct Foo(i128);
 
 #[no_mangle]
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn foo(x: Foo) -> Foo { x }
 
 fn main() {
diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr
new file mode 100644 (file)
index 0000000..f673fba
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-40000.rs:6:9
+   |
+LL |     foo(bar);
+   |         ^^^
+
+error: aborting due to previous error
+
index 983fdb13083a1a9eaff415ddabb3a1bcbe32b9ce..3eb3482ac910ea030b1c72c1ced510d5175160dd 100644 (file)
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/issue-40000.rs:6:9
    |
 LL |     foo(bar);
-   |         ^^^ expected concrete lifetime, found bound lifetime parameter
+   |         ^^^ one type is more general than the other
    |
-   = note: expected struct `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>`
-              found struct `std::boxed::Box<dyn std::ops::Fn(_)>`
+   = note: expected trait object `dyn for<'r> std::ops::Fn(&'r i32)`
+              found trait object `dyn std::ops::Fn(&i32)`
 
 error: aborting due to previous error
 
index cc365dc4c938e2655053d46c9881edc02464610e..a088f91554dfb6734adcde64d115bbb8624091a8 100644 (file)
@@ -1,20 +1,20 @@
 mod foo {
-    pub struct B(());
+    pub struct Bx(());
 }
 
 mod bar {
-    use foo::B;
+    use foo::Bx;
 
     fn foo() {
-        B(());
-        //~^ ERROR expected function, tuple struct or tuple variant, found struct `B` [E0423]
+        Bx(());
+        //~^ ERROR expected function, tuple struct or tuple variant, found struct `Bx` [E0423]
     }
 }
 
 mod baz {
     fn foo() {
-        B(());
-        //~^ ERROR cannot find function, tuple struct or tuple variant `B` in this scope [E0425]
+        Bx(());
+        //~^ ERROR cannot find function, tuple struct or tuple variant `Bx` in this scope [E0425]
     }
 }
 
index e7e251e39c04fbcd02dea89abb726d4e2fc64ef0..9fad43757ba62fdf8e6f1a3c11d46207d1fca78f 100644 (file)
@@ -1,18 +1,18 @@
-error[E0423]: expected function, tuple struct or tuple variant, found struct `B`
+error[E0423]: expected function, tuple struct or tuple variant, found struct `Bx`
   --> $DIR/issue-42944.rs:9:9
    |
-LL |         B(());
-   |         ^ constructor is not visible here due to private fields
+LL |         Bx(());
+   |         ^^ constructor is not visible here due to private fields
 
-error[E0425]: cannot find function, tuple struct or tuple variant `B` in this scope
+error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this scope
   --> $DIR/issue-42944.rs:16:9
    |
-LL |         B(());
-   |         ^ not found in this scope
+LL |         Bx(());
+   |         ^^ not found in this scope
    |
 help: consider importing this tuple struct
    |
-LL |     use foo::B;
+LL |     use foo::Bx;
    |
 
 error: aborting due to 2 previous errors
index b259e9e269d06836ad5447cd5ca074da0f7f260d..99cae46fd9cf2b9c33d7f0704ee44d6b0ba6e43f 100644 (file)
@@ -9,11 +9,12 @@ impl<'a> Trait<'a> for Type {
 }
 
 pub fn break_me<T, F>(f: F)
-where T: for<'b> Trait<'b>,
-      F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
+where
+    T: for<'b> Trait<'b>,
+    F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+{
     break_me::<Type, fn(_)>;
     //~^ ERROR: type mismatch in function arguments
-    //~| ERROR: type mismatch resolving
 }
 
 fn main() {}
index 99fb2a1f5d030fc3889f44e1507e881e10ef37b5..80aca482b3d29b8c8e614353bd7e9f4360d02178 100644 (file)
@@ -1,29 +1,18 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/issue-43623.rs:14:5
+  --> $DIR/issue-43623.rs:16:5
    |
 LL | pub fn break_me<T, F>(f: F)
    |        -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
-   |          -------------------------------------- required by this bound in `break_me`
+...
+LL |     F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+   |                ------------------------------ required by this bound in `break_me`
+LL | {
 LL |     break_me::<Type, fn(_)>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |     |
-   |     expected signature of `for<'b> fn(<Type as Trait<'b>>::Assoc) -> _`
-   |     found signature of `fn(_) -> _`
+   |     expected signature of `fn(<Type as Trait<'b>>::Assoc) -> _`
+   |     found signature of `fn(()) -> _`
 
-error[E0271]: type mismatch resolving `for<'b> <fn(_) as std::ops::FnOnce<(<Type as Trait<'b>>::Assoc,)>>::Output == ()`
-  --> $DIR/issue-43623.rs:14:5
-   |
-LL | pub fn break_me<T, F>(f: F)
-   |        -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
-   |                  ------------------------------ required by this bound in `break_me`
-LL |     break_me::<Type, fn(_)>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
index ecee595d4ab6adb1b39526629fe4d31a8aa6d73e..a86ec7fabea4bf37690c55ff9175e20eacb00782 100644 (file)
@@ -15,12 +15,10 @@ error[E0423]: expected function, found module `foo`
 LL |     foo();
    |     ^^^ not a function
    |
-help: consider importing one of these items instead
+help: consider importing this function instead
    |
 LL | use foo::foo;
    |
-LL | use m1::foo;
-   |
 
 error: aborting due to 2 previous errors
 
index a094180572daa702ec1d72c11b278bc4c0b9a69d..469ea93e904686e08b416c449f10988084aea6b1 100644 (file)
@@ -4,12 +4,10 @@ error[E0425]: cannot find function `foo` in this scope
 LL |         fn sub() -> isize { foo(); 1 }
    |                             ^^^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing this function
    |
 LL |         use foo::foo;
    |
-LL |         use m1::foo;
-   |
 
 error: aborting due to previous error
 
index 43b49e463128fc0eff4bcf501ad2b71b2b329711..daf67219f4d0acf122df231618faca7c3007411a 100644 (file)
@@ -1,4 +1,4 @@
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
   --> $DIR/issue-44078.rs:2:8
    |
 LL |       "😊"";
@@ -8,3 +8,4 @@ LL | | }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0765`.
index d4ddba52df14a9f9f812dc3621361a6bf39733a7..d00f3d91b49da640f3a063a9c071155fc7e663ae 100644 (file)
@@ -1,30 +1,24 @@
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/issue-45730.rs:3:23
+  --> $DIR/issue-45730.rs:3:28
    |
 LL |     let x: *const _ = 0 as _;
-   |                       ^^^^^-
-   |                            |
-   |                            help: consider giving more type information
+   |                            ^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/issue-45730.rs:5:23
+  --> $DIR/issue-45730.rs:5:28
    |
 LL |     let x: *const _ = 0 as *const _;
-   |                       ^^^^^--------
-   |                            |
-   |                            help: consider giving more type information
+   |                            ^^^^^^^^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/issue-45730.rs:8:13
+  --> $DIR/issue-45730.rs:8:44
    |
 LL |     let x = 0 as *const i32 as *const _ as *mut _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------
-   |                                            |
-   |                                            help: consider giving more type information
+   |                                            ^^^^^^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
index e1967eb7655425e642cfaaf60efc7350081810f0..273187a5a13beb44b38cdfd24b3c891614288d08 100644 (file)
@@ -1,4 +1,4 @@
-static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];   //~ ERROR E0658
+static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];   //~ ERROR E0764
 fn write<T: AsRef<[u8]>>(buffer: T) { }
 
 fn main() {
index 771e368a35d930a83d1da694d8bb10da01182f63..5421721dec2e315c72272de197f4628b70c92f23 100644 (file)
@@ -1,11 +1,8 @@
-error[E0658]: references in statics may only refer to immutable values
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/issue-46604.rs:1:25
    |
 LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];
-   |                         ^^^^^^^^^^^^^^^^^^^^ statics require immutable values
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                         ^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item
   --> $DIR/issue-46604.rs:6:5
@@ -15,5 +12,5 @@ LL |     buf[0]=2;
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0594, E0658.
+Some errors have detailed explanations: E0594, E0764.
 For more information about an error, try `rustc --explain E0594`.
index 87965c204ada7e9f131c0d848a6345cc2b07d90b..8dc9351260ebcc6a4bb3979e2d665723bb5fddfa 100644 (file)
@@ -11,7 +11,7 @@
 // ignore-asmjs wasm2js does not support source maps yet
 
 #![feature(non_ascii_idents)]
-#[allow(uncommon_codepoints)]
+#![allow(uncommon_codepoints)]
 
 #[path = "issue-48508-aux.rs"]
 mod other_file;
index 782037a1fe5d4642483103adac351fb2f27e9807..0dc588d75c654dfc7338d77ef605ea2140514935 100644 (file)
@@ -10,5 +10,4 @@ fn main() {
 
     [(); return while let Some(n) = Some(0) {}];
     //~^ ERROR return statement outside of function body
-    //~| ERROR `while` is not allowed in a `const`
 }
index 696030850436f744921399b133df0da6e52538dc..023d9013ab4ed48061d41dc68685977a9888d462 100644 (file)
@@ -1,13 +1,3 @@
-error[E0658]: `while` is not allowed in a `const`
-  --> $DIR/issue-51714.rs:11:17
-   |
-LL |     [(); return while let Some(n) = Some(0) {}];
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #52000 <https://github.com/rust-lang/rust/issues/52000> for more information
-   = help: add `#![feature(const_loop)]` to the crate attributes to enable
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
 error[E0572]: return statement outside of function body
   --> $DIR/issue-51714.rs:2:14
    |
@@ -32,7 +22,6 @@ error[E0572]: return statement outside of function body
 LL |     [(); return while let Some(n) = Some(0) {}];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0572, E0658.
-For more information about an error, try `rustc --explain E0572`.
+For more information about this error, try `rustc --explain E0572`.
index 3691fe19117746649fa1fa33fdf88c16a8e207f9..52d26d0954af894a155a16d888c774b60f15a7b4 100644 (file)
@@ -6,7 +6,9 @@ trait Foo {
 
 struct Bar;
 impl Foo for Bar {
+    #[allow(improper_ctypes_definitions)]
     extern fn borrow(&self) {}
+    #[allow(improper_ctypes_definitions)]
     extern fn take(self: Box<Self>) {}
 }
 
index f4f0f17d00199c3860526bae6b47437245a11d2c..078a7ef2173bd349961bca1d9f8ff5eca58e788e 100644 (file)
@@ -6,10 +6,10 @@ LL |     let x = |ref x: isize| { x += 1; };
    |                              |
    |                              cannot use `+=` on type `&isize`
    |
-help: `+=` can be used on 'isize', you can dereference `x`
+help: `+=` can be used on `isize`, you can dereference `x`
    |
 LL |     let x = |ref x: isize| { *x += 1; };
-   |                              ^^
+   |                              ^
 
 error: aborting due to previous error
 
index 862218e21927985751ae8eed9fe40679b046aa8c..f7cb296d3b8bb738bb0b5a4b3f72a4cb66eb2d4a 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
-
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 pub trait Foo {
     fn abc() -> u32;
diff --git a/src/test/ui/issues/issue-55380.stderr b/src/test/ui/issues/issue-55380.stderr
new file mode 100644 (file)
index 0000000..451beeb
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-55380.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 2edc00974645530ad741960f43c8b1d3f3a5e6ec..47cc64ec470a5f5b0167c8a2300251bd7bdfbafd 100644 (file)
@@ -4,6 +4,8 @@ error[E0599]: no function or associated item named `make_g` found for fn pointer
 LL |     let x = <fn (&())>::make_g();
    |                         ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())`
    |
+   = note: the method `make_g` exists but the following trait bounds were not satisfied:
+           `for<'r> fn(&'r ()): X`
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `X` defines an item `make_g`, perhaps you need to implement it
   --> $DIR/issue-57362-2.rs:8:1
index 2f8bf1e936905420222a62ebdd1c88ee4b6338a9..d9be27250cdeafacab6898a83925d9adf735400e 100644 (file)
@@ -1,11 +1,13 @@
 // run-pass
 #![allow(dead_code)]
+#![warn(clashing_extern_declarations)]
 // pretty-expanded FIXME #23616
 
 extern {
     #[link_name = "malloc"]
     fn malloc1(len: i32) -> *const u8;
     #[link_name = "malloc"]
+    //~^ WARN `malloc2` redeclares `malloc` with a different signature
     fn malloc2(len: i32, foo: i32) -> *const u8;
 }
 
diff --git a/src/test/ui/issues/issue-5791.stderr b/src/test/ui/issues/issue-5791.stderr
new file mode 100644 (file)
index 0000000..cf60e60
--- /dev/null
@@ -0,0 +1,21 @@
+warning: `malloc2` redeclares `malloc` with a different signature
+  --> $DIR/issue-5791.rs:9:5
+   |
+LL | /     #[link_name = "malloc"]
+LL | |     fn malloc1(len: i32) -> *const u8;
+   | |______________________________________- `malloc` previously declared here
+LL | /     #[link_name = "malloc"]
+LL | |
+LL | |     fn malloc2(len: i32, foo: i32) -> *const u8;
+   | |________________________________________________^ this signature doesn't match the previous declaration
+   |
+note: the lint level is defined here
+  --> $DIR/issue-5791.rs:3:9
+   |
+LL | #![warn(clashing_extern_declarations)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected `unsafe extern "C" fn(i32) -> *const u8`
+              found `unsafe extern "C" fn(i32, i32) -> *const u8`
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/issues/issue-59326.rs b/src/test/ui/issues/issue-59326.rs
new file mode 100644 (file)
index 0000000..c0e8837
--- /dev/null
@@ -0,0 +1,26 @@
+// check-pass
+trait Service {
+    type S;
+}
+
+trait Framing {
+    type F;
+}
+
+impl Framing for () {
+    type F = ();
+}
+
+trait HttpService<F: Framing>: Service<S = F::F> {}
+
+type BoxService = Box<dyn HttpService<(), S = ()>>;
+
+fn build_server<F: FnOnce() -> BoxService>(_: F) {}
+
+fn make_server<F: Framing>() -> Box<dyn HttpService<F, S = F::F>> {
+    unimplemented!()
+}
+
+fn main() {
+    build_server(|| make_server())
+}
index e5a9caa32fae701643bc10721e7c6583b227feb9..9c2b2dc9f4daec0b3fc68c30a25d26694002bdc1 100644 (file)
@@ -7,11 +7,13 @@ impl<'a> Trait<'a> for () {
 }
 
 pub fn foo<T, F>(_: T, _: F)
-where T: for<'a> Trait<'a>,
-      F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
+where
+    T: for<'a> Trait<'a>,
+    F: for<'a> FnMut(<T as Trait<'a>>::Item),
+{
+}
 
 fn main() {
     foo((), drop)
     //~^ ERROR type mismatch in function arguments
-    //~| ERROR type mismatch resolving
 }
index e74a34e247a6763e3381b031daaca69dd7854db2..ad679bfa22063cd39d21f78c34dd65002fba3cf5 100644 (file)
@@ -1,31 +1,18 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/issue-60283.rs:14:13
+  --> $DIR/issue-60283.rs:17:13
    |
 LL | pub fn foo<T, F>(_: T, _: F)
    |        --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL |       F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
-   |          ------------------------------------- required by this bound in `foo`
+...
+LL |     F: for<'a> FnMut(<T as Trait<'a>>::Item),
+   |                ----------------------------- required by this bound in `foo`
 ...
 LL |     foo((), drop)
    |             ^^^^
    |             |
-   |             expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
-   |             found signature of `fn(_) -> _`
-
-error[E0271]: type mismatch resolving `for<'a> <fn(_) {std::mem::drop::<_>} as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()`
-  --> $DIR/issue-60283.rs:14:5
-   |
-LL | pub fn foo<T, F>(_: T, _: F)
-   |        --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL |       F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
-   |                  ----------------------------- required by this bound in `foo`
-...
-LL |     foo((), drop)
-   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |             expected signature of `fn(<() as Trait<'a>>::Item) -> _`
+   |             found signature of `fn(()) -> _`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
index 02305191f6ebc4eb1abb47e6969b4ca30df2a9af..4585bcc8cd57fac92d54a14143465527e85b8259 100644 (file)
@@ -19,7 +19,6 @@ fn c() {
 fn d() {
     [0; match [|f @ &ref _| () ] {} ]
     //~^ ERROR expected identifier, found reserved identifier `_`
-    //~| ERROR `match` is not allowed in a `const`
     //~| ERROR mismatched types
 }
 
index ea461cc5d03fade0436ed69a1ff6a9c53a1465d3..f0b93ac91111a88bbcea399c7b418593826d3e50 100644 (file)
@@ -26,15 +26,6 @@ error: expected identifier, found reserved identifier `_`
 LL |     [0; match [|f @ &ref _| () ] {} ]
    |                          ^ expected identifier, found reserved identifier
 
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/issue-66706.rs:20:9
-   |
-LL |     [0; match [|f @ &ref _| () ] {} ]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
 error[E0282]: type annotations needed
   --> $DIR/issue-66706.rs:2:11
    |
@@ -65,7 +56,7 @@ LL | fn d() {
 LL |     [0; match [|f @ &ref _| () ] {} ]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
 
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0282, E0308, E0658.
+Some errors have detailed explanations: E0282, E0308.
 For more information about an error, try `rustc --explain E0282`.
index 1400c6f97b60509f31e419574d63a1e642c5168f..b0fcb74764b987b8e3f2fe1160cf4d1d2ee48a9e 100644 (file)
@@ -18,7 +18,6 @@ fn identity<T>(x: T) -> T {
 }
 
 fn rec<T>(mut it: T)
-//~^ ERROR reached the recursion limit while instantiating
 where
     T: Iterator,
 {
@@ -26,5 +25,6 @@ fn rec<T>(mut it: T)
         T::count(it);
     } else {
         rec(identity(&mut it))
+        //~^ ERROR reached the recursion limit while instantiating
     }
 }
index 881f9d221d6aedf9bf2cb4e8a2c710da3ba2f56e..3bb2016f07d24f03fc2f609343be749f589e3408 100644 (file)
@@ -1,10 +1,16 @@
 error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>`
+  --> $DIR/issue-67552.rs:27:9
+   |
+LL |         rec(identity(&mut it))
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `rec` defined here
   --> $DIR/issue-67552.rs:20:1
    |
 LL | / fn rec<T>(mut it: T)
-LL | |
 LL | | where
 LL | |     T: Iterator,
+LL | | {
 ...  |
 LL | |     }
 LL | | }
diff --git a/src/test/ui/issues/issue-72690.rs b/src/test/ui/issues/issue-72690.rs
new file mode 100644 (file)
index 0000000..4edbd9c
--- /dev/null
@@ -0,0 +1,62 @@
+fn no_err() {
+    |x: String| x;
+    let _ = String::from("x");
+}
+
+fn err() {
+    String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn arg_pat_closure_err() {
+    |x| String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn local_pat_closure_err() {
+    let _ = "x".as_ref(); //~ ERROR type annotations needed
+}
+
+fn err_first_arg_pat() {
+    String::from("x".as_ref()); //~ ERROR type annotations needed
+    |x: String| x;
+}
+
+fn err_second_arg_pat() {
+    |x: String| x;
+    String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn err_mid_arg_pat() {
+    |x: String| x;
+    |x: String| x;
+    |x: String| x;
+    |x: String| x;
+    String::from("x".as_ref()); //~ ERROR type annotations needed
+    |x: String| x;
+    |x: String| x;
+    |x: String| x;
+    |x: String| x;
+}
+
+fn err_first_local_pat() {
+    String::from("x".as_ref()); //~ ERROR type annotations needed
+    let _ = String::from("x");
+}
+
+fn err_second_local_pat() {
+    let _ = String::from("x");
+    String::from("x".as_ref()); //~ ERROR type annotations needed
+}
+
+fn err_mid_local_pat() {
+    let _ = String::from("x");
+    let _ = String::from("x");
+    let _ = String::from("x");
+    let _ = String::from("x");
+    String::from("x".as_ref()); //~ ERROR type annotations needed
+    let _ = String::from("x");
+    let _ = String::from("x");
+    let _ = String::from("x");
+    let _ = String::from("x");
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-72690.stderr b/src/test/ui/issues/issue-72690.stderr
new file mode 100644 (file)
index 0000000..64e78dd
--- /dev/null
@@ -0,0 +1,88 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:7:5
+   |
+LL |     String::from("x".as_ref());
+   |     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+   |
+   = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+   = note: required by `std::convert::From::from`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-72690.rs:11:6
+   |
+LL |     |x| String::from("x".as_ref());
+   |      ^ consider giving this closure parameter a type
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:15:17
+   |
+LL |     let _ = "x".as_ref();
+   |                 ^^^^^^ cannot infer type for type `str`
+   |
+   = note: cannot satisfy `str: std::convert::AsRef<_>`
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:19:5
+   |
+LL |     String::from("x".as_ref());
+   |     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+   |
+   = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+   = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:25:5
+   |
+LL |     String::from("x".as_ref());
+   |     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+   |
+   = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+   = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-72690.rs:33:5
+   |
+LL |     String::from("x".as_ref());
+   |     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+   |
+   = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+   = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed for `std::string::String`
+  --> $DIR/issue-72690.rs:41:5
+   |
+LL |     String::from("x".as_ref());
+   |     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+LL |     let _ = String::from("x");
+   |         - consider giving this pattern a type
+   |
+   = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+   = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed for `std::string::String`
+  --> $DIR/issue-72690.rs:47:5
+   |
+LL |     let _ = String::from("x");
+   |         - consider giving this pattern a type
+LL |     String::from("x".as_ref());
+   |     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+   |
+   = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+   = note: required by `std::convert::From::from`
+
+error[E0283]: type annotations needed for `std::string::String`
+  --> $DIR/issue-72690.rs:55:5
+   |
+LL |     let _ = String::from("x");
+   |         - consider giving this pattern a type
+...
+LL |     String::from("x".as_ref());
+   |     ^^^^^^^^^^^^ cannot infer type for struct `std::string::String`
+   |
+   = note: cannot satisfy `std::string::String: std::convert::From<&_>`
+   = note: required by `std::convert::From::from`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
index 3556ec08247b5af88e540557ec093ae18119e9d7..eb8d66790ccea455e0e18b5fc71147d0da371787 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:14:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:16:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:18:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:20:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:22:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^^^ attempt to divide 1_isize by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -48,103 +48,103 @@ error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^ attempt to divide 1_i8 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i16 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i32 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i64 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^^ attempt to divide 1_i128 by zero
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:44:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:56:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
 
 error: aborting due to 24 previous errors
 
index 3556ec08247b5af88e540557ec093ae18119e9d7..eb8d66790ccea455e0e18b5fc71147d0da371787 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:14:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:16:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:18:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:20:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:22:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^^^ attempt to divide 1_isize by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -48,103 +48,103 @@ error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^ attempt to divide 1_i8 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i16 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i32 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i64 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^^ attempt to divide 1_i128 by zero
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:44:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:56:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
 
 error: aborting due to 24 previous errors
 
index 3556ec08247b5af88e540557ec093ae18119e9d7..eb8d66790ccea455e0e18b5fc71147d0da371787 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:14:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@ error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:16:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:18:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:20:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:22:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to divide with overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^^^ attempt to divide 1_isize by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -48,103 +48,103 @@ error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^ attempt to divide 1_i8 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i16 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i32 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^ attempt to divide 1_i64 by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to divide by zero
+   |                                    ^^^^^^^^^ attempt to divide 1_i128 by zero
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:44:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:56:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
+   |                                    ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
 
 error: aborting due to 24 previous errors
 
index 80f360155cb49f272b08c2d6f44c946a7f8fac71..14bdd8511119e0fdda184fb679c9d44925c5218c 100644 (file)
@@ -3,12 +3,10 @@
 
 // build-fail
 
-fn generic<T>() {
+fn generic<T>() { //~ WARN function cannot return without recursing
     generic::<Option<T>>();
 }
-//~^^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
-//~| WARN function cannot return without recursing
-
+//~^^ ERROR reached the recursion limit while instantiating `generic::<std::option::Option<
 
 
 fn main () {
index ee0672c598d5c10a177cc3fff6769766f157061e..70709fd33ac3ac170f287fbeaaf70ce118c59c2f 100644 (file)
@@ -10,6 +10,12 @@ LL |     generic::<Option<T>>();
    = help: a `loop` may express intention better if this is on purpose
 
 error: reached the recursion limit while instantiating `generic::<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<std::option::Option<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+  --> $DIR/issue-8727.rs:7:5
+   |
+LL |     generic::<Option<T>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `generic` defined here
   --> $DIR/issue-8727.rs:6:1
    |
 LL | / fn generic<T>() {
index cd8ebdffb730bc845adfd0069f7638a39b9176c8..1a371c6b17000b6c93d2a491f88321ba4ee95230 100644 (file)
@@ -10,15 +10,15 @@ error: layout_of(E) = Layout {
         ],
     },
     variants: Multiple {
-        discr: Scalar {
+        tag: Scalar {
             value: Int(
                 I32,
                 false,
             ),
             valid_range: 0..=0,
         },
-        discr_kind: Tag,
-        discr_index: 0,
+        tag_encoding: Direct,
+        tag_field: 0,
         variants: [
             Layout {
                 fields: Arbitrary {
@@ -202,15 +202,15 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
         ],
     },
     variants: Multiple {
-        discr: Scalar {
+        tag: Scalar {
             value: Int(
                 I32,
                 false,
             ),
             valid_range: 0..=1,
         },
-        discr_kind: Tag,
-        discr_index: 0,
+        tag_encoding: Direct,
+        tag_field: 0,
         variants: [
             Layout {
                 fields: Arbitrary {
diff --git a/src/test/ui/lint/auxiliary/external_extern_fn.rs b/src/test/ui/lint/auxiliary/external_extern_fn.rs
new file mode 100644 (file)
index 0000000..b2caebc
--- /dev/null
@@ -0,0 +1,3 @@
+extern {
+    pub fn extern_fn(x: u8);
+}
diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs
new file mode 100644 (file)
index 0000000..5446141
--- /dev/null
@@ -0,0 +1,186 @@
+// check-pass
+// aux-build:external_extern_fn.rs
+#![crate_type = "lib"]
+#![warn(clashing_extern_declarations)]
+
+extern crate external_extern_fn;
+
+extern "C" {
+    fn clash(x: u8);
+    fn no_clash(x: u8);
+}
+
+fn redeclared_different_signature() {
+    extern "C" {
+        fn clash(x: u64); //~ WARN `clash` redeclared with a different signature
+    }
+
+    unsafe {
+        clash(123);
+        no_clash(123);
+    }
+}
+
+fn redeclared_same_signature() {
+    extern "C" {
+        fn no_clash(x: u8);
+    }
+    unsafe {
+        no_clash(123);
+    }
+}
+
+extern "C" {
+    fn extern_fn(x: u64);
+}
+
+fn extern_clash() {
+    extern "C" {
+        fn extern_fn(x: u32); //~ WARN `extern_fn` redeclared with a different signature
+    }
+    unsafe {
+        extern_fn(123);
+    }
+}
+
+fn extern_no_clash() {
+    unsafe {
+        external_extern_fn::extern_fn(123);
+        crate::extern_fn(123);
+    }
+}
+extern "C" {
+    fn some_other_new_name(x: i16);
+
+    #[link_name = "extern_link_name"]
+    fn some_new_name(x: i16);
+
+    #[link_name = "link_name_same"]
+    fn both_names_different(x: i16);
+}
+
+fn link_name_clash() {
+    extern "C" {
+        fn extern_link_name(x: u32);
+        //~^ WARN `extern_link_name` redeclared with a different signature
+
+        #[link_name = "some_other_new_name"]
+        //~^ WARN `some_other_extern_link_name` redeclares `some_other_new_name` with a different
+        fn some_other_extern_link_name(x: u32);
+
+        #[link_name = "link_name_same"]
+        //~^ WARN `other_both_names_different` redeclares `link_name_same` with a different
+        fn other_both_names_different(x: u32);
+    }
+}
+
+mod a {
+    extern "C" {
+        fn different_mod(x: u8);
+    }
+}
+mod b {
+    extern "C" {
+        fn different_mod(x: u64); //~ WARN `different_mod` redeclared with a different signature
+    }
+}
+
+extern "C" {
+    fn variadic_decl(x: u8, ...);
+}
+
+fn variadic_clash() {
+    extern "C" {
+        fn variadic_decl(x: u8); //~ WARN `variadic_decl` redeclared with a different signature
+    }
+}
+
+#[no_mangle]
+fn no_mangle_name(x: u8) {}
+
+extern "C" {
+    #[link_name = "unique_link_name"]
+    fn link_name_specified(x: u8);
+}
+
+fn tricky_no_clash() {
+    extern "C" {
+        // Shouldn't warn, because the declaration above actually declares a different symbol (and
+        // Rust's name resolution rules around shadowing will handle this gracefully).
+        fn link_name_specified() -> u32;
+
+        // The case of a no_mangle name colliding with an extern decl (see #28179) is related but
+        // shouldn't be reported by ClashingExternDeclarations, because this is an example of
+        // unmangled name clash causing bad behaviour in functions with a defined body.
+        fn no_mangle_name() -> u32;
+    }
+}
+
+mod banana {
+    mod one {
+        #[repr(C)]
+        struct Banana {
+            weight: u32,
+            length: u16,
+        }
+        extern "C" {
+            fn weigh_banana(count: *const Banana) -> u64;
+        }
+    }
+
+    mod two {
+        #[repr(C)]
+        struct Banana {
+            weight: u32,
+            length: u16,
+        } // note: distinct type
+        extern "C" {
+          // This should not trigger the lint because two::Banana is structurally equivalent to
+          // one::Banana.
+            fn weigh_banana(count: *const Banana) -> u64;
+        }
+    }
+
+    mod three {
+        // This _should_ trigger the lint, because repr(packed) should generate a struct that has a
+        // different layout.
+        #[repr(packed)]
+        struct Banana {
+            weight: u32,
+            length: u16,
+        }
+        #[allow(improper_ctypes)]
+        extern "C" {
+            fn weigh_banana(count: *const Banana) -> u64;
+            //~^ WARN `weigh_banana` redeclared with a different signature
+        }
+    }
+}
+
+mod sameish_members {
+    mod a {
+        #[repr(C)]
+        struct Point {
+            x: i16,
+            y: i16,
+        }
+
+        extern "C" {
+            fn draw_point(p: Point);
+        }
+    }
+    mod b {
+        #[repr(C)]
+        struct Point {
+            coordinates: [i16; 2],
+        }
+
+        // It's possible we are overconservative for this case, as accessing the elements of the
+        // coordinates array might end up correctly accessing `.x` and `.y`. However, this may not
+        // always be the case, for every architecture and situation. This is also a really odd
+        // thing to do anyway.
+        extern "C" {
+            fn draw_point(p: Point); //~ WARN `draw_point` redeclared with a different
+        }
+    }
+}
diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr
new file mode 100644 (file)
index 0000000..96e51ab
--- /dev/null
@@ -0,0 +1,121 @@
+warning: `clash` redeclared with a different signature
+  --> $DIR/clashing-extern-fn.rs:15:9
+   |
+LL |     fn clash(x: u8);
+   |     ---------------- `clash` previously declared here
+...
+LL |         fn clash(x: u64);
+   |         ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+note: the lint level is defined here
+  --> $DIR/clashing-extern-fn.rs:4:9
+   |
+LL | #![warn(clashing_extern_declarations)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: expected `unsafe extern "C" fn(u8)`
+              found `unsafe extern "C" fn(u64)`
+
+warning: `extern_fn` redeclared with a different signature
+  --> $DIR/clashing-extern-fn.rs:39:9
+   |
+LL |     fn extern_fn(x: u64);
+   |     --------------------- `extern_fn` previously declared here
+...
+LL |         fn extern_fn(x: u32);
+   |         ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(u64)`
+              found `unsafe extern "C" fn(u32)`
+
+warning: `extern_link_name` redeclared with a different signature
+  --> $DIR/clashing-extern-fn.rs:64:9
+   |
+LL | /     #[link_name = "extern_link_name"]
+LL | |     fn some_new_name(x: i16);
+   | |_____________________________- `extern_link_name` previously declared here
+...
+LL |           fn extern_link_name(x: u32);
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(i16)`
+              found `unsafe extern "C" fn(u32)`
+
+warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
+  --> $DIR/clashing-extern-fn.rs:67:9
+   |
+LL |       fn some_other_new_name(x: i16);
+   |       ------------------------------- `some_other_new_name` previously declared here
+...
+LL | /         #[link_name = "some_other_new_name"]
+LL | |
+LL | |         fn some_other_extern_link_name(x: u32);
+   | |_______________________________________________^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(i16)`
+              found `unsafe extern "C" fn(u32)`
+
+warning: `other_both_names_different` redeclares `link_name_same` with a different signature
+  --> $DIR/clashing-extern-fn.rs:71:9
+   |
+LL | /     #[link_name = "link_name_same"]
+LL | |     fn both_names_different(x: i16);
+   | |____________________________________- `link_name_same` previously declared here
+...
+LL | /         #[link_name = "link_name_same"]
+LL | |
+LL | |         fn other_both_names_different(x: u32);
+   | |______________________________________________^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(i16)`
+              found `unsafe extern "C" fn(u32)`
+
+warning: `different_mod` redeclared with a different signature
+  --> $DIR/clashing-extern-fn.rs:84:9
+   |
+LL |         fn different_mod(x: u8);
+   |         ------------------------ `different_mod` previously declared here
+...
+LL |         fn different_mod(x: u64);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(u8)`
+              found `unsafe extern "C" fn(u64)`
+
+warning: `variadic_decl` redeclared with a different signature
+  --> $DIR/clashing-extern-fn.rs:94:9
+   |
+LL |     fn variadic_decl(x: u8, ...);
+   |     ----------------------------- `variadic_decl` previously declared here
+...
+LL |         fn variadic_decl(x: u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(u8, ...)`
+              found `unsafe extern "C" fn(u8)`
+
+warning: `weigh_banana` redeclared with a different signature
+  --> $DIR/clashing-extern-fn.rs:154:13
+   |
+LL |             fn weigh_banana(count: *const Banana) -> u64;
+   |             --------------------------------------------- `weigh_banana` previously declared here
+...
+LL |             fn weigh_banana(count: *const Banana) -> u64;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64`
+              found `unsafe extern "C" fn(*const banana::three::Banana) -> u64`
+
+warning: `draw_point` redeclared with a different signature
+  --> $DIR/clashing-extern-fn.rs:183:13
+   |
+LL |             fn draw_point(p: Point);
+   |             ------------------------ `draw_point` previously declared here
+...
+LL |             fn draw_point(p: Point);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+   |
+   = note: expected `unsafe extern "C" fn(sameish_members::a::Point)`
+              found `unsafe extern "C" fn(sameish_members::b::Point)`
+
+warning: 9 warnings emitted
+
diff --git a/src/test/ui/lint/crate_level_only_lint.rs b/src/test/ui/lint/crate_level_only_lint.rs
new file mode 100644 (file)
index 0000000..d9673fa
--- /dev/null
@@ -0,0 +1,22 @@
+#![deny(uncommon_codepoints, unused_attributes)]
+
+mod foo {
+#![allow(uncommon_codepoints)]
+//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+
+#[allow(uncommon_codepoints)]
+//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+const BAR: f64 = 0.000001;
+
+}
+
+#[allow(uncommon_codepoints)]
+//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+fn main() {
+}
diff --git a/src/test/ui/lint/crate_level_only_lint.stderr b/src/test/ui/lint/crate_level_only_lint.stderr
new file mode 100644 (file)
index 0000000..8fb06df
--- /dev/null
@@ -0,0 +1,62 @@
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:4:10
+   |
+LL | #![allow(uncommon_codepoints)]
+   |          ^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/crate_level_only_lint.rs:1:30
+   |
+LL | #![deny(uncommon_codepoints, unused_attributes)]
+   |                              ^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:9:9
+   |
+LL | #[allow(uncommon_codepoints)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:17:9
+   |
+LL | #[allow(uncommon_codepoints)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:4:10
+   |
+LL | #![allow(uncommon_codepoints)]
+   |          ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:9:9
+   |
+LL | #[allow(uncommon_codepoints)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:17:9
+   |
+LL | #[allow(uncommon_codepoints)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:4:10
+   |
+LL | #![allow(uncommon_codepoints)]
+   |          ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:9:9
+   |
+LL | #[allow(uncommon_codepoints)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+  --> $DIR/crate_level_only_lint.rs:17:9
+   |
+LL | #[allow(uncommon_codepoints)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
index 6826d2cd67eb9489f251b21038e0c15e6dd1fa1d..fe3c392ccf1001eff9b73779b9e909ed95fa617b 100644 (file)
@@ -1,5 +1,6 @@
 #![allow(unused_variables)]
 #![allow(non_camel_case_types)]
+#![allow(clashing_extern_declarations)]
 #![deny(dead_code)]
 
 #![crate_type="lib"]
index 6d174e8d9bc382bc9d554ab7635535eae60fa47f..cf8f01ea19f0cd1409fc79570895589967209a9a 100644 (file)
@@ -1,35 +1,35 @@
 error: struct is never constructed: `Foo`
-  --> $DIR/lint-dead-code-3.rs:13:8
+  --> $DIR/lint-dead-code-3.rs:14:8
    |
 LL | struct Foo;
    |        ^^^
    |
 note: the lint level is defined here
-  --> $DIR/lint-dead-code-3.rs:3:9
+  --> $DIR/lint-dead-code-3.rs:4:9
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
 
 error: associated function is never used: `foo`
-  --> $DIR/lint-dead-code-3.rs:15:8
+  --> $DIR/lint-dead-code-3.rs:16:8
    |
 LL |     fn foo(&self) {
    |        ^^^
 
 error: function is never used: `bar`
-  --> $DIR/lint-dead-code-3.rs:20:4
+  --> $DIR/lint-dead-code-3.rs:21:4
    |
 LL | fn bar() {
    |    ^^^
 
 error: enum is never used: `c_void`
-  --> $DIR/lint-dead-code-3.rs:59:6
+  --> $DIR/lint-dead-code-3.rs:60:6
    |
 LL | enum c_void {}
    |      ^^^^^^
 
 error: function is never used: `free`
-  --> $DIR/lint-dead-code-3.rs:61:5
+  --> $DIR/lint-dead-code-3.rs:62:5
    |
 LL |     fn free(p: *const c_void);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/lint/lint-ctypes-73249-1.rs b/src/test/ui/lint/lint-ctypes-73249-1.rs
new file mode 100644 (file)
index 0000000..cf416c3
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+    type Assoc: 'static;
+}
+
+impl Foo for () {
+    type Assoc = u32;
+}
+
+extern "C" {
+    pub fn lint_me(x: Bar<()>);
+}
+
+#[repr(transparent)]
+pub struct Bar<T: Foo> {
+    value: &'static <T as Foo>::Assoc,
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-2.rs b/src/test/ui/lint/lint-ctypes-73249-2.rs
new file mode 100644 (file)
index 0000000..86cc5e2
--- /dev/null
@@ -0,0 +1,29 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for () { }
+
+type Qux = impl Baz;
+
+fn assign() -> Qux {}
+
+pub trait Foo {
+    type Assoc: 'static;
+}
+
+impl Foo for () {
+    type Assoc = Qux;
+}
+
+#[repr(transparent)]
+pub struct A<T: Foo> {
+    x: &'static <T as Foo>::Assoc,
+}
+
+extern "C" {
+    pub fn lint_me() -> A<()>; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-2.stderr b/src/test/ui/lint/lint-ctypes-73249-2.stderr
new file mode 100644 (file)
index 0000000..36dbe32
--- /dev/null
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73249-2.rs:26:25
+   |
+LL |     pub fn lint_me() -> A<()>;
+   |                         ^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73249-2.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73249-3.rs b/src/test/ui/lint/lint-ctypes-73249-3.rs
new file mode 100644 (file)
index 0000000..25c4e7c
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+fn assign() -> Qux { 3 }
+
+#[repr(C)]
+pub struct A {
+    x: Qux,
+}
+
+extern "C" {
+    pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-3.stderr b/src/test/ui/lint/lint-ctypes-73249-3.stderr
new file mode 100644 (file)
index 0000000..7d13328
--- /dev/null
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73249-3.rs:18:25
+   |
+LL |     pub fn lint_me() -> A;
+   |                         ^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73249-3.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73249-4.rs b/src/test/ui/lint/lint-ctypes-73249-4.rs
new file mode 100644 (file)
index 0000000..6c72bd6
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+#![deny(improper_ctypes)]
+
+use std::marker::PhantomData;
+
+trait Foo {
+    type Assoc;
+}
+
+impl Foo for () {
+    type Assoc = PhantomData<()>;
+}
+
+#[repr(transparent)]
+struct Wow<T> where T: Foo<Assoc = PhantomData<T>> {
+    x: <T as Foo>::Assoc,
+    v: u32,
+}
+
+extern "C" {
+    fn test(v: Wow<()>);
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-5.rs b/src/test/ui/lint/lint-ctypes-73249-5.rs
new file mode 100644 (file)
index 0000000..61e4698
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+fn assign() -> Qux { 3 }
+
+#[repr(transparent)]
+pub struct A {
+    x: Qux,
+}
+
+extern "C" {
+    pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73249-5.stderr b/src/test/ui/lint/lint-ctypes-73249-5.stderr
new file mode 100644 (file)
index 0000000..d2780cb
--- /dev/null
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73249-5.rs:18:25
+   |
+LL |     pub fn lint_me() -> A;
+   |                         ^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73249-5.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73249.rs b/src/test/ui/lint/lint-ctypes-73249.rs
new file mode 100644 (file)
index 0000000..5b48fa9
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+    type Assoc;
+}
+
+impl Foo for () {
+    type Assoc = u32;
+}
+
+extern "C" {
+    pub fn lint_me(x: Bar<()>);
+}
+
+#[repr(transparent)]
+pub struct Bar<T: Foo> {
+    value: <T as Foo>::Assoc,
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.rs b/src/test/ui/lint/lint-ctypes-73251-1.rs
new file mode 100644 (file)
index 0000000..2ce8098
--- /dev/null
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+pub trait Foo {
+    type Assoc;
+}
+
+impl Foo for u32 {
+    type Assoc = Qux;
+}
+
+fn assign() -> Qux { 1 }
+
+extern "C" {
+    pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.stderr b/src/test/ui/lint/lint-ctypes-73251-1.stderr
new file mode 100644 (file)
index 0000000..0b4237b
--- /dev/null
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73251-1.rs:21:25
+   |
+LL |     pub fn lint_me() -> <u32 as Foo>::Assoc;
+   |                         ^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73251-1.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs
new file mode 100644 (file)
index 0000000..3427c65
--- /dev/null
@@ -0,0 +1,32 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait TraitA {
+    type Assoc;
+}
+
+impl TraitA for u32 {
+    type Assoc = u32;
+}
+
+pub trait TraitB {
+    type Assoc;
+}
+
+impl<T> TraitB for T where T: TraitA {
+    type Assoc = <T as TraitA>::Assoc;
+}
+
+type AliasA = impl TraitA<Assoc = u32>;
+
+type AliasB = impl TraitB<Assoc = AliasA>;
+
+fn use_of_a() -> AliasA { 3 }
+
+fn use_of_b() -> AliasB { 3 }
+
+extern "C" {
+    pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr
new file mode 100644 (file)
index 0000000..43f7629
--- /dev/null
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl TraitA`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73251-2.rs:29:25
+   |
+LL |     pub fn lint_me() -> <AliasB as TraitB>::Assoc;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73251-2.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73251.rs b/src/test/ui/lint/lint-ctypes-73251.rs
new file mode 100644 (file)
index 0000000..ebc2ca7
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+    type Assoc;
+}
+
+impl Foo for () {
+    type Assoc = u32;
+}
+
+type Bar = impl Foo<Assoc = u32>;
+
+fn assign() -> Bar {}
+
+extern "C" {
+    pub fn lint_me() -> <Bar as Foo>::Assoc;
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-fn.rs b/src/test/ui/lint/lint-ctypes-fn.rs
new file mode 100644 (file)
index 0000000..67dd7ab
--- /dev/null
@@ -0,0 +1,182 @@
+#![feature(rustc_private)]
+
+#![allow(private_in_public)]
+#![deny(improper_ctypes_definitions)]
+
+extern crate libc;
+
+use std::default::Default;
+use std::marker::PhantomData;
+
+trait Mirror { type It: ?Sized; }
+
+impl<T: ?Sized> Mirror for T { type It = Self; }
+
+#[repr(C)]
+pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
+
+#[repr(C)]
+pub struct StructWithProjectionAndLifetime<'a>(
+    &'a mut <StructWithProjectionAndLifetime<'a> as Mirror>::It
+);
+
+pub type I32Pair = (i32, i32);
+
+#[repr(C)]
+pub struct ZeroSize;
+
+pub type RustFn = fn();
+
+pub type RustBadRet = extern fn() -> Box<u32>;
+
+pub type CVoidRet = ();
+
+pub struct Foo;
+
+#[repr(transparent)]
+pub struct TransparentI128(i128);
+
+#[repr(transparent)]
+pub struct TransparentStr(&'static str);
+
+#[repr(transparent)]
+pub struct TransparentBadFn(RustBadRet);
+
+#[repr(transparent)]
+pub struct TransparentInt(u32);
+
+#[repr(transparent)]
+pub struct TransparentRef<'a>(&'a TransparentInt);
+
+#[repr(transparent)]
+pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
+
+#[repr(transparent)]
+pub struct TransparentUnit<U>(f32, PhantomData<U>);
+
+#[repr(transparent)]
+pub struct TransparentCustomZst(i32, ZeroSize);
+
+#[repr(C)]
+pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
+
+pub extern "C" fn ptr_type1(size: *const Foo) { }
+
+pub extern "C" fn ptr_type2(size: *const Foo) { }
+
+pub extern "C" fn slice_type(p: &[u32]) { }
+//~^ ERROR: uses type `[u32]`
+
+pub extern "C" fn str_type(p: &str) { }
+//~^ ERROR: uses type `str`
+
+pub extern "C" fn box_type(p: Box<u32>) { }
+//~^ ERROR uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn char_type(p: char) { }
+//~^ ERROR uses type `char`
+
+pub extern "C" fn i128_type(p: i128) { }
+//~^ ERROR uses type `i128`
+
+pub extern "C" fn u128_type(p: u128) { }
+//~^ ERROR uses type `u128`
+
+pub extern "C" fn tuple_type(p: (i32, i32)) { }
+//~^ ERROR uses type `(i32, i32)`
+
+pub extern "C" fn tuple_type2(p: I32Pair) { }
+//~^ ERROR uses type `(i32, i32)`
+
+pub extern "C" fn zero_size(p: ZeroSize) { }
+//~^ ERROR uses type `ZeroSize`
+
+pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
+//~^ ERROR uses type `ZeroSizeWithPhantomData`
+
+pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
+//~^ ERROR uses type `std::marker::PhantomData<bool>`
+    Default::default()
+}
+
+pub extern "C" fn fn_type(p: RustFn) { }
+//~^ ERROR uses type `fn()`
+
+pub extern "C" fn fn_type2(p: fn()) { }
+//~^ ERROR uses type `fn()`
+
+pub extern "C" fn fn_contained(p: RustBadRet) { }
+//~^ ERROR: uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn transparent_i128(p: TransparentI128) { }
+//~^ ERROR: uses type `i128`
+
+pub extern "C" fn transparent_str(p: TransparentStr) { }
+//~^ ERROR: uses type `str`
+
+pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
+//~^ ERROR: uses type `std::boxed::Box<u32>`
+
+pub extern "C" fn good3(fptr: Option<extern fn()>) { }
+
+pub extern "C" fn good4(aptr: &[u8; 4 as usize]) { }
+
+pub extern "C" fn good5(s: StructWithProjection) { }
+
+pub extern "C" fn good6(s: StructWithProjectionAndLifetime) { }
+
+pub extern "C" fn good7(fptr: extern fn() -> ()) { }
+
+pub extern "C" fn good8(fptr: extern fn() -> !) { }
+
+pub extern "C" fn good9() -> () { }
+
+pub extern "C" fn good10() -> CVoidRet { }
+
+pub extern "C" fn good11(size: isize) { }
+
+pub extern "C" fn good12(size: usize) { }
+
+pub extern "C" fn good13(n: TransparentInt) { }
+
+pub extern "C" fn good14(p: TransparentRef) { }
+
+pub extern "C" fn good15(p: TransparentLifetime) { }
+
+pub extern "C" fn good16(p: TransparentUnit<ZeroSize>) { }
+
+pub extern "C" fn good17(p: TransparentCustomZst) { }
+
+#[allow(improper_ctypes_definitions)]
+pub extern "C" fn good18(_: &String) { }
+
+#[cfg(not(target_arch = "wasm32"))]
+pub extern "C" fn good1(size: *const libc::c_int) { }
+
+#[cfg(not(target_arch = "wasm32"))]
+pub extern "C" fn good2(size: *const libc::c_uint) { }
+
+pub extern "C" fn unused_generic1<T>(size: *const Foo) { }
+
+pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
+//~^ ERROR uses type `std::marker::PhantomData<bool>`
+    Default::default()
+}
+
+pub extern "C" fn used_generic1<T>(x: T) { }
+
+pub extern "C" fn used_generic2<T>(x: T, size: *const Foo) { }
+
+pub extern "C" fn used_generic3<T: Default>() -> T {
+    Default::default()
+}
+
+pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
+//~^ ERROR: uses type `std::vec::Vec<T>`
+
+pub extern "C" fn used_generic5<T>() -> Vec<T> {
+//~^ ERROR: uses type `std::vec::Vec<T>`
+    Default::default()
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr
new file mode 100644 (file)
index 0000000..66cf195
--- /dev/null
@@ -0,0 +1,191 @@
+error: `extern` fn uses type `[u32]`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:67:33
+   |
+LL | pub extern "C" fn slice_type(p: &[u32]) { }
+   |                                 ^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-fn.rs:4:9
+   |
+LL | #![deny(improper_ctypes_definitions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
+
+error: `extern` fn uses type `str`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:70:31
+   |
+LL | pub extern "C" fn str_type(p: &str) { }
+   |                               ^^^^ not FFI-safe
+   |
+   = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:73:31
+   |
+LL | pub extern "C" fn box_type(p: Box<u32>) { }
+   |                               ^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `char`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:76:32
+   |
+LL | pub extern "C" fn char_type(p: char) { }
+   |                                ^^^^ not FFI-safe
+   |
+   = help: consider using `u32` or `libc::wchar_t` instead
+   = note: the `char` type has no C equivalent
+
+error: `extern` fn uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:79:32
+   |
+LL | pub extern "C" fn i128_type(p: i128) { }
+   |                                ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `u128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:82:32
+   |
+LL | pub extern "C" fn u128_type(p: u128) { }
+   |                                ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:85:33
+   |
+LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
+   |                                 ^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider using a struct instead
+   = note: tuples have unspecified layout
+
+error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:88:34
+   |
+LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
+   |                                  ^^^^^^^ not FFI-safe
+   |
+   = help: consider using a struct instead
+   = note: tuples have unspecified layout
+
+error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:91:32
+   |
+LL | pub extern "C" fn zero_size(p: ZeroSize) { }
+   |                                ^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a member to this struct
+   = note: this struct has no fields
+note: the type is defined here
+  --> $DIR/lint-ctypes-fn.rs:26:1
+   |
+LL | pub struct ZeroSize;
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:94:40
+   |
+LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
+note: the type is defined here
+  --> $DIR/lint-ctypes-fn.rs:61:1
+   |
+LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:97:51
+   |
+LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
+   |                                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
+
+error: `extern` fn uses type `fn()`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:102:30
+   |
+LL | pub extern "C" fn fn_type(p: RustFn) { }
+   |                              ^^^^^^ not FFI-safe
+   |
+   = help: consider using an `extern fn(...) -> ...` function pointer instead
+   = note: this function pointer has Rust-specific calling convention
+
+error: `extern` fn uses type `fn()`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:105:31
+   |
+LL | pub extern "C" fn fn_type2(p: fn()) { }
+   |                               ^^^^ not FFI-safe
+   |
+   = help: consider using an `extern fn(...) -> ...` function pointer instead
+   = note: this function pointer has Rust-specific calling convention
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:108:35
+   |
+LL | pub extern "C" fn fn_contained(p: RustBadRet) { }
+   |                                   ^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `i128`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:111:39
+   |
+LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
+   |                                       ^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+error: `extern` fn uses type `str`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:114:38
+   |
+LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
+   |                                      ^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider using `*const u8` and a length instead
+   = note: string slices have no C equivalent
+
+error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:117:37
+   |
+LL | pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
+   |                                     ^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:161:43
+   |
+LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
+   |                                           ^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: composed only of `PhantomData`
+
+error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:174:39
+   |
+LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
+   |                                       ^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:177:41
+   |
+LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
+   |                                         ^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: aborting due to 20 previous errors
+
index 8dbfeff7972fbb9ac8efb58781df5448383d5d96..d33b99bdc43870f85f97d719a7fa582036be8216 100644 (file)
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:17:20
+  --> $DIR/lint-exceeding-bitshifts.rs:18:20
    |
 LL |     const N: i32 = T::N << 42;
-   |                    ^^^^^^^^^^ attempt to shift left with overflow
+   |                    ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:9:9
+  --> $DIR/lint-exceeding-bitshifts.rs:10:9
    |
 LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:21:13
+  --> $DIR/lint-exceeding-bitshifts.rs:22:13
    |
 LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left with overflow
+   |             ^^^^^^^ attempt to shift left by 42_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:26:15
+  --> $DIR/lint-exceeding-bitshifts.rs:27:15
    |
 LL |       let n = 1u8 << 8;
-   |               ^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:28:15
+  --> $DIR/lint-exceeding-bitshifts.rs:29:15
    |
 LL |       let n = 1u16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:30:15
+  --> $DIR/lint-exceeding-bitshifts.rs:31:15
    |
 LL |       let n = 1u32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:32:15
+  --> $DIR/lint-exceeding-bitshifts.rs:33:15
    |
 LL |       let n = 1u64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:34:15
+  --> $DIR/lint-exceeding-bitshifts.rs:35:15
    |
 LL |       let n = 1i8 << 8;
-   |               ^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:36:15
+  --> $DIR/lint-exceeding-bitshifts.rs:37:15
    |
 LL |       let n = 1i16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:38:15
+  --> $DIR/lint-exceeding-bitshifts.rs:39:15
    |
 LL |       let n = 1i32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:40:15
+  --> $DIR/lint-exceeding-bitshifts.rs:41:15
    |
 LL |       let n = 1i64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:43:15
+  --> $DIR/lint-exceeding-bitshifts.rs:44:15
    |
 LL |       let n = 1u8 >> 8;
-   |               ^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:45:15
+  --> $DIR/lint-exceeding-bitshifts.rs:46:15
    |
 LL |       let n = 1u16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:47:15
+  --> $DIR/lint-exceeding-bitshifts.rs:48:15
    |
 LL |       let n = 1u32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:49:15
+  --> $DIR/lint-exceeding-bitshifts.rs:50:15
    |
 LL |       let n = 1u64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:51:15
+  --> $DIR/lint-exceeding-bitshifts.rs:52:15
    |
 LL |       let n = 1i8 >> 8;
-   |               ^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:53:15
+  --> $DIR/lint-exceeding-bitshifts.rs:54:15
    |
 LL |       let n = 1i16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:55:15
+  --> $DIR/lint-exceeding-bitshifts.rs:56:15
    |
 LL |       let n = 1i32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:57:15
+  --> $DIR/lint-exceeding-bitshifts.rs:58:15
    |
 LL |       let n = 1i64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:61:15
+  --> $DIR/lint-exceeding-bitshifts.rs:62:15
    |
 LL |       let n = n << 8;
-   |               ^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:63:15
+  --> $DIR/lint-exceeding-bitshifts.rs:64:15
    |
 LL |       let n = 1u8 << -8;
-   |               ^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:68:15
+  --> $DIR/lint-exceeding-bitshifts.rs:69:15
    |
 LL |       let n = 1u8 << (4+4);
-   |               ^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:70:15
+  --> $DIR/lint-exceeding-bitshifts.rs:71:15
    |
 LL |       let n = 1i64 >> [64][0];
-   |               ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:76:15
+  --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_isize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:77:15
+  --> $DIR/lint-exceeding-bitshifts.rs:78:15
    |
 LL |       let n = 1_usize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
 
 warning: 24 warnings emitted
 
index 8dbfeff7972fbb9ac8efb58781df5448383d5d96..d33b99bdc43870f85f97d719a7fa582036be8216 100644 (file)
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:17:20
+  --> $DIR/lint-exceeding-bitshifts.rs:18:20
    |
 LL |     const N: i32 = T::N << 42;
-   |                    ^^^^^^^^^^ attempt to shift left with overflow
+   |                    ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:9:9
+  --> $DIR/lint-exceeding-bitshifts.rs:10:9
    |
 LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:21:13
+  --> $DIR/lint-exceeding-bitshifts.rs:22:13
    |
 LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left with overflow
+   |             ^^^^^^^ attempt to shift left by 42_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:26:15
+  --> $DIR/lint-exceeding-bitshifts.rs:27:15
    |
 LL |       let n = 1u8 << 8;
-   |               ^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:28:15
+  --> $DIR/lint-exceeding-bitshifts.rs:29:15
    |
 LL |       let n = 1u16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:30:15
+  --> $DIR/lint-exceeding-bitshifts.rs:31:15
    |
 LL |       let n = 1u32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:32:15
+  --> $DIR/lint-exceeding-bitshifts.rs:33:15
    |
 LL |       let n = 1u64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:34:15
+  --> $DIR/lint-exceeding-bitshifts.rs:35:15
    |
 LL |       let n = 1i8 << 8;
-   |               ^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:36:15
+  --> $DIR/lint-exceeding-bitshifts.rs:37:15
    |
 LL |       let n = 1i16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:38:15
+  --> $DIR/lint-exceeding-bitshifts.rs:39:15
    |
 LL |       let n = 1i32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:40:15
+  --> $DIR/lint-exceeding-bitshifts.rs:41:15
    |
 LL |       let n = 1i64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:43:15
+  --> $DIR/lint-exceeding-bitshifts.rs:44:15
    |
 LL |       let n = 1u8 >> 8;
-   |               ^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:45:15
+  --> $DIR/lint-exceeding-bitshifts.rs:46:15
    |
 LL |       let n = 1u16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:47:15
+  --> $DIR/lint-exceeding-bitshifts.rs:48:15
    |
 LL |       let n = 1u32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:49:15
+  --> $DIR/lint-exceeding-bitshifts.rs:50:15
    |
 LL |       let n = 1u64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:51:15
+  --> $DIR/lint-exceeding-bitshifts.rs:52:15
    |
 LL |       let n = 1i8 >> 8;
-   |               ^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:53:15
+  --> $DIR/lint-exceeding-bitshifts.rs:54:15
    |
 LL |       let n = 1i16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:55:15
+  --> $DIR/lint-exceeding-bitshifts.rs:56:15
    |
 LL |       let n = 1i32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:57:15
+  --> $DIR/lint-exceeding-bitshifts.rs:58:15
    |
 LL |       let n = 1i64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:61:15
+  --> $DIR/lint-exceeding-bitshifts.rs:62:15
    |
 LL |       let n = n << 8;
-   |               ^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:63:15
+  --> $DIR/lint-exceeding-bitshifts.rs:64:15
    |
 LL |       let n = 1u8 << -8;
-   |               ^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:68:15
+  --> $DIR/lint-exceeding-bitshifts.rs:69:15
    |
 LL |       let n = 1u8 << (4+4);
-   |               ^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:70:15
+  --> $DIR/lint-exceeding-bitshifts.rs:71:15
    |
 LL |       let n = 1i64 >> [64][0];
-   |               ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:76:15
+  --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_isize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:77:15
+  --> $DIR/lint-exceeding-bitshifts.rs:78:15
    |
 LL |       let n = 1_usize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
 
 warning: 24 warnings emitted
 
index 8dbfeff7972fbb9ac8efb58781df5448383d5d96..d33b99bdc43870f85f97d719a7fa582036be8216 100644 (file)
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:17:20
+  --> $DIR/lint-exceeding-bitshifts.rs:18:20
    |
 LL |     const N: i32 = T::N << 42;
-   |                    ^^^^^^^^^^ attempt to shift left with overflow
+   |                    ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:9:9
+  --> $DIR/lint-exceeding-bitshifts.rs:10:9
    |
 LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:21:13
+  --> $DIR/lint-exceeding-bitshifts.rs:22:13
    |
 LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left with overflow
+   |             ^^^^^^^ attempt to shift left by 42_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:26:15
+  --> $DIR/lint-exceeding-bitshifts.rs:27:15
    |
 LL |       let n = 1u8 << 8;
-   |               ^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:28:15
+  --> $DIR/lint-exceeding-bitshifts.rs:29:15
    |
 LL |       let n = 1u16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:30:15
+  --> $DIR/lint-exceeding-bitshifts.rs:31:15
    |
 LL |       let n = 1u32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:32:15
+  --> $DIR/lint-exceeding-bitshifts.rs:33:15
    |
 LL |       let n = 1u64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:34:15
+  --> $DIR/lint-exceeding-bitshifts.rs:35:15
    |
 LL |       let n = 1i8 << 8;
-   |               ^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:36:15
+  --> $DIR/lint-exceeding-bitshifts.rs:37:15
    |
 LL |       let n = 1i16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:38:15
+  --> $DIR/lint-exceeding-bitshifts.rs:39:15
    |
 LL |       let n = 1i32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:40:15
+  --> $DIR/lint-exceeding-bitshifts.rs:41:15
    |
 LL |       let n = 1i64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:43:15
+  --> $DIR/lint-exceeding-bitshifts.rs:44:15
    |
 LL |       let n = 1u8 >> 8;
-   |               ^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:45:15
+  --> $DIR/lint-exceeding-bitshifts.rs:46:15
    |
 LL |       let n = 1u16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:47:15
+  --> $DIR/lint-exceeding-bitshifts.rs:48:15
    |
 LL |       let n = 1u32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:49:15
+  --> $DIR/lint-exceeding-bitshifts.rs:50:15
    |
 LL |       let n = 1u64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:51:15
+  --> $DIR/lint-exceeding-bitshifts.rs:52:15
    |
 LL |       let n = 1i8 >> 8;
-   |               ^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:53:15
+  --> $DIR/lint-exceeding-bitshifts.rs:54:15
    |
 LL |       let n = 1i16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:55:15
+  --> $DIR/lint-exceeding-bitshifts.rs:56:15
    |
 LL |       let n = 1i32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:57:15
+  --> $DIR/lint-exceeding-bitshifts.rs:58:15
    |
 LL |       let n = 1i64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:61:15
+  --> $DIR/lint-exceeding-bitshifts.rs:62:15
    |
 LL |       let n = n << 8;
-   |               ^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:63:15
+  --> $DIR/lint-exceeding-bitshifts.rs:64:15
    |
 LL |       let n = 1u8 << -8;
-   |               ^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:68:15
+  --> $DIR/lint-exceeding-bitshifts.rs:69:15
    |
 LL |       let n = 1u8 << (4+4);
-   |               ^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:70:15
+  --> $DIR/lint-exceeding-bitshifts.rs:71:15
    |
 LL |       let n = 1i64 >> [64][0];
-   |               ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:76:15
+  --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_isize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
 
 warning: this arithmetic operation will overflow
-  --> $DIR/lint-exceeding-bitshifts.rs:77:15
+  --> $DIR/lint-exceeding-bitshifts.rs:78:15
    |
 LL |       let n = 1_usize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left with overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
 
 warning: 24 warnings emitted
 
index 4d56d103a8343c95c5a9777fd3f53d174d61e0ab..a76ca93f8e1a3885606400bfecb61542ff57b4b7 100644 (file)
@@ -4,6 +4,7 @@
 //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O
 // build-pass
 // ignore-pass (test emits codegen-time warnings and verifies that they are not errors)
+// normalize-stderr-test "shift left by (64|32)_usize which" -> "shift left by %BITS% which"
 
 #![crate_type="lib"]
 #![warn(arithmetic_overflow, const_err)]
index 12093837d2630bcb8387a60a63cef752e8c02b6d..e15ed2e70b896fa2b497e2c0cdef2ef34dd7889d 100644 (file)
@@ -2,8 +2,14 @@
 #![deny(confusable_idents)]
 #![allow(uncommon_codepoints, non_upper_case_globals)]
 
-const s: usize = 42; //~ ERROR identifier pair considered confusable
+const s: usize = 42;
 
 fn main() {
-    let s = "rust";
+    let s = "rust"; //~ ERROR identifier pair considered confusable
+    not_affected();
+}
+
+fn not_affected() {
+    let s1 = 1;
+    let sl = 'l';
 }
index 40ee18acb3cd4c68e426ebdc3f35654827844d45..218f94f7b5829483beb10155f6a0fbc223693043 100644 (file)
@@ -1,11 +1,11 @@
-error: identifier pair considered confusable between `s` and `s`
-  --> $DIR/lint-confusable-idents.rs:5:7
+error: identifier pair considered confusable between `s` and `s`
+  --> $DIR/lint-confusable-idents.rs:8:9
    |
 LL | const s: usize = 42;
-   |       ^^
+   |       -- this is where the previous identifier occurred
 ...
 LL |     let s = "rust";
-   |         - this is where the previous identifier occurred
+   |         ^
    |
 note: the lint level is defined here
   --> $DIR/lint-confusable-idents.rs:2:9
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables-2.rs
new file mode 100644 (file)
index 0000000..a5b4546
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+#![feature(non_ascii_idents)]
+#![deny(mixed_script_confusables)]
+
+struct ΑctuallyNotLatin;
+
+fn main() {
+    let λ = 42; // this usage of Greek confirms that Greek is used intentionally.
+}
+
+mod роре {
+    const エ: &'static str = "アイウ";
+
+    // this usage of Katakana confirms that Katakana is used intentionally.
+    fn ニャン() {
+        let д: usize = 100; // this usage of Cyrillic confirms that Cyrillic is used intentionally.
+
+        println!("meow!");
+    }
+}
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs
new file mode 100644 (file)
index 0000000..4637b03
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(non_ascii_idents)]
+#![deny(mixed_script_confusables)]
+
+struct ΑctuallyNotLatin;
+//~^ ERROR The usage of Script Group `Greek` in this crate consists solely of
+
+fn main() {
+    let v = ΑctuallyNotLatin;
+}
+
+mod роре {
+//~^ ERROR The usage of Script Group `Cyrillic` in this crate consists solely of
+    const エ: &'static str = "アイウ";
+    //~^ ERROR The usage of Script Group `Japanese, Katakana` in this crate consists solely of
+}
diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr
new file mode 100644 (file)
index 0000000..6f75a1e
--- /dev/null
@@ -0,0 +1,34 @@
+error: The usage of Script Group `Greek` in this crate consists solely of mixed script confusables
+  --> $DIR/lint-mixed-script-confusables.rs:4:8
+   |
+LL | struct ΑctuallyNotLatin;
+   |        ^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-mixed-script-confusables.rs:2:9
+   |
+LL | #![deny(mixed_script_confusables)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: The usage includes 'Α' (U+0391).
+   = note: Please recheck to make sure their usages are indeed what you want.
+
+error: The usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables
+  --> $DIR/lint-mixed-script-confusables.rs:11:5
+   |
+LL | mod роре {
+   |     ^^^^
+   |
+   = note: The usage includes 'е' (U+0435), 'о' (U+043E), 'р' (U+0440).
+   = note: Please recheck to make sure their usages are indeed what you want.
+
+error: The usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables
+  --> $DIR/lint-mixed-script-confusables.rs:13:11
+   |
+LL |     const エ: &'static str = "アイウ";
+   |           ^^
+   |
+   = note: The usage includes 'エ' (U+30A8).
+   = note: Please recheck to make sure their usages are indeed what you want.
+
+error: aborting due to 3 previous errors
+
index 057329a0a650cfc061bd3d0103ce9d5c64df9ac0..20d00cf701a1569fe5f33ef0b0d0fdbcdc3900a1 100644 (file)
@@ -7,5 +7,7 @@ fn coöperation() {} //~ ERROR identifier contains non-ASCII characters
 
 fn main() {
     let naïveté = 2; //~ ERROR identifier contains non-ASCII characters
-    println!("{}", naïveté); //~ ERROR identifier contains non-ASCII characters
+
+    // using the same identifier the second time won't trigger the lint.
+    println!("{}", naïveté);
 }
index 6c9f0866c017a59102d903b821c9659af2cb1400..048b6ff5d687f011dac0ac01991bf589e4821f70 100644 (file)
@@ -22,11 +22,5 @@ error: identifier contains non-ASCII characters
 LL |     let naïveté = 2;
    |         ^^^^^^^
 
-error: identifier contains non-ASCII characters
-  --> $DIR/lint-non-ascii-idents.rs:10:20
-   |
-LL |     println!("{}", naïveté);
-   |                    ^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
index 7ac0d035d5bf1eb146367728ef84c92103f91bdc..b5e251e047b5ad1f8ca37054603d4b1fb9577185 100644 (file)
@@ -7,5 +7,7 @@ fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints
 
 fn main() {
     let ㇻㇲㇳ = "rust"; //~ ERROR identifier contains uncommon Unicode codepoints
-    println!("{}", ㇻㇲㇳ); //~ ERROR identifier contains uncommon Unicode codepoints
+
+    // using the same identifier the second time won't trigger the lint.
+    println!("{}", ㇻㇲㇳ);
 }
index b270bd1f051c261894ee5dd3636c9964ddf8718f..05ea3d5de7dbc9759ec0482fd006d8fbad544a7c 100644 (file)
@@ -22,11 +22,5 @@ error: identifier contains uncommon Unicode codepoints
 LL |     let ㇻㇲㇳ = "rust";
    |         ^^^^^^
 
-error: identifier contains uncommon Unicode codepoints
-  --> $DIR/lint-uncommon-codepoints.rs:10:20
-   |
-LL |     println!("{}", ㇻㇲㇳ);
-   |                    ^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs
new file mode 100644 (file)
index 0000000..fbf4aee
--- /dev/null
@@ -0,0 +1,27 @@
+// Test that we give a note when the old LUB/GLB algorithm would have
+// succeeded but the new code (which requires equality) gives an
+// error. However, now that we handle subtyping correctly, we no
+// longer get an error, because we recognize these two types as
+// equivalent!
+//
+// check-pass
+
+fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+    // The two types above are actually equivalent. With the older
+    // leak check, though, we didn't consider them as equivalent, and
+    // hence we gave errors. But now we've fixed that.
+    let z = match 22 {
+        0 => x,
+        _ => y,
+    };
+}
+
+fn foo_cast(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+    let z = match 22 {
+        // No error with an explicit cast:
+        0 => x as for<'a> fn(&'a u8, &'a u8),
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
new file mode 100644 (file)
index 0000000..b95e247
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs
new file mode 100644 (file)
index 0000000..918542d
--- /dev/null
@@ -0,0 +1,24 @@
+// Test taking the LUB of two function types that are not equatable but where one is more
+// general than the other. Test the case where the more general type (`x`) is the first
+// match arm specifically.
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => x,
+        _ => y, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr
new file mode 100644 (file)
index 0000000..305e952
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+   |
+LL |       let z = match 22 {
+   |  _____________-
+LL | |         0 => x,
+   | |              - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+LL | |         _ => y,
+   | |              ^ one type is more general than the other
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+              found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs
new file mode 100644 (file)
index 0000000..4bdd05b
--- /dev/null
@@ -0,0 +1,33 @@
+// Test taking the LUB of two function types that are not equatable but where
+// one is more general than the other. Test the case where the more general type
+// (`x`) is the second match arm specifically.
+//
+// FIXME(#73154) Skip for compare-mode because the pure NLL checker accepts this
+// test. (Note that it still errors in old-lub-glb-hr-noteq1.rs). What happens
+// is that, due to the ordering of the match arms, we pick the correct "more
+// general" fn type, and we ignore the errors from the non-NLL type checker that
+// requires equality. The NLL type checker only requires a subtyping
+// relationship, and that holds.
+//
+// ignore-compare-mode-nll
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => y,
+        _ => x, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr
new file mode 100644 (file)
index 0000000..252e13a
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/old-lub-glb-hr-noteq2.rs:20:14
+   |
+LL |       let z = match 22 {
+   |  _____________-
+LL | |         0 => y,
+   | |              - this is found to be of type `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+LL | |         _ => x,
+   | |              ^ one type is more general than the other
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+              found fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs
deleted file mode 100644 (file)
index bc7b787..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Test that we give a note when the old LUB/GLB algorithm would have
-// succeeded but the new code (which requires equality) gives an
-// error. However, now that we handle subtyping correctly, we no
-// longer get an error, because we recognize these two types as
-// equivalent!
-//
-// Whoops -- now that we reinstituted the leak-check, we get an error
-// again.
-
-fn foo(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
-    let z = match 22 {
-        0 => x,
-        _ => y, //~ ERROR `match` arms have incompatible types
-    };
-}
-
-fn bar(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
-    let z = match 22 {
-        // No error with an explicit cast:
-        0 => x as for<'a> fn(&'a u8, &'a u8),
-        _ => y,
-    };
-}
-
-fn main() {
-}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
deleted file mode 100644 (file)
index 6d5d511..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/old-lub-glb-hr.rs:16:14
-   |
-LL |       let z = match 22 {
-   |  _____________-
-LL | |         0 => x,
-   | |              - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)`
-LL | |         _ => y,
-   | |              ^ expected bound lifetime parameter, found concrete lifetime
-LL | |     };
-   | |_____- `match` arms have incompatible types
-   |
-   = note:    expected type `for<'r, 's> fn(&'r u8, &'s u8)`
-           found fn pointer `for<'a> fn(&'a u8, &'a u8)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
new file mode 100644 (file)
index 0000000..51bf96f
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to 2 previous errors
+
index 63bbae59991bc3e9ad736754c36aaecdc7619449..39d351c235574e2f86a02cdc63b3bafa4e4ff2e5 100644 (file)
@@ -1,22 +1,17 @@
 // Test that we give a note when the old LUB/GLB algorithm would have
 // succeeded but the new code (which is stricter) gives an error.
 
-trait Foo<T, U> { }
+trait Foo<T, U> {}
 
-fn foo(
-    x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
-    y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn foo(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
     let z = match 22 {
+        //~^ ERROR mismatched types
         0 => x,
-        _ => y, //~ ERROR `match` arms have incompatible types
+        _ => y,
     };
 }
 
-fn bar(
-    x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
-    y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn bar(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
     // Accepted with explicit case:
     let z = match 22 {
         0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>,
@@ -24,5 +19,4 @@ fn bar(
     };
 }
 
-fn main() {
-}
+fn main() {}
index 65c797f6b19d70083531f76d7c1fa928aa850d81..6eabe5eaeeeebcbd2f7f5141dfde79a2faa28846 100644 (file)
@@ -1,17 +1,16 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/old-lub-glb-object.rs:12:14
+error[E0308]: mismatched types
+  --> $DIR/old-lub-glb-object.rs:7:13
    |
 LL |       let z = match 22 {
-   |  _____________-
+   |  _____________^
+LL | |
 LL | |         0 => x,
-   | |              - this is found to be of type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
 LL | |         _ => y,
-   | |              ^ expected bound lifetime parameter 'a, found concrete lifetime
 LL | |     };
-   | |_____- `match` arms have incompatible types
+   | |_____^ one type is more general than the other
    |
-   = note:   expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
-           found reference `&dyn for<'a> Foo<&'a u8, &'a u8>`
+   = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
+              found trait object `dyn for<'a> Foo<&'a u8, &'a u8>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mir-dataflow/liveness-projection.rs b/src/test/ui/mir-dataflow/liveness-projection.rs
new file mode 100644 (file)
index 0000000..486f31b
--- /dev/null
@@ -0,0 +1,32 @@
+#![feature(core_intrinsics, rustc_attrs)]
+
+use std::intrinsics::rustc_peek;
+
+#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)]
+fn foo() {
+    {
+        let mut x: (i32, i32) = (42, 0);
+
+        // Assignment to a projection does not cause `x` to become live
+        unsafe { rustc_peek(x); } //~ ERROR bit not set
+        x.1 = 42;
+
+        x = (0, 42);
+
+        // ...but a read from a projection does.
+        unsafe { rustc_peek(x); }
+        println!("{}", x.1);
+    }
+
+    {
+        let mut x = 42;
+
+        // Derefs are treated like a read of a local even if they are on the LHS of an assignment.
+        let p = &mut x;
+        unsafe { rustc_peek(&p); }
+        *p = 24;
+        unsafe { rustc_peek(&p); } //~ ERROR bit not set
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mir-dataflow/liveness-projection.stderr b/src/test/ui/mir-dataflow/liveness-projection.stderr
new file mode 100644 (file)
index 0000000..f9480c8
--- /dev/null
@@ -0,0 +1,16 @@
+error: rustc_peek: bit not set
+  --> $DIR/liveness-projection.rs:11:18
+   |
+LL |         unsafe { rustc_peek(x); }
+   |                  ^^^^^^^^^^^^^
+
+error: rustc_peek: bit not set
+  --> $DIR/liveness-projection.rs:28:18
+   |
+LL |         unsafe { rustc_peek(&p); }
+   |                  ^^^^^^^^^^^^^^
+
+error: stop_after_dataflow ended compilation
+
+error: aborting due to 3 previous errors
+
index 69fd64c1c092c262e52dfa631a3889d9036fdaef..4574dbd8529aa56a88c29ee278e3355df2dd176e 100644 (file)
@@ -1,8 +1,10 @@
 // run-pass
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn tuple2() -> (u16, u8) {
     (1, 2)
 }
 
+#[allow(improper_ctypes_definitions)]
 pub extern "C" fn tuple3() -> (u8, u8, u8) {
     (1, 2, 3)
 }
index fc0db03e3a96894350a9611f398c150de1afebe3..d93a25c8ef4d372148b92ce6e6c2ed0b8031bd04 100644 (file)
@@ -74,6 +74,7 @@ fn test8() -> isize {
     Two::two()
 }
 
+#[allow(improper_ctypes_definitions)]
 extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
     x + y.0 * y.1
 }
index 0940dbe6a5e87bc2de526500c0a2aea0462974f4..136c03cd9f1bcad4a1b1062f2fdc44515f81ffba 100644 (file)
@@ -19,6 +19,6 @@ fn mod_by_zero() {
 fn oob_error_for_slices() {
     let a: *const [_] = &[1, 2, 3];
     unsafe {
-        let _b = (*a)[3]; //~ ERROR this operation will panic at runtime [unconditional_panic]
+        let _b = (*a)[3];
     }
 }
index 41f03789f237f62cf0b260d3b9a4613e07c1c18e..b4f74a52a74cd1f412973e4de93fe03c9433ea67 100644 (file)
@@ -2,7 +2,7 @@ error: this operation will panic at runtime
   --> $DIR/mir_detects_invalid_ops.rs:11:14
    |
 LL |     let _z = 1 / y;
-   |              ^^^^^ attempt to divide by zero
+   |              ^^^^^ attempt to divide 1_i32 by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -10,13 +10,7 @@ error: this operation will panic at runtime
   --> $DIR/mir_detects_invalid_ops.rs:16:14
    |
 LL |     let _z = 1 % y;
-   |              ^^^^^ attempt to calculate the remainder with a divisor of zero
+   |              ^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
 
-error: this operation will panic at runtime
-  --> $DIR/mir_detects_invalid_ops.rs:22:18
-   |
-LL |         let _b = (*a)[3];
-   |                  ^^^^^^^ index out of bounds: the len is 3 but the index is 3
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
index f94dfd100a6f4dff17580d211659a5e2ee014fd3..95936de218b8fe5d25de453501655ddde3c5ba76 100644 (file)
@@ -24,41 +24,31 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/cast-rfc0401.rs:29:13
    |
 LL |     let _ = v as &u8;
-   |             ^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `*const u8` as `E`
   --> $DIR/cast-rfc0401.rs:30:13
    |
 LL |     let _ = v as E;
-   |             ^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `*const u8` as `fn()`
   --> $DIR/cast-rfc0401.rs:31:13
    |
 LL |     let _ = v as fn();
-   |             ^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^ invalid cast
 
 error[E0605]: non-primitive cast: `*const u8` as `(u32,)`
   --> $DIR/cast-rfc0401.rs:32:13
    |
 LL |     let _ = v as (u32,);
-   |             ^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8`
   --> $DIR/cast-rfc0401.rs:33:13
    |
 LL |     let _ = Some(&v) as *const u8;
-   |             ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0606]: casting `*const u8` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:35:13
@@ -102,7 +92,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/cast-rfc0401.rs:41:13
    |
 LL |     let _ = 0x61u32 as char;
-   |             ^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^ invalid cast
 
 error[E0606]: casting `bool` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:43:13
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr
new file mode 100644 (file)
index 0000000..6ed91b2
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:3:14
+   |
+LL |     a.iter().map(|_: (u32, u32)| 45);
+   |              ^^^ ------------------ found signature of `fn((u32, u32)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:4:14
+   |
+LL |     a.iter().map(|_: &(u16, u16)| 45);
+   |              ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:5:14
+   |
+LL |     a.iter().map(|_: (u16, u16)| 45);
+   |              ^^^ ------------------ found signature of `fn((u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0631`.
index 521bd3695dfe5316763e698bd27d199fa1d5c79a..e278049c8cc42d2e4a2d61ea3f1d83429dd14a18 100644 (file)
@@ -7,6 +7,9 @@ fn main() {
 
 fn baz<F: Fn(*mut &u32)>(_: F) {}
 fn _test<'a>(f: fn(*mut &'a u32)) {
-    baz(f); //~ ERROR type mismatch
-     //~| ERROR type mismatch
+    baz(f);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
 }
index 69a4b458ebf5089a0c3a33e1f6ebe7ccaab2d56a..664fa4bcaf3289cbb5562d004f8d76ab4a090804 100644 (file)
@@ -22,28 +22,43 @@ LL |     a.iter().map(|_: (u16, u16)| 45);
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
 
-error[E0631]: type mismatch in function arguments
-  --> $DIR/closure-arg-type-mismatch.rs:10:9
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
 LL |     baz(f);
-   |         ^
-   |         |
-   |         expected signature of `for<'r> fn(*mut &'r u32) -> _`
-   |         found signature of `fn(*mut &'a u32) -> _`
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+              found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
+   |
+LL |     baz(f);
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+              found type `std::ops::FnOnce<(*mut &'a u32,)>`
 
-error[E0271]: type mismatch resolving `for<'r> <fn(*mut &'a u32) as std::ops::FnOnce<(*mut &'r u32,)>>::Output == ()`
+error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
 LL |     baz(f);
-   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+              found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
+   |
+LL |     baz(f);
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+              found type `std::ops::FnOnce<(*mut &'a u32,)>`
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
new file mode 100644 (file)
index 0000000..745a61b
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
index 40a4641fe719602f3991dc7a49478f3d5dfafc54..d2b78b4b7dba57e3f2ea0b239ad6fe86e891e693 100644 (file)
@@ -5,6 +5,5 @@ impl<T: Fn(&())> Foo for T {}
 fn baz<T: Foo>(_: T) {}
 
 fn main() {
-    baz(|_| ()); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
+    baz(|_| ()); //~ ERROR mismatched types
 }
index 389b21574465aa7bc8e94244fb401313eaa8f633..d6c17d125cf1ea681fa103714e13f5610b113dc6 100644 (file)
@@ -1,28 +1,12 @@
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()`
+error[E0308]: mismatched types
   --> $DIR/closure-mismatch.rs:8:5
    |
-LL | fn baz<T: Foo>(_: T) {}
-   |           --- required by this bound in `baz`
-...
 LL |     baz(|_| ());
-   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |     ^^^ one type is more general than the other
    |
-   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
+   = note: expected type `for<'r> std::ops::Fn<(&'r (),)>`
+              found type `std::ops::Fn<(&(),)>`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/closure-mismatch.rs:8:5
-   |
-LL | fn baz<T: Foo>(_: T) {}
-   |           --- required by this bound in `baz`
-...
-LL |     baz(|_| ());
-   |     ^^^ ------ found signature of `fn(_) -> _`
-   |     |
-   |     expected signature of `for<'r> fn(&'r ()) -> _`
-   |
-   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
index 69a9d03e474bab2b1c85316a787eaaa346d833d3..d39b0a3207763a37eb1f89165afd06be0bd5dcca 100644 (file)
@@ -17,12 +17,11 @@ error[E0605]: non-primitive cast: `{integer}` as `()`
   --> $DIR/issue-26480.rs:22:19
    |
 LL |     ($x:expr) => ($x as ())
-   |                   ^^^^^^^^
+   |                   ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 ...
 LL |     cast!(2);
    |     --------- in this macro invocation
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/moves/issue-46099-move-in-macro.rs b/src/test/ui/moves/issue-46099-move-in-macro.rs
new file mode 100644 (file)
index 0000000..576fe1f
--- /dev/null
@@ -0,0 +1,15 @@
+// Regression test for issue #46099
+// Tests that we don't emit spurious
+// 'value moved in previous iteration of loop' message
+
+macro_rules! test {
+    ($v:expr) => {{
+        drop(&$v);
+        $v
+    }}
+}
+
+fn main() {
+    let b = Box::new(true);
+    test!({b}); //~ ERROR use of moved value
+}
diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr
new file mode 100644 (file)
index 0000000..83c99db
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0382]: use of moved value: `b`
+  --> $DIR/issue-46099-move-in-macro.rs:14:12
+   |
+LL |     let b = Box::new(true);
+   |         - move occurs because `b` has type `std::boxed::Box<bool>`, which does not implement the `Copy` trait
+LL |     test!({b});
+   |            ^
+   |            |
+   |            value moved here
+   |            value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
index 8bd405279c526afd165159f6c7cfab774d4ede03..00d89f550714c4af313a32be92e70a0841f4e2ab 100644 (file)
@@ -5,7 +5,10 @@ LL |     let x: Box<_> = box 1;
    |         - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
 ...
 LL |         (_, 2) if take(x) => (),
-   |                        ^ value moved here, in previous iteration of loop
+   |                        ^
+   |                        |
+   |                        value moved here
+   |                        value used here after move
 
 error: aborting due to previous error
 
index fb8562d00ead1f4654941cca4e43e4caa446d7be..952985fcddee6c18268718248bf22ad9e355ff07 100644 (file)
@@ -8,6 +8,10 @@ LL |     consume(node) + r
    |             ^^^^ value used here after partial move
    |
    = note: move occurs because value has type `std::boxed::Box<List>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `node.next.0`
+   |
+LL |         Some(ref right) => consume(right),
+   |              ^^^
 
 error: aborting due to previous error
 
index c80055f00d7d9ecafee88a26261870d34491caaa..ee730910ee44153be90e0c503aaa40b825cfacd0 100644 (file)
@@ -16,7 +16,7 @@ help: consider importing one of these items instead
    |
 LL | use m2::S;
    |
-LL | use namespace_mix::xm2::S;
+LL | use xm2::S;
    |
 
 error[E0423]: expected value, found type alias `xm1::S`
@@ -39,7 +39,7 @@ help: consider importing one of these items instead
    |
 LL | use m2::S;
    |
-LL | use namespace_mix::xm2::S;
+LL | use xm2::S;
    |
 
 error[E0423]: expected value, found struct variant `m7::V`
@@ -61,7 +61,7 @@ help: consider importing one of these items instead
    |
 LL | use m8::V;
    |
-LL | use namespace_mix::xm8::V;
+LL | use xm8::V;
    |
 
 error[E0423]: expected value, found struct variant `xm7::V`
@@ -83,7 +83,7 @@ help: consider importing one of these items instead
    |
 LL | use m8::V;
    |
-LL | use namespace_mix::xm8::V;
+LL | use xm8::V;
    |
 
 error[E0277]: the trait bound `c::Item: Impossible` is not satisfied
diff --git a/src/test/ui/never_type/issue-51506.rs b/src/test/ui/never_type/issue-51506.rs
new file mode 100644 (file)
index 0000000..d0fe6a0
--- /dev/null
@@ -0,0 +1,41 @@
+#![feature(never_type, specialization)]
+#![allow(incomplete_features)]
+
+use std::iter::{self, Empty};
+
+trait Trait {
+    type Out: Iterator<Item = u32>;
+
+    fn f(&self) -> Option<Self::Out>;
+}
+
+impl<T> Trait for T {
+    default type Out = !; //~ ERROR: `!` is not an iterator
+
+    default fn f(&self) -> Option<Self::Out> {
+        None
+    }
+}
+
+struct X;
+
+impl Trait for X {
+    type Out = Empty<u32>;
+
+    fn f(&self) -> Option<Self::Out> {
+        Some(iter::empty())
+    }
+}
+
+fn f<T: Trait>(a: T) {
+    if let Some(iter) = a.f() {
+        println!("Some");
+        for x in iter {
+            println!("x = {}", x);
+        }
+    }
+}
+
+pub fn main() {
+    f(10);
+}
diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr
new file mode 100644 (file)
index 0000000..73865a9
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0277]: `!` is not an iterator
+  --> $DIR/issue-51506.rs:13:5
+   |
+LL |     type Out: Iterator<Item = u32>;
+   |     ------------------------------- required by `Trait::Out`
+...
+LL |     default type Out = !;
+   |     ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator
+   |
+   = help: the trait `std::iter::Iterator` is not implemented for `!`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 2b15da3710e62f4cb6147d21173998227afb90d4..4f36a4ccab28f701419059b3bd9b2503a95562af 100644 (file)
@@ -5,6 +5,10 @@ LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `maybe.0`
+   |
+LL |         if let Some(ref thing) = maybe {
+   |                     ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nonscalar-cast.fixed b/src/test/ui/nonscalar-cast.fixed
new file mode 100644 (file)
index 0000000..0a4b984
--- /dev/null
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+    x: isize
+}
+
+impl From<Foo> for isize {
+    fn from(val: Foo) -> isize {
+        val.x
+    }
+}
+
+fn main() {
+    println!("{}", isize::from(Foo { x: 1 })); //~ non-primitive cast: `Foo` as `isize` [E0605]
+}
index 7e6f1fd038fb7a0bb0ba20cbfe9e33e9894f1156..59fcf09666b24f32aa36a63b8029b8acd1064dba 100644 (file)
@@ -1,8 +1,16 @@
+// run-rustfix
+
 #[derive(Debug)]
 struct Foo {
     x: isize
 }
 
+impl From<Foo> for isize {
+    fn from(val: Foo) -> isize {
+        val.x
+    }
+}
+
 fn main() {
     println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605]
 }
index 9338688b037ffd7f798d720f347dec311c56e11a..2a7037121876d8725202c24c4131c23e8b811df4 100644 (file)
@@ -1,10 +1,10 @@
 error[E0605]: non-primitive cast: `Foo` as `isize`
-  --> $DIR/nonscalar-cast.rs:7:20
+  --> $DIR/nonscalar-cast.rs:15:20
    |
 LL |     println!("{}", Foo { x: 1 } as isize);
-   |                    ^^^^^^^^^^^^^^^^^^^^^
+   |                    ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })`
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
index 54008d33968bc7df658399d5abf8dae721d8e3f2..995afeeed880ccf5083867512109b8890ecc1a2c 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-lsh-1.rs:7:14
    |
 LL |     let _x = 1_i32 << 32;
-   |              ^^^^^^^^^^^ attempt to shift left with overflow
+   |              ^^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-1.rs:4:9
index 872e71bb73796ce15b872ce508b21beb0ceba6aa..e6f6b1ccd192dace68367da03fb7c404bde605e3 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-lsh-2.rs:7:14
    |
 LL |     let _x = 1 << -1;
-   |              ^^^^^^^ attempt to shift left with overflow
+   |              ^^^^^^^ attempt to shift left by -1_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-2.rs:4:9
index d55ed4a046c9dd94b47fe008de4b2623e146fcfa..e57b892b8085da2149156fb3d7762b28a65ff58d 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-lsh-3.rs:7:14
    |
 LL |     let _x = 1_u64 << 64;
-   |              ^^^^^^^^^^^ attempt to shift left with overflow
+   |              ^^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-3.rs:4:9
index 1ef8dd3466c0a20e3bfcc6a59051e188e52268de..f20b41c1baa4f76015006ab03bfc3c85ff87d526 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-lsh-4.rs:11:13
    |
 LL |     let x = 1_i8 << 17;
-   |             ^^^^^^^^^^ attempt to shift left with overflow
+   |             ^^^^^^^^^^ attempt to shift left by 17_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-4.rs:7:9
index 236303e2e9aa3ac5d98baf7f51216db9c61ad695..18861a1b96fa870bf7b7043121ec93e7346a2ace 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-rsh-1.rs:7:14
    |
 LL |     let _x = -1_i32 >> 32;
-   |              ^^^^^^^^^^^^ attempt to shift right with overflow
+   |              ^^^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-1.rs:4:9
index 981c8986f76b9d24da09efbae033dc75af2b6b6b..a2fb2b90535c30fbaac861752152f470a8941ea6 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-rsh-2.rs:7:14
    |
 LL |     let _x = -1_i32 >> -1;
-   |              ^^^^^^^^^^^^ attempt to shift right with overflow
+   |              ^^^^^^^^^^^^ attempt to shift right by -1_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-2.rs:4:9
index c2994503f0efc51858ccd36875c57d7bb621b5f5..24588b4a6b9b6719b803b79bc92353261a4450f7 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-rsh-3.rs:7:14
    |
 LL |     let _x = -1_i64 >> 64;
-   |              ^^^^^^^^^^^^ attempt to shift right with overflow
+   |              ^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-3.rs:4:9
index 3db1da06dbed849978652aae84f16f84ff24691d..3f59653ea6075568d9bf16be3c269ea1c339d3ad 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-rsh-4.rs:11:13
    |
 LL |     let x = 2_i8 >> 17;
-   |             ^^^^^^^^^^ attempt to shift right with overflow
+   |             ^^^^^^^^^^ attempt to shift right by 17_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-4.rs:7:9
index bd3eae82977e342bd1f4be12e30134f911fc5247..8b0daf1551e4bab57c19a26b4d977eebf8617cf4 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-rsh-5.rs:7:14
    |
 LL |     let _n = 1i64 >> [64][0];
-   |              ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+   |              ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-5.rs:4:9
index 5d76639fb50f376cf076e5cc0053e507693c76f7..53a1445b54e387171e37550aa8ddf688fb09d178 100644 (file)
@@ -2,7 +2,7 @@ error: this arithmetic operation will overflow
   --> $DIR/overflowing-rsh-6.rs:7:14
    |
 LL |     let _n = 1i64 >> [64][0];
-   |              ^^^^^^^^^^^^^^^ attempt to shift right with overflow
+   |              ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-6.rs:4:9
diff --git a/src/test/ui/numeric/numeric-cast-no-fix.rs b/src/test/ui/numeric/numeric-cast-no-fix.rs
new file mode 100644 (file)
index 0000000..63e5f09
--- /dev/null
@@ -0,0 +1,87 @@
+#[allow(unused_must_use)]
+fn main() {
+    let x_usize: usize = 1;
+    let x_u128: u128 = 2;
+    let x_u64: u64 = 3;
+    let x_u32: u32 = 4;
+    let x_u16: u16 = 5;
+    let x_u8: u8 = 6;
+
+    x_usize > -1_isize;
+    //~^ ERROR mismatched types
+    x_u128 > -1_isize;
+    //~^ ERROR mismatched types
+    x_u64 > -1_isize;
+    //~^ ERROR mismatched types
+    x_u32 > -1_isize;
+    //~^ ERROR mismatched types
+    x_u16 > -1_isize;
+    //~^ ERROR mismatched types
+    x_u8 > -1_isize;
+    //~^ ERROR mismatched types
+
+    x_usize > -1_i128;
+    //~^ ERROR mismatched types
+    x_u128 > -1_i128;
+    //~^ ERROR mismatched types
+    x_u64 > -1_i128;
+    //~^ ERROR mismatched types
+    x_u32 > -1_i128;
+    //~^ ERROR mismatched types
+    x_u16 > -1_i128;
+    //~^ ERROR mismatched types
+    x_u8 > -1_i128;
+    //~^ ERROR mismatched types
+
+    x_usize > -1_i64;
+    //~^ ERROR mismatched types
+    x_u128 > -1_i64;
+    //~^ ERROR mismatched types
+    x_u64 > -1_i64;
+    //~^ ERROR mismatched types
+    x_u32 > -1_i64;
+    //~^ ERROR mismatched types
+    x_u16 > -1_i64;
+    //~^ ERROR mismatched types
+    x_u8 > -1_i64;
+    //~^ ERROR mismatched types
+
+    x_usize > -1_i32;
+    //~^ ERROR mismatched types
+    x_u128 > -1_i32;
+    //~^ ERROR mismatched types
+    x_u64 > -1_i32;
+    //~^ ERROR mismatched types
+    x_u32 > -1_i32;
+    //~^ ERROR mismatched types
+    x_u16 > -1_i32;
+    //~^ ERROR mismatched types
+    x_u8 > -1_i32;
+    //~^ ERROR mismatched types
+
+    x_usize > -1_i16;
+    //~^ ERROR mismatched types
+    x_u128 > -1_i16;
+    //~^ ERROR mismatched types
+    x_u64 > -1_i16;
+    //~^ ERROR mismatched types
+    x_u32 > -1_i16;
+    //~^ ERROR mismatched types
+    x_u16 > -1_i16;
+    //~^ ERROR mismatched types
+    x_u8 > -1_i16;
+    //~^ ERROR mismatched types
+
+    x_usize > -1_i8;
+    //~^ ERROR mismatched types
+    x_u128 > -1_i8;
+    //~^ ERROR mismatched types
+    x_u64 > -1_i8;
+    //~^ ERROR mismatched types
+    x_u32 > -1_i8;
+    //~^ ERROR mismatched types
+    x_u16 > -1_i8;
+    //~^ ERROR mismatched types
+    x_u8 > -1_i8;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/numeric/numeric-cast-no-fix.stderr b/src/test/ui/numeric/numeric-cast-no-fix.stderr
new file mode 100644 (file)
index 0000000..4852e70
--- /dev/null
@@ -0,0 +1,324 @@
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:10:15
+   |
+LL |     x_usize > -1_isize;
+   |               ^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: `-1_isize` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:12:14
+   |
+LL |     x_u128 > -1_isize;
+   |              ^^^^^^^^ expected `u128`, found `isize`
+   |
+   = note: `-1_isize` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:14:13
+   |
+LL |     x_u64 > -1_isize;
+   |             ^^^^^^^^ expected `u64`, found `isize`
+   |
+   = note: `-1_isize` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:16:13
+   |
+LL |     x_u32 > -1_isize;
+   |             ^^^^^^^^ expected `u32`, found `isize`
+   |
+   = note: `-1_isize` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:18:13
+   |
+LL |     x_u16 > -1_isize;
+   |             ^^^^^^^^ expected `u16`, found `isize`
+   |
+   = note: `-1_isize` cannot fit into type `u16`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:20:12
+   |
+LL |     x_u8 > -1_isize;
+   |            ^^^^^^^^ expected `u8`, found `isize`
+   |
+help: you can convert `x_u8` from `u8` to `isize`, matching the type of `-1_isize`
+   |
+LL |     isize::from(x_u8) > -1_isize;
+   |     ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:23:15
+   |
+LL |     x_usize > -1_i128;
+   |               ^^^^^^^ expected `usize`, found `i128`
+   |
+   = note: `-1_i128` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:25:14
+   |
+LL |     x_u128 > -1_i128;
+   |              ^^^^^^^ expected `u128`, found `i128`
+   |
+   = note: `-1_i128` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:27:13
+   |
+LL |     x_u64 > -1_i128;
+   |             ^^^^^^^ expected `u64`, found `i128`
+   |
+help: you can convert `x_u64` from `u64` to `i128`, matching the type of `-1_i128`
+   |
+LL |     i128::from(x_u64) > -1_i128;
+   |     ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:29:13
+   |
+LL |     x_u32 > -1_i128;
+   |             ^^^^^^^ expected `u32`, found `i128`
+   |
+help: you can convert `x_u32` from `u32` to `i128`, matching the type of `-1_i128`
+   |
+LL |     i128::from(x_u32) > -1_i128;
+   |     ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:31:13
+   |
+LL |     x_u16 > -1_i128;
+   |             ^^^^^^^ expected `u16`, found `i128`
+   |
+help: you can convert `x_u16` from `u16` to `i128`, matching the type of `-1_i128`
+   |
+LL |     i128::from(x_u16) > -1_i128;
+   |     ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:33:12
+   |
+LL |     x_u8 > -1_i128;
+   |            ^^^^^^^ expected `u8`, found `i128`
+   |
+help: you can convert `x_u8` from `u8` to `i128`, matching the type of `-1_i128`
+   |
+LL |     i128::from(x_u8) > -1_i128;
+   |     ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:36:15
+   |
+LL |     x_usize > -1_i64;
+   |               ^^^^^^ expected `usize`, found `i64`
+   |
+   = note: `-1_i64` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:38:14
+   |
+LL |     x_u128 > -1_i64;
+   |              ^^^^^^ expected `u128`, found `i64`
+   |
+   = note: `-1_i64` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:40:13
+   |
+LL |     x_u64 > -1_i64;
+   |             ^^^^^^ expected `u64`, found `i64`
+   |
+   = note: `-1_i64` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:42:13
+   |
+LL |     x_u32 > -1_i64;
+   |             ^^^^^^ expected `u32`, found `i64`
+   |
+help: you can convert `x_u32` from `u32` to `i64`, matching the type of `-1_i64`
+   |
+LL |     i64::from(x_u32) > -1_i64;
+   |     ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:44:13
+   |
+LL |     x_u16 > -1_i64;
+   |             ^^^^^^ expected `u16`, found `i64`
+   |
+help: you can convert `x_u16` from `u16` to `i64`, matching the type of `-1_i64`
+   |
+LL |     i64::from(x_u16) > -1_i64;
+   |     ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:46:12
+   |
+LL |     x_u8 > -1_i64;
+   |            ^^^^^^ expected `u8`, found `i64`
+   |
+help: you can convert `x_u8` from `u8` to `i64`, matching the type of `-1_i64`
+   |
+LL |     i64::from(x_u8) > -1_i64;
+   |     ^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:49:15
+   |
+LL |     x_usize > -1_i32;
+   |               ^^^^^^ expected `usize`, found `i32`
+   |
+   = note: `-1_i32` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:51:14
+   |
+LL |     x_u128 > -1_i32;
+   |              ^^^^^^ expected `u128`, found `i32`
+   |
+   = note: `-1_i32` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:53:13
+   |
+LL |     x_u64 > -1_i32;
+   |             ^^^^^^ expected `u64`, found `i32`
+   |
+   = note: `-1_i32` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:55:13
+   |
+LL |     x_u32 > -1_i32;
+   |             ^^^^^^ expected `u32`, found `i32`
+   |
+   = note: `-1_i32` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:57:13
+   |
+LL |     x_u16 > -1_i32;
+   |             ^^^^^^ expected `u16`, found `i32`
+   |
+help: you can convert `x_u16` from `u16` to `i32`, matching the type of `-1_i32`
+   |
+LL |     i32::from(x_u16) > -1_i32;
+   |     ^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:59:12
+   |
+LL |     x_u8 > -1_i32;
+   |            ^^^^^^ expected `u8`, found `i32`
+   |
+help: you can convert `x_u8` from `u8` to `i32`, matching the type of `-1_i32`
+   |
+LL |     i32::from(x_u8) > -1_i32;
+   |     ^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:62:15
+   |
+LL |     x_usize > -1_i16;
+   |               ^^^^^^ expected `usize`, found `i16`
+   |
+   = note: `-1_i16` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:64:14
+   |
+LL |     x_u128 > -1_i16;
+   |              ^^^^^^ expected `u128`, found `i16`
+   |
+   = note: `-1_i16` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:66:13
+   |
+LL |     x_u64 > -1_i16;
+   |             ^^^^^^ expected `u64`, found `i16`
+   |
+   = note: `-1_i16` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:68:13
+   |
+LL |     x_u32 > -1_i16;
+   |             ^^^^^^ expected `u32`, found `i16`
+   |
+   = note: `-1_i16` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:70:13
+   |
+LL |     x_u16 > -1_i16;
+   |             ^^^^^^ expected `u16`, found `i16`
+   |
+   = note: `-1_i16` cannot fit into type `u16`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:72:12
+   |
+LL |     x_u8 > -1_i16;
+   |            ^^^^^^ expected `u8`, found `i16`
+   |
+help: you can convert `x_u8` from `u8` to `i16`, matching the type of `-1_i16`
+   |
+LL |     i16::from(x_u8) > -1_i16;
+   |     ^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:75:15
+   |
+LL |     x_usize > -1_i8;
+   |               ^^^^^ expected `usize`, found `i8`
+   |
+   = note: `-1_i8` cannot fit into type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:77:14
+   |
+LL |     x_u128 > -1_i8;
+   |              ^^^^^ expected `u128`, found `i8`
+   |
+   = note: `-1_i8` cannot fit into type `u128`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:79:13
+   |
+LL |     x_u64 > -1_i8;
+   |             ^^^^^ expected `u64`, found `i8`
+   |
+   = note: `-1_i8` cannot fit into type `u64`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:81:13
+   |
+LL |     x_u32 > -1_i8;
+   |             ^^^^^ expected `u32`, found `i8`
+   |
+   = note: `-1_i8` cannot fit into type `u32`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:83:13
+   |
+LL |     x_u16 > -1_i8;
+   |             ^^^^^ expected `u16`, found `i8`
+   |
+   = note: `-1_i8` cannot fit into type `u16`
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-cast-no-fix.rs:85:12
+   |
+LL |     x_u8 > -1_i8;
+   |            ^^^^^ expected `u8`, found `i8`
+   |
+   = note: `-1_i8` cannot fit into type `u8`
+
+error: aborting due to 36 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 70a9bf22b8db372779e8bd2efbee667875c49af6..1b1e0d9610724b6e83c1a48c19e2a0ff427fb158 100644 (file)
@@ -1,13 +1,13 @@
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/object-lifetime-default-from-box-error.rs:18:5
    |
 LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
-   |             --------------- data with this lifetime...
+   |             --------------- this data with an anonymous lifetime `'_`...
 ...
 LL |     ss.r
-   |     ^^^^ ...is captured and required to be `'static` here
+   |     ^^^^ ...is captured and required to live as long as `'static` here
    |
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1
+help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound
    |
 LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> {
    |                                                   ^^^^
@@ -23,4 +23,5 @@ LL |     ss.r = b;
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0621`.
+Some errors have detailed explanations: E0621, E0759.
+For more information about an error, try `rustc --explain E0621`.
diff --git a/src/test/ui/or-patterns/const-fn.rs b/src/test/ui/or-patterns/const-fn.rs
new file mode 100644 (file)
index 0000000..f4af2f0
--- /dev/null
@@ -0,0 +1,30 @@
+// check-pass
+#![feature(or_patterns)]
+
+const fn foo((Ok(a) | Err(a)): Result<i32, i32>) {
+    let x = Ok(3);
+    let Ok(y) | Err(y) = x;
+}
+
+const X: () = {
+    let x = Ok(3);
+    let Ok(y) | Err(y) = x;
+};
+
+static Y: () = {
+    let x = Ok(3);
+    let Ok(y) | Err(y) = x;
+};
+
+static mut Z: () = {
+    let x = Ok(3);
+    let Ok(y) | Err(y) = x;
+};
+
+fn main() {
+    let _: [(); {
+        let x = Ok(3);
+        let Ok(y) | Err(y) = x;
+        2
+    }];
+}
index 31b3407a46e08f371e6b85657d6ef67b4bf92365..f2d5de75b65bd37f36852edffe4c9a2657fdc1bf 100644 (file)
@@ -4,15 +4,15 @@
 // We wrap patterns in a tuple because top-level or-patterns were special-cased.
 fn main() {
     match (0u8, 0u8) {
-        //~^ ERROR non-exhaustive patterns: `(2u8..=u8::MAX, _)`
+        //~^ ERROR non-exhaustive patterns: `(2_u8..=u8::MAX, _)`
         (0 | 1, 2 | 3) => {}
     }
     match ((0u8,),) {
-        //~^ ERROR non-exhaustive patterns: `((4u8..=u8::MAX))`
+        //~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX))`
         ((0 | 1,) | (2 | 3,),) => {}
     }
     match (Some(0u8),) {
-        //~^ ERROR non-exhaustive patterns: `(Some(2u8..=u8::MAX))`
+        //~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX))`
         (None | Some(0 | 1),) => {}
     }
 }
index 653f4978ab350c2fb5abfe4a3cfaa3b22917602d..7e8bb73190747fd19e1efb397d740254f339a441 100644 (file)
@@ -1,26 +1,26 @@
-error[E0004]: non-exhaustive patterns: `(2u8..=u8::MAX, _)` not covered
+error[E0004]: non-exhaustive patterns: `(2_u8..=u8::MAX, _)` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:6:11
    |
 LL |     match (0u8, 0u8) {
-   |           ^^^^^^^^^^ pattern `(2u8..=u8::MAX, _)` not covered
+   |           ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, u8)`
 
-error[E0004]: non-exhaustive patterns: `((4u8..=u8::MAX))` not covered
+error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:10:11
    |
 LL |     match ((0u8,),) {
-   |           ^^^^^^^^^ pattern `((4u8..=u8::MAX))` not covered
+   |           ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `((u8,),)`
 
-error[E0004]: non-exhaustive patterns: `(Some(2u8..=u8::MAX))` not covered
+error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
   --> $DIR/exhaustiveness-non-exhaustive.rs:14:11
    |
 LL |     match (Some(0u8),) {
-   |           ^^^^^^^^^^^^ pattern `(Some(2u8..=u8::MAX))` not covered
+   |           ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(std::option::Option<u8>,)`
diff --git a/src/test/ui/or-patterns/feature-gate-const-fn.rs b/src/test/ui/or-patterns/feature-gate-const-fn.rs
deleted file mode 100644 (file)
index d21cf3d..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#![feature(or_patterns)]
-
-const fn foo((Ok(a) | Err(a)): Result<i32, i32>) {
-    //~^ ERROR or-pattern is not allowed in a `const fn`
-    let x = Ok(3);
-    let Ok(y) | Err(y) = x;
-    //~^ ERROR or-pattern is not allowed in a `const fn`
-}
-
-const X: () = {
-    let x = Ok(3);
-    let Ok(y) | Err(y) = x;
-    //~^ ERROR or-pattern is not allowed in a `const`
-};
-
-static Y: () = {
-    let x = Ok(3);
-    let Ok(y) | Err(y) = x;
-    //~^ ERROR or-pattern is not allowed in a `static`
-};
-
-static mut Z: () = {
-    let x = Ok(3);
-    let Ok(y) | Err(y) = x;
-    //~^ ERROR or-pattern is not allowed in a `static mut`
-};
-
-fn main() {
-    let _: [(); {
-        let x = Ok(3);
-        let Ok(y) | Err(y) = x;
-        //~^ ERROR or-pattern is not allowed in a `const`
-        2
-    }];
-}
diff --git a/src/test/ui/or-patterns/feature-gate-const-fn.stderr b/src/test/ui/or-patterns/feature-gate-const-fn.stderr
deleted file mode 100644 (file)
index 345d6c7..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-error[E0658]: or-pattern is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-fn.rs:3:15
-   |
-LL | const fn foo((Ok(a) | Err(a)): Result<i32, i32>) {
-   |               ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-fn.rs:6:9
-   |
-LL |     let Ok(y) | Err(y) = x;
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `const`
-  --> $DIR/feature-gate-const-fn.rs:12:9
-   |
-LL |     let Ok(y) | Err(y) = x;
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `static`
-  --> $DIR/feature-gate-const-fn.rs:18:9
-   |
-LL |     let Ok(y) | Err(y) = x;
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-fn.rs:24:9
-   |
-LL |     let Ok(y) | Err(y) = x;
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: or-pattern is not allowed in a `const`
-  --> $DIR/feature-gate-const-fn.rs:31:13
-   |
-LL |         let Ok(y) | Err(y) = x;
-   |             ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index 2eadef9cb5c118b870aec2e41ddd36451d6efabd..2acf1f41c6fa60c1a11492235eda8f27ebc7d2f1 100644 (file)
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:4:9
    |
 LL |     let 0 | (1 | 2) = 0;
-   |         ^^^^^^^^^^^ patterns `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+   |         ^^^^^^^^^^^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched
 LL |     if let 0 | (1 | 2) = 0 { /* */ }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0004]: non-exhaustive patterns: `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:5:11
    |
 LL |     match 0 {
-   |           ^ patterns `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered
+   |           ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
index ad50b415869dd6f322e2b567dcf5dc5012541fc8..9f4ac0fea36ef03ba41bb048a197ad87627bb0af 100644 (file)
@@ -1,10 +1,8 @@
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/order-dependent-cast-inference.rs:5:17
+  --> $DIR/order-dependent-cast-inference.rs:5:22
    |
 LL |     let mut y = 0 as *const _;
-   |                 ^^^^^--------
-   |                      |
-   |                      help: consider giving more type information
+   |                      ^^^^^^^^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
index dd09d68367ec3f5037647bcaa97e90c4d1c1d1f5..1e413120a371730bb854e0823c77a9c50e8ac612 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 
 #![feature(marker_trait_attr)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 #[marker]
 trait MyMarker {}
diff --git a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr
new file mode 100644 (file)
index 0000000..16df31b
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 215a2921315213ad680a802ea98155c5ab34766f..a8759d2090d0fd72cadba4ca5ee34df6e8be0585 100644 (file)
@@ -1,6 +1,7 @@
 // Semantically, we do not allow e.g., `static X: u8 = 0;` as an associated item.
 
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 fn main() {}
 
index 612297c9cd8b1a9e064b74b13ae69564528420d1..bc3054c3e30622a37f899c8c8db63315845d6c90 100644 (file)
@@ -1,17 +1,17 @@
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:9:5
+  --> $DIR/assoc-static-semantic-fail.rs:10:5
    |
 LL |     static IA: u8 = 0;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:11:5
+  --> $DIR/assoc-static-semantic-fail.rs:12:5
    |
 LL |     static IB: u8;
    |     ^^^^^^^^^^^^^^
 
 error: a static item cannot be `default`
-  --> $DIR/assoc-static-semantic-fail.rs:14:5
+  --> $DIR/assoc-static-semantic-fail.rs:15:5
    |
 LL |     default static IC: u8 = 0;
    |     ^^^^^^^ `default` because of this
@@ -19,13 +19,13 @@ LL |     default static IC: u8 = 0;
    = note: only associated `fn`, `const`, and `type` items can be `default`
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:14:5
+  --> $DIR/assoc-static-semantic-fail.rs:15:5
    |
 LL |     default static IC: u8 = 0;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a static item cannot be `default`
-  --> $DIR/assoc-static-semantic-fail.rs:17:16
+  --> $DIR/assoc-static-semantic-fail.rs:18:16
    |
 LL |     pub(crate) default static ID: u8;
    |                ^^^^^^^ `default` because of this
@@ -33,25 +33,25 @@ LL |     pub(crate) default static ID: u8;
    = note: only associated `fn`, `const`, and `type` items can be `default`
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:17:5
+  --> $DIR/assoc-static-semantic-fail.rs:18:5
    |
 LL |     pub(crate) default static ID: u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:24:5
+  --> $DIR/assoc-static-semantic-fail.rs:25:5
    |
 LL |     static TA: u8 = 0;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:26:5
+  --> $DIR/assoc-static-semantic-fail.rs:27:5
    |
 LL |     static TB: u8;
    |     ^^^^^^^^^^^^^^
 
 error: a static item cannot be `default`
-  --> $DIR/assoc-static-semantic-fail.rs:28:5
+  --> $DIR/assoc-static-semantic-fail.rs:29:5
    |
 LL |     default static TC: u8 = 0;
    |     ^^^^^^^ `default` because of this
@@ -59,13 +59,13 @@ LL |     default static TC: u8 = 0;
    = note: only associated `fn`, `const`, and `type` items can be `default`
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:28:5
+  --> $DIR/assoc-static-semantic-fail.rs:29:5
    |
 LL |     default static TC: u8 = 0;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a static item cannot be `default`
-  --> $DIR/assoc-static-semantic-fail.rs:31:16
+  --> $DIR/assoc-static-semantic-fail.rs:32:16
    |
 LL |     pub(crate) default static TD: u8;
    |                ^^^^^^^ `default` because of this
@@ -73,25 +73,25 @@ LL |     pub(crate) default static TD: u8;
    = note: only associated `fn`, `const`, and `type` items can be `default`
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:31:5
+  --> $DIR/assoc-static-semantic-fail.rs:32:5
    |
 LL |     pub(crate) default static TD: u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:38:5
+  --> $DIR/assoc-static-semantic-fail.rs:39:5
    |
 LL |     static TA: u8 = 0;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:40:5
+  --> $DIR/assoc-static-semantic-fail.rs:41:5
    |
 LL |     static TB: u8;
    |     ^^^^^^^^^^^^^^
 
 error: a static item cannot be `default`
-  --> $DIR/assoc-static-semantic-fail.rs:43:5
+  --> $DIR/assoc-static-semantic-fail.rs:44:5
    |
 LL |     default static TC: u8 = 0;
    |     ^^^^^^^ `default` because of this
@@ -99,13 +99,13 @@ LL |     default static TC: u8 = 0;
    = note: only associated `fn`, `const`, and `type` items can be `default`
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:43:5
+  --> $DIR/assoc-static-semantic-fail.rs:44:5
    |
 LL |     default static TC: u8 = 0;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a static item cannot be `default`
-  --> $DIR/assoc-static-semantic-fail.rs:46:9
+  --> $DIR/assoc-static-semantic-fail.rs:47:9
    |
 LL |     pub default static TD: u8;
    |         ^^^^^^^ `default` because of this
@@ -113,13 +113,13 @@ LL |     pub default static TD: u8;
    = note: only associated `fn`, `const`, and `type` items can be `default`
 
 error: associated `static` items are not allowed
-  --> $DIR/assoc-static-semantic-fail.rs:46:5
+  --> $DIR/assoc-static-semantic-fail.rs:47:5
    |
 LL |     pub default static TD: u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: associated constant in `impl` without body
-  --> $DIR/assoc-static-semantic-fail.rs:11:5
+  --> $DIR/assoc-static-semantic-fail.rs:12:5
    |
 LL |     static IB: u8;
    |     ^^^^^^^^^^^^^-
@@ -127,7 +127,7 @@ LL |     static IB: u8;
    |                  help: provide a definition for the constant: `= <expr>;`
 
 error: associated constant in `impl` without body
-  --> $DIR/assoc-static-semantic-fail.rs:17:5
+  --> $DIR/assoc-static-semantic-fail.rs:18:5
    |
 LL |     pub(crate) default static ID: u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -135,13 +135,13 @@ LL |     pub(crate) default static ID: u8;
    |                                     help: provide a definition for the constant: `= <expr>;`
 
 error[E0449]: unnecessary visibility qualifier
-  --> $DIR/assoc-static-semantic-fail.rs:31:5
+  --> $DIR/assoc-static-semantic-fail.rs:32:5
    |
 LL |     pub(crate) default static TD: u8;
    |     ^^^^^^^^^^
 
 error: associated constant in `impl` without body
-  --> $DIR/assoc-static-semantic-fail.rs:40:5
+  --> $DIR/assoc-static-semantic-fail.rs:41:5
    |
 LL |     static TB: u8;
    |     ^^^^^^^^^^^^^-
@@ -149,7 +149,7 @@ LL |     static TB: u8;
    |                  help: provide a definition for the constant: `= <expr>;`
 
 error: associated constant in `impl` without body
-  --> $DIR/assoc-static-semantic-fail.rs:46:5
+  --> $DIR/assoc-static-semantic-fail.rs:47:5
    |
 LL |     pub default static TD: u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -157,11 +157,20 @@ LL |     pub default static TD: u8;
    |                              help: provide a definition for the constant: `= <expr>;`
 
 error[E0449]: unnecessary visibility qualifier
-  --> $DIR/assoc-static-semantic-fail.rs:46:5
+  --> $DIR/assoc-static-semantic-fail.rs:47:5
    |
 LL |     pub default static TD: u8;
    |     ^^^ `pub` not permitted here because it's implied
 
-error: aborting due to 24 previous errors
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/assoc-static-semantic-fail.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error: aborting due to 24 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0449`.
index dadf3971220f7054ae75af19ef90c11c6a3578b2..9683a83e72095b09ecdc07abad6385811d48ccde 100644 (file)
@@ -8,5 +8,5 @@ pub fn main() {
     b' ';  //~ ERROR byte constant must be escaped
     b''';  //~ ERROR byte constant must be escaped
     b'é';  //~ ERROR byte constant must be ASCII
-    b'a  //~ ERROR unterminated byte constant
+    b'a  //~ ERROR unterminated byte constant [E0763]
 }
index 53d50af88d33b84d2a8b75b99a98af06d084452a..7bbdc07cd835fa02c70a119c299e5a0a53056128 100644 (file)
@@ -34,7 +34,7 @@ error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte
 LL |     b'é';
    |       ^
 
-error: unterminated byte constant
+error[E0763]: unterminated byte constant
   --> $DIR/byte-literals.rs:11:6
    |
 LL |     b'a
@@ -42,3 +42,4 @@ LL |     b'a
 
 error: aborting due to 7 previous errors
 
+For more information about this error, try `rustc --explain E0763`.
index ca964cd4b8f21e995c1cfc2b1e75af5849b249ac..9be9064414796b52b1b10131584e1b6cc98a6087 100644 (file)
@@ -22,7 +22,7 @@ error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte
 LL |     b"é";
    |       ^
 
-error: unterminated double quote byte string
+error[E0766]: unterminated double quote byte string
   --> $DIR/byte-string-literals.rs:7:6
    |
 LL |       b"a
@@ -32,3 +32,4 @@ LL | | }
 
 error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0766`.
index 64ba4b5531184bbdf49a71b007bd2fad41c6d245..52338c1f13aadde7c3ac78af8ef1284bbe6f4ead 100644 (file)
@@ -1,6 +1,7 @@
 // Test successful and unsuccessful parsing of the `default` contextual keyword
 
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 trait Foo {
     fn foo<T: Default>() -> T;
index 15c49e8b6270b3789e467dc72c784c177e0295f2..dea35666f37b56c80f12150bc9e2aa2ba4a9284f 100644 (file)
@@ -1,5 +1,5 @@
 error: `default` is not followed by an item
-  --> $DIR/default.rs:22:5
+  --> $DIR/default.rs:23:5
    |
 LL |     default pub fn foo<T: Default>() -> T { T::default() }
    |     ^^^^^^^ the `default` qualifier
@@ -7,7 +7,7 @@ LL |     default pub fn foo<T: Default>() -> T { T::default() }
    = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
 
 error: non-item in item list
-  --> $DIR/default.rs:22:13
+  --> $DIR/default.rs:23:13
    |
 LL | impl Foo for u32 {
    |                  - item list starts here
@@ -18,13 +18,22 @@ LL | }
    | - item list ends here
 
 error[E0449]: unnecessary visibility qualifier
-  --> $DIR/default.rs:16:5
+  --> $DIR/default.rs:17:5
    |
 LL |     pub default fn foo<T: Default>() -> T {
    |     ^^^ `pub` not permitted here because it's implied
 
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0046]: not all trait items implemented, missing: `foo`
-  --> $DIR/default.rs:21:1
+  --> $DIR/default.rs:22:1
    |
 LL |     fn foo<T: Default>() -> T;
    |     -------------------------- `foo` from trait
@@ -32,7 +41,7 @@ LL |     fn foo<T: Default>() -> T;
 LL | impl Foo for u32 {
    | ^^^^^^^^^^^^^^^^ missing `foo` in implementation
 
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0046, E0449.
 For more information about an error, try `rustc --explain E0046`.
index 4ecb21d26ab9b7fe6f99cec1d1122b8acec0b45b..8f5d7f4f7f8fd966a2eb93b521671be2aa0c1a74 100644 (file)
@@ -1,3 +1,4 @@
+#![allow(clashing_extern_declarations)]
 // check-pass
 
 // In this test we check that the parser accepts an ABI string when it
index 57de4b87b0fe6bbbada21a4dd7fe1b5755f8eff0..5259dfe2e656c9f255920434c7706e45a00799ae 100644 (file)
@@ -1,4 +1,6 @@
 // ignore-tidy-trailing-newlines
 // error-pattern: aborting due to 3 previous errors
+#![allow(uncommon_codepoints)]
+
 y![
 Ϥ,
\ No newline at end of file
index 8191c9682cefd8f597d5f61b2deae9de426cc9d4..d5e07622b11b99dce7867a65762ed90655b5d692 100644 (file)
@@ -1,5 +1,5 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/issue-62524.rs:4:3
+  --> $DIR/issue-62524.rs:6:3
    |
 LL | y![
    |   - unclosed delimiter
@@ -7,7 +7,7 @@ LL | Ϥ,
    |   ^
 
 error: macros that expand to items must be delimited with braces or followed by a semicolon
-  --> $DIR/issue-62524.rs:3:3
+  --> $DIR/issue-62524.rs:5:3
    |
 LL |   y![
    |  ___^
@@ -24,7 +24,7 @@ LL | Ϥ,;
    |   ^
 
 error: cannot find macro `y` in this scope
-  --> $DIR/issue-62524.rs:3:1
+  --> $DIR/issue-62524.rs:5:1
    |
 LL | y![
    | ^
diff --git a/src/test/ui/parser/let-binop.rs b/src/test/ui/parser/let-binop.rs
new file mode 100644 (file)
index 0000000..7f58f5d
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    let a: i8 *= 1; //~ ERROR can't reassign to an uninitialized variable
+    let _ = a;
+    let b += 1; //~ ERROR can't reassign to an uninitialized variable
+    let _ = b;
+    let c *= 1; //~ ERROR can't reassign to an uninitialized variable
+    let _ = c;
+}
diff --git a/src/test/ui/parser/let-binop.stderr b/src/test/ui/parser/let-binop.stderr
new file mode 100644 (file)
index 0000000..7143149
--- /dev/null
@@ -0,0 +1,20 @@
+error: can't reassign to an uninitialized variable
+  --> $DIR/let-binop.rs:2:15
+   |
+LL |     let a: i8 *= 1;
+   |               ^^ help: initialize the variable
+
+error: can't reassign to an uninitialized variable
+  --> $DIR/let-binop.rs:4:11
+   |
+LL |     let b += 1;
+   |           ^^ help: initialize the variable
+
+error: can't reassign to an uninitialized variable
+  --> $DIR/let-binop.rs:6:11
+   |
+LL |     let c *= 1;
+   |           ^^ help: initialize the variable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/shebang/shebang-empty.rs b/src/test/ui/parser/shebang/shebang-empty.rs
new file mode 100644 (file)
index 0000000..e38cc63
--- /dev/null
@@ -0,0 +1,4 @@
+#!
+
+// check-pass
+fn main() {}
diff --git a/src/test/ui/parser/shebang/shebang-space.rs b/src/test/ui/parser/shebang/shebang-space.rs
new file mode 100644 (file)
index 0000000..0978b75
--- /dev/null
@@ -0,0 +1,5 @@
+#!    
+
+// check-pass
+// ignore-tidy-end-whitespace
+fn main() {}
index 09f967f161ede7b2ee5cad3375d6959085292fa5..34aee7f69359ee2c0d63ddd6f77c5c99c1d39c3d 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 fn main() {}
 
index 6bb946d5b647095b518e539efb86c504763d93cb..e8ff93f63237da3e779aecefef2816d9563d0936 100644 (file)
@@ -46,5 +46,14 @@ LL |     default fn f2() {}
    |     |
    |     `default` because of this
 
-error: aborting due to 6 previous errors
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error: aborting due to 6 previous errors; 1 warning emitted
 
index 4d98515c224ad80b9b7bb7cdfe331164b6fb2b73..94b300a7bd765839364e4ba1ed41c139089639b3 100644 (file)
@@ -1,4 +1,4 @@
-error: unterminated double quote string
+error[E0765]: unterminated double quote string
   --> $DIR/unbalanced-doublequote.rs:5:5
    |
 LL | /     "
@@ -7,3 +7,4 @@ LL | | }
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0765`.
index f2186b9298e688d12c4e35f577d8ef9b66c0ce8f..8a6ea8e91a25afec56935b275eafbcb560af5ecf 100644 (file)
@@ -46,6 +46,10 @@ LL |         Some(_z @ ref _y) => {}
    |              value moved here
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0`
+   |
+LL |         Some(ref _z @ ref _y) => {}
+   |              ^^^
 
 error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19
@@ -57,6 +61,10 @@ LL |         Some(_z @ ref mut _y) => {}
    |              value moved here
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0`
+   |
+LL |         Some(ref _z @ ref mut _y) => {}
+   |              ^^^
 
 error: aborting due to 6 previous errors
 
index f819e671436ec0a55bcf64674c3aa0c1b127e191..5058998f2a7c1c79eb9df0d99000c8da4e2cace1 100644 (file)
@@ -357,6 +357,10 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   value moved here
    |
    = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+   |
+LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+   |                   ^^^
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38
@@ -379,6 +383,10 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      value moved here
    |
    = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+   |
+LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+   |                                      ^^^
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30
@@ -412,6 +420,10 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   value moved here
    |
    = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+   |
+LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+   |                   ^^^
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38
@@ -434,6 +446,10 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      value moved here
    |
    = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving the value
+   |
+LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+   |                                      ^^^
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30
index 6427a30b8f2ed8354c91828924cd94c63534cb9e..161ac477183c32b9294ec4baeaf9f9bee1c52eca 100644 (file)
@@ -10,20 +10,20 @@ note: the lint level is defined here
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error[E0004]: non-exhaustive patterns: `128u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
   --> $DIR/exhaustive_integer_patterns.rs:28:11
    |
 LL |     match x {
-   |           ^ pattern `128u8..=u8::MAX` not covered
+   |           ^ pattern `128_u8..=u8::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
+error[E0004]: non-exhaustive patterns: `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered
   --> $DIR/exhaustive_integer_patterns.rs:33:11
    |
 LL |     match x {
-   |           ^ patterns `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
+   |           ^ patterns `11_u8..=19_u8`, `31_u8..=34_u8`, `36_u8..=69_u8` and 1 more not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
@@ -34,11 +34,11 @@ error: unreachable pattern
 LL |         -2..=20 => {}
    |         ^^^^^^^
 
-error[E0004]: non-exhaustive patterns: `i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
+error[E0004]: non-exhaustive patterns: `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered
   --> $DIR/exhaustive_integer_patterns.rs:41:11
    |
 LL |     match x {
-   |           ^ patterns `i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
+   |           ^ patterns `i8::MIN..=-8_i8`, `-6_i8`, `121_i8..=124_i8` and 1 more not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
@@ -52,38 +52,38 @@ LL |     match 0i8 {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i8`
 
-error[E0004]: non-exhaustive patterns: `0i16` not covered
+error[E0004]: non-exhaustive patterns: `0_i16` not covered
   --> $DIR/exhaustive_integer_patterns.rs:91:11
    |
 LL |     match 0i16 {
-   |           ^^^^ pattern `0i16` not covered
+   |           ^^^^ pattern `0_i16` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i16`
 
-error[E0004]: non-exhaustive patterns: `128u8..=u8::MAX` not covered
+error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered
   --> $DIR/exhaustive_integer_patterns.rs:109:11
    |
 LL |     match 0u8 {
-   |           ^^^ pattern `128u8..=u8::MAX` not covered
+   |           ^^^ pattern `128_u8..=u8::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u8`
 
-error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=u8::MAX, Some(_))` not covered
+error[E0004]: non-exhaustive patterns: `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered
   --> $DIR/exhaustive_integer_patterns.rs:121:11
    |
 LL |     match (0u8, Some(())) {
-   |           ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=u8::MAX, Some(_))` not covered
+   |           ^^^^^^^^^^^^^^^ patterns `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, std::option::Option<()>)`
 
-error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered
+error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
   --> $DIR/exhaustive_integer_patterns.rs:126:11
    |
 LL |     match (0u8, true) {
-   |           ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered
+   |           ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(u8, bool)`
@@ -92,7 +92,7 @@ error: multiple patterns covering the same range
   --> $DIR/exhaustive_integer_patterns.rs:141:9
    |
 LL |         0 .. 2 => {}
-   |         ------ this range overlaps on `1u8`
+   |         ------ this range overlaps on `1_u8`
 LL |         1 ..= 2 => {}
    |         ^^^^^^^ overlapping patterns
    |
@@ -111,20 +111,20 @@ LL |     match 0u128 {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `5u128..=u128::MAX` not covered
+error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
   --> $DIR/exhaustive_integer_patterns.rs:150:11
    |
 LL |     match 0u128 {
-   |           ^^^^^ pattern `5u128..=u128::MAX` not covered
+   |           ^^^^^ pattern `5_u128..=u128::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
 
-error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered
+error[E0004]: non-exhaustive patterns: `0_u128..=3_u128` not covered
   --> $DIR/exhaustive_integer_patterns.rs:154:11
    |
 LL |     match 0u128 {
-   |           ^^^^^ pattern `0u128..=3u128` not covered
+   |           ^^^^^ pattern `0_u128..=3_u128` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `u128`
index 6e65c51dd3cf32ae9e14cd3a8b2b20c380d51bf9..04feef1706cf433dff5f486f86d5da353d7a932c 100644 (file)
@@ -2,7 +2,7 @@ warning: multiple patterns covering the same range
   --> $DIR/issue-43253.rs:16:9
    |
 LL |         1..10 => {},
-   |         ----- this range overlaps on `9i32`
+   |         ----- this range overlaps on `9_i32`
 LL |         9..=10 => {},
    |         ^^^^^^ overlapping patterns
    |
index 0e12b89de1b9104ca43eff20110ad0b51d2746af..ffc8433403fd59d96de8e2caa10fe9750c066106 100644 (file)
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `&[0u8..=64u8, _, _, _]` and `&[66u8..=u8::MAX, _, _, _]` not covered
+error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
   --> $DIR/match-byte-array-patterns-2.rs:4:11
    |
 LL |     match buf {
-   |           ^^^ patterns `&[0u8..=64u8, _, _, _]` and `&[66u8..=u8::MAX, _, _, _]` not covered
+   |           ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `&[u8; 4]`
index c6a9329f9e8e124ef31988d1823f8db06a9b132a..a35d61e4b710be63198d39488c98c71420218f0b 100644 (file)
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `i32::MIN..=0i32` and `2i32..=i32::MAX` not covered
+error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
   --> $DIR/match-non-exhaustive.rs:2:11
    |
 LL |     match 0 { 1 => () }
-   |           ^ patterns `i32::MIN..=0i32` and `2i32..=i32::MAX` not covered
+   |           ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `i32`
index 9177345bc6f50603d757d492cccfe8ec0adff9c4..a28cfb579f4f1771af1e8ae356162504af8b909f 100644 (file)
@@ -11,8 +11,8 @@ fn main() {
     match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
       None => {}
     }
-    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3i32)`
-                      //  and `(_, _, 5i32..=i32::MAX)` not covered
+    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)`
+                      //  and `(_, _, 5_i32..=i32::MAX)` not covered
       (_, _, 4) => {}
     }
     match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered
index 3cdbd8a3433f4144ca590d654cb1608ef656f516..056efb9b75ddd7083b72fa84bd197059bb1e8d83 100644 (file)
@@ -36,11 +36,11 @@ LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `std::option::Option<i32>`
 
-error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3i32)` and `(_, _, 5i32..=i32::MAX)` not covered
+error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
   --> $DIR/non-exhaustive-match.rs:14:11
    |
 LL |     match (2, 3, 4) {
-   |           ^^^^^^^^^ patterns `(_, _, i32::MIN..=3i32)` and `(_, _, 5i32..=i32::MAX)` not covered
+   |           ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `(i32, i32, i32)`
index 3ef2ead32cb7ceedf069e125748e228c6ff17bbf..75658c490c4e2eea349771ebd9b840bc2dd8c056 100644 (file)
@@ -5,5 +5,5 @@ fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
 
 fn main() {
     let (1, (Some(1), 2..=3)) = (1, (None, 2));
-    //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered
+    //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
 }
index ac729ae9f7cdff4c5230ed9c51c6b36283c3ed0d..8d0409a6af940ddb62384bb0c57866c5a4c9704a 100644 (file)
@@ -6,11 +6,11 @@ LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
    |
    = note: the matched value is of type `(isize, (std::option::Option<isize>, isize))`
 
-error[E0005]: refutable pattern in local binding: `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered
+error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
   --> $DIR/refutable-pattern-errors.rs:7:9
    |
 LL |     let (1, (Some(1), 2..=3)) = (1, (None, 2));
-   |         ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered
+   |         ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
index 7b9e30f40fbb3ca48e4b878b0fcb44c13e3df5d8..9a34171a391c456d4a6399b41acb540358cb1b6e 100644 (file)
@@ -1,17 +1,17 @@
-error[E0004]: non-exhaustive patterns: `isize::MIN..=-6isize` and `21isize..=isize::MAX` not covered
+error[E0004]: non-exhaustive patterns: `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered
   --> $DIR/precise_pointer_size_matching.rs:24:11
    |
 LL |     match 0isize {
-   |           ^^^^^^ patterns `isize::MIN..=-6isize` and `21isize..=isize::MAX` not covered
+   |           ^^^^^^ patterns `isize::MIN..=-6_isize` and `21_isize..=isize::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `isize`
 
-error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=usize::MAX` not covered
+error[E0004]: non-exhaustive patterns: `0_usize` and `21_usize..=usize::MAX` not covered
   --> $DIR/precise_pointer_size_matching.rs:29:11
    |
 LL |     match 0usize {
-   |           ^^^^^^ patterns `0usize` and `21usize..=usize::MAX` not covered
+   |           ^^^^^^ patterns `0_usize` and `21_usize..=usize::MAX` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
    = note: the matched value is of type `usize`
index 4d2af735fa6b940d3ec2db9477b87c9e0e227e9f..eda9d4c128d81dee01ee130853d50ffb28fd3255 100644 (file)
@@ -11,14 +11,10 @@ help: a unit struct with a similar name exists
    |
 LL |     Baz();
    |     ^^^
-help: consider importing one of these items instead
-   |
-LL | use foo1::Bar;
+help: consider importing this function instead
    |
 LL | use foo2::Bar;
    |
-LL | use foo3::Bar;
-   |
 
 error[E0425]: cannot find function, tuple struct or tuple variant `Bar` in this scope
   --> $DIR/privacy-ns1.rs:51:5
@@ -33,14 +29,10 @@ help: a unit struct with a similar name exists
    |
 LL |     Baz();
    |     ^^^
-help: consider importing one of these items
-   |
-LL | use foo1::Bar;
+help: consider importing this function
    |
 LL | use foo2::Bar;
    |
-LL | use foo3::Bar;
-   |
 
 error[E0412]: cannot find type `Bar` in this scope
   --> $DIR/privacy-ns1.rs:52:17
@@ -55,14 +47,10 @@ help: a struct with a similar name exists
    |
 LL |     let _x: Box<Baz>;
    |                 ^^^
-help: consider importing one of these items
+help: consider importing this trait
    |
 LL | use foo1::Bar;
    |
-LL | use foo2::Bar;
-   |
-LL | use foo3::Bar;
-   |
 
 error[E0107]: wrong number of const arguments: expected 0, found 1
   --> $DIR/privacy-ns1.rs:35:17
index f1aa523742ae43857a4d59ba37c512fcba6d378b..d7d9b83527509b3232f3005d35aee782a290e656 100644 (file)
@@ -4,14 +4,10 @@ error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar
 LL |     Bar();
    |     ^^^ not a function, tuple struct or tuple variant
    |
-help: consider importing one of these items instead
-   |
-LL | use foo1::Bar;
+help: consider importing this function instead
    |
 LL | use foo2::Bar;
    |
-LL | use foo3::Bar;
-   |
 
 error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar`
   --> $DIR/privacy-ns2.rs:26:5
@@ -26,14 +22,10 @@ help: a unit struct with a similar name exists
    |
 LL |     Baz();
    |     ^^^
-help: consider importing one of these items instead
-   |
-LL | use foo1::Bar;
+help: consider importing this function instead
    |
 LL | use foo2::Bar;
    |
-LL | use foo3::Bar;
-   |
 
 error[E0573]: expected type, found function `Bar`
   --> $DIR/privacy-ns2.rs:43:14
@@ -45,14 +37,10 @@ help: use `=` if you meant to assign
    |
 LL |     let _x = Bar();
    |            ^
-help: consider importing one of these items instead
+help: consider importing this trait instead
    |
 LL | use foo1::Bar;
    |
-LL | use foo2::Bar;
-   |
-LL | use foo3::Bar;
-   |
 
 error[E0603]: trait `Bar` is private
   --> $DIR/privacy-ns2.rs:63:15
diff --git a/src/test/ui/proc-macro/auxiliary/first-second.rs b/src/test/ui/proc-macro/auxiliary/first-second.rs
new file mode 100644 (file)
index 0000000..6331608
--- /dev/null
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group, Delimiter};
+
+#[proc_macro_attribute]
+pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    let tokens: TokenStream = "#[derive(Second)]".parse().unwrap();
+    let wrapped = TokenTree::Group(Group::new(Delimiter::None, item.into_iter().collect()));
+    tokens.into_iter().chain(std::iter::once(wrapped)).collect()
+}
+
+#[proc_macro_derive(Second)]
+pub fn second(item: TokenStream) -> TokenStream {
+    TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/recollect.rs b/src/test/ui/proc-macro/auxiliary/recollect.rs
new file mode 100644 (file)
index 0000000..d4494a5
--- /dev/null
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn recollect(tokens: TokenStream) -> TokenStream {
+    tokens.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/weird-hygiene.rs b/src/test/ui/proc-macro/auxiliary/weird-hygiene.rs
new file mode 100644 (file)
index 0000000..338e436
--- /dev/null
@@ -0,0 +1,48 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, Group};
+
+fn find_my_ident(tokens: TokenStream) -> Option<TokenStream> {
+    for token in tokens {
+        if let TokenTree::Ident(ident) = &token {
+            if ident.to_string() == "hidden_ident" {
+                return Some(vec![token].into_iter().collect())
+            }
+        } else if let TokenTree::Group(g) = token {
+            if let Some(stream) = find_my_ident(g.stream()) {
+                return Some(stream)
+            }
+        }
+    }
+    return None;
+}
+
+
+#[proc_macro_derive(WeirdDerive)]
+pub fn weird_derive(item: TokenStream) -> TokenStream {
+    let my_ident = find_my_ident(item).expect("Missing 'my_ident'!");
+    let tokens: TokenStream = "call_it!();".parse().unwrap();
+    let final_call = tokens.into_iter().map(|tree| {
+        if let TokenTree::Group(g) = tree {
+            return Group::new(g.delimiter(), my_ident.clone()).into()
+        } else {
+            return tree
+        }
+    }).collect();
+    final_call
+}
+
+#[proc_macro]
+pub fn recollect(item: TokenStream) -> TokenStream {
+    item.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn recollect_attr(_attr: TokenStream, mut item: TokenStream) -> TokenStream {
+    item.into_iter().collect()
+}
diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs
new file mode 100644 (file)
index 0000000..a404dda
--- /dev/null
@@ -0,0 +1,22 @@
+// aux-build:test-macros.rs
+// check-pass
+
+extern crate test_macros;
+use test_macros::recollect;
+
+macro_rules! use_expr {
+    ($expr:expr) => {
+        recollect!($expr)
+    }
+}
+
+#[allow(dead_code)]
+struct Foo;
+impl Foo {
+    #[allow(dead_code)]
+    fn use_self(self) {
+        drop(use_expr!(self));
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/macro-rules-derive.rs b/src/test/ui/proc-macro/macro-rules-derive.rs
new file mode 100644 (file)
index 0000000..5b4d577
--- /dev/null
@@ -0,0 +1,20 @@
+// aux-build:first-second.rs
+// FIXME: The spans here are bad, see PR #73084
+
+extern crate first_second;
+use first_second::*;
+
+macro_rules! produce_it {
+    ($name:ident) => {
+        #[first] //~ ERROR cannot find type
+        struct $name {
+            field: MissingType
+        }
+    }
+}
+
+produce_it!(MyName);
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/test/ui/proc-macro/macro-rules-derive.stderr b/src/test/ui/proc-macro/macro-rules-derive.stderr
new file mode 100644 (file)
index 0000000..4b72d29
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `MissingType` in this scope
+  --> $DIR/macro-rules-derive.rs:9:9
+   |
+LL |         #[first]
+   |         ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/proc-macro/weird-hygiene.rs b/src/test/ui/proc-macro/weird-hygiene.rs
new file mode 100644 (file)
index 0000000..3f48191
--- /dev/null
@@ -0,0 +1,48 @@
+// aux-build:weird-hygiene.rs
+// check-pass
+// FIXME: This should actually error, see PR #73084
+
+#![feature(stmt_expr_attributes)]
+#![feature(proc_macro_hygiene)]
+
+extern crate weird_hygiene;
+use weird_hygiene::*;
+
+macro_rules! other {
+    ($tokens:expr) => {
+        macro_rules! call_it {
+            ($outer_ident:ident) => {
+                macro_rules! inner {
+                    () => {
+                        $outer_ident;
+                    }
+                }
+            }
+        }
+
+        #[derive(WeirdDerive)]
+        enum MyEnum {
+            Value = (stringify!($tokens + hidden_ident), 1).1
+        }
+
+        inner!();
+    }
+}
+
+macro_rules! invoke_it {
+    ($token:expr) => {
+        #[recollect_attr] {
+            $token;
+            hidden_ident
+        }
+    }
+}
+
+fn main() {
+    // `other` and `invoke_it` are both macro_rules! macros,
+    // so it should be impossible for them to ever see `hidden_ident`,
+    // even if they invoke a proc macro.
+    let hidden_ident = "Hello1";
+    other!(50);
+    invoke_it!(25);
+}
diff --git a/src/test/ui/range/issue-73553-misinterp-range-literal.rs b/src/test/ui/range/issue-73553-misinterp-range-literal.rs
new file mode 100644 (file)
index 0000000..e65dba0
--- /dev/null
@@ -0,0 +1,16 @@
+type Range = std::ops::Range<usize>;
+
+fn demo(r: &Range) {
+    println!("{:?}", r);
+}
+
+fn tell(x: usize) -> usize {
+    x
+}
+
+fn main() {
+    demo(tell(1)..tell(10));
+    //~^ ERROR mismatched types
+    demo(1..10);
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/range/issue-73553-misinterp-range-literal.stderr b/src/test/ui/range/issue-73553-misinterp-range-literal.stderr
new file mode 100644 (file)
index 0000000..5167b87
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-73553-misinterp-range-literal.rs:12:10
+   |
+LL |     demo(tell(1)..tell(10));
+   |          ^^^^^^^^^^^^^^^^^
+   |          |
+   |          expected reference, found struct `std::ops::Range`
+   |          help: consider borrowing here: `&(tell(1)..tell(10))`
+   |
+   = note: expected reference `&std::ops::Range<usize>`
+                 found struct `std::ops::Range<usize>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-73553-misinterp-range-literal.rs:14:10
+   |
+LL |     demo(1..10);
+   |          ^^^^^
+   |          |
+   |          expected reference, found struct `std::ops::Range`
+   |          help: consider borrowing here: `&(1..10)`
+   |
+   = note: expected reference `&std::ops::Range<usize>`
+                 found struct `std::ops::Range<{integer}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index de6df4cd0268c1a7587115e2485d827c36f0454e..0552847c48ca9ac7b3ecaeac38d422e7e89b296c 100644 (file)
@@ -1,4 +1,22 @@
 error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::<S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>> - shim(Some(S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>))`
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | |     // Code here does not matter - this is replaced by the
+LL | |     // real drop glue by the compiler.
+LL | |     drop_in_place(to_drop)
+LL | | }
+   | |_^
+   |
+note: `std::intrinsics::drop_in_place` defined here
+  --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+   |
+LL | / pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+LL | |     // Code here does not matter - this is replaced by the
+LL | |     // real drop glue by the compiler.
+LL | |     drop_in_place(to_drop)
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
index bf1eaef367d69d05b0ae4519fb5eda80fd6700f7..373cc17d0e0fe1c05ceccc17740f8e3733a13d9a 100644 (file)
@@ -12,11 +12,10 @@ fn dot(&self, other:Cons<T>) -> isize {
     self.head * other.head + self.tail.dot(other.tail)
   }
 }
-fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize { //~ ERROR recursion limit
+fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
   match n {    0 => {first.dot(second)}
-      // FIXME(#4287) Error message should be here. It should be
-      // a type error to instantiate `test` at a type other than T.
     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+    //~^ ERROR recursion limit
   }
 }
 pub fn main() {
index 1a65b0e84f6a3e399855166184b8e43b5f135bb6..0c0eba68c83b4d1ac7cd4181db93e553e0c9ca93 100644 (file)
@@ -1,11 +1,16 @@
 error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Cons<Nil>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+  --> $DIR/recursion.rs:17:11
+   |
+LL |     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `test` defined here
   --> $DIR/recursion.rs:15:1
    |
 LL | / fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
 LL | |   match n {    0 => {first.dot(second)}
-LL | |       // FIXME(#4287) Error message should be here. It should be
-LL | |       // a type error to instantiate `test` at a type other than T.
 LL | |     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
+LL | |
 LL | |   }
 LL | | }
    | |_^
index 9ff8e21bb58bdb0a560a4c94ff27d5b543da4cd6..97d2c174d9adbf082682c9b7e5d476eb967815ea 100644 (file)
@@ -28,6 +28,10 @@ LL |     x;
    |     ^ value used here after partial move
    |
    = note: move occurs because value has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
+help: borrow this field in the pattern to avoid moving `x.0.0`
+   |
+LL |         (Some(ref y), ()) => {},
+   |               ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
new file mode 100644 (file)
index 0000000..d762f55
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+   |
+LL |     want_G(baz);
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 2dd0c9796e2584eaa12fb5a23b90a0e05d859d4e..539221b5a046c20c694430ab05cb46f77305282c 100644 (file)
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -25,7 +25,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -37,7 +37,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
@@ -48,5 +48,4 @@ fn supply_G() {
     want_G(baz); //~ ERROR mismatched types
 }
 
-pub fn main() {
-}
+pub fn main() {}
index 27704b3e0a8c7421414764b1fb62e28d74f11b33..c9ce936c7d43fc06e0691eb6304ae940d71fd50e 100644 (file)
@@ -1,21 +1,12 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
 error[E0308]: mismatched types
   --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12
    |
 LL |     want_G(baz);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |            ^^^ one type is more general than the other
    |
    = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
-                 found fn item `for<'r> fn(&'r S) -> &'r S {baz}`
+              found fn pointer `for<'r> fn(&'r S) -> &'r S`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0308`.
index c3e8789a903b16446fa43f720c2d278f5a597aa4..695f5506d5e38aadb36977a37f8e02c128ef450d 100644 (file)
@@ -1,14 +1,40 @@
-error[E0308]: mismatched types
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
+error: lifetime may not live long enough
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:5
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:5
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y);
+   |     ^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
index 159d32b50b03c5da035e3f52cf88871689c55935..b83e07663faba54cd662b74a0010c5818830e8dc 100644 (file)
@@ -20,12 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                           ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error: aborting due to 3 previous errors
 
index 2aadd8f4f8c7ed550742175169dabd8db5a0150e..a28f7aa3e08ca73b14f95ae8b84d032875f333cd 100644 (file)
@@ -1,14 +1,46 @@
-error[E0308]: mismatched types
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
+error: lifetime may not live long enough
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
+   |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
+   |
+LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y, z);
+   |     ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            -----------------------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-                 found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+   |
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
index dda6129e195369e1848b738f139dc3032407865d..c93f2890f1110082975608d909ee967f41d4c44b 100644 (file)
@@ -31,12 +31,10 @@ error[E0308]: mismatched types
   --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            -----------------------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                                        ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-                 found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+              found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
 
 error: aborting due to 4 previous errors
 
index bf02ba8eb9199d2a4c090f200239d3f11436e8ca..7e8f78067e08af9d8d699016cb12f2e4026488e3 100644 (file)
@@ -1,21 +1,21 @@
-error[E0621]: explicit lifetime required in the type of `v`
+error: lifetime may not live long enough
   --> $DIR/region-object-lifetime-in-coercion.rs:8:12
    |
 LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
-   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+   |         - let's call the lifetime of this reference `'1`
 LL |     let x: Box<dyn Foo + 'static> = Box::new(v);
-   |            ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+   |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
 
-error[E0621]: explicit lifetime required in the type of `v`
-  --> $DIR/region-object-lifetime-in-coercion.rs:14:5
+error: lifetime may not live long enough
+  --> $DIR/region-object-lifetime-in-coercion.rs:13:5
    |
 LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
-   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+   |         - let's call the lifetime of this reference `'1`
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^ lifetime `'static` required
+   |     ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-in-coercion.rs:20:5
+  --> $DIR/region-object-lifetime-in-coercion.rs:19:5
    |
 LL | fn c(v: &[u8]) -> Box<dyn Foo> {
    |         - let's call the lifetime of this reference `'1`
@@ -24,7 +24,7 @@ LL |     Box::new(v)
    |     ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/region-object-lifetime-in-coercion.rs:24:5
+  --> $DIR/region-object-lifetime-in-coercion.rs:23:5
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |      -- -- lifetime `'b` defined here
@@ -37,4 +37,3 @@ LL |     Box::new(v)
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0621`.
index d56eaf77b6646fe2163dd211eb0d5bb31da2d34a..5d199149c39b860d029bc80728988afe33c76b25 100644 (file)
@@ -5,13 +5,12 @@ trait Foo {}
 impl<'a> Foo for &'a [u8] {}
 
 fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
-    let x: Box<dyn Foo + 'static> = Box::new(v);
-    //~^ ERROR explicit lifetime required in the type of `v` [E0621]
+    let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR cannot infer an appropriate lifetime
     x
 }
 
 fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
-    Box::new(v) //~ ERROR explicit lifetime required in the type of `v` [E0621]
+    Box::new(v) //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn c(v: &[u8]) -> Box<dyn Foo> {
index 1462af44cb15a6702f085410026d272bbe4600d2..7f5a3a47976c7d38f812fa9fb9a1232657dd2a1c 100644 (file)
@@ -1,61 +1,76 @@
-error[E0621]: explicit lifetime required in the type of `v`
-  --> $DIR/region-object-lifetime-in-coercion.rs:8:37
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/region-object-lifetime-in-coercion.rs:8:46
    |
 LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
-   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+   |         ----- this data with an anonymous lifetime `'_`...
 LL |     let x: Box<dyn Foo + 'static> = Box::new(v);
-   |                                     ^^^^^^^^^^^ lifetime `'static` required
+   |                                              ^ ...is captured here, requiring it to live as long as `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                                 ^^
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+   |         ^^^^^^^^^^^^^
 
-error[E0621]: explicit lifetime required in the type of `v`
-  --> $DIR/region-object-lifetime-in-coercion.rs:14:5
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/region-object-lifetime-in-coercion.rs:13:14
    |
 LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
-   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+   |         ----- this data with an anonymous lifetime `'_`...
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^ lifetime `'static` required
+   |              ^ ...is captured here, requiring it to live as long as `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
+   |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
+   |                                 ^^
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
+   |         ^^^^^^^^^^^^^
 
-error: cannot infer an appropriate lifetime
-  --> $DIR/region-object-lifetime-in-coercion.rs:20:14
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/region-object-lifetime-in-coercion.rs:19:14
    |
 LL | fn c(v: &[u8]) -> Box<dyn Foo> {
-   |         ----- data with this lifetime...
+   |         ----- this data with an anonymous lifetime `'_`...
 ...
 LL |     Box::new(v)
-   |     ---------^-
-   |     |        |
-   |     |        ...and is captured here
-   |     ...is required to be `'static` by this...
+   |              ^ ...is captured here, requiring it to live as long as `'static`
    |
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 17:1
+help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
    |
 LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
    |                               ^^^^
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/region-object-lifetime-in-coercion.rs:24:14
+  --> $DIR/region-object-lifetime-in-coercion.rs:23:14
    |
 LL |     Box::new(v)
    |              ^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 23:6...
-  --> $DIR/region-object-lifetime-in-coercion.rs:23:6
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:6...
+  --> $DIR/region-object-lifetime-in-coercion.rs:22:6
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |      ^^
 note: ...so that the expression is assignable
-  --> $DIR/region-object-lifetime-in-coercion.rs:24:14
+  --> $DIR/region-object-lifetime-in-coercion.rs:23:14
    |
 LL |     Box::new(v)
    |              ^
    = note: expected `&[u8]`
               found `&'a [u8]`
-note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 23:9...
-  --> $DIR/region-object-lifetime-in-coercion.rs:23:9
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 22:9...
+  --> $DIR/region-object-lifetime-in-coercion.rs:22:9
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |         ^^
 note: ...so that the expression is assignable
-  --> $DIR/region-object-lifetime-in-coercion.rs:24:5
+  --> $DIR/region-object-lifetime-in-coercion.rs:23:5
    |
 LL |     Box::new(v)
    |     ^^^^^^^^^^^
@@ -64,5 +79,5 @@ LL |     Box::new(v)
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0495, E0621.
+Some errors have detailed explanations: E0495, E0759.
 For more information about an error, try `rustc --explain E0495`.
index 147f7f3541816c0b0ffca03bf433a4bbc73ca6e4..114e4052aae09b63159cc61e3899af7c0e982403 100644 (file)
@@ -1,28 +1,20 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/regions-close-object-into-object-2.rs:10:11
    |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
+   |                         ------------------ this data with lifetime `'a`...
 LL |     box B(&*v) as Box<dyn X>
-   |           ^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
-  --> $DIR/regions-close-object-into-object-2.rs:9:6
+   |           ^^^ ...is captured here, requiring it to live as long as `'static`
    |
-LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
-   |      ^^
-note: ...so that the type `(dyn A<T> + 'a)` is not borrowed for too long
-  --> $DIR/regions-close-object-into-object-2.rs:10:11
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
-LL |     box B(&*v) as Box<dyn X>
-   |           ^^^
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
-  --> $DIR/regions-close-object-into-object-2.rs:10:5
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
+   |                                                            ^^
+help: alternatively, add an explicit `'static` bound to this reference
    |
-LL |     box B(&*v) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected `std::boxed::Box<(dyn X + 'static)>`
-              found `std::boxed::Box<dyn X>`
+LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> {
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
index 6e7d6152cd09a28cfef15cbaeebb8caa8ab6879c..850d81940791fd168afbe9224765cf642bbaaf61 100644 (file)
@@ -1,28 +1,20 @@
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/regions-close-object-into-object-4.rs:10:11
    |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+   |                   ---------------- this data with lifetime `'a`...
 LL |     box B(&*v) as Box<dyn X>
-   |           ^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
-  --> $DIR/regions-close-object-into-object-4.rs:9:6
+   |           ^^^ ...is captured here, requiring it to live as long as `'static`
    |
-LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-   |      ^^
-note: ...so that the type `(dyn A<U> + 'a)` is not borrowed for too long
-  --> $DIR/regions-close-object-into-object-4.rs:10:11
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
-LL |     box B(&*v) as Box<dyn X>
-   |           ^^^
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
-  --> $DIR/regions-close-object-into-object-4.rs:10:5
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
+   |                                                    ^^
+help: alternatively, add an explicit `'static` bound to this reference
    |
-LL |     box B(&*v) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected `std::boxed::Box<(dyn X + 'static)>`
-              found `std::boxed::Box<dyn X>`
+LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> {
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
index fa2cc37d05b2b917b060b7271a78ab6573f34068..de14d5ba82a1b7dfc10348ceafbfb012c771034e 100644 (file)
@@ -5,6 +5,8 @@
 // *ANY* lifetime and returns a reference with the 'static lifetime.
 // This can safely be considered to be an instance of `F` because all
 // lifetimes are sublifetimes of 'static.
+//
+// check-pass
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -26,7 +28,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -38,10 +40,9 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
deleted file mode 100644 (file)
index a8a7e97..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static.rs:41:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
index 434a3e47b492a6b51fb73685d2db658136eaa5c3..37f7fcf2e331a882e5a4e2594f7c14a5d1454f50 100644 (file)
@@ -1,14 +1,40 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
+error: lifetime may not live long enough
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:8:5
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:14:5
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y);
+   |     ^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
index 01f43aeebaf7cb3a77a051efd20bd81149cf9082..2b2dd0dbbf2509ed209d24e1cf3963003fab6aed 100644 (file)
@@ -20,12 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                           ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/regions/regions-proc-bound-capture.nll.stderr b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr
new file mode 100644 (file)
index 0000000..75890b8
--- /dev/null
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-proc-bound-capture.rs:9:5
+   |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+   |                   - let's call the lifetime of this reference `'1`
+LL |     // This is illegal, because the region bound on `proc` is 'static.
+LL |     Box::new(move || { *x })
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
index 0c903b738499265288fc5c0bcd5fc928c8e976ff..8617c0e9da8f76f51a6319847965b265e8aff148 100644 (file)
@@ -4,9 +4,9 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> {
     Box::new(move|| { *x })
 }
 
-fn static_proc(x: &isize) -> Box<dyn FnMut()->(isize) + 'static> {
+fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
     // This is illegal, because the region bound on `proc` is 'static.
-    Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621]
+    Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() { }
index c53af34456ef3126650fd5dc2c7da6aba2dce916..67eee3bb6e28127bbd8db3417d40386340b6a38f 100644 (file)
@@ -1,12 +1,21 @@
-error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/regions-proc-bound-capture.rs:9:5
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/regions-proc-bound-capture.rs:9:14
    |
-LL | fn static_proc(x: &isize) -> Box<dyn FnMut()->(isize) + 'static> {
-   |                   ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize`
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+   |                   ------ this data with an anonymous lifetime `'_`...
 LL |     // This is illegal, because the region bound on `proc` is 'static.
-LL |     Box::new(move|| { *x })
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+LL |     Box::new(move || { *x })
+   |              ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static`
+   |
+help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
+   |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
+   |                                                           ^^
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+   |                   ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0621`.
+For more information about this error, try `rustc --explain E0759`.
index 6a081e23d9d375f6dfe51cbada2b04e0275f1398..2eab3ebc7687d8cf1dbf6f85ec9bddb43bd54488 100644 (file)
@@ -39,12 +39,16 @@ error[E0308]: mismatched types
    |
 LL |     let f = [0; -4_isize];
    |                 ^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: `-4_isize` cannot fit into type `usize`
 
 error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:22:23
    |
 LL |     let f = [0_usize; -1_isize];
    |                       ^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: `-1_isize` cannot fit into type `usize`
 
 error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:25:17
index d3e1953435359487261a14f34b7edf8736cf458e..538eeead9fc9da401d05656a641772cc1376295a 100644 (file)
@@ -25,11 +25,8 @@ LL | use mul1::Mul;
    |
 LL | use mul2::Mul;
    |
-LL | use mul3::Mul;
-   |
-LL | use mul4::Mul;
+LL | use std::ops::Mul;
    |
-     and 2 other candidates
 
 error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
   --> $DIR/issue-21221-1.rs:63:6
index f9263d2af5026993d80a4b10ea48caca218b4def..d4fd7cb1257e051469f95a879c2fd1ab4e1f7547 100644 (file)
@@ -4,7 +4,9 @@ error[E0405]: cannot find trait `T` in this scope
 LL | impl T for Foo { }
    |      ^ not found in this scope
    |
-help: consider importing this trait
+help: consider importing one of these items
+   |
+LL | use baz::T;
    |
 LL | use foo::bar::T;
    |
index d9b1b9c59558a7a1f48e55376bcb4cd0b27031ee..16baa6c9b623311e58b0b4b6168b412118466e8c 100644 (file)
@@ -132,7 +132,7 @@ LL |     let _: E = m::n::Z;
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0423]: expected value, found enum `m::n::Z`
@@ -165,7 +165,7 @@ LL |     let _: E = m::n::Z::Fn;
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0412]: cannot find type `Z` in this scope
@@ -183,7 +183,7 @@ LL |     let _: E = m::n::Z::Struct;
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0423]: expected value, found struct variant `m::n::Z::Struct`
@@ -212,7 +212,7 @@ LL |     let _: E = m::n::Z::Unit {};
    |            ^
 help: consider importing this enum
    |
-LL | use m::n::Z;
+LL | use m::Z;
    |
 
 error[E0603]: enum `Z` is private
index 9f3b9651642a2e447cf6e9cd5999267372f51af4..f21eac37c17b5325405b37638ee5fba497d0d15c 100644 (file)
@@ -1,13 +1,10 @@
 fn main() {
     [(); return match 0 { n => n }];
     //~^ ERROR: return statement outside of function body
-    //~| ERROR: `match` is not allowed in a `const`
 
     [(); return match 0 { 0 => 0 }];
     //~^ ERROR: return statement outside of function body
-    //~| ERROR: `match` is not allowed in a `const`
 
     [(); return match () { 'a' => 0, _ => 0 }];
     //~^ ERROR: return statement outside of function body
-    //~| ERROR: `match` is not allowed in a `const`
 }
index c475c7de4381baa6b6ede193206c8993824de7da..8e801e3fbb7abd9f030b1b2ad719008205f5f860 100644 (file)
@@ -1,30 +1,3 @@
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/return-match-array-const.rs:2:17
-   |
-LL |     [(); return match 0 { n => n }];
-   |                 ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/return-match-array-const.rs:6:17
-   |
-LL |     [(); return match 0 { 0 => 0 }];
-   |                 ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/return-match-array-const.rs:10:17
-   |
-LL |     [(); return match () { 'a' => 0, _ => 0 }];
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
 error[E0572]: return statement outside of function body
   --> $DIR/return-match-array-const.rs:2:10
    |
@@ -32,18 +5,17 @@ LL |     [(); return match 0 { n => n }];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0572]: return statement outside of function body
-  --> $DIR/return-match-array-const.rs:6:10
+  --> $DIR/return-match-array-const.rs:5:10
    |
 LL |     [(); return match 0 { 0 => 0 }];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0572]: return statement outside of function body
-  --> $DIR/return-match-array-const.rs:10:10
+  --> $DIR/return-match-array-const.rs:8:10
    |
 LL |     [(); return match () { 'a' => 0, _ => 0 }];
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0572, E0658.
-For more information about an error, try `rustc --explain E0572`.
+For more information about this error, try `rustc --explain E0572`.
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs
new file mode 100644 (file)
index 0000000..3fb1cf9
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(non_ascii_idents)]
+
+extern crate ьаг; //~ ERROR cannot load a crate with a non-ascii name `ьаг`
+//~| ERROR can't find crate for `ьаг`
+
+fn main() {}
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr
new file mode 100644 (file)
index 0000000..1e42423
--- /dev/null
@@ -0,0 +1,15 @@
+error: cannot load a crate with a non-ascii name `ьаг`
+  --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1
+   |
+LL | extern crate ьаг;
+   | ^^^^^^^^^^^^^^^^^
+
+error[E0463]: can't find crate for `ьаг`
+  --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1
+   |
+LL | extern crate ьаг;
+   | ^^^^^^^^^^^^^^^^^ can't find crate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs
new file mode 100644 (file)
index 0000000..e1acdbf
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags:--extern му_сгате
+// edition:2018
+#![feature(non_ascii_idents)]
+
+use му_сгате::baz; //~  ERROR cannot load a crate with a non-ascii name `му_сгате`
+                   //~| can't find crate for `му_сгате`
+
+
+fn main() {}
diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr
new file mode 100644 (file)
index 0000000..c06405e
--- /dev/null
@@ -0,0 +1,15 @@
+error: cannot load a crate with a non-ascii name `му_сгате`
+  --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5
+   |
+LL | use му_сгате::baz;
+   |     ^^^^^^^^
+
+error[E0463]: can't find crate for `му_сгате`
+  --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5
+   |
+LL | use му_сгате::baz;
+   |     ^^^^^^^^ can't find crate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0463`.
index d5756737f1791cd9c88c221ca4f0f0f6b8f4a176..71af704c69f0d1e7865b0b9e870ad91c90027c5c 100644 (file)
@@ -216,17 +216,14 @@ fn inside_const_generic_arguments() {
 
     if let A::<{
         true && let 1 = 1 //~ ERROR `let` expressions are not supported here
-        //~| ERROR `match` is not allowed in a `const`
     }>::O = 5 {}
 
     while let A::<{
         true && let 1 = 1 //~ ERROR `let` expressions are not supported here
-        //~| ERROR `match` is not allowed in a `const`
     }>::O = 5 {}
 
     if A::<{
         true && let 1 = 1 //~ ERROR `let` expressions are not supported here
-        //~| ERROR `match` is not allowed in a `const`
     }>::O == 5 {}
 
     // In the cases above we have `ExprKind::Block` to help us out.
index 4c3a00e5f3583dbd0cf6b11a4b71cad4882cee26..7f343d1a853ac95bb6d205581a7f147a089ba2ec 100644 (file)
@@ -1,5 +1,5 @@
 error: expected one of `,` or `>`, found `&&`
-  --> $DIR/disallowed-positions.rs:239:14
+  --> $DIR/disallowed-positions.rs:236:14
    |
 LL |         true && let 1 = 1
    |              ^^ expected one of `,` or `>`
@@ -482,7 +482,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:223:17
+  --> $DIR/disallowed-positions.rs:222:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -491,7 +491,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:228:17
+  --> $DIR/disallowed-positions.rs:226:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -516,33 +516,6 @@ LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
 
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/disallowed-positions.rs:218:17
-   |
-LL |         true && let 1 = 1
-   |                 ^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/disallowed-positions.rs:223:17
-   |
-LL |         true && let 1 = 1
-   |                 ^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
-error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/disallowed-positions.rs:228:17
-   |
-LL |         true && let 1 = 1
-   |                 ^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
-
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:32:8
    |
@@ -983,7 +956,7 @@ LL |         let 0 = 0?;
    = help: the trait `std::ops::Try` is not implemented for `{integer}`
    = note: required by `std::ops::Try::into_result`
 
-error: aborting due to 106 previous errors; 2 warnings emitted
+error: aborting due to 103 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0658.
+Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
index f7af1b506f0dba01b4d8c4239329c8850901e744..655d4d7400b78a93caeb62d57818207bd73577aa 100644 (file)
@@ -4,12 +4,13 @@
 #![allow(incomplete_features)]
 
 pub trait MyTrait {
-    fn method(&self);
+    fn method(&self) -> Option<()>;
 }
 
 impl const MyTrait for () {
-    fn method(&self) {
-        match *self {} //~ ERROR `match` is not allowed in a `const fn`
+    fn method(&self) -> Option<()> {
+        Some(())?; //~ ERROR `?` is not allowed in a `const fn`
+        None
     }
 }
 
index 563a9afe5bb84e9231cd943fc403172533476ae5..8c76d7eb597b6a29c08e42820c934acc1a739bc1 100644 (file)
@@ -1,12 +1,9 @@
-error[E0658]: `match` is not allowed in a `const fn`
+error[E0744]: `?` is not allowed in a `const fn`
   --> $DIR/hir-const-check.rs:12:9
    |
-LL |         match *self {}
-   |         ^^^^^^^^^^^^^^
-   |
-   = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information
-   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+LL |         Some(())?;
+   |         ^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr
new file mode 100644 (file)
index 0000000..848d4fe
--- /dev/null
@@ -0,0 +1,68 @@
+error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+  --> $DIR/rfc1623.rs:21:1
+   |
+LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+   |
+   = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `SomeStruct`
+   = note: required because it appears within the type `&SomeStruct`
+   = note: shared static variables must have a type that implements `Sync`
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 55f5d0b94dcb05b72c3e1b5762f1de2a5722f029..aa6b1c0012c933f6be3931067e83f445a7fde682 100644 (file)
@@ -8,23 +8,21 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
 static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
     &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
 
-
 struct SomeStruct<'x, 'y, 'z: 'x> {
     foo: &'x Foo<'z>,
     bar: &'x Bar<'z>,
-    f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
+    f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
 }
 
 fn id<T>(t: T) -> T {
     t
 }
 
-static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types
+static SOME_STRUCT: &SomeStruct = &SomeStruct {
     foo: &Foo { bools: &[false, true] },
     bar: &Bar { bools: &[true, true] },
     f: &id,
-    //~^ ERROR type mismatch in function arguments
-    //~| ERROR type mismatch resolving
+    //~^ ERROR mismatched types
 };
 
 // very simple test for a 'static static with default lifetime
index ca956004ef76f5aac107abaf37c30600b4abd5fa..2efc58ac3819c52010f89a77e2e88f4854e9607b 100644 (file)
@@ -1,46 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/rfc1623.rs:22:35
-   |
-LL |   static SOME_STRUCT: &SomeStruct = SomeStruct {
-   |  ___________________________________^
-LL | |     foo: &Foo { bools: &[false, true] },
-LL | |     bar: &Bar { bools: &[true, true] },
-LL | |     f: &id,
-LL | |
-LL | |
-LL | | };
-   | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct`
-   |
-help: consider borrowing here
-   |
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
-LL |     foo: &Foo { bools: &[false, true] },
-LL |     bar: &Bar { bools: &[true, true] },
-LL |     f: &id,
-LL |
-LL |
- ...
-
-error[E0631]: type mismatch in function arguments
-  --> $DIR/rfc1623.rs:25:8
-   |
-LL | fn id<T>(t: T) -> T {
-   | ------------------- found signature of `fn(_) -> _`
-...
-LL |     f: &id,
-   |        ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _`
-   |
-   = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
-
-error[E0271]: type mismatch resolving `for<'a, 'b> <fn(_) -> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>`
-  --> $DIR/rfc1623.rs:25:8
+  --> $DIR/rfc1623.rs:24:8
    |
 LL |     f: &id,
-   |        ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |        ^^^ one type is more general than the other
    |
-   = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: expected type `std::ops::FnOnce<(&'a Foo<'b>,)>`
+              found type `std::ops::FnOnce<(&Foo<'_>,)>`
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0308, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
index f8650cd86d51e8bf80942d0e32d21e0ba5cba970..cee73b0425ad52210f7032b7e6b9262babad2b51 100644 (file)
@@ -1,5 +1,5 @@
 // needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
 //
 // compile-flags: -Z sanitizer=address -O -g
 //
index 1ca082c8b47042f8444a34801e2ca12c0515b34b..095a6f4697b1c15a35a1e5139531b3ec5b4bfa46 100644 (file)
@@ -1,5 +1,5 @@
 // needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
 //
 // compile-flags: -Z sanitizer=address -O
 //
index 9c198543a86649572cd42aa4fc6105d4231b985b..79dfe58f04d0b48274bac1512000aec19a327098 100644 (file)
@@ -2,8 +2,10 @@
 // the `#[cfg(sanitize = "option")]` attribute is configured.
 
 // needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-address
+// needs-sanitizer-leak
+// needs-sanitizer-memory
+// needs-sanitizer-thread
 // check-pass
 // revisions: address leak memory thread
 //[address]compile-flags: -Zsanitizer=address --cfg address
diff --git a/src/test/ui/sanitize/incompatible.rs b/src/test/ui/sanitize/incompatible.rs
new file mode 100644 (file)
index 0000000..4947f3b
--- /dev/null
@@ -0,0 +1,6 @@
+// compile-flags: -Z sanitizer=address -Z sanitizer=memory --target x86_64-unknown-linux-gnu
+// error-pattern: error: `-Zsanitizer=address` is incompatible with `-Zsanitizer=memory`
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
diff --git a/src/test/ui/sanitize/incompatible.stderr b/src/test/ui/sanitize/incompatible.stderr
new file mode 100644 (file)
index 0000000..f86db41
--- /dev/null
@@ -0,0 +1,4 @@
+error: `-Zsanitizer=address` is incompatible with `-Zsanitizer=memory`
+
+error: aborting due to previous error
+
index 458f99143b6488ada45e038b0ba973d7f260ca15..b2e182238ce288803b0cd9116c8be6d8fb939d01 100644 (file)
@@ -4,7 +4,7 @@
 // miscompilation which was subsequently detected by AddressSanitizer as UB.
 //
 // needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
 //
 // compile-flags: -Copt-level=0 -Zsanitizer=address
 // run-pass
index 5c2f2cb4e868bb0012a960f21a61e7f85f044017..c9f10fe4f467ed73c8bdc7a4a92944bcf49c788e 100644 (file)
@@ -1,5 +1,5 @@
 // needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-leak
 //
 // compile-flags: -Z sanitizer=leak -O
 //
index 3e1cf4509a31ff953cc9a914b9caef79083e729b..a26649a5800131e20a6820ec72a123263552a84a 100644 (file)
@@ -1,6 +1,5 @@
 // needs-sanitizer-support
-// only-linux
-// only-x86_64
+// needs-sanitizer-memory
 //
 // compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
 //
index d0984bbe65fd58a745954e32cec4663988734dcd..64d6ccf34091681d386c7c3f746c7e529e2d15fb 100644 (file)
@@ -4,7 +4,7 @@
 //
 // min-llvm-version 9.0
 // needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
 //
 // no-prefer-dynamic
 // revisions: opt0 opt1
index 26590be8b1870f5155534a920ddc318721b172b3..c70cf5accc0776611cf557a43178b708e002708e 100644 (file)
@@ -11,7 +11,7 @@
 // would occasionally fail, making test flaky.
 //
 // needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-thread
 //
 // compile-flags: -Z sanitizer=thread -O
 //
index 444333c3f01e22a3413e6e8875193e7b8102c819..6ccc9988cdeccdd3fe74973f00b5a176be059770 100644 (file)
@@ -1,6 +1,5 @@
-// ignore-tidy-linelength
 // compile-flags: -Z sanitizer=leak --target i686-unknown-linux-gnu
-// error-pattern: error: LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target
+// error-pattern: error: `-Zsanitizer=leak` only works with targets:
 
 #![feature(no_core)]
 #![no_core]
index 38be58dd4b36598babb4049de8cfdee4352c1af1..f5961a11b1f1c4a741e4cff730f20ab3cbd152b5 100644 (file)
@@ -1,4 +1,4 @@
-error: LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target
+error: `-Zsanitizer=leak` only works with targets: aarch64-unknown-linux-gnu, x86_64-apple-darwin, x86_64-unknown-linux-gnu
 
 error: aborting due to previous error
 
index 6a2067e157af56c7e2b76ad53831acc510e65c95..30be2ae6f090641e4bdacb7374f0940b521370fd 100644 (file)
@@ -1,5 +1,5 @@
 // needs-sanitizer-support
-// only-x86_64
+// needs-sanitizer-address
 //
 // compile-flags: -Zsanitizer=address
 // run-fail
index 1aeabce5e8aaf267fa616f22b6d3ff8bf93f7d68..f2fbb0ba7d7556738dd6951afe48ea920e2553d7 100644 (file)
@@ -1,11 +1,17 @@
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                ^^^^  ----------     ---------- ...and required to be `'static` by this
+   |                ^^^^  ----------     ---------- ...and is required to live as long as `'static` here
    |                |     |
-   |                |     data with this lifetime...
+   |                |     this data with an anonymous lifetime `'_`...
    |                ...is captured here...
+   |
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+   |                                                ^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0759`.
index 04c475be787b89af4af76ca7f5cb93c83e167882..2e10ab3d3f9b84a8c1802524008ab8020e311bd2 100644 (file)
@@ -1,16 +1,21 @@
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
-   |                ----------     ----------   ^^^^ ...and is captured here
-   |                |              |
-   |                |              ...is required to be `'static` by this...
-   |                data with this lifetime...
+   |                ----------                  ^^^^ ...is captured here...
+   |                |
+   |                this data with an anonymous lifetime `'_`...
    |
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5
+note: ...and is required to live as long as `'static` here
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
+   |                               ^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
    |                                          ^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/shebang.rs b/src/test/ui/shebang.rs
deleted file mode 100644 (file)
index 3d3ba46..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env rustx
-
-// run-pass
-
-pub fn main() { println!("Hello World"); }
index d05e89e257f459fc293a73ba9b6d536e97c56240..29d1b000943211902f8973e1aee5c19a4da506da 100644 (file)
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/E0493.rs:17:17
    |
 LL | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - value is dropped here
+   |                 |
+   |                 constants cannot evaluate destructors
 
 error: aborting due to previous error
 
index 54d51492ab3494b6ca0147ff1dca4b216da25fd1..fc39b553a61ac31cef08b8161cd2a66d01c2d859 100644 (file)
@@ -2,7 +2,7 @@
 
 // Make sure we don't crash with a cycle error during coherence.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Trait<T> {
     type Assoc;
diff --git a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr
new file mode 100644 (file)
index 0000000..250f48f
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/assoc-ty-graph-cycle.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 79cb6594397214f51400d18b7f3af403ba7749dc..fc28d0c815eb3366dbc62e206e5d0a18aa90b4ef 100644 (file)
@@ -2,7 +2,7 @@
 
 // aux-build:cross_crates_defaults.rs
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 extern crate cross_crates_defaults;
 
diff --git a/src/test/ui/specialization/cross-crate-defaults.stderr b/src/test/ui/specialization/cross-crate-defaults.stderr
new file mode 100644 (file)
index 0000000..f18bc99
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/cross-crate-defaults.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs
new file mode 100644 (file)
index 0000000..272a5e3
--- /dev/null
@@ -0,0 +1,24 @@
+// Check that we check that default associated types satisfy the required
+// bounds on them.
+
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X {
+    type U: Clone;
+    fn unsafe_clone(&self, x: Option<&Self::U>) {
+        x.cloned();
+    }
+}
+
+// We cannot normalize `<T as X>::U` to `str` here, because the default could
+// be overridden. The error here must therefore be found by a method other than
+// normalization.
+impl<T> X for T {
+    default type U = str;
+    //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    1.unsafe_clone(None);
+}
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
new file mode 100644 (file)
index 0000000..90ad5d4
--- /dev/null
@@ -0,0 +1,21 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-associated-type-bound-1.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied
+  --> $DIR/deafult-associated-type-bound-1.rs:18:5
+   |
+LL |     type U: Clone;
+   |     -------------- required by `X::U`
+...
+LL |     default type U = str;
+   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/deafult-associated-type-bound-2.rs
new file mode 100644 (file)
index 0000000..0a21b1f
--- /dev/null
@@ -0,0 +1,22 @@
+// Check that generic predicates are also checked for default associated types.
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X<T> {
+    type U: PartialEq<T>;
+    fn unsafe_compare(x: Option<Self::U>, y: Option<T>) {
+        match (x, y) {
+            (Some(a), Some(b)) => a == b,
+            _ => false,
+        };
+    }
+}
+
+impl<B: 'static, T> X<B> for T {
+    default type U = &'static B;
+    //~^ ERROR can't compare `&'static B` with `B`
+}
+
+pub fn main() {
+    <i32 as X<i32>>::unsafe_compare(None, None);
+}
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
new file mode 100644 (file)
index 0000000..ea40f84
--- /dev/null
@@ -0,0 +1,23 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-associated-type-bound-2.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: can't compare `&'static B` with `B`
+  --> $DIR/deafult-associated-type-bound-2.rs:16:5
+   |
+LL |     type U: PartialEq<T>;
+   |     --------------------- required by `X::U`
+...
+LL |     default type U = &'static B;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
+   |
+   = help: the trait `std::cmp::PartialEq<B>` is not implemented for `&'static B`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
new file mode 100644 (file)
index 0000000..8a94ea6
--- /dev/null
@@ -0,0 +1,27 @@
+// Check that default generics associated types are validated.
+
+#![feature(specialization)]
+#![feature(generic_associated_types)]
+//~^^ WARNING `specialization` is incomplete
+//~^^ WARNING the feature `generic_associated_types` is incomplete
+
+trait X {
+    type U<'a>: PartialEq<&'a Self>;
+    fn unsafe_compare<'b>(x: Option<Self::U<'b>>, y: Option<&'b Self>) {
+        match (x, y) {
+            (Some(a), Some(b)) => a == b,
+            _ => false,
+        };
+    }
+}
+
+impl<T: 'static> X for T {
+    default type U<'a> = &'a T;
+    //~^ ERROR can't compare `T` with `T`
+}
+
+struct NotComparable;
+
+pub fn main() {
+    <NotComparable as X>::unsafe_compare(None, None);
+}
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
new file mode 100644 (file)
index 0000000..7f3c49e
--- /dev/null
@@ -0,0 +1,36 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-generic-associated-type-bound.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-generic-associated-type-bound.rs:4:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: can't compare `T` with `T`
+  --> $DIR/deafult-generic-associated-type-bound.rs:19:5
+   |
+LL |     type U<'a>: PartialEq<&'a Self>;
+   |     -------------------------------- required by `X::U`
+...
+LL |     default type U<'a> = &'a T;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T`
+   |
+   = help: the trait `std::cmp::PartialEq` is not implemented for `T`
+   = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T`
+help: consider further restricting this bound
+   |
+LL | impl<T: 'static + std::cmp::PartialEq> X for T {
+   |                 ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.
index 15550bcce2a8a95f3e4616b49ea1f25c231fcea9..5d67160eb96ad8f2114c424ee0f778fa535818f8 100644 (file)
@@ -5,7 +5,7 @@
 
 // aux-build:go_trait.rs
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 extern crate go_trait;
 
diff --git a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr
new file mode 100644 (file)
index 0000000..1b50329
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/allowed-cross-crate.rs:8:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index f9c73a19cfa4665e64f0d83c2de3ecb9ae2dc184..13258ac8c9fe670ba2f39aa6e7e20efe2bcedab4 100644 (file)
@@ -2,7 +2,7 @@
 
 // Test that you can list the more specific impl before the more general one.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
     type Out;
diff --git a/src/test/ui/specialization/defaultimpl/out-of-order.stderr b/src/test/ui/specialization/defaultimpl/out-of-order.stderr
new file mode 100644 (file)
index 0000000..deae021
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/out-of-order.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index ed38bb3fc3a12e36a39f679cf3988443afe17c6b..0add4d5516c7b3433980eb8b0676daeb8213bb3a 100644 (file)
@@ -4,7 +4,7 @@
 // projections involve specialization, so long as the associated type is
 // provided by the most specialized impl.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Assoc {
     type Output;
diff --git a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr
new file mode 100644 (file)
index 0000000..46899ca
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/overlap-projection.rs:7:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 897a7aade2fe1dd9c5c6784f66a2c8f94ffb45bb..4a9140969324dd46b94ae8cc22ef55313e8b844e 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 #![allow(dead_code)]
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Make sure we *can* project non-defaulted associated types
 // cf compile-fail/specialization-default-projection.rs
diff --git a/src/test/ui/specialization/defaultimpl/projection.stderr b/src/test/ui/specialization/defaultimpl/projection.stderr
new file mode 100644 (file)
index 0000000..8629c6c
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/projection.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 37005f839d4889225f682689417af88a55fc234d..661724eef8a4386a7edc2de3c191074e9d54a74a 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Check a number of scenarios in which one impl tries to override another,
 // without correctly using `default`.
index 13636b28b126c675f5e54eb7ea75b733a3e0310d..7958eddbeba251aefe0bcde14803c2c6698e83ff 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-no-default.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
   --> $DIR/specialization-no-default.rs:20:5
    |
@@ -65,6 +74,6 @@ LL |       fn redundant(&self) {}
    |
    = note: to specialize, `redundant` in the parent `impl` must be marked `default`
 
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0520`.
index 2b8ca6bb1ddbbed1a5ac924ffa7c7ed8b557cd61..89fef5b5ef9692838a27c0756ace6c2a623543ba 100644 (file)
@@ -3,7 +3,7 @@
 // Tests that we can combine a default impl that supplies one method with a
 // full impl that supplies the other, and they can invoke one another.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
     fn foo_one(&self) -> &'static str;
diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr
new file mode 100644 (file)
index 0000000..dc377dd
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-trait-item-not-implemented-rpass.rs:6:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 2a121e61aaa977c7524e25ad7f9d0eaf4a254a9f..3c5414469fac2ef6a5c2146d6c0c3d4cc98faea4 100644 (file)
@@ -1,6 +1,6 @@
 // Tests that default impls do not have to supply all items but regular impls do.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
     fn foo_one(&self) -> &'static str;
index b862a937066d4f2659f86af1b4a3f35212c7aea5..9d1eca1d6af76d4403bdee7ad868b3f2cb34384a 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-trait-item-not-implemented.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0046]: not all trait items implemented, missing: `foo_two`
   --> $DIR/specialization-trait-item-not-implemented.rs:18:1
    |
@@ -7,6 +16,6 @@ LL |     fn foo_two(&self) -> &'static str;
 LL | impl Foo for MyStruct {}
    | ^^^^^^^^^^^^^^^^^^^^^ missing `foo_two` in implementation
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0046`.
index 5c104449fe9c0b4ce69b3a4c7515010f54c3bff9..35e3b8725a82a522ff3ac19e1a812e211a4319f0 100644 (file)
@@ -2,7 +2,7 @@
 // - default impls do not have to supply all items and
 // - a default impl does not count as an impl (in this case, an incomplete default impl).
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
     fn foo_one(&self) -> &'static str;
index a55d79ee03534ee5746fbb4823ea108c9c52e443..6b8e559bc36343ed23eb191681bcc8c2fd2a019e 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-trait-not-implemented.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope
   --> $DIR/specialization-trait-not-implemented.rs:22:29
    |
@@ -19,6 +28,6 @@ note: `Foo` defines an item `foo_one`, perhaps you need to implement it
 LL | trait Foo {
    | ^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0599`.
index 232338d9d4d99134e6c47ed2c846d62c98de40d2..afd634725e365adfcfe9eeee34096d7fa0cf3d15 100644 (file)
@@ -1,6 +1,6 @@
 // Tests that a default impl still has to have a WF trait ref.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo<'a, T: Eq + 'a> { }
 
index f499c1f5698595e1de2a708386d8d5605265e67a..d45825651a8e27d1e9efd010a04c743d0983b836 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-wfcheck.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0277]: the trait bound `U: std::cmp::Eq` is not satisfied
   --> $DIR/specialization-wfcheck.rs:7:17
    |
@@ -12,6 +21,6 @@ help: consider restricting type parameter `U`
 LL | default impl<U: std::cmp::Eq> Foo<'static, U> for () {}
    |               ^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0277`.
index 8134333c58f7305bc366d7dd83ed1ae9d78a4ebc..8558a1efb82f3694167495e620a56af2cffafe90 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(negative_impls)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 struct S;
 struct Z;
index 254eaf51a646b8e7a396a9354f11b0d0edb1ea86..2449849725f383c71b2c0483ee61de7f78b110fc 100644 (file)
@@ -8,6 +8,15 @@ LL | default impl S {}
    |
    = note: only trait implementations may be annotated with `default`
 
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/validation.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error: impls of auto traits cannot be default
   --> $DIR/validation.rs:9:21
    |
@@ -36,6 +45,6 @@ error[E0750]: negative impls cannot be default impls
 LL | default impl !Tr for S {}
    | ^^^^^^^      ^
 
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0750`.
index 9546a5dd5f51699d64f466a3c9c94b2c4198ad2c..89350602f3652bc58710e4c2d8387bb01c3c77ad 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 pub struct Cloned<I>(I);
 
diff --git a/src/test/ui/specialization/issue-36804.stderr b/src/test/ui/specialization/issue-36804.stderr
new file mode 100644 (file)
index 0000000..744d882
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-36804.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 8ac6d8e9311fc5a9c079eb314ef9cb556e2b4d4b..9dd47a4a17e434b054255396fa66209ba3e329ce 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Regression test for a specialization-related ICE (#39448).
 
index 861a1d9e8fc661a8b13229485435c03c551e02bc..f3bb69b8f712a986fd7501ce83dfb45894f1ab79 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-39448.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0275]: overflow evaluating the requirement `T: FromA<U>`
   --> $DIR/issue-39448.rs:45:13
    |
@@ -7,6 +16,6 @@ LL |     x.foo(y.to()).to()
    = note: required because of the requirements on the impl of `FromA<U>` for `T`
    = note: required because of the requirements on the impl of `ToA<T>` for `U`
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0275`.
index 20e81e4359bacf0e177b28c8971796f4553c31d2..72630ee9c7055c7020511533e4a3b682d37f72aa 100644 (file)
@@ -4,7 +4,7 @@
 
 // check-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
     fn foo(&self);
diff --git a/src/test/ui/specialization/issue-39618.stderr b/src/test/ui/specialization/issue-39618.stderr
new file mode 100644 (file)
index 0000000..d40d17d
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-39618.rs:7:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/specialization/issue-44861.rs b/src/test/ui/specialization/issue-44861.rs
new file mode 100644 (file)
index 0000000..c37a627
--- /dev/null
@@ -0,0 +1,40 @@
+#![crate_type = "lib"]
+#![feature(specialization)]
+#![feature(unsize, coerce_unsized)]
+#![allow(incomplete_features)]
+
+use std::ops::CoerceUnsized;
+
+pub struct SmartassPtr<A: Smartass+?Sized>(A::Data);
+
+pub trait Smartass {
+    type Data;
+    type Data2: CoerceUnsized<*const [u8]>;
+}
+
+pub trait MaybeObjectSafe {}
+
+impl MaybeObjectSafe for () {}
+
+impl<T> Smartass for T {
+    type Data = <Self as Smartass>::Data2;
+    default type Data2 = ();
+    //~^ ERROR: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied
+}
+
+impl Smartass for () {
+    type Data2 = *const [u8; 1];
+}
+
+impl Smartass for dyn MaybeObjectSafe {
+    type Data = *const [u8];
+    type Data2 = *const [u8; 0];
+}
+
+impl<U: Smartass+?Sized, T: Smartass+?Sized> CoerceUnsized<SmartassPtr<T>> for SmartassPtr<U>
+    where <U as Smartass>::Data: std::ops::CoerceUnsized<<T as Smartass>::Data>
+{}
+
+pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeObjectSafe> {
+    s
+}
diff --git a/src/test/ui/specialization/issue-44861.stderr b/src/test/ui/specialization/issue-44861.stderr
new file mode 100644 (file)
index 0000000..b41b17e
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied
+  --> $DIR/issue-44861.rs:21:5
+   |
+LL |     type Data2: CoerceUnsized<*const [u8]>;
+   |     --------------------------------------- required by `Smartass::Data2`
+...
+LL |     default type Data2 = ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::CoerceUnsized<*const [u8]>` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 93f081d9558199ddd7f55bcc5310d9656e972b8c..29fc12066e8752d4d59d2e620e074fb0de6ed6b9 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 pub trait Foo {
     fn foo();
diff --git a/src/test/ui/specialization/issue-50452.stderr b/src/test/ui/specialization/issue-50452.stderr
new file mode 100644 (file)
index 0000000..c01817e
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-50452.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 1e1bfe9cf0755cec1035e40bfe117df5e70c7818..8046587020661b57a0ad2f63450a9d9068a3c86b 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Regression test for #52050: when inserting the blanket impl `I`
 // into the tree, we had to replace the child node for `Foo`, which
index 36f96b011983f0db757362adbeb9d23edc7d15a4..a7564ced055d5ef1ff5afad749b8e46291a60270 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-52050.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()`:
   --> $DIR/issue-52050.rs:28:1
    |
@@ -13,6 +22,6 @@ LL |   impl IntoPyDictPointer for ()
    |
    = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/specialization/issue-59435.rs b/src/test/ui/specialization/issue-59435.rs
new file mode 100644 (file)
index 0000000..47323d3
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+struct MyStruct {}
+
+trait MyTrait {
+    type MyType: Default;
+}
+
+impl MyTrait for i32 {
+    default type MyType = MyStruct;
+    //~^ ERROR: the trait bound `MyStruct: std::default::Default` is not satisfied
+}
+
+fn main() {
+    let _x: <i32 as MyTrait>::MyType = <i32 as MyTrait>::MyType::default();
+}
diff --git a/src/test/ui/specialization/issue-59435.stderr b/src/test/ui/specialization/issue-59435.stderr
new file mode 100644 (file)
index 0000000..fd512a5
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `MyStruct: std::default::Default` is not satisfied
+  --> $DIR/issue-59435.rs:11:5
+   |
+LL |     type MyType: Default;
+   |     --------------------- required by `MyTrait::MyType`
+...
+LL |     default type MyType = MyStruct;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `MyStruct`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index c3764ffaab83fd1f74867914e25fb7411d013be6..10f185c335144a198833f417d9f7f214f581947a 100644 (file)
@@ -4,7 +4,7 @@
 // check-pass
 // edition:2018
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 fn main() {}
 
diff --git a/src/test/ui/specialization/issue-63716-parse-async.stderr b/src/test/ui/specialization/issue-63716-parse-async.stderr
new file mode 100644 (file)
index 0000000..43620e1
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-63716-parse-async.rs:7:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 4371dd2e16747784fc67047d13384ac5a8cccbe0..d41b5355c2cded91a2db374db9e96214be95a947 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // check-pass
 
diff --git a/src/test/ui/specialization/issue-70442.stderr b/src/test/ui/specialization/issue-70442.stderr
new file mode 100644 (file)
index 0000000..f71e4c7
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-70442.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 403f718d7dd9fbf8350a772ebd46b8ba91faace6..b7d6ac829dd1482115632309389b38940af10805 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(specialization, associated_type_defaults)]
+//~^ WARN the feature `specialization` is incomplete
 
 // Test that attempting to override a non-default method or one not in the
 // parent impl causes an error.
index e6c5fc1441b2f4a934fb5644bcb0727a31b11d04..eae045b92c04d49521d2fb697391c9243fd5e0f6 100644 (file)
@@ -1,5 +1,14 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/non-defaulted-item-fail.rs:1:12
+   |
+LL | #![feature(specialization, associated_type_defaults)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
-  --> $DIR/non-defaulted-item-fail.rs:29:5
+  --> $DIR/non-defaulted-item-fail.rs:30:5
    |
 LL | / impl<T> Foo for Box<T> {
 LL | |     type Ty = bool;
@@ -14,7 +23,7 @@ LL |       type Ty = Vec<()>;
    = note: to specialize, `Ty` in the parent `impl` must be marked `default`
 
 error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
-  --> $DIR/non-defaulted-item-fail.rs:31:5
+  --> $DIR/non-defaulted-item-fail.rs:32:5
    |
 LL | / impl<T> Foo for Box<T> {
 LL | |     type Ty = bool;
@@ -29,7 +38,7 @@ LL |       const CONST: u8 = 42;
    = note: to specialize, `CONST` in the parent `impl` must be marked `default`
 
 error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
-  --> $DIR/non-defaulted-item-fail.rs:33:5
+  --> $DIR/non-defaulted-item-fail.rs:34:5
    |
 LL | / impl<T> Foo for Box<T> {
 LL | |     type Ty = bool;
@@ -44,7 +53,7 @@ LL |       fn foo(&self) -> bool { true }
    = note: to specialize, `foo` in the parent `impl` must be marked `default`
 
 error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
-  --> $DIR/non-defaulted-item-fail.rs:45:5
+  --> $DIR/non-defaulted-item-fail.rs:46:5
    |
 LL | impl<T> Foo for Vec<T> {}
    | ------------------------- parent `impl` is here
@@ -55,7 +64,7 @@ LL |     type Ty = Vec<()>;
    = note: to specialize, `Ty` in the parent `impl` must be marked `default`
 
 error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default`
-  --> $DIR/non-defaulted-item-fail.rs:47:5
+  --> $DIR/non-defaulted-item-fail.rs:48:5
    |
 LL | impl<T> Foo for Vec<T> {}
    | ------------------------- parent `impl` is here
@@ -66,7 +75,7 @@ LL |     const CONST: u8 = 42;
    = note: to specialize, `CONST` in the parent `impl` must be marked `default`
 
 error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
-  --> $DIR/non-defaulted-item-fail.rs:49:5
+  --> $DIR/non-defaulted-item-fail.rs:50:5
    |
 LL | impl<T> Foo for Vec<T> {}
    | ------------------------- parent `impl` is here
@@ -76,6 +85,6 @@ LL |     fn foo(&self) -> bool { true }
    |
    = note: to specialize, `foo` in the parent `impl` must be marked `default`
 
-error: aborting due to 6 previous errors
+error: aborting due to 6 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0520`.
index 15550bcce2a8a95f3e4616b49ea1f25c231fcea9..5d67160eb96ad8f2114c424ee0f778fa535818f8 100644 (file)
@@ -5,7 +5,7 @@
 
 // aux-build:go_trait.rs
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 extern crate go_trait;
 
diff --git a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr
new file mode 100644 (file)
index 0000000..7d08754
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-allowed-cross-crate.rs:8:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index b6a7a48972ac2691714c1fb161993c1f5daf22b4..cbfcb4719f6a495e14ecd30121eaf1b11473fafa 100644 (file)
@@ -2,7 +2,7 @@
 
 // Test that non-method associated functions can be specialized
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
     fn mk() -> Self;
diff --git a/src/test/ui/specialization/specialization-assoc-fns.stderr b/src/test/ui/specialization/specialization-assoc-fns.stderr
new file mode 100644 (file)
index 0000000..b127386
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-assoc-fns.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 6c359e51bc2e49c23a21b582911fc24a99a5cff8..721c934dbfab96cbb06b2a63cb0260c2db581cc0 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Tests a variety of basic specialization scenarios and method
 // dispatch for them.
diff --git a/src/test/ui/specialization/specialization-basics.stderr b/src/test/ui/specialization/specialization-basics.stderr
new file mode 100644 (file)
index 0000000..ad00cd8
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-basics.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index fa63c86632985ae3c37e90dd67a0f6d6fc25c779..4171505aa374c7d1066450bf9c73fb27789d08de 100644 (file)
@@ -2,7 +2,7 @@
 
 // aux-build:specialization_cross_crate.rs
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 extern crate specialization_cross_crate;
 
diff --git a/src/test/ui/specialization/specialization-cross-crate.stderr b/src/test/ui/specialization/specialization-cross-crate.stderr
new file mode 100644 (file)
index 0000000..7481eed
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-cross-crate.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 9ae3d1e9f3931cb58b3dd1f0e595a1a306903b4c..dcf68afa945bf2ff83408a44447e61e702c5aca5 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Test that default methods are cascaded correctly
 
diff --git a/src/test/ui/specialization/specialization-default-methods.stderr b/src/test/ui/specialization/specialization-default-methods.stderr
new file mode 100644 (file)
index 0000000..4fa19ad
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-default-methods.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index e9343f2360170fc1282fb581459e890d35217dc9..7f3ae951287ca3daf1aab119c55a6b2409497764 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Make sure we can't project defaulted associated types
 
index ac15ab0681a028c7ce328ca2ba041bf6e502137b..456eb6d5ca553b446a0fb1a7cf85fa366ce305d8 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-default-projection.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0308]: mismatched types
   --> $DIR/specialization-default-projection.rs:21:5
    |
@@ -28,6 +37,6 @@ LL |     generic::<()>()
    = help: consider constraining the associated type `<() as Foo>::Assoc` to `()`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0308`.
index acb86d889d43c0c8f533c820435ce769ee0be101..346471f11e4a8d5c7c34ecac81502da8d70392a2 100644 (file)
@@ -2,7 +2,7 @@
 // associated type in the impl defining it -- otherwise, what happens
 // if it's overridden?
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Example {
     type Output;
index 7233387eba1fabcdeba657c874762056c91af620..5e0221f07882ec994ff9a2f94eaff8d6c62b7ef2 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-default-types.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0308]: mismatched types
   --> $DIR/specialization-default-types.rs:15:9
    |
@@ -24,6 +33,6 @@ LL |     Example::generate(t)
    = help: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>`
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0308`.
index 57346b26d24ec2d8e85544aee516d8261e75dd1d..ae739b2358d5869074269f32e064e4a68e6c90fe 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Check a number of scenarios in which one impl tries to override another,
 // without correctly using `default`.
index 992e9abbd4ce2e4db90a339393e1dc94e95bf2b9..bb8b2a6c98e09f4ef997abd47b090bf65213f082 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-no-default.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
   --> $DIR/specialization-no-default.rs:20:5
    |
@@ -65,6 +74,6 @@ LL |       default fn redundant(&self) {}
    |
    = note: to specialize, `redundant` in the parent `impl` must be marked `default`
 
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0520`.
index 5606eaea3073dfb23dcecc911d725a89f6757e6c..be8dcc4232e7b7c96aad6fdf8866be7d4665c05a 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 #![allow(dead_code)]
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Ensure that specialization works for impls defined directly on a projection
 
diff --git a/src/test/ui/specialization/specialization-on-projection.stderr b/src/test/ui/specialization/specialization-on-projection.stderr
new file mode 100644 (file)
index 0000000..d91668d
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-on-projection.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 94e764f76366ee86bcd7c899f60122643682c067..cb7563e2760c2d4cc1f0162571cc1ca8668f0bcb 100644 (file)
@@ -2,7 +2,7 @@
 
 // Test that you can list the more specific impl before the more general one.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo {
     type Out;
diff --git a/src/test/ui/specialization/specialization-out-of-order.stderr b/src/test/ui/specialization/specialization-out-of-order.stderr
new file mode 100644 (file)
index 0000000..a17f9f1
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-out-of-order.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 90dbef3075b7f54f8e3e4fdf7f7b718e8542c54f..550d37082953990ee21f23d69f4fba62f5ff9fa6 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(negative_impls)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait MyTrait {}
 
index e2616534d20412679359a1147a8a2f52500c16af..6141174ba8c03c084ac83c92c8b73db3202e312d 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-overlap-negative.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0751]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType<_>`:
   --> $DIR/specialization-overlap-negative.rs:9:1
    |
@@ -6,6 +15,6 @@ LL | unsafe impl<T: Clone> Send for TestType<T> {}
 LL | impl<T: MyTrait> !Send for TestType<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0751`.
index 00b83c7e7a1b8eddd7d2328677901477c2973f55..b07efb2a5c1cdd631c3d664f70e83f31a1383f36 100644 (file)
@@ -4,7 +4,7 @@
 // projections involve specialization, so long as the associated type is
 // provided by the most specialized impl.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Assoc {
     type Output;
diff --git a/src/test/ui/specialization/specialization-overlap-projection.stderr b/src/test/ui/specialization/specialization-overlap-projection.stderr
new file mode 100644 (file)
index 0000000..6f1a594
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-overlap-projection.rs:7:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index c8ef8d61c1e8f0ebc0ab4ceb70815b883b31d2a4..6bee22ceb8b645a2c923941cc2fe09b1edbb478a 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Foo { fn foo() {} }
 impl<T: Clone> Foo for T {}
index 4275e7bdd85e27a2ca7f89b999d0e9b70852d94e..cf0f186a18337be7e57c8f6239316f36cb9bb69d 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-overlap.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0119]: conflicting implementations of trait `Foo` for type `std::vec::Vec<_>`:
   --> $DIR/specialization-overlap.rs:5:1
    |
@@ -30,6 +39,6 @@ LL | impl<T: Clone> Qux for T {}
 LL | impl<T: Eq> Qux for T {}
    | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
 
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0119`.
index e78035f171075c5016a8a525ee4dc907325fe5d3..17897d8b803d9a967ed33c674e93e7f9a172dd53 100644 (file)
@@ -2,7 +2,7 @@
 
 #![feature(optin_builtin_traits)]
 #![feature(negative_impls)]
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 auto trait Foo {}
 
index 44e60cad67aa4b3fe8f1af5430be8871aa066cc6..c44af22b8e63b8092722cf34cfda7362466d37b7 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-polarity.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0751]: found both positive and negative implementation of trait `Foo` for type `u8`:
   --> $DIR/specialization-polarity.rs:10:1
    |
@@ -14,6 +23,6 @@ LL | impl<T> !Bar for T {}
 LL | impl Bar for u8 {}
    | ^^^^^^^^^^^^^^^ positive implementation here
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0751`.
index 0081ed455c96044b546e4d5891b042eceaaf08ed..f1f0b47bb65036e223f36029b2184e1196a5b120 100644 (file)
@@ -2,7 +2,7 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Regression test for ICE when combining specialized associated types and type
 // aliases
diff --git a/src/test/ui/specialization/specialization-projection-alias.stderr b/src/test/ui/specialization/specialization-projection-alias.stderr
new file mode 100644 (file)
index 0000000..0c3659a
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-projection-alias.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 86cdccf131e223a0a1db1b0ef0cfbf01477223e6..700975e3b828f3e1ab739360f9610e67569ac584 100644 (file)
@@ -1,7 +1,7 @@
 // run-pass
 #![allow(dead_code)]
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Make sure we *can* project non-defaulted associated types
 // cf compile-fail/specialization-default-projection.rs
diff --git a/src/test/ui/specialization/specialization-projection.stderr b/src/test/ui/specialization/specialization-projection.stderr
new file mode 100644 (file)
index 0000000..c5c86f5
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-projection.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index a0f71d876931ed5291134d2513aaab69d825e5b6..fb85d8019218a7b551f15661cfc788538584ab01 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Test that you can specialize via an explicit trait hierarchy
 
diff --git a/src/test/ui/specialization/specialization-super-traits.stderr b/src/test/ui/specialization/specialization-super-traits.stderr
new file mode 100644 (file)
index 0000000..05bdfd4
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-super-traits.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index 2e32e3ff02d3e7c3ab75294037259af56466b9b4..5c2781a9c63a6eb4267ed4bb53f5d0dfb874f1ac 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Iterator {
     fn next(&self);
diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr
new file mode 100644 (file)
index 0000000..6284dd8
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-translate-projections-with-lifetimes.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index bdc6501df44b84e99a82bd4f875dfc481f6a3240..62d63590a6688e238923122058c70780eee462b4 100644 (file)
@@ -4,7 +4,7 @@
 // type parameters *and* rely on projections, and the type parameters are input
 // types on the trait.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Trait<T> {
     fn convert(&self) -> T;
diff --git a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr
new file mode 100644 (file)
index 0000000..b177941
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-translate-projections-with-params.rs:7:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index fcccb67902e58a92b95e1e86bfc369df809b404c..92ea9e2b85d3256830ed2a384350a743e1f7c549 100644 (file)
@@ -3,7 +3,7 @@
 // Ensure that provided items are inherited properly even when impls vary in
 // type parameters *and* rely on projections.
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 use std::convert::Into;
 
diff --git a/src/test/ui/specialization/specialization-translate-projections.stderr b/src/test/ui/specialization/specialization-translate-projections.stderr
new file mode 100644 (file)
index 0000000..fbb28e6
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-translate-projections.rs:6:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index bc08f33f8209371b7cf1af73fe34a199e5ef4fe0..ed81734f6ebd7cd981f0d8d968f47044ed3ccab7 100644 (file)
@@ -2,7 +2,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:9:60
    |
 LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
-   |                                                            ^^^^^^^^ statics cannot evaluate destructors
+   |                                                            ^^^^^^^^- value is dropped here
+   |                                                            |
+   |                                                            statics cannot evaluate destructors
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-drop-scope.rs:9:60
@@ -18,7 +20,9 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:13:59
    |
 LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
-   |                                                           ^^^^^^^^ constants cannot evaluate destructors
+   |                                                           ^^^^^^^^- value is dropped here
+   |                                                           |
+   |                                                           constants cannot evaluate destructors
 
 error[E0716]: temporary value dropped while borrowed
   --> $DIR/static-drop-scope.rs:13:59
@@ -34,37 +38,50 @@ error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:17:28
    |
 LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1;
-   |                            ^^^^^^^^^^^^^ statics cannot evaluate destructors
+   |                            ^^^^^^^^^^^^^ - value is dropped here
+   |                            |
+   |                            statics cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:20:27
    |
 LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1;
-   |                           ^^^^^^^^^^^^^ constants cannot evaluate destructors
+   |                           ^^^^^^^^^^^^^ - value is dropped here
+   |                           |
+   |                           constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:23:24
    |
 LL | const fn const_drop<T>(_: T) {}
-   |                        ^ constant functions cannot evaluate destructors
+   |                        ^      - value is dropped here
+   |                        |
+   |                        constant functions cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:27:5
    |
 LL |     (x, ()).1
    |     ^^^^^^^ constant functions cannot evaluate destructors
+LL |
+LL | }
+   | - value is dropped here
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:31:34
    |
 LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1;
-   |                                  ^^^^^^^^^^^^^^^^^^^ constants cannot evaluate destructors
+   |                                  ^^^^^^^^^^^^^^^^^^^ - value is dropped here
+   |                                  |
+   |                                  constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/static-drop-scope.rs:36:43
    |
 LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1;
-   |                                           ^^^^^^^^^^^ constants cannot evaluate destructors
+   |                                           ^^^^^^^^^^^ - value is dropped here
+   |                                           |
+   |                                           constants cannot evaluate destructors
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs
new file mode 100644 (file)
index 0000000..ef64d79
--- /dev/null
@@ -0,0 +1,28 @@
+trait Trait {
+    fn func1() -> Struct1<Self>; //~ ERROR E0277
+    fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277
+    fn func3() -> Struct3<Self>; //~ ERROR E0277
+    fn func4() -> Struct4<Self>; //~ ERROR E0277
+}
+
+struct Struct1<T>{
+    _t: std::marker::PhantomData<*const T>,
+}
+struct Struct2<'a, T>{
+    _t: &'a T,
+}
+struct Struct3<T>{
+    _t: T,
+}
+
+struct X<T>(T);
+
+struct Struct4<T>{
+    _t: X<T>,
+}
+
+struct Struct5<T: ?Sized>{
+    _t: X<T>, //~ ERROR E0277
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr
new file mode 100644 (file)
index 0000000..ee08f51
--- /dev/null
@@ -0,0 +1,107 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5
+   |
+LL | struct X<T>(T);
+   |          - required by this bound in `X`
+...
+LL | struct Struct5<T: ?Sized>{
+   |                - this type parameter needs to be `std::marker::Sized`
+LL |     _t: X<T>,
+   |     ^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `T`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
+   |
+LL | struct X<T>(T);
+   |          ^  - ...if indirection was used here: `Box<T>`
+   |          |
+   |          this could be changed to `T: ?Sized`...
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:2:19
+   |
+LL |     fn func1() -> Struct1<Self>;
+   |                   ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct1<T>{
+   |                - required by this bound in `Struct1`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+   |
+LL |     fn func1() -> Struct1<Self> where Self: std::marker::Sized;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Struct1<T: ?Sized>{
+   |                 ^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:3:23
+   |
+LL |     fn func2<'a>() -> Struct2<'a, Self>;
+   |                       ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct2<'a, T>{
+   |                    - required by this bound in `Struct2`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+   |
+LL |     fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Struct2<'a, T: ?Sized>{
+   |                     ^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:4:19
+   |
+LL |     fn func3() -> Struct3<Self>;
+   |                   ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct3<T>{
+   |                - required by this bound in `Struct3`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
+   |
+LL | struct Struct3<T>{
+   |                ^ this could be changed to `T: ?Sized`...
+LL |     _t: T,
+   |         - ...if indirection was used here: `Box<T>`
+help: consider further restricting `Self`
+   |
+LL |     fn func3() -> Struct3<Self> where Self: std::marker::Sized;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/adt-param-with-implicit-sized-bound.rs:5:19
+   |
+LL |     fn func4() -> Struct4<Self>;
+   |                   ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL | struct Struct4<T>{
+   |                - required by this bound in `Struct4`
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `Self`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider further restricting `Self`
+   |
+LL |     fn func4() -> Struct4<Self> where Self: std::marker::Sized;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | struct Struct4<T: ?Sized>{
+   |                 ^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 99ba4e2a646e52c82d5ec451cafe1b55483a3918..11372494772d0962c55e4d66faf252c6330ec8f5 100644 (file)
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `fn() -> impl std::future::Future {foo}: std::future::Future` is not satisfied
+error[E0277]: `fn() -> impl std::future::Future {foo}` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9
    |
 LL | async fn foo() {}
@@ -8,14 +8,15 @@ LL | fn bar(f: impl Future<Output=()>) {}
    |                ----------------- required by this bound in `bar`
 ...
 LL |     bar(foo);
-   |         ^^^ the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
+   |         ^^^ `fn() -> impl std::future::Future {foo}` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
 help: use parentheses to call the function
    |
 LL |     bar(foo());
    |            ^^
 
-error[E0277]: the trait bound `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]: std::future::Future` is not satisfied
+error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
    |
 LL | fn bar(f: impl Future<Output=()>) {}
@@ -24,8 +25,9 @@ LL | fn bar(f: impl Future<Output=()>) {}
 LL |     let async_closure = async || ();
    |                         -------- consider calling this closure
 LL |     bar(async_closure);
-   |         ^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
+   |         ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
    |
+   = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
 help: use parentheses to call the closure
    |
 LL |     bar(async_closure());
index 21fb8d4a2e68dc37d1b4276675c5a64f214362f6..ac819dce6db2b5cf2fc838cc1cf84361b71876f1 100644 (file)
@@ -1,6 +1,6 @@
 fn main() {
     let A = 3;
-    //~^ ERROR refutable pattern in local binding: `i32::MIN..=1i32` and
+    //~^ ERROR refutable pattern in local binding: `i32::MIN..=1_i32` and
     //~| interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     //~| SUGGESTION a_var
index 7a6269da07f3260658cf2c9eecdfd740bc291731..af64c09d5cadb5e6d3858b6c7603c46a271165c8 100644 (file)
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=1i32` and `3i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding: `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
   --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
    |
 LL |     let A = 3;
diff --git a/src/test/ui/suggestions/invalid-bin-op.rs b/src/test/ui/suggestions/invalid-bin-op.rs
new file mode 100644 (file)
index 0000000..bea1b91
--- /dev/null
@@ -0,0 +1,7 @@
+pub fn foo<T>(s: S<T>, t: S<T>) {
+    let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `S<T>`
+}
+
+struct S<T>(T);
+
+fn main() {}
diff --git a/src/test/ui/suggestions/invalid-bin-op.stderr b/src/test/ui/suggestions/invalid-bin-op.stderr
new file mode 100644 (file)
index 0000000..7668edd
--- /dev/null
@@ -0,0 +1,13 @@
+error[E0369]: binary operation `==` cannot be applied to type `S<T>`
+  --> $DIR/invalid-bin-op.rs:2:15
+   |
+LL |     let _ = s == t;
+   |             - ^^ - S<T>
+   |             |
+   |             S<T>
+   |
+   = note: the trait `std::cmp::PartialEq` is not implemented for `S<T>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
index 5cf170d566ca94acb9767161c8e4609de7d1526b..9ab060328537b56b08f0f3dcf6b023edfcd3fea5 100644 (file)
@@ -6,20 +6,23 @@ LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        |
    |        help: consider introducing lifetime `'a` here: `'a,`
 
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/missing-lifetimes-in-signature.rs:19:5
    |
 LL |   fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
-   |                            ------     ------------- ...is required to be `'static` by this...
-   |                            |
-   |                            data with this lifetime...
+   |                            ------ this data with an anonymous lifetime `'_`...
 ...
 LL | /     move || {
 LL | |         *dest = g.get();
 LL | |     }
-   | |_____^ ...and is captured here
+   | |_____^ ...is captured here...
    |
-help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 15:1
+note: ...and is required to live as long as `'static` here
+  --> $DIR/missing-lifetimes-in-signature.rs:15:37
+   |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+   |                                     ^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `dest`, you can add an explicit `'_` lifetime bound
    |
 LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |                                                   ^^^^
@@ -122,5 +125,5 @@ LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0261, E0309, E0621.
+Some errors have detailed explanations: E0261, E0309, E0621, E0759.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr
new file mode 100644 (file)
index 0000000..2407d13
--- /dev/null
@@ -0,0 +1,53 @@
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             -         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |             |
+   |             let's call the lifetime of this reference `'1`
+   |
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:39:9
+   |
+LL |       fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |               - let's call the lifetime of this reference `'1`
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:50:9
+   |
+LL |       fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |               -- lifetime `'a` defined here
+LL | /         Iter {
+LL | |             current: None,
+LL | |             remaining: self.0.iter(),
+LL | |         }
+   | |_________^ returning this value requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             --               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+   |             |
+   |             lifetime `'a` defined here
+   |
+   = help: consider replacing `'a` with `'static`
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.rs
new file mode 100644 (file)
index 0000000..f78edb1
--- /dev/null
@@ -0,0 +1,68 @@
+trait Foo {}
+impl<'a, T: Foo> Foo for &'a T {}
+impl<T: Foo + ?Sized> Foo for Box<T> {}
+
+struct Iter<'a, T> {
+    current: Option<Box<dyn Foo + 'a>>,
+    remaining: T,
+}
+
+impl<'a, T> Iterator for Iter<'a, T>
+where
+    T: Iterator,
+    T::Item: Foo + 'a,
+{
+    type Item = Box<dyn Foo + 'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let result = self.current.take();
+        self.current = Box::new(self.remaining.next()).map(|f| Box::new(f) as _);
+        result
+    }
+}
+
+struct Bar(Vec<Box<dyn Foo>>);
+
+impl Bar {
+    fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Baz(Vec<Box<dyn Foo>>);
+
+impl Baz {
+    fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Bat(Vec<Box<dyn Foo>>);
+
+impl Bat {
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+struct Ban(Vec<Box<dyn Foo>>);
+
+impl Ban {
+    fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+        Iter {
+            current: None,
+            remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
new file mode 100644 (file)
index 0000000..1257e9b
--- /dev/null
@@ -0,0 +1,95 @@
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:30:31
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |             ----- this data with an anonymous lifetime `'_`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                                                          ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
+   |                                                        ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:41:31
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |             ----- this data with an anonymous lifetime `'_`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:38:23
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
+   |                                                        ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:52:31
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                 -------- this data with lifetime `'a`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:49:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
+   |                                                               ^^^^
+
+error[E0759]: cannot infer an appropriate lifetime
+  --> $DIR/trait-object-nested-in-impl-trait.rs:63:31
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                 -------- this data with lifetime `'a`...
+...
+LL |             remaining: self.0.iter(),
+   |                        ------ ^^^^
+   |                        |
+   |                        ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
+   |                                                                 ^^^^
+help: to declare that the trait object captures data from argument `self`, you can add an explicit `'a` lifetime bound
+   |
+LL |     fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> {
+   |                                                               ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/suggestions/missing-trait-bound-for-op.fixed b/src/test/ui/suggestions/missing-trait-bound-for-op.fixed
new file mode 100644 (file)
index 0000000..6b24375
--- /dev/null
@@ -0,0 +1,7 @@
+// run-rustfix
+
+pub fn foo<T: std::cmp::PartialEq>(s: &[T], t: &[T]) {
+    let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `&[T]`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-trait-bound-for-op.rs b/src/test/ui/suggestions/missing-trait-bound-for-op.rs
new file mode 100644 (file)
index 0000000..df47be0
--- /dev/null
@@ -0,0 +1,7 @@
+// run-rustfix
+
+pub fn foo<T>(s: &[T], t: &[T]) {
+    let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `&[T]`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-trait-bound-for-op.stderr b/src/test/ui/suggestions/missing-trait-bound-for-op.stderr
new file mode 100644 (file)
index 0000000..0e0d397
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0369]: binary operation `==` cannot be applied to type `&[T]`
+  --> $DIR/missing-trait-bound-for-op.rs:4:15
+   |
+LL |     let _ = s == t;
+   |             - ^^ - &[T]
+   |             |
+   |             &[T]
+   |
+help: consider restricting type parameter `T`
+   |
+LL | pub fn foo<T: std::cmp::PartialEq>(s: &[T], t: &[T]) {
+   |             ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
index 96f1656bae4ac321c6b2cbfdb4149e3ed7744635..3c2226574ee9e7ca42f3c6dbf06caf77d6267e1b 100644 (file)
@@ -125,6 +125,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), C=()
    |                                                        ^^
    |
    = note: lifetime arguments must be provided before type arguments
+   = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
 
 error[E0747]: lifetime provided when a type was expected
   --> $DIR/suggest-move-types.rs:82:56
@@ -133,6 +134,7 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime<T, 'a, A=(), B=(), U, '
    |                                                        ^^
    |
    = note: lifetime arguments must be provided before type arguments
+   = help: reorder the arguments: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/suggestions/type-not-found-in-adt-field.rs b/src/test/ui/suggestions/type-not-found-in-adt-field.rs
new file mode 100644 (file)
index 0000000..4cbfe58
--- /dev/null
@@ -0,0 +1,9 @@
+struct Struct {
+    m: Vec<Someunknownname<String, ()>>, //~ ERROR cannot find type `Someunknownname` in this scope
+    //~^ NOTE not found in this scope
+}
+struct OtherStruct { //~ HELP you might be missing a type parameter
+    m: K, //~ ERROR cannot find type `K` in this scope
+    //~^ NOTE not found in this scope
+}
+fn main() {}
diff --git a/src/test/ui/suggestions/type-not-found-in-adt-field.stderr b/src/test/ui/suggestions/type-not-found-in-adt-field.stderr
new file mode 100644 (file)
index 0000000..e990fb5
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0412]: cannot find type `Someunknownname` in this scope
+  --> $DIR/type-not-found-in-adt-field.rs:2:12
+   |
+LL |     m: Vec<Someunknownname<String, ()>>,
+   |            ^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `K` in this scope
+  --> $DIR/type-not-found-in-adt-field.rs:6:8
+   |
+LL | struct OtherStruct {
+   |                   - help: you might be missing a type parameter: `<K>`
+LL |     m: K,
+   |        ^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/tag-variant-cast-non-nullary.fixed b/src/test/ui/tag-variant-cast-non-nullary.fixed
new file mode 100644 (file)
index 0000000..53e68c2
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+enum NonNullary {
+    Nullary,
+    Other(isize),
+}
+
+impl From<NonNullary> for isize {
+    fn from(val: NonNullary) -> isize {
+        match val {
+            NonNullary::Nullary => 0,
+            NonNullary::Other(i) => i,
+        }
+    }
+}
+
+fn main() {
+    let v = NonNullary::Nullary;
+    let val = isize::from(v); //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
+}
index bb34e82cdca374cbef1f97d6536add58f46c1203..0d0c6188ad114f2d3cb5c8efd121092f228ab320 100644 (file)
@@ -1,8 +1,19 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
 enum NonNullary {
     Nullary,
     Other(isize),
 }
 
+impl From<NonNullary> for isize {
+    fn from(val: NonNullary) -> isize {
+        match val {
+            NonNullary::Nullary => 0,
+            NonNullary::Other(i) => i,
+        }
+    }
+}
+
 fn main() {
     let v = NonNullary::Nullary;
     let val = v as isize; //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
index 87ec20f20d789de2925220635f5b6848397a1a91..ae2f5a7aead552f9346eb0a231865d2d2690ce62 100644 (file)
@@ -1,10 +1,10 @@
 error[E0605]: non-primitive cast: `NonNullary` as `isize`
-  --> $DIR/tag-variant-cast-non-nullary.rs:8:15
+  --> $DIR/tag-variant-cast-non-nullary.rs:19:15
    |
 LL |     let val = v as isize;
-   |               ^^^^^^^^^^
+   |               ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/terminal-width/flag-human.rs b/src/test/ui/terminal-width/flag-human.rs
new file mode 100644 (file)
index 0000000..e445a84
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: -Z terminal-width=20
+
+// This test checks that `-Z terminal-width` effects the human error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+    let _: () = 42;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/terminal-width/flag-human.stderr b/src/test/ui/terminal-width/flag-human.stderr
new file mode 100644 (file)
index 0000000..393dcf2
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/flag-human.rs:7:17
+   |
+LL | ..._: () = 42;
+   |       --   ^^ expected `()`, found integer
+   |       |
+   |       expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/terminal-width/flag-json.rs b/src/test/ui/terminal-width/flag-json.rs
new file mode 100644 (file)
index 0000000..eabdc59
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: -Z terminal-width=20 --error-format=json
+
+// This test checks that `-Z terminal-width` effects the JSON error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+    let _: () = 42;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/terminal-width/flag-json.stderr b/src/test/ui/terminal-width/flag-json.stderr
new file mode 100644 (file)
index 0000000..29730cc
--- /dev/null
@@ -0,0 +1,32 @@
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code example:
+
+```compile_fail,E0308
+let x: i32 = \"I am not a number!\";
+//     ~~~   ~~~~~~~~~~~~~~~~~~~~
+//      |             |
+//      |    initializing expression;
+//      |    compiler infers type `&str`
+//      |
+//    type `i32` assigned to variable `x`
+```
+
+This error occurs when the compiler is unable to infer the concrete type of a
+variable. It can occur in several cases, the most common being a mismatch
+between two types: the type the author explicitly assigned, and the type the
+compiler inferred.
+"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":"    let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":"    let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
+  --> $DIR/flag-json.rs:7:17
+   |
+LL | ..._: () = 42;
+   |       --   ^^ expected `()`, found integer
+   |       |
+   |       expected due to this
+
+"}
+{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
+
+"}
+{"message":"For more information about this error, try `rustc --explain E0308`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0308`.
+"}
diff --git a/src/test/ui/tls.rs b/src/test/ui/tls.rs
new file mode 100644 (file)
index 0000000..fbd3413
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+// ignore-emscripten no threads support
+// compile-flags: -O
+
+#![feature(thread_local)]
+
+#[thread_local]
+static S: u32 = 222;
+
+fn main() {
+    let local = &S as *const u32 as usize;
+    let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap();
+    assert_ne!(local, foreign);
+}
diff --git a/src/test/ui/traits/auto-traits.rs b/src/test/ui/traits/auto-traits.rs
deleted file mode 100644 (file)
index 15fdddc..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// run-pass
-#![allow(unused_doc_comments)]
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Auto {}
-unsafe auto trait AutoUnsafe {}
-
-impl !Auto for bool {}
-impl !AutoUnsafe for bool {}
-
-struct AutoBool(bool);
-
-impl Auto for AutoBool {}
-unsafe impl AutoUnsafe for AutoBool {}
-
-fn take_auto<T: Auto>(_: T) {}
-fn take_auto_unsafe<T: AutoUnsafe>(_: T) {}
-
-fn main() {
-    // Parse inside functions.
-    auto trait AutoInner {}
-    unsafe auto trait AutoUnsafeInner {}
-
-    take_auto(0);
-    take_auto(AutoBool(true));
-    take_auto_unsafe(0);
-    take_auto_unsafe(AutoBool(true));
-
-    /// Auto traits are allowed in trait object bounds.
-    let _: &(dyn Send + Auto) = &0;
-}
index 2d50bc83ec304f2a1847298744ca511f5f462bf3..c68bca432fa8667e7b5777dacc4959284f44b719 100644 (file)
@@ -1,5 +1,6 @@
 #![feature(negative_impls)]
 #![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
 
 trait MyTrait {
     type Foo;
index a70bbe6b948d1ce1ac5079523e7fff352e619fb1..50e74373b53bbd4c867a8fd16aa49e47123ea5c5 100644 (file)
@@ -1,9 +1,18 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/negative-default-impls.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0750]: negative impls cannot be default impls
-  --> $DIR/negative-default-impls.rs:8:1
+  --> $DIR/negative-default-impls.rs:9:1
    |
 LL | default impl !MyTrait for u32 {}
    | ^^^^^^^      ^
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0750`.
index 877c3e8af4f1ae617215c78e0ecf88b1e2e0136f..35297ab124ed06f44381764f7ca535ac608bd1fd 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 #![feature(negative_impls)]
 
 // Test a negative impl that "specializes" another negative impl.
diff --git a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr
new file mode 100644 (file)
index 0000000..8b536de
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/negative-specializes-negative.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
index da22e43377f52a1ec51e17a4402726a14f8f7f2f..4281eedaf631c9173ac175c84d5d44cfd04486eb 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 #![feature(negative_impls)]
 
 // Negative impl for u32 cannot "specialize" the base impl.
index 079546a7df40b8816e96fa6c39f2ed943d117d37..89ef15e89ac96a177a06ddff4ea54b3c835ec453 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/negative-specializes-positive-item.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
   --> $DIR/negative-specializes-positive-item.rs:11:1
    |
@@ -7,6 +16,6 @@ LL | impl<T> MyTrait for T {
 LL | impl !MyTrait for u32 {}
    | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0751`.
index 1939a098b50ee08aa8d892f7e38cc5459b486a49..0e227691e0404e20186f2627ab651ba055215b6f 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 #![feature(negative_impls)]
 
 // Negative impl for u32 cannot "specialize" the base impl.
index ea005c1cbe0c69dab2a0a017b0464c757d32e193..e45d5a251ab263b0bcad9c2b255718b45a4d310d 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/negative-specializes-positive.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
   --> $DIR/negative-specializes-positive.rs:7:1
    |
@@ -6,6 +15,6 @@ LL | impl<T> MyTrait for T {}
 LL | impl !MyTrait for u32 {}
    | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0751`.
index f2c5f507a4ebbd5fcf5126b97589fdd05e893fd8..a06b357654068b2604fca2540ff841b3a7e38f74 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 #![feature(negative_impls)]
 
 trait MyTrait {}
index a24d7aa442f4ab97326a87a2ae287e26adffd323..49c16d474040e81102a085d941e5cbb25b382230 100644 (file)
@@ -1,3 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/positive-specializes-negative.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
 error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
   --> $DIR/positive-specializes-negative.rs:7:1
    |
@@ -6,6 +15,6 @@ LL | impl<T> !MyTrait for T {}
 LL | impl MyTrait for u32 {}
    | ^^^^^^^^^^^^^^^^^^^^ positive implementation here
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0751`.
index 7fd5c11fcf09049992102ec9a4f31d5750ae6175..3be4f1109731176d132b4bd27ae86e38932082ee 100644 (file)
@@ -20,13 +20,6 @@ error[E0599]: no method named `b` found for struct `S` in the current scope
 LL | struct S;
    | --------- method `b` not found for this
 ...
-LL |         fn b(&self) { }
-   |            -
-   |            |
-   |            the method is available for `std::boxed::Box<S>` here
-   |            the method is available for `std::sync::Arc<S>` here
-   |            the method is available for `std::rc::Rc<S>` here
-...
 LL |     S.b();
    |       ^ method not found in `S`
    |
index 29216f36f5f313aa4484b5c89df975fa52a24d51..507d53dc07c4c9e4d2684db8afee0dfb3be963cf 100644 (file)
@@ -5,6 +5,11 @@ LL |     a * b
    |     - ^ - f64
    |     |
    |     &T
+   |
+help: consider further restricting this bound
+   |
+LL | fn foo<T: MyMul<f64, f64> + std::ops::Mul<Output = f64>>(a: &T, b: f64) -> f64 {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed
new file mode 100644 (file)
index 0000000..2bb34b0
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+use std::net::TcpListener;
+
+struct NoToSocketAddrs(String);
+
+impl std::ops::Deref for NoToSocketAddrs {
+    type Target = String;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn main() {
+    let _works = TcpListener::bind("some string");
+    let bad = NoToSocketAddrs("bad".to_owned());
+    let _errors = TcpListener::bind(&*bad);
+    //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs
new file mode 100644 (file)
index 0000000..33d5246
--- /dev/null
@@ -0,0 +1,18 @@
+// run-rustfix
+use std::net::TcpListener;
+
+struct NoToSocketAddrs(String);
+
+impl std::ops::Deref for NoToSocketAddrs {
+    type Target = String;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn main() {
+    let _works = TcpListener::bind("some string");
+    let bad = NoToSocketAddrs("bad".to_owned());
+    let _errors = TcpListener::bind(&bad);
+    //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr
new file mode 100644 (file)
index 0000000..0bf9794
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+  --> $DIR/trait-suggest-deferences-issue-39029.rs:16:37
+   |
+LL |     let _errors = TcpListener::bind(&bad);
+   |                                     ^^^^
+   |                                     |
+   |                                     the trait `std::net::ToSocketAddrs` is not implemented for `NoToSocketAddrs`
+   |                                     help: consider adding dereference here: `&*bad`
+   | 
+  ::: $SRC_DIR/libstd/net/tcp.rs:LL:COL
+   |
+LL |     pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+   |                    ------------- required by this bound in `std::net::TcpListener::bind`
+   |
+   = note: required because of the requirements on the impl of `std::net::ToSocketAddrs` for `&NoToSocketAddrs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed
new file mode 100644 (file)
index 0000000..fa7b916
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+fn takes_str(_x: &str) {}
+
+fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+
+trait SomeTrait {}
+impl SomeTrait for &'_ str {}
+impl SomeTrait for char {}
+
+fn main() {
+    let string = String::new();
+    takes_str(&string);             // Ok
+    takes_type_parameter(&*string);  // Error
+    //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs
new file mode 100644 (file)
index 0000000..e785f01
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+fn takes_str(_x: &str) {}
+
+fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+
+trait SomeTrait {}
+impl SomeTrait for &'_ str {}
+impl SomeTrait for char {}
+
+fn main() {
+    let string = String::new();
+    takes_str(&string);             // Ok
+    takes_type_parameter(&string);  // Error
+    //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr
new file mode 100644 (file)
index 0000000..9c2a582
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `&std::string::String: SomeTrait` is not satisfied
+  --> $DIR/trait-suggest-deferences-issue-62530.rs:13:26
+   |
+LL | fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+   |                                            --------- required by this bound in `takes_type_parameter`
+...
+LL |     takes_type_parameter(&string);  // Error
+   |                          ^^^^^^^
+   |                          |
+   |                          the trait `SomeTrait` is not implemented for `&std::string::String`
+   |                          help: consider adding dereference here: `&*string`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed b/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed
new file mode 100644 (file)
index 0000000..b7160b7
--- /dev/null
@@ -0,0 +1,36 @@
+// run-rustfix
+use std::ops::Deref;
+
+trait Happy {}
+struct LDM;
+impl Happy for &LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+    type Target = LDM;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Bar {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Baz {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+    let baz = Baz(Bar(Foo(LDM)));
+    foo(&***baz);
+    //~^ ERROR the trait bound `&Baz: Happy` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs
new file mode 100644 (file)
index 0000000..9ac5517
--- /dev/null
@@ -0,0 +1,36 @@
+// run-rustfix
+use std::ops::Deref;
+
+trait Happy {}
+struct LDM;
+impl Happy for &LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+    type Target = LDM;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Bar {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Baz {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+    let baz = Baz(Bar(Foo(LDM)));
+    foo(&baz);
+    //~^ ERROR the trait bound `&Baz: Happy` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr
new file mode 100644 (file)
index 0000000..add34a5
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `&Baz: Happy` is not satisfied
+  --> $DIR/trait-suggest-deferences-multiple-0.rs:34:9
+   |
+LL | fn foo<T>(_: T) where T: Happy {}
+   |                          ----- required by this bound in `foo`
+...
+LL |     foo(&baz);
+   |         ^^^^
+   |         |
+   |         the trait `Happy` is not implemented for `&Baz`
+   |         help: consider adding dereference here: `&***baz`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs
new file mode 100644 (file)
index 0000000..91c6c79
--- /dev/null
@@ -0,0 +1,54 @@
+use std::ops::{Deref, DerefMut};
+
+trait Happy {}
+struct LDM;
+impl Happy for &mut LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+    type Target = LDM;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Bar {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Baz {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl DerefMut for Foo {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Bar {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Baz {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+    // Currently the compiler doesn't try to suggest dereferences for situations
+    // where DerefMut involves. So this test is meant to ensure compiler doesn't
+    // generate incorrect help message.
+    let mut baz = Baz(Bar(Foo(LDM)));
+    foo(&mut baz);
+    //~^ ERROR the trait bound `&mut Baz: Happy` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr
new file mode 100644 (file)
index 0000000..e90278f
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&mut Baz: Happy` is not satisfied
+  --> $DIR/trait-suggest-deferences-multiple-1.rs:52:9
+   |
+LL | fn foo<T>(_: T) where T: Happy {}
+   |                          ----- required by this bound in `foo`
+...
+LL |     foo(&mut baz);
+   |         ^^^^^^^^ the trait `Happy` is not implemented for `&mut Baz`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/traits-inductive-overflow-lifetime.rs b/src/test/ui/traits/traits-inductive-overflow-lifetime.rs
new file mode 100644 (file)
index 0000000..205d50a
--- /dev/null
@@ -0,0 +1,30 @@
+// Test that we don't hit the recursion limit for short cycles involving lifetimes.
+
+// Shouldn't hit this, we should realize that we're in a cycle sooner.
+#![recursion_limit="20"]
+
+trait NotAuto {}
+trait Y {
+    type P;
+}
+
+impl<'a> Y for C<'a> {
+    type P = Box<X<C<'a>>>;
+}
+
+struct C<'a>(&'a ());
+struct X<T: Y>(T::P);
+
+impl<T: NotAuto> NotAuto for Box<T> {}
+impl<T: Y> NotAuto for X<T> where T::P: NotAuto {}
+impl<'a> NotAuto for C<'a> {}
+
+fn is_send<S: NotAuto>() {}
+//~^ NOTE: required
+
+fn main() {
+    // Should only be a few notes.
+    is_send::<X<C<'static>>>();
+    //~^ ERROR overflow evaluating
+    //~| NOTE: required
+}
diff --git a/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr b/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr
new file mode 100644 (file)
index 0000000..9a22722
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0275]: overflow evaluating the requirement `std::boxed::Box<X<C<'_>>>: NotAuto`
+  --> $DIR/traits-inductive-overflow-lifetime.rs:27:5
+   |
+LL | fn is_send<S: NotAuto>() {}
+   |               ------- required by this bound in `is_send`
+...
+LL |     is_send::<X<C<'static>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
index 002fba9ce810131711b900581d2b2ef68238397c..499334d983b1f1b38965c06be88b0cca8dac5279 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(specialization)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 trait Specializable { type Output; }
 
diff --git a/src/test/ui/transmute-specialization.stderr b/src/test/ui/transmute-specialization.stderr
new file mode 100644 (file)
index 0000000..0231505
--- /dev/null
@@ -0,0 +1,11 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/transmute-specialization.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
new file mode 100644 (file)
index 0000000..8c9cb74
--- /dev/null
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
+
index 1c2051e7eaeebef25bdef7008e334b58493be71a..41e019247c9426c5edbfcd33cf7ac84390a7da24 100644 (file)
@@ -14,8 +14,8 @@ trait Foo {
 struct X;
 
 impl Foo for X {
-    type Bar = impl Baz<Self, Self>; //~ ERROR type mismatch in closure arguments
-    //~^ ERROR type mismatch resolving
+    type Bar = impl Baz<Self, Self>;
+    //~^ ERROR mismatched types
 
     fn bar(&self) -> Self::Bar {
         |x| x
index cc121ac89fb8d756033655c89870fb82000950dc..cd637056c94add66003e178a0a50eeb2ac962b44 100644 (file)
@@ -1,23 +1,12 @@
-error[E0631]: type mismatch in closure arguments
+error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
    |
 LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r X) -> _`
-...
-LL |         |x| x
-   |         ----- found signature of `fn(_) -> _`
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: the return type of a function must have a statically known size
+   = note: expected type `std::ops::FnOnce<(&X,)>`
+              found type `std::ops::FnOnce<(&X,)>`
 
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-57611-trait-alias.rs:21:9: 21:14] as std::ops::FnOnce<(&'r X,)>>::Output == &'r X`
-  --> $DIR/issue-57611-trait-alias.rs:17:16
-   |
-LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
-   |
-   = note: the return type of a function must have a statically known size
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
index 4fbbf3475280355f7a93983c669e399efc80bef4..a6b7e35b488b17388d9fc2502c64001a8d0c9aa6 100644 (file)
@@ -16,9 +16,7 @@ error[E0605]: non-primitive cast: `impl std::fmt::Debug` as `&'static str`
   --> $DIR/never_reveal_concrete_type.rs:14:13
    |
 LL |     let _ = x as &'static str;
-   |             ^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs b/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs
new file mode 100644 (file)
index 0000000..e443626
--- /dev/null
@@ -0,0 +1,25 @@
+// check-pass
+
+// rust-lang/rust#68590: confusing diagnostics when reborrowing through DerefMut.
+
+use std::cell::RefCell;
+
+struct A;
+
+struct S<'a> {
+    a: &'a mut A,
+}
+
+fn take_a(_: &mut A) {}
+
+fn test<'a>(s: &RefCell<S<'a>>) {
+    let mut guard = s.borrow_mut();
+    take_a(guard.a);
+    let _s2 = S { a: guard.a };
+}
+
+fn main() {
+    let a = &mut A;
+    let s = RefCell::new(S { a });
+    test(&s);
+}
diff --git a/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs b/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs
new file mode 100644 (file)
index 0000000..3ea0538
--- /dev/null
@@ -0,0 +1,21 @@
+// check-pass
+
+// rust-lang/rust#72225: confusing diagnostics when calling FnMut through DerefMut.
+
+use std::cell::RefCell;
+
+struct S {
+    f: Box<dyn FnMut()>
+}
+
+fn test(s: &RefCell<S>) {
+    let mut guard = s.borrow_mut();
+    (guard.f)();
+}
+
+fn main() {
+    let s = RefCell::new(S {
+        f: Box::new(|| ())
+    });
+    test(&s);
+}
diff --git a/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.rs b/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.rs
new file mode 100644 (file)
index 0000000..0cf77da
--- /dev/null
@@ -0,0 +1,58 @@
+// check-pass
+//
+// rust-lang/rust#73592: borrow_mut through Deref should work.
+//
+// Before #72280, when we see something like `&mut *rcvr.method()`, we
+// incorrectly requires `rcvr` to be type-checked as a mut place. While this
+// requirement is usually correct for smart pointers, it is overly restrictive
+// for types like `Mutex` or `RefCell` which can produce a guard that
+// implements `DerefMut` from `&self`.
+//
+// Making it more confusing, because we use Deref as the fallback when DerefMut
+// is implemented, we won't see an issue when the smart pointer does not
+// implement `DerefMut`. It only causes an issue when `rcvr` is obtained via a
+// type that implements both `Deref` or `DerefMut`.
+//
+// This bug is only discovered in #73592 after it is already fixed as a side-effect
+// of a refactoring made in #72280.
+
+#![warn(unused_mut)]
+
+use std::pin::Pin;
+use std::cell::RefCell;
+
+struct S(RefCell<()>);
+
+fn test_pin(s: Pin<&S>) {
+    // This works before #72280.
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_pin_mut(s: Pin<&mut S>) {
+    // This should compile but didn't before #72280.
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_vec(s: &Vec<RefCell<()>>) {
+    // This should compile but didn't before #72280.
+    let _ = &mut *s[0].borrow_mut();
+}
+
+fn test_mut_pin(mut s: Pin<&S>) {
+    //~^ WARN variable does not need to be mutable
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn test_mut_pin_mut(mut s: Pin<&mut S>) {
+    //~^ WARN variable does not need to be mutable
+    let _ = &mut *s.0.borrow_mut();
+}
+
+fn main() {
+    let mut s = S(RefCell::new(()));
+    test_pin(Pin::new(&s));
+    test_pin_mut(Pin::new(&mut s));
+    test_mut_pin(Pin::new(&s));
+    test_mut_pin_mut(Pin::new(&mut s));
+    test_vec(&vec![s.0]);
+}
diff --git a/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.stderr b/src/test/ui/typeck/issue-73592-borrow_mut-through-deref.stderr
new file mode 100644 (file)
index 0000000..51303ad
--- /dev/null
@@ -0,0 +1,24 @@
+warning: variable does not need to be mutable
+  --> $DIR/issue-73592-borrow_mut-through-deref.rs:41:17
+   |
+LL | fn test_mut_pin(mut s: Pin<&S>) {
+   |                 ----^
+   |                 |
+   |                 help: remove this `mut`
+   |
+note: the lint level is defined here
+  --> $DIR/issue-73592-borrow_mut-through-deref.rs:19:9
+   |
+LL | #![warn(unused_mut)]
+   |         ^^^^^^^^^^
+
+warning: variable does not need to be mutable
+  --> $DIR/issue-73592-borrow_mut-through-deref.rs:46:21
+   |
+LL | fn test_mut_pin_mut(mut s: Pin<&mut S>) {
+   |                     ----^
+   |                     |
+   |                     help: remove this `mut`
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.rs b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.rs
deleted file mode 100644 (file)
index 8824a6d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Magic : Sized where Option<Self> : Magic {} //~ ERROR E0568
-impl<T:Magic> Magic for T {}
-
-fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
-
-#[derive(Debug)]
-struct NoClone;
-
-fn main() {
-    let (a, b) = copy(NoClone);
-    println!("{:?} {:?}", a, b);
-}
diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr
deleted file mode 100644 (file)
index 63b3300..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0568]: auto traits cannot have super traits
-  --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:20
-   |
-LL | auto trait Magic : Sized where Option<Self> : Magic {}
-   |            -----   ^^^^^ help: remove the super traits
-   |            |
-   |            auto trait cannot have super traits
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0568`.
diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.rs b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.rs
deleted file mode 100644 (file)
index edbca91..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// This test is for #29859, we need to ensure auto traits,
-// (also known previously as default traits), do not have
-// supertraits. Since the compiler synthesizes these
-// instances on demand, we are essentially enabling
-// users to write axioms if we view trait selection,
-// as a proof system.
-//
-// For example the below test allows us to add the rule:
-//  forall (T : Type), T : Copy
-//
-// Providing a copy instance for *any* type, which
-// is most definitely unsound. Imagine copying a
-// type that contains a mutable reference, enabling
-// mutable aliasing.
-//
-// You can imagine an even more dangerous test,
-// which currently compiles on nightly.
-//
-// fn main() {
-//    let mut i = 10;
-//    let (a, b) = copy(&mut i);
-//    println!("{:?} {:?}", a, b);
-// }
-
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Magic: Copy {} //~ ERROR E0568
-impl<T:Magic> Magic for T {}
-
-fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
-
-#[derive(Debug)]
-struct NoClone;
-
-fn main() {
-    let (a, b) = copy(NoClone);
-    println!("{:?} {:?}", a, b);
-}
diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr
deleted file mode 100644 (file)
index 796638f..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0568]: auto traits cannot have super traits
-  --> $DIR/typeck-auto-trait-no-supertraits.rs:28:19
-   |
-LL | auto trait Magic: Copy {}
-   |            -----  ^^^^ help: remove the super traits
-   |            |
-   |            auto trait cannot have super traits
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0568`.
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.rs b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.rs
deleted file mode 100644 (file)
index 71ac2b4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait MyTrait {}
-
-struct MyS;
-
-struct MyS2;
-
-impl !MyTrait for MyS2 {}
-
-fn is_mytrait<T: MyTrait>() {}
-
-fn main() {
-    is_mytrait::<MyS>();
-
-    is_mytrait::<(MyS2, MyS)>();
-    //~^ ERROR `MyS2: MyTrait` is not satisfied
-}
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr
deleted file mode 100644 (file)
index 53ba9b8..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)`
-  --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:5
-   |
-LL | fn is_mytrait<T: MyTrait>() {}
-   |                  ------- required by this bound in `is_mytrait`
-...
-LL |     is_mytrait::<(MyS2, MyS)>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`
-   |
-   = help: the following implementations were found:
-             <MyS2 as MyTrait>
-   = note: required because it appears within the type `(MyS2, MyS)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.rs b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.rs
deleted file mode 100644 (file)
index 6483b92..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait MyTrait {}
-
-impl<T> !MyTrait for *mut T {}
-
-struct MyS;
-
-struct MyS2;
-
-impl !MyTrait for MyS2 {}
-
-struct MyS3;
-
-fn is_mytrait<T: MyTrait>() {}
-
-fn main() {
-    is_mytrait::<MyS>();
-
-    is_mytrait::<MyS2>();
-    //~^ ERROR `MyS2: MyTrait` is not satisfied
-}
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr
deleted file mode 100644 (file)
index bc50000..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied
-  --> $DIR/typeck-default-trait-impl-constituent-types.rs:21:18
-   |
-LL | fn is_mytrait<T: MyTrait>() {}
-   |                  ------- required by this bound in `is_mytrait`
-...
-LL |     is_mytrait::<MyS2>();
-   |                  ^^^^ the trait `MyTrait` is not implemented for `MyS2`
-   |
-   = help: the following implementations were found:
-             <MyS2 as MyTrait>
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation.rs b/src/test/ui/typeck/typeck-default-trait-impl-negation.rs
deleted file mode 100644 (file)
index 47cab60..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait MyTrait {}
-
-unsafe auto trait MyUnsafeTrait {}
-
-struct ThisImplsTrait;
-
-impl !MyUnsafeTrait for ThisImplsTrait {}
-
-
-struct ThisImplsUnsafeTrait;
-
-impl !MyTrait for ThisImplsUnsafeTrait {}
-
-fn is_my_trait<T: MyTrait>() {}
-fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
-
-fn main() {
-    is_my_trait::<ThisImplsTrait>();
-    is_my_trait::<ThisImplsUnsafeTrait>();
-    //~^ ERROR `ThisImplsUnsafeTrait: MyTrait` is not satisfied
-
-    is_my_unsafe_trait::<ThisImplsTrait>();
-    //~^ ERROR `ThisImplsTrait: MyUnsafeTrait` is not satisfied
-
-    is_my_unsafe_trait::<ThisImplsUnsafeTrait>();
-}
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr
deleted file mode 100644 (file)
index 76a6994..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0277]: the trait bound `ThisImplsUnsafeTrait: MyTrait` is not satisfied
-  --> $DIR/typeck-default-trait-impl-negation.rs:22:19
-   |
-LL | fn is_my_trait<T: MyTrait>() {}
-   |                   ------- required by this bound in `is_my_trait`
-...
-LL |     is_my_trait::<ThisImplsUnsafeTrait>();
-   |                   ^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait`
-   |
-   = help: the following implementations were found:
-             <ThisImplsUnsafeTrait as MyTrait>
-
-error[E0277]: the trait bound `ThisImplsTrait: MyUnsafeTrait` is not satisfied
-  --> $DIR/typeck-default-trait-impl-negation.rs:25:26
-   |
-LL | fn is_my_unsafe_trait<T: MyUnsafeTrait>() {}
-   |                          ------------- required by this bound in `is_my_unsafe_trait`
-...
-LL |     is_my_unsafe_trait::<ThisImplsTrait>();
-   |                          ^^^^^^^^^^^^^^ the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait`
-   |
-   = help: the following implementations were found:
-             <ThisImplsTrait as MyUnsafeTrait>
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-precedence.rs b/src/test/ui/typeck/typeck-default-trait-impl-precedence.rs
deleted file mode 100644 (file)
index 614a5ff..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Test that declaring that `&T` is `Defaulted` if `T:Signed` implies
-// that other `&T` is NOT `Defaulted` if `T:Signed` does not hold. In
-// other words, the auto impl only applies if there are no existing
-// impls whose types unify.
-
-#![feature(optin_builtin_traits)]
-#![feature(negative_impls)]
-
-auto trait Defaulted { }
-impl<'a,T:Signed> Defaulted for &'a T { }
-impl<'a,T:Signed> Defaulted for &'a mut T { }
-fn is_defaulted<T:Defaulted>() { }
-
-trait Signed { }
-impl Signed for i32 { }
-
-fn main() {
-    is_defaulted::<&'static i32>();
-    is_defaulted::<&'static u32>();
-    //~^ ERROR `u32: Signed` is not satisfied
-}
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr b/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr
deleted file mode 100644 (file)
index 5962d19..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0277]: the trait bound `u32: Signed` is not satisfied
-  --> $DIR/typeck-default-trait-impl-precedence.rs:19:5
-   |
-LL | fn is_defaulted<T:Defaulted>() { }
-   |                   --------- required by this bound in `is_defaulted`
-...
-LL |     is_defaulted::<&'static u32>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
-   |
-   = note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
index a6e26614a6a50bd6122e64110f3da370b924d8cd..e2082d4f78e7026bac85bd273ee34027880b416b 100644 (file)
@@ -1,23 +1,29 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-unsafe fn square(x: &isize) -> isize { (*x) * (*x) }
+unsafe fn square(x: &isize) -> isize {
+    (*x) * (*x)
+}
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+    0
+}
 
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn c() {
@@ -25,4 +31,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
index b9ee9e460201a371c1dc89536ffb4aec9cb69489..b06f745e7c1f184f56a096ddd3272d0cd12e527d 100644 (file)
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-LL |     let x = call_it(&square, 22);
-   |                     ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-LL |     let y = call_it_mut(&mut square, 22);
-   |                         ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:24:26
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 LL |     let z = call_it_once(square, 22);
    |                          ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
    |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index dd3b1afc39f3114fed39a0992589ec2eeb0ae045..dd76c597d28ad1f461d31858fcdcd66cf5daded3 100644 (file)
@@ -1,23 +1,29 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-extern "C" fn square(x: &isize) -> isize { (*x) * (*x) }
+extern "C" fn square(x: &isize) -> isize {
+    (*x) * (*x)
+}
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+    0
+}
 
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn c() {
@@ -25,4 +31,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
index 654b626cf65ccd6ad447c648d12ae4b4c3256fe4..8f6945cda806c69aa4956039d634ab20f58cd820 100644 (file)
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:12:21
+  --> $DIR/unboxed-closures-wrong-abi.rs:20:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:12:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-LL |     let x = call_it(&square, 22);
-   |                     ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:18:25
+  --> $DIR/unboxed-closures-wrong-abi.rs:25:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:18:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-LL |     let y = call_it_mut(&mut square, 22);
-   |                         ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:24:26
+  --> $DIR/unboxed-closures-wrong-abi.rs:30:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 LL |     let z = call_it_once(square, 22);
    |                          ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
    |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index c689d79266187ccb9e82c36b64b4eed07f7f3591..02e8b7b47ae19843a9ef1215eeb2aaf578e917f0 100644 (file)
@@ -1,24 +1,30 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-unsafe fn square(x: isize) -> isize { x * x }
+unsafe fn square(x: isize) -> isize {
+    x * x
+}
 // note: argument type here is `isize`, not `&isize`
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+    0
+}
 
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn c() {
@@ -26,4 +32,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
index 434c8a579f67139b8702148e8efa8e30eb0cde39..93a645b485ef0374ea65871ada6bc3a3a8b6b5ea 100644 (file)
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-LL |     let x = call_it(&square, 22);
-   |                     ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-LL |     let y = call_it_mut(&mut square, 22);
-   |                         ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:25:26
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 LL |     let z = call_it_once(square, 22);
    |                          ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
    |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
index 3577dd59289e5ca7c3a42750cb845fcf3c4b162d..dda5de431d30944e4e0f9a1f4f6c5c221773c609 100644 (file)
@@ -1,16 +1,17 @@
-error: cannot infer an appropriate lifetime
+error[E0759]: cannot infer an appropriate lifetime
   --> $DIR/dyn-trait-underscore.rs:8:20
    |
 LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
-   |                ---- data with this lifetime...
+   |                ---- this data with an anonymous lifetime `'_`...
 LL |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
 LL |     Box::new(items.iter())
-   |     ---------------^^^^--- ...is captured and required to be `'static` here
+   |     ---------------^^^^--- ...is captured and required to live as long as `'static` here
    |
-help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1
+help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound
    |
 LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
    |                                                   ^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0759`.
index a39af7832f8c959600b5726f2b91f0a920157289..a9f10dfec994a9e4c7a71ca776e2fca44abb058f 100644 (file)
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `E` as `isize`
   --> $DIR/uninhabited-enum-cast.rs:4:20
    |
 LL |     println!("{}", (e as isize).to_string());
-   |                    ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                    ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
index 7e9c8559a4b39f01317ccf14b9011f0a2f79af60..dd54c222f64bbb0a548f93473e83f2f46e3d61ef 100644 (file)
@@ -4,12 +4,12 @@ error[E0382]: borrow of moved value: `x`
 LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
    |                                               - move occurs because `x` has type `T`, which does not implement the `Copy` trait
 LL |     !x;
-   |     -- `x` moved due to this method call
+   |     -- `x` moved due to usage in operator
 LL | 
 LL |     x.clone();
    |     ^ value borrowed here after move
    |
-note: this function consumes the receiver `self` by taking ownership of it, which moves `x`
+note: calling this operator moves the left-hand side
   --> $SRC_DIR/libcore/ops/bit.rs:LL:COL
    |
 LL |     fn not(self) -> Self::Output;
index d9d85ee913266576d462962d865c93b87503b380..963d892931a7503b874cb5f9cf8d373694ffc01d 100644 (file)
@@ -1,13 +1,13 @@
 #![stable(feature = "foo", since = "1.33.0")]
 #![feature(staged_api)]
-#![feature(const_compare_raw_pointers)]
+#![feature(const_raw_ptr_deref)]
 #![feature(const_fn)]
 
 #[stable(feature = "foo", since = "1.33.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
-const fn unstable(a: *const i32, b: *const i32) -> bool {
-    a == b
-    //~^ pointer operation is unsafe
+const fn unstable(a: *const i32, b: i32) -> bool {
+    *a == b
+    //~^ dereference of raw pointer is unsafe
 }
 
 fn main() {}
index d8f3737c8f541958c9354ba11645c10e4133f080..4642a7a5fc9f83dd3a98a981dc9d19267844a4f7 100644 (file)
@@ -1,10 +1,10 @@
-error[E0133]: pointer operation is unsafe and requires unsafe function or block
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
   --> $DIR/unsafe-unstable-const-fn.rs:9:5
    |
-LL |     a == b
-   |     ^^^^^^ pointer operation
+LL |     *a == b
+   |     ^^ dereference of raw pointer
    |
-   = note: operations on pointers in constants
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
index f43d00f97398d03c93518a6ac8c56c200b7dcc34..1908aee25ea7bf6e094db07ba296ff89b8937534 100644 (file)
@@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
+  --> $DIR/unsized-enum.rs:4:10
+   |
+LL | enum Foo<U> { FooSome(U), FooNone }
+   |          ^            - ...if indirection was used here: `Box<U>`
+   |          |
+   |          this could be changed to `U: ?Sized`...
 
 error: aborting due to previous error
 
index 808c9c583d458bbf8b682c9b6f17c724026fddd5..e0f077d66f99c8920ea3372279d71c7706251dea 100644 (file)
@@ -11,6 +11,13 @@ LL | impl<X: ?Sized> S5<X> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
+  --> $DIR/unsized-inherent-impl-self-type.rs:5:11
+   |
+LL | struct S5<Y>(Y);
+   |           ^  - ...if indirection was used here: `Box<Y>`
+   |           |
+   |           this could be changed to `Y: ?Sized`...
 
 error: aborting due to previous error
 
index 42fc5569eceb47e1cdbb6297961dcc77dfce313b..d92d1d9113e5c56377e8ac4415114357a52562a5 100644 (file)
@@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/unsized-struct.rs:4:12
+   |
+LL | struct Foo<T> { data: T }
+   |            ^          - ...if indirection was used here: `Box<T>`
+   |            |
+   |            this could be changed to `T: ?Sized`...
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/unsized-struct.rs:13:24
index c2b2fe40ce67f099c0f7a8e8d6440c4607124819..73c5439da53b67e83e3c1b66033ef78a04b7ce43 100644 (file)
@@ -11,6 +11,13 @@ LL | impl<X: ?Sized> T3<X> for S5<X> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
+  --> $DIR/unsized-trait-impl-self-type.rs:8:11
+   |
+LL | struct S5<Y>(Y);
+   |           ^  - ...if indirection was used here: `Box<Y>`
+   |           |
+   |           this could be changed to `Y: ?Sized`...
 
 error: aborting due to previous error
 
index 4cf054d177f6624476794b56deec67457a3ba9ca..e423a9bdeab6f9f1c00b86f6a5ca516fdb3c9df9 100644 (file)
@@ -11,6 +11,10 @@ LL | impl<X: ?Sized> T2<X> for S4<X> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait T2<Z: ?Sized> {
+   |           ^^^^^^^^
 
 error: aborting due to previous error
 
index 828e8bc9f4aa17fc6393a963b77a33a734516ec6..e0a0389dc46908247f7093f74dd12a77d554e496 100644 (file)
@@ -48,6 +48,10 @@ LL |     f5(x1);
    = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+   |        ^^^^^^^^
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:40:8
@@ -91,6 +95,10 @@ LL |     f5(&(32, *x1));
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+   |        ^^^^^^^^
 
 error: aborting due to 6 previous errors
 
index d18644f005a887d4742b3c0ca5c39116256191fb..e616a5cf0f9c216a7a473b472f883df748f27de8 100644 (file)
@@ -11,6 +11,10 @@ LL | impl<X: ?Sized + T> T1<X> for S3<X> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | trait T1<Z: T + ?Sized> {
+   |               ^^^^^^^^
 
 error: aborting due to previous error
 
index f59d5502aae30b3c98053b2e371ae910b87651a9..6c54086cc2009a4059218f16825fd85dde53da3f 100644 (file)
@@ -1,3 +1,5 @@
+#![allow(mixed_script_confusables)]
+
 fn foo<
     'β, //~ ERROR non-ascii idents are not fully supported
     γ  //~ ERROR non-ascii idents are not fully supported
index 877412df8fa1c8495d2a9f3cac74a5b8998441f9..2fc0b1c39effb54f6766d3f6f0b8cd413dbae562 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:2:5
+  --> $DIR/utf8_idents.rs:4:5
    |
 LL |     'β,
    |     ^^
@@ -8,7 +8,7 @@ LL |     'β,
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:3:5
+  --> $DIR/utf8_idents.rs:5:5
    |
 LL |     γ
    |     ^
@@ -17,7 +17,7 @@ LL |     γ
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:8:5
+  --> $DIR/utf8_idents.rs:10:5
    |
 LL |     δ: usize
    |     ^
@@ -26,7 +26,7 @@ LL |     δ: usize
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 error[E0658]: non-ascii idents are not fully supported
-  --> $DIR/utf8_idents.rs:12:9
+  --> $DIR/utf8_idents.rs:14:9
    |
 LL |     let α = 0.00001f64;
    |         ^
@@ -35,7 +35,7 @@ LL |     let α = 0.00001f64;
    = help: add `#![feature(non_ascii_idents)]` to the crate attributes to enable
 
 warning: type parameter `γ` should have an upper camel case name
-  --> $DIR/utf8_idents.rs:3:5
+  --> $DIR/utf8_idents.rs:5:5
    |
 LL |     γ
    |     ^ help: convert the identifier to upper camel case: `Γ`
index 59a4f9bad9dfa40c6f3f74cecb46286fc1e3b861..731d31ac34f628d7009c171e5d2c0977fd00a21b 100644 (file)
@@ -23,6 +23,13 @@ LL | struct Vec<T> {
    |
    = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/wf-fn-where-clause.rs:16:12
+   |
+LL | struct Vec<T> {
+   |            ^ this could be changed to `T: ?Sized`...
+LL |     t: T,
+   |        - ...if indirection was used here: `Box<T>`
 
 error[E0038]: the trait `std::marker::Copy` cannot be made into an object
   --> $DIR/wf-fn-where-clause.rs:12:16
diff --git a/src/test/ui/where-clauses/where-for-self-2.nll.stderr b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
new file mode 100644 (file)
index 0000000..d0c476d
--- /dev/null
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/where-for-self-2.rs:23:5
+   |
+LL |     foo(&X);
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
index 31174fd4cf16373b5201e1d91f785350d42bff34..37c6954fd52ee1d49c4fe7b46d2f934ab2786eb1 100644 (file)
@@ -14,9 +14,11 @@ fn bar(&self) {}
 }
 
 fn foo<T>(x: &T)
-    where for<'a> &'a T: Bar
-{}
+where
+    for<'a> &'a T: Bar,
+{
+}
 
 fn main() {
-    foo(&X); //~ ERROR trait bound
+    foo(&X); //~ ERROR implementation of `Bar` is not general enough
 }
index 9976243b200dc907562306b21bee2ef8995e799e..30eb78b2da4f73d1def0a8c41f4d2a81197bb935 100644 (file)
@@ -1,17 +1,16 @@
-error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied
-  --> $DIR/where-for-self-2.rs:21:5
+error: implementation of `Bar` is not general enough
+  --> $DIR/where-for-self-2.rs:23:5
    |
-LL | fn foo<T>(x: &T)
-   |    --- required by a bound in this
-LL |     where for<'a> &'a T: Bar
-   |                          --- required by this bound in `foo`
+LL | / trait Bar {
+LL | |     fn bar(&self);
+LL | | }
+   | |_- trait `Bar` defined here
 ...
-LL |     foo(&X);
-   |     ^^^ the trait `for<'a> Bar` is not implemented for `&'a _`
+LL |       foo(&X);
+   |       ^^^ implementation of `Bar` is not general enough
    |
-   = help: the following implementations were found:
-             <&'static u32 as Bar>
+   = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
+   = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
index 0d426386768c8f450a1488c476e8597cf6f92980..d8677ee959abded82e73e4449e49f72be5dab3de 100644 (file)
@@ -7,7 +7,6 @@ fn f() where
     //~^ ERROR use of undeclared lifetime name `'a`
     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
     //~^ ERROR use of undeclared lifetime name `'b`
-    //~| ERROR nested quantification of lifetimes
 {}
 
 fn main() {}
index 49799a93017ebe2ce90acb7ef8a024f0a110a375..6c52664154bbf333667287e087c21af0396527b6 100644 (file)
@@ -7,12 +7,6 @@ LL |     for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
 LL |     (dyn for<'a> Trait1<'a>): Trait1<'a>,
    |                                      ^^ undeclared lifetime
 
-error[E0316]: nested quantification of lifetimes
-  --> $DIR/where-lifetime-resolution.rs:8:17
-   |
-LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
-   |                 ^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/where-lifetime-resolution.rs:8:52
    |
@@ -22,6 +16,6 @@ LL | fn f() where
 LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
    |                                                    ^^ undeclared lifetime
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0261`.
index 39baa6b8540df7dc320df87c372019667097c63b..614e25589601e8664f613640ed93100b2663bf68 100644 (file)
@@ -4,10 +4,7 @@
 //! via `x.py dist hash-and-sign`; the cmdline arguments are set up
 //! by rustbuild (in `src/bootstrap/dist.rs`).
 
-#![deny(warnings)]
-
 use serde::Serialize;
-use toml;
 
 use std::collections::BTreeMap;
 use std::collections::HashMap;
index 79c769c3d7b4c2cf6a93781575b7f592ef974255..c26576f9adddd254b3dd63aecba176434290a9f6 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 79c769c3d7b4c2cf6a93781575b7f592ef974255
+Subproject commit c26576f9adddd254b3dd63aecba176434290a9f6
index 6968822c1b8aec7f37790c3169774cb07f9a1c8a..ecaeda68695a703737aa9608861305bcbc2ba783 100644 (file)
@@ -1,5 +1,3 @@
-#![deny(warnings)]
-
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE.md b/src/tools/clippy/.github/ISSUE_TEMPLATE.md
deleted file mode 100644 (file)
index 15006a0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<!--
-Hi there! Whether you've come to make a suggestion for a new lint, an improvement to an existing lint or to report a bug or a false positive in Clippy, you've come to the right place.
-
-For bug reports and false positives, please include the output of `cargo clippy -V` in the report.
-
-Thank you for using Clippy!
-
-Write your comment below this line: -->
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md
new file mode 100644 (file)
index 0000000..9aef3eb
--- /dev/null
@@ -0,0 +1,4 @@
+---
+name: Blank Issue
+about: Create a blank issue.
+---
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644 (file)
index 0000000..d8f0c44
--- /dev/null
@@ -0,0 +1,47 @@
+---
+name: Bug Report
+about: Create a bug report for Clippy
+labels: L-bug
+---
+<!--
+Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
+along with any information you feel relevant to replicating the bug.
+-->
+
+I tried this code:
+
+```rust
+<code>
+```
+
+I expected to see this happen: *explanation*
+
+Instead, this happened: *explanation*
+
+### Meta
+
+- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
+- `rustc -Vv`:
+  ```
+  rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+  binary: rustc
+  commit-hash: f455e46eae1a227d735091091144601b467e1565
+  commit-date: 2020-06-20
+  host: x86_64-unknown-linux-gnu
+  release: 1.46.0-nightly
+  LLVM version: 10.0
+  ```
+
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+-->
+<details><summary>Backtrace</summary>
+  <p>
+  
+  ```
+  <backtrace>
+  ```
+  
+  </p>
+</details>
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/config.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644 (file)
index 0000000..bd7dc0a
--- /dev/null
@@ -0,0 +1,5 @@
+blank_issues_enabled: true
+contact_links:
+  - name: Rust Programming Language Forum
+    url: https://users.rust-lang.org
+    about: Please ask and answer questions about Rust here.
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md
new file mode 100644 (file)
index 0000000..3abe76b
--- /dev/null
@@ -0,0 +1,53 @@
+---
+name: Internal Compiler Error
+about: Create a report for an internal compiler error in Clippy.
+labels: L-bug, L-crash
+---
+<!--
+Thank you for finding an Internal Compiler Error! 🧊  If possible, try to provide
+a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
+how to create smaller examples.
+
+http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
+
+-->
+
+### Code
+
+```rust
+<code>
+```
+
+### Meta
+
+- `cargo clippy -V`: e.g. clippy 0.0.212 (f455e46 2020-06-20)
+- `rustc -Vv`:
+  ```
+  rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+  binary: rustc
+  commit-hash: f455e46eae1a227d735091091144601b467e1565
+  commit-date: 2020-06-20
+  host: x86_64-unknown-linux-gnu
+  release: 1.46.0-nightly
+  LLVM version: 10.0
+  ```
+
+### Error output
+
+```
+<output>
+```
+
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+-->
+<details><summary>Backtrace</summary>
+  <p>
+  
+  ```
+  <backtrace>
+  ```
+  
+  </p>
+</details>
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md
new file mode 100644 (file)
index 0000000..70445d7
--- /dev/null
@@ -0,0 +1,35 @@
+---
+name: New lint suggestion
+about: Suggest a new Clippy lint.
+labels: L-lint
+---
+
+### What it does
+
+*What does this lint do?*
+
+### Categories (optional)
+
+- Kind: *See <https://github.com/rust-lang/rust-clippy/blob/master/README.md#clippy> for list of lint kinds*
+
+*What benefit of this lint over old code?*
+
+For example:
+- Remove bounce checking inserted by ...
+- Remove the need to duplicating/storing/typo ...
+
+### Drawbacks
+
+None.
+
+### Example
+
+```rust
+<code>
+```
+
+Could be written as:
+
+```rust
+<code>
+```
index 97aa220afea540e16a4a18ff05b67fc030f136c4..137a73630940a4a69d2f77949fefc76ea177dcca 100644 (file)
@@ -28,4 +28,5 @@ Delete this line and everything above before opening your PR.
 
 ---
 
+*Please keep the line below*
 changelog: none
index a2e87f5eb3745837c4a71cc2dad41a3473677bd3..2c17c4203ae5c737e8005ae3454656e99619bd99 100644 (file)
@@ -26,4 +26,16 @@ unset CARGO_MANIFEST_DIR
 sed -e "s,tests/ui,\$DIR," -e "/= help/d" cstring.stderr > normalized.stderr
 diff normalized.stderr tests/ui/cstring.stderr
 
+
+# make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
+SYSROOT=`rustc --print sysroot`
+diff <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose)
+
+
+echo "fn main() {}" > target/driver_test.rs
+# we can't run 2 rustcs on the same file at the same time
+CLIPPY=`LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver ./target/driver_test.rs --rustc`
+RUSTC=`rustc ./target/driver_test.rs`
+diff <($CLIPPY) <($RUSTC)
+
 # TODO: CLIPPY_CONF_DIR / CARGO_MANIFEST_DIR
index 6cbe10a5352d1d1cf3b91caccfd3c59f8408c2da..cc09b99cf1dd198b1e327e294a15683a78d16a2c 100644 (file)
@@ -86,7 +86,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
                     _ => (),
                 }
 
-                let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r));
+                let (l_ty, r_ty) = (cx.tables().expr_ty(l), cx.tables().expr_ty(r));
                 if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
                     span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
                     self.expr_span = Some(expr.span);
@@ -96,8 +96,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
                 }
             },
             hir::ExprKind::Unary(hir::UnOp::UnNeg, arg) => {
-                let ty = cx.tables.expr_ty(arg);
-                if constant_simple(cx, cx.tables, expr).is_none() {
+                let ty = cx.tables().expr_ty(arg);
+                if constant_simple(cx, cx.tables(), expr).is_none() {
                     if ty.is_integral() {
                         span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
                         self.expr_span = Some(expr.span);
index f8a8fdcd3aa35e9753f3b8cfa79c069b2df403c6..c4536b57f8a99d8fa13b9792847e3a0a5b3cd126 100644 (file)
@@ -72,7 +72,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
             }
             if_chain! {
                 if let ExprKind::Unary(_, ref lit) = e.kind;
-                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables, lit);
+                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), lit);
                 if is_true;
                 then {
                     lint_true(true);
@@ -121,7 +121,7 @@ fn match_assert_with_message<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx E
         if let ExprKind::DropTemps(ref expr) = expr.kind;
         if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind;
         // bind the first argument of the `assert!` macro
-        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables, expr);
+        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), expr);
         // arm 1 pattern
         if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind;
         if let ExprKind::Lit(ref lit) = lit_expr.kind;
index 13e61fe98bac1d6ff18a1f61dce52ba52acf9a45..51a7647d3208f70a7a7ca80232d91328ad02eba3 100644 (file)
@@ -82,8 +82,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
             hir::ExprKind::Assign(assignee, e, _) => {
                 if let hir::ExprKind::Binary(op, l, r) = &e.kind {
                     let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
-                        let ty = cx.tables.expr_ty(assignee);
-                        let rty = cx.tables.expr_ty(rhs);
+                        let ty = cx.tables().expr_ty(assignee);
+                        let rty = cx.tables().expr_ty(rhs);
                         macro_rules! ops {
                             ($op:expr,
                              $cx:expr,
@@ -167,7 +167,7 @@ macro_rules! ops {
                         // a = b commutative_op a
                         // Limited to primitive type as these ops are know to be commutative
                         if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
-                            && cx.tables.expr_ty(assignee).is_primitive_ty()
+                            && cx.tables().expr_ty(assignee).is_primitive_ty()
                         {
                             match op.node {
                                 hir::BinOpKind::Add
index fca9aaaff9dcea4d9d2cabb54df37e8df501c8bd..65e1e2c519c268dba0b9ad3ead327cb8d43b22b0 100644 (file)
@@ -53,7 +53,7 @@
 ];
 
 fn type_is_atomic(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables.expr_ty(expr).kind {
+    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables().expr_ty(expr).kind {
         ATOMIC_TYPES
             .iter()
             .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty]))
@@ -76,7 +76,7 @@ fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
         if method == "load" || method == "store";
         let ordering_arg = if method == "load" { &args[1] } else { &args[2] };
         if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind;
-        if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
+        if let Some(ordering_def_id) = cx.tables().qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
         then {
             if method == "load" &&
                 match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) {
@@ -107,12 +107,12 @@ fn check_memory_fence(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Call(ref func, ref args) = expr.kind;
         if let ExprKind::Path(ref func_qpath) = func.kind;
-        if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+        if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
         if ["fence", "compiler_fence"]
             .iter()
             .any(|func| match_def_path(cx, def_id, &["core", "sync", "atomic", func]));
         if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
-        if let Some(ordering_def_id) = cx.tables.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
+        if let Some(ordering_def_id) = cx.tables().qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
         if match_ordering_def_path(cx, ordering_def_id, &["Relaxed"]);
         then {
             span_lint_and_help(
index ccb62cb038fd0a4c7aab05a7178d31e840d7e6e1..a53f3249b85b6baf69534dbc4436676f49c9b17b 100644 (file)
@@ -319,7 +319,7 @@ fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
 }
 
 fn fetch_int_literal(cx: &LateContext<'_, '_>, lit: &Expr<'_>) -> Option<u128> {
-    match constant(cx, cx.tables, lit)?.0 {
+    match constant(cx, cx.tables(), lit)?.0 {
         Constant::Int(n) => Some(n),
         _ => None,
     }
index f92c564543b89bd46aba72bc7646a09bc190a7e9..cc399a1f8a00946dba1a0c31d820925a8541beb3 100644 (file)
@@ -248,7 +248,7 @@ fn simplify_not(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<String> {
             })
         },
         ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => {
-            let type_of_receiver = cx.tables.expr_ty(&args[0]);
+            let type_of_receiver = cx.tables().expr_ty(&args[0]);
             if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type))
                 && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type))
             {
@@ -450,7 +450,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                 self.bool_expr(e)
             },
             ExprKind::Unary(UnOp::UnNot, inner) => {
-                if self.cx.tables.node_types()[inner.hir_id].is_bool() {
+                if self.cx.tables().node_types()[inner.hir_id].is_bool() {
                     self.bool_expr(e);
                 } else {
                     walk_expr(self, e);
@@ -465,7 +465,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 }
 
 fn implements_ord<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool {
-    let ty = cx.tables.expr_ty(expr);
+    let ty = cx.tables().expr_ty(expr);
     get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
 }
 
index 531531a654d0efb1e13f56ad7a6abec5f871b0a1..c00bb23069bf4af91454cbd23fd17a1f458e0aec 100644 (file)
@@ -53,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
                     if let ExprKind::Binary(ref op, ref l, ref r) = body.value.kind;
                     if op.node == BinOpKind::Eq;
                     if match_type(cx,
-                               walk_ptrs_ty(cx.tables.expr_ty(&filter_args[0])),
+                               walk_ptrs_ty(cx.tables().expr_ty(&filter_args[0])),
                                &paths::SLICE_ITER);
                     then {
                         let needle = match get_path_name(l) {
@@ -63,7 +63,7 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
                                 _ => { return; }
                             }
                         };
-                        if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables.expr_ty(needle)).kind {
+                        if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables().expr_ty(needle)).kind {
                             return;
                         }
                         let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
index 3ba72e84fa827a7dace8698873b845b815fe1ae6..78e509d2ecd83f3def224dea25fc18624ed6fb32 100644 (file)
@@ -60,7 +60,7 @@ fn check<'a, 'tcx>(
         let mut helper = CCHelper { cc: 1, returns: 0 };
         helper.visit_expr(expr);
         let CCHelper { cc, returns } = helper;
-        let ret_ty = cx.tables.node_type(expr.hir_id);
+        let ret_ty = cx.tables().node_type(expr.hir_id);
         let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) {
             returns
         } else {
index 93e29edcaa58fead1be38d9718804bd9d4892f84..9c0d33f92801537baac83fb8693844fb8c79d772 100644 (file)
@@ -99,7 +99,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                 }
 
                 // Check that the type being compared implements `core::cmp::Ord`
-                let ty = cx.tables.expr_ty(lhs1);
+                let ty = cx.tables().expr_ty(lhs1);
                 let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]));
 
                 if !is_ord {
index 22c5acca064e9242b4f7c1f962ccd25044ba9d08..550752396c7324f7f857199be2c37c34844b605f 100644 (file)
@@ -396,7 +396,7 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
-            (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty(left).kind {
+            (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty_opt(left)?.kind {
                 ty::Int(ity) => {
                     let l = sext(self.lcx.tcx, l, ity);
                     let r = sext(self.lcx.tcx, r, ity);
index b6d50bdfa1466f61ea04325ad4bc02c840ba9963..efd4a31f5596068fa4ac250778e4a52c574e6314 100644 (file)
@@ -192,7 +192,7 @@ fn lint_same_then_else(cx: &LateContext<'_, '_>, blocks: &[&Block<'_>]) {
 /// Implementation of `IFS_SAME_COND`.
 fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
     let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 {
-        let mut h = SpanlessHash::new(cx, cx.tables);
+        let mut h = SpanlessHash::new(cx, cx.tables());
         h.hash_expr(expr);
         h.finish()
     };
@@ -215,7 +215,7 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
 /// Implementation of `SAME_FUNCTIONS_IN_IF_CONDITION`.
 fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
     let hash: &dyn Fn(&&Expr<'_>) -> u64 = &|expr| -> u64 {
-        let mut h = SpanlessHash::new(cx, cx.tables);
+        let mut h = SpanlessHash::new(cx, cx.tables());
         h.hash_expr(expr);
         h.finish()
     };
@@ -251,7 +251,7 @@ fn same_bindings<'tcx>(lhs: &FxHashMap<Symbol, Ty<'tcx>>, rhs: &FxHashMap<Symbol
 
     if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
         let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
-            let mut h = SpanlessHash::new(cx, cx.tables);
+            let mut h = SpanlessHash::new(cx, cx.tables());
             h.hash_expr(&arm.body);
             h.finish()
         };
@@ -320,7 +320,7 @@ fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat<'_>, map: &mut
             },
             PatKind::Binding(.., ident, ref as_pat) => {
                 if let Entry::Vacant(v) = map.entry(ident.name) {
-                    v.insert(cx.tables.pat_ty(pat));
+                    v.insert(cx.tables().pat_ty(pat));
                 }
                 if let Some(ref as_pat) = *as_pat {
                     bindings_impl(cx, as_pat, map);
index 635d609c382890f1a04ae880afdaf965f535c6f6..69ae509fb23e925213df20409b058da08449ed76 100644 (file)
@@ -36,7 +36,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Call(ref path, ..) = expr.kind;
             if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
             if let ExprKind::Path(ref qpath) = path.kind;
-            if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
+            if let Some(def_id) = cx.tables().qpath_res(qpath, path.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
             then {
                 match qpath {
@@ -54,7 +54,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
 
                         // TODO: Work out a way to put "whatever the imported way of referencing
                         // this type in this file" rather than a fully-qualified type.
-                        let expr_ty = cx.tables.expr_ty(expr);
+                        let expr_ty = cx.tables().expr_ty(expr);
                         if let ty::Adt(..) = expr_ty.kind {
                             let replacement = format!("{}::default()", expr_ty);
                             span_lint_and_sugg(
index 1cd30ae2c6381f844c92af3f1ea4f86fbf2d1bda..1c6cc936900969786b9ce1c7791e089c2aec1c07 100644 (file)
@@ -73,12 +73,9 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
 fn lint_deref(cx: &LateContext<'_, '_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) {
     match method_name {
         "deref" => {
-            if cx
-                .tcx
-                .lang_items()
-                .deref_trait()
-                .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(&call_expr), id, &[]))
-            {
+            if cx.tcx.lang_items().deref_trait().map_or(false, |id| {
+                implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
+            }) {
                 span_lint_and_sugg(
                     cx,
                     EXPLICIT_DEREF_METHODS,
@@ -91,12 +88,9 @@ fn lint_deref(cx: &LateContext<'_, '_>, method_name: &str, call_expr: &Expr<'_>,
             }
         },
         "deref_mut" => {
-            if cx
-                .tcx
-                .lang_items()
-                .deref_mut_trait()
-                .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(&call_expr), id, &[]))
-            {
+            if cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
+                implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
+            }) {
                 span_lint_and_sugg(
                     cx,
                     EXPLICIT_DEREF_METHODS,
index 9de9056c14029a8d1bb6bd7a8b4244068ca889d6..014873eb1325531035d5c049a699bbe34bdda0ad 100644 (file)
@@ -119,7 +119,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                 let lint;
                 let msg;
                 let arg = &args[0];
-                let arg_ty = cx.tables.expr_ty(arg);
+                let arg_ty = cx.tables().expr_ty(arg);
 
                 if let ty::Ref(..) = arg_ty.kind {
                     if match_def_path(cx, def_id, &paths::DROP) {
index 7171dcef968c14150ebc548734c534c97ed2b4fc..5eb320ceca2478c172615249e132ac9055be73e4 100644 (file)
@@ -43,8 +43,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind;
             if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind;
-            if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::DURATION);
-            if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables, right);
+            if match_type(cx, walk_ptrs_ty(cx.tables().expr_ty(&args[0])), &paths::DURATION);
+            if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables(), right);
             then {
                 let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {
                     ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
index f625058b6703cec269e01a9f2c0da9b8e4f2e9fe..e37e23b8944d791391a5f0cdbe5dc9a695d3c28b 100644 (file)
@@ -109,7 +109,7 @@ fn check_cond<'a, 'tcx, 'b>(
         if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind;
         then {
             let map = &params[0];
-            let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map));
+            let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(map));
 
             return if match_type(cx, obj_ty, &paths::BTREEMAP) {
                 Some(("BTreeMap", map, key))
index d7819d737ea0445565b4bd67f7b1467b4b6b4f25..98757624a13b5c82517d774e536d30f92b47106c 100644 (file)
@@ -103,8 +103,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                     (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},
                     // &foo == &bar
                     (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
-                        let lty = cx.tables.expr_ty(l);
-                        let rty = cx.tables.expr_ty(r);
+                        let lty = cx.tables().expr_ty(l);
+                        let rty = cx.tables().expr_ty(r);
                         let lcpy = is_copy(cx, lty);
                         let rcpy = is_copy(cx, rty);
                         // either operator autorefs or both args are copyable
@@ -126,7 +126,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                             )
                         } else if lcpy
                             && !rcpy
-                            && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
+                            && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()])
                         {
                             span_lint_and_then(
                                 cx,
@@ -145,7 +145,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                             )
                         } else if !lcpy
                             && rcpy
-                            && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
+                            && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()])
                         {
                             span_lint_and_then(
                                 cx,
@@ -166,10 +166,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                     },
                     // &foo == bar
                     (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), _) => {
-                        let lty = cx.tables.expr_ty(l);
+                        let lty = cx.tables().expr_ty(l);
                         let lcpy = is_copy(cx, lty);
                         if (requires_ref || lcpy)
-                            && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
+                            && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()])
                         {
                             span_lint_and_then(
                                 cx,
@@ -190,10 +190,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                     },
                     // foo == &bar
                     (_, &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => {
-                        let rty = cx.tables.expr_ty(r);
+                        let rty = cx.tables().expr_ty(r);
                         let rcpy = is_copy(cx, rty);
                         if (requires_ref || rcpy)
-                            && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
+                            && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()])
                         {
                             span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |diag| {
                                 let rsnip = snippet(cx, r.span, "...").to_string();
index 3ff0506e28d007ffeefdcb784b2685a3029a1a0e..804a9c1904b73bf33ec8d71a84dbc211a5a02afc 100644 (file)
@@ -48,7 +48,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
 }
 
 fn check(cx: &LateContext<'_, '_>, e: &Expr<'_>, span: Span) {
-    if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables, e) {
+    if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables(), e) {
         span_lint(
             cx,
             ERASING_OP,
index 7227683aa5ac2c0104f1a535c1bbbdbb641da55b..bb74f193a48e7482005216d4a5ff6eae12b3ad42 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_target::abi::LayoutOf;
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 use crate::utils::span_lint;
 
@@ -84,7 +84,7 @@ fn check_fn(
 
         let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
         cx.tcx.infer_ctxt().enter(|infcx| {
-            ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.tables).consume_body(body);
+            ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body);
         });
 
         for node in v.set {
@@ -112,9 +112,9 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
 }
 
 impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
-    fn consume(&mut self, cmt: &Place<'tcx>, mode: ConsumeMode) {
-        if cmt.projections.is_empty() {
-            if let PlaceBase::Local(lid) = cmt.base {
+    fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, mode: ConsumeMode) {
+        if cmt.place.projections.is_empty() {
+            if let PlaceBase::Local(lid) = cmt.place.base {
                 if let ConsumeMode::Move = mode {
                     // moved out or in. clearly can't be localized
                     self.set.remove(&lid);
@@ -132,16 +132,16 @@ fn consume(&mut self, cmt: &Place<'tcx>, mode: ConsumeMode) {
         }
     }
 
-    fn borrow(&mut self, cmt: &Place<'tcx>, _: ty::BorrowKind) {
-        if cmt.projections.is_empty() {
-            if let PlaceBase::Local(lid) = cmt.base {
+    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: ty::BorrowKind) {
+        if cmt.place.projections.is_empty() {
+            if let PlaceBase::Local(lid) = cmt.place.base {
                 self.set.remove(&lid);
             }
         }
     }
 
-    fn mutate(&mut self, cmt: &Place<'tcx>) {
-        if cmt.projections.is_empty() {
+    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
+        if cmt.place.projections.is_empty() {
             let map = &self.cx.tcx.hir();
             if is_argument(*map, cmt.hir_id) {
                 // Skip closure arguments
@@ -150,7 +150,7 @@ fn mutate(&mut self, cmt: &Place<'tcx>) {
                     return;
                 }
 
-                if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
+                if is_non_trait_box(cmt.place.ty) && !self.is_large_box(cmt.place.ty) {
                     self.set.insert(cmt.hir_id);
                 }
                 return;
index a889856de274215b324197e4a20ba2cb80489dbb..0ac8b95de8d61163578d856556276406ee9f86d2 100644 (file)
@@ -97,7 +97,7 @@ fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
             // Are the expression or the arguments type-adjusted? Then we need the closure
             if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));
 
-            let fn_ty = cx.tables.expr_ty(caller);
+            let fn_ty = cx.tables().expr_ty(caller);
 
             if matches!(fn_ty.kind, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));
 
@@ -128,7 +128,7 @@ fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
             // Are the expression or the arguments type-adjusted? Then we need the closure
             if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));
 
-            let method_def_id = cx.tables.type_dependent_def_id(ex.hir_id).unwrap();
+            let method_def_id = cx.tables().type_dependent_def_id(ex.hir_id).unwrap();
             if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));
 
             if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter());
@@ -153,7 +153,7 @@ fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
 /// Tries to determine the type for universal function call to be used instead of the closure
 fn get_ufcs_type_name(cx: &LateContext<'_, '_>, method_def_id: def_id::DefId, self_arg: &Expr<'_>) -> Option<String> {
     let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
-    let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id);
+    let actual_type_of_self = &cx.tables().node_type(self_arg.hir_id);
 
     if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
         if match_borrow_depth(expected_type_of_self, &actual_type_of_self)
index 74144fb299de2c6727f1e62429127c56997bf7c4..04af6c2c1f85d45797ea8121c660df310978b9db 100644 (file)
@@ -75,7 +75,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                 if let ExprKind::Path(ref qpath) = lhs.kind {
                     if let QPath::Resolved(_, ref path) = *qpath {
                         if path.segments.len() == 1 {
-                            if let def::Res::Local(var) = cx.tables.qpath_res(qpath, lhs.hir_id) {
+                            if let def::Res::Local(var) = cx.tables().qpath_res(qpath, lhs.hir_id) {
                                 let mut visitor = ReadVisitor {
                                     cx,
                                     var,
@@ -137,7 +137,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
             ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
             ExprKind::Call(ref func, _) => {
-                let typ = self.cx.tables.expr_ty(func);
+                let typ = self.cx.tables().expr_ty(func);
                 match typ.kind {
                     ty::FnDef(..) | ty::FnPtr(_) => {
                         let sig = typ.fn_sig(self.cx.tcx);
@@ -149,7 +149,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                 }
             },
             ExprKind::MethodCall(..) => {
-                let borrowed_table = self.cx.tables;
+                let borrowed_table = self.cx.tables();
                 if borrowed_table.expr_ty(e).is_never() {
                     self.report_diverging_sub_expr(e);
                 }
@@ -309,7 +309,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 if_chain! {
                     if let QPath::Resolved(None, ref path) = *qpath;
                     if path.segments.len() == 1;
-                    if let def::Res::Local(local_id) = self.cx.tables.qpath_res(qpath, expr.hir_id);
+                    if let def::Res::Local(local_id) = self.cx.tables().qpath_res(qpath, expr.hir_id);
                     if local_id == self.var;
                     // Check that this is a read, not a write.
                     if !is_in_assignment_position(self.cx, expr);
index 4c604cd01075e66f783ce87beb7a7f062a82dd19..cd3d443ec58ef06dd2ec2956566ddf61f727e64d 100644 (file)
@@ -61,7 +61,7 @@
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatLiteral {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
-            let ty = cx.tables.expr_ty(expr);
+            let ty = cx.tables().expr_ty(expr);
             if let ty::Float(fty) = ty.kind;
             if let hir::ExprKind::Lit(ref lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
index ad4f66c52c2c85c18bbb21c1d19a965057e9aa51..76713cb1afc41b0c4d968203102e88d25829ba28 100644 (file)
 // Returns the specialized log method for a given base if base is constant
 // and is one of 2, 10 and e
 fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr<'_>) -> Option<&'static str> {
-    if let Some((value, _)) = constant(cx, cx.tables, base) {
+    if let Some((value, _)) = constant(cx, cx.tables(), base) {
         if F32(2.0) == value || F64(2.0) == value {
             return Some("log2");
         } else if F32(10.0) == value || F64(10.0) == value {
@@ -136,7 +136,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_, '_>, mut expr: &'a Expr<'a>) -
     if_chain! {
         // if the expression is a float literal and it is unsuffixed then
         // add a suffix so the suggestion is valid and unambiguous
-        if let ty::Float(float_ty) = cx.tables.expr_ty(expr).kind;
+        if let ty::Float(float_ty) = cx.tables().expr_ty(expr).kind;
         if let ExprKind::Lit(lit) = &expr.kind;
         if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
         then {
@@ -188,7 +188,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
         rhs,
     ) = &args[0].kind
     {
-        let recv = match (constant(cx, cx.tables, lhs), constant(cx, cx.tables, rhs)) {
+        let recv = match (constant(cx, cx.tables(), lhs), constant(cx, cx.tables(), rhs)) {
             (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs,
             (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs,
             _ => return,
@@ -233,7 +233,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
 
 fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
-    if let Some((value, _)) = constant(cx, cx.tables, &args[0]) {
+    if let Some((value, _)) = constant(cx, cx.tables(), &args[0]) {
         let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
             "exp"
         } else if F32(2.0) == value || F64(2.0) == value {
@@ -254,7 +254,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     }
 
     // Check argument
-    if let Some((value, _)) = constant(cx, cx.tables, &args[1]) {
+    if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) {
         let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
             (
                 SUBOPTIMAL_FLOPS,
@@ -298,11 +298,11 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) = expr.kind;
-        if cx.tables.expr_ty(lhs).is_floating_point();
-        if let Some((value, _)) = constant(cx, cx.tables, rhs);
+        if cx.tables().expr_ty(lhs).is_floating_point();
+        if let Some((value, _)) = constant(cx, cx.tables(), rhs);
         if F32(1.0) == value || F64(1.0) == value;
         if let ExprKind::MethodCall(ref path, _, ref method_args, _) = lhs.kind;
-        if cx.tables.expr_ty(&method_args[0]).is_floating_point();
+        if cx.tables().expr_ty(&method_args[0]).is_floating_point();
         if path.ident.name.as_str() == "exp";
         then {
             span_lint_and_sugg(
@@ -324,8 +324,8 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
 fn is_float_mul_expr<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
     if_chain! {
         if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lhs, ref rhs) = &expr.kind;
-        if cx.tables.expr_ty(lhs).is_floating_point();
-        if cx.tables.expr_ty(rhs).is_floating_point();
+        if cx.tables().expr_ty(lhs).is_floating_point();
+        if cx.tables().expr_ty(rhs).is_floating_point();
         then {
             return Some((lhs, rhs));
         }
@@ -404,7 +404,7 @@ fn are_exprs_equal(cx: &LateContext<'_, '_>, expr1: &Expr<'_>, expr2: &Expr<'_>)
 
 /// Returns true iff expr is some zero literal
 fn is_zero(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-    match constant_simple(cx, cx.tables, expr) {
+    match constant_simple(cx, cx.tables(), expr) {
         Some(Constant::Int(i)) => i == 0,
         Some(Constant::F32(f)) => f == 0.0,
         Some(Constant::F64(f)) => f == 0.0,
@@ -482,7 +482,7 @@ fn check_custom_abs(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind {
-            let recv_ty = cx.tables.expr_ty(&args[0]);
+            let recv_ty = cx.tables().expr_ty(&args[0]);
 
             if recv_ty.is_floating_point() {
                 match &*path.ident.name.as_str() {
index 4cae5ca2c4326b6d52310d3b36ea786bde4e8f8f..58cf0027ea4d4183f9c4468f3ac0de3a425e0638 100644 (file)
@@ -88,13 +88,13 @@ fn on_argumentv1_new<'a, 'tcx>(
         // matches `core::fmt::Display::fmt`
         if args.len() == 2;
         if let ExprKind::Path(ref qpath) = args[1].kind;
-        if let Some(did) = cx.tables.qpath_res(qpath, args[1].hir_id).opt_def_id();
+        if let Some(did) = cx.tables().qpath_res(qpath, args[1].hir_id).opt_def_id();
         if match_def_path(cx, did, &paths::DISPLAY_FMT_METHOD);
         // check `(arg0,)` in match block
         if let PatKind::Tuple(ref pats, None) = arms[0].pat.kind;
         if pats.len() == 1;
         then {
-            let ty = walk_ptrs_ty(cx.tables.pat_ty(&pats[0]));
+            let ty = walk_ptrs_ty(cx.tables().pat_ty(&pats[0]));
             if ty.kind != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                 return None;
             }
index 991d129e8f0d612a7d7187abe0d007c5592502b3..1f9bd7a691b520bed9c788980974d3050d14e69d 100644 (file)
@@ -513,7 +513,7 @@ fn is_mutable_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Span,
         // primitive types are never mutable
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
         ty::Adt(ref adt, ref substs) => {
-            tys.insert(adt.did) && !ty.is_freeze(cx.tcx, cx.param_env, span)
+            tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
                 || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path))
                     && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
         },
index 3629ba623ce43a64dc6176ccac1e21722fe3cbd0..57a7fbb56567913ffd82f66c27ba847a7ba54bbc 100644 (file)
@@ -54,7 +54,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
 
             // Argument 0 (the struct we're calling the method on) is a vector
             if let Some(struct_calling_on) = args.get(0);
-            let struct_ty = cx.tables.expr_ty(struct_calling_on);
+            let struct_ty = cx.tables().expr_ty(struct_calling_on);
             if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type));
 
             // Argument to "get" is a subtraction
index 78e07d25f67c573cf122a36039ac487312149dd8..1c25e050997ea0365bc1864db5773b69e2eae7cd 100644 (file)
@@ -62,8 +62,8 @@ fn is_allowed(cx: &LateContext<'_, '_>, cmp: BinOp, left: &Expr<'_>, right: &Exp
     // `1 << 0` is a common pattern in bit manipulation code
     if_chain! {
         if let BinOpKind::Shl = cmp.node;
-        if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables, right);
-        if let Some(Constant::Int(1)) = constant_simple(cx, cx.tables, left);
+        if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables(), right);
+        if let Some(Constant::Int(1)) = constant_simple(cx, cx.tables(), left);
         then {
             return true;
         }
@@ -74,8 +74,8 @@ fn is_allowed(cx: &LateContext<'_, '_>, cmp: BinOp, left: &Expr<'_>, right: &Exp
 
 #[allow(clippy::cast_possible_wrap)]
 fn check(cx: &LateContext<'_, '_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
-    if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) {
-        let check = match cx.tables.expr_ty(e).kind {
+    if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables(), e) {
+        let check = match cx.tables().expr_ty(e).kind {
             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
             ty::Uint(uty) => clip(cx.tcx, !0, uty),
             _ => return,
index 04d17c91d63c1515dd73532581ab68984c15796d..e357c7b3b2eb265200c6446d04f04e28af33b382 100644 (file)
@@ -149,7 +149,7 @@ fn is_mutex_lock_call<'a>(cx: &LateContext<'a, '_>, expr: &'a Expr<'_>) -> Optio
     if_chain! {
         if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind;
         if path.ident.to_string() == "lock";
-        let ty = cx.tables.expr_ty(&args[0]);
+        let ty = cx.tables().expr_ty(&args[0]);
         if is_type_diagnostic_item(cx, ty, sym!(mutex_type));
         then {
             Some(&args[0])
index 6a1fcdd1ce445edc5a30021a2f2b70233ce9ee19..3f1ae9b86d38784e9bfaa1e283b87c35152f3636 100644 (file)
@@ -45,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
             if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _)  = body[0].pat.kind; //get operation
             if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
-            if is_type_diagnostic_item(cx, cx.tables.expr_ty(&result_types[0]), sym!(result_type));
+            if is_type_diagnostic_item(cx, cx.tables().expr_ty(&result_types[0]), sym!(result_type));
             if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
 
             then {
index c4308fd26a3021092e9f653a016461e7904760c8..5a0531ff749e9d4b41a7c0c62016446d315be1e9 100644 (file)
@@ -108,7 +108,7 @@ fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
         ExprKind::Call(expr, ..) => {
             if_chain! {
                 if let ExprKind::Path(qpath) = &expr.kind;
-                if let Some(path_def_id) = cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id();
+                if let Some(path_def_id) = cx.tables().qpath_res(qpath, expr.hir_id).opt_def_id();
                 if match_def_path(cx, path_def_id, &BEGIN_PANIC) ||
                     match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT);
                 then { }
index fdaf37e5e08fa79abb7a21ae94550db6aadfdfd6..1a6cb0b0c566e11b9b6d2ac96b856ece277896b3 100644 (file)
@@ -81,7 +81,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) {
                 };
 
                 // Check if the variable in the condition statement is an integer
-                if !cx.tables.expr_ty(cond_var).is_integral() {
+                if !cx.tables().expr_ty(cond_var).is_integral() {
                     return;
                 }
 
@@ -93,7 +93,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) {
                     ExprKind::Lit(ref cond_lit) => {
                         // Check if the constant is zero
                         if let LitKind::Int(0, _) = cond_lit.node {
-                            if cx.tables.expr_ty(cond_left).is_signed() {
+                            if cx.tables().expr_ty(cond_left).is_signed() {
                             } else {
                                 print_lint_and_sugg(cx, &var_name, expr);
                             };
index c5808dd540b6f43c3940e217d1328c549bf3f08b..c5e4abc94a8a669e9962a6715f3e1279dcd54474 100644 (file)
@@ -88,7 +88,7 @@
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Index(ref array, ref index) = &expr.kind {
-            let ty = cx.tables.expr_ty(array);
+            let ty = cx.tables().expr_ty(array);
             if let Some(range) = higher::range(cx, index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
                 if let ty::Array(_, s) = ty.kind {
@@ -143,7 +143,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                 // Catchall non-range index, i.e., [n] or [n << m]
                 if let ty::Array(..) = ty.kind {
                     // Index is a constant uint.
-                    if let Some(..) = constant(cx, cx.tables, index) {
+                    if let Some(..) = constant(cx, cx.tables(), index) {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
                         return;
                     }
@@ -169,14 +169,14 @@ fn to_const_range<'a, 'tcx>(
     range: higher::Range<'_>,
     array_size: u128,
 ) -> (Option<u128>, Option<u128>) {
-    let s = range.start.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
+    let s = range.start.map(|expr| constant(cx, cx.tables(), expr).map(|(c, _)| c));
     let start = match s {
         Some(Some(Constant::Int(x))) => Some(x),
         Some(_) => None,
         None => Some(0),
     };
 
-    let e = range.end.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
+    let e = range.end.map(|expr| constant(cx, cx.tables(), expr).map(|(c, _)| c));
     let end = match e {
         Some(Some(Constant::Int(x))) => {
             if range.limits == RangeLimits::Closed {
index a860a9def24224725444f7535b6b10b2431cecbf..38f086c9221fea82c0a39ea71e140b0f2c143e17 100644 (file)
@@ -230,13 +230,14 @@ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Finitene
                 }
             }
             if method.ident.name == sym!(last) && args.len() == 1 {
-                let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR)
-                    .map_or(false, |id| !implements_trait(cx, cx.tables.expr_ty(&args[0]), id, &[]));
+                let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR).map_or(false, |id| {
+                    !implements_trait(cx, cx.tables().expr_ty(&args[0]), id, &[])
+                });
                 if not_double_ended {
                     return is_infinite(cx, &args[0]);
                 }
             } else if method.ident.name == sym!(collect) {
-                let ty = cx.tables.expr_ty(expr);
+                let ty = cx.tables().expr_ty(expr);
                 if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
                     return is_infinite(cx, &args[0]);
                 }
index d537ef3f3238e05c9cb0029d959800fbd1ca145f..83ae1c1a971e165fd28cdba9753b717ea6bddcc1 100644 (file)
@@ -50,7 +50,7 @@ fn is_integer_division<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Ex
         if let hir::ExprKind::Binary(binop, left, right) = &expr.kind;
         if let hir::BinOpKind::Div = &binop.node;
         then {
-            let (left_ty, right_ty) = (cx.tables.expr_ty(left), cx.tables.expr_ty(right));
+            let (left_ty, right_ty) = (cx.tables().expr_ty(left), cx.tables().expr_ty(right));
             return left_ty.is_integral() && right_ty.is_integral();
         }
     }
index deb57db1678965e946466bd042adc1d108e6e0e6..0301f263489f4938610cb264a3889bb4a833f6bb 100644 (file)
@@ -42,7 +42,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeStackArrays {
     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::Repeat(_, _) = expr.kind;
-            if let ty::Array(element_type, cst) = cx.tables.expr_ty(expr).kind;
+            if let ty::Array(element_type, cst) = cx.tables().expr_ty(expr).kind;
             if let ConstKind::Value(val) = cst.val;
             if let ConstValue::Scalar(element_count) = val;
             if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
index 13e85fda8ffebb607bc7390db32c4bfed5274098..e17297e9695164b38821f46d1b2a57d4c3fcdf6b 100644 (file)
@@ -211,7 +211,8 @@ fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef<'_>, name: &str) -
 }
 
 fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
+    {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -299,7 +300,7 @@ fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
         return false;
     }
 
-    let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
+    let ty = &walk_ptrs_ty(cx.tables().expr_ty(expr));
     match ty.kind {
         ty::Dynamic(ref tt, ..) => {
             if let Some(principal) = tt.principal() {
index 6d3fb317bcfc5fa0f0a612780bb798b6ecab9112..299202981b1f3ad2b72e161eb737f507a0d15455 100644 (file)
@@ -100,14 +100,14 @@ struct BorrowVisitor<'a, 'tcx> {
 impl BorrowVisitor<'_, '_> {
     fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> {
         match &expr.kind {
-            ExprKind::MethodCall(..) => self.cx.tables.type_dependent_def_id(expr.hir_id),
+            ExprKind::MethodCall(..) => self.cx.tables().type_dependent_def_id(expr.hir_id),
             ExprKind::Call(
                 Expr {
                     kind: ExprKind::Path(qpath),
                     ..
                 },
                 ..,
-            ) => self.cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id(),
+            ) => self.cx.tables().qpath_res(qpath, expr.hir_id).opt_def_id(),
             _ => None,
         }
     }
index d7bf8a1476817c28892be2a3033f120fb2585301..7b03812b8226098a6db41294b7da5a9272cd6451 100644 (file)
@@ -73,10 +73,9 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block<'_
                 then {
                     let span = stmt.span.to(if_.span);
 
-                    let has_interior_mutability = !cx.tables.node_type(canonical_id).is_freeze(
-                        cx.tcx,
+                    let has_interior_mutability = !cx.tables().node_type(canonical_id).is_freeze(
+                        cx.tcx.at(span),
                         cx.param_env,
-                        span
                     );
                     if has_interior_mutability { return; }
 
index 710dec8d33fc9e085d83582857e7698fb99389a7..0864bbe0f91272e2c845eefc128a1daa51e247e0 100644 (file)
@@ -35,7 +35,7 @@
     /// **What it does:** Checks for `let _ = sync_lock`
     ///
     /// **Why is this bad?** This statement immediately drops the lock instead of
-    /// extending it's lifetime to the end of the scope, which is often not intended.
+    /// extending its lifetime to the end of the scope, which is often not intended.
     /// To extend lock lifetime to the end of the scope, use an underscore-prefixed
     /// name instead (i.e. _lock). If you want to explicitly drop the lock,
     /// `std::mem::drop` conveys your intention better and is less error-prone.
@@ -76,7 +76,7 @@ fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &Local<'_>) {
             if let PatKind::Wild = local.pat.kind;
             if let Some(ref init) = local.init;
             then {
-                let init_ty = cx.tables.expr_ty(init);
+                let init_ty = cx.tables().expr_ty(init);
                 let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
                     GenericArgKind::Type(inner_ty) => {
                         SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
@@ -94,7 +94,7 @@ fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &Local<'_>) {
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
                     )
-                } else if is_must_use_ty(cx, cx.tables.expr_ty(init)) {
+                } else if is_must_use_ty(cx, cx.tables().expr_ty(init)) {
                     span_lint_and_help(
                         cx,
                         LET_UNDERSCORE_MUST_USE,
index cd258c7b506c39ccd635b4560fd19004958b0d6e..501220f28e5db4d2fb57facf9825dcd142392432 100644 (file)
@@ -1,63 +1,44 @@
 // error-pattern:cargo-clippy
 
 #![feature(bindings_after_at)]
-#![feature(box_syntax)]
 #![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(concat_idents)]
+#![feature(crate_visibility_modifier)]
+#![feature(drain_filter)]
 #![feature(or_patterns)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
-#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
 #![recursion_limit = "512"]
-#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
-#![deny(rustc::internal)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
-#![feature(crate_visibility_modifier)]
-#![feature(concat_idents)]
-#![feature(drain_filter)]
+#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
+#![warn(trivial_casts, trivial_numeric_casts)]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![deny(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
-#[allow(unused_extern_crates)]
 extern crate rustc_ast;
-#[allow(unused_extern_crates)]
 extern crate rustc_ast_pretty;
-#[allow(unused_extern_crates)]
 extern crate rustc_attr;
-#[allow(unused_extern_crates)]
 extern crate rustc_data_structures;
-#[allow(unused_extern_crates)]
-extern crate rustc_driver;
-#[allow(unused_extern_crates)]
 extern crate rustc_errors;
-#[allow(unused_extern_crates)]
 extern crate rustc_hir;
-#[allow(unused_extern_crates)]
 extern crate rustc_hir_pretty;
-#[allow(unused_extern_crates)]
 extern crate rustc_index;
-#[allow(unused_extern_crates)]
 extern crate rustc_infer;
-#[allow(unused_extern_crates)]
 extern crate rustc_lexer;
-#[allow(unused_extern_crates)]
 extern crate rustc_lint;
-#[allow(unused_extern_crates)]
 extern crate rustc_middle;
-#[allow(unused_extern_crates)]
 extern crate rustc_mir;
-#[allow(unused_extern_crates)]
 extern crate rustc_parse;
-#[allow(unused_extern_crates)]
 extern crate rustc_parse_format;
-#[allow(unused_extern_crates)]
 extern crate rustc_session;
-#[allow(unused_extern_crates)]
 extern crate rustc_span;
-#[allow(unused_extern_crates)]
 extern crate rustc_target;
-#[allow(unused_extern_crates)]
 extern crate rustc_trait_selection;
-#[allow(unused_extern_crates)]
 extern crate rustc_typeck;
 
 use rustc_data_structures::fx::FxHashSet;
 /// # Example
 ///
 /// ```
-/// # #![feature(rustc_private)]
-/// # #[allow(unused_extern_crates)]
-/// # extern crate rustc_middle;
-/// # #[allow(unused_extern_crates)]
-/// # extern crate rustc_session;
-/// # #[macro_use]
-/// # use clippy_lints::declare_clippy_lint;
+/// #![feature(rustc_private)]
+/// extern crate rustc_session;
 /// use rustc_session::declare_tool_lint;
+/// use clippy_lints::declare_clippy_lint;
 ///
 /// declare_clippy_lint! {
 ///     /// **What it does:** Checks for ... (describe what the lint matches).
@@ -1062,7 +1039,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
     let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
     store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
-    store.register_early_pass(|| box macro_use::MacroUseImports);
     store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
     store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
     store.register_late_pass(|| box unnamed_address::UnnamedAddress);
@@ -1080,6 +1056,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         single_char_binding_names_threshold,
     });
     store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
+    store.register_late_pass(|| box macro_use::MacroUseImports::default());
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1187,6 +1164,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::OPTION_OPTION),
         LintId::of(&unicode::NON_ASCII_LITERAL),
         LintId::of(&unicode::UNICODE_NOT_NFC),
+        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unused_self::UNUSED_SELF),
         LintId::of(&wildcard_imports::ENUM_GLOB_USE),
         LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
@@ -1440,7 +1418,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
         LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
-        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
         LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
         LintId::of(&unwrap::PANICKING_UNWRAP),
@@ -1624,7 +1601,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::UNNECESSARY_CAST),
         LintId::of(&types::VEC_BOX),
         LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
-        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
         LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
index 318d0b69d57b7924ae7dd9adb8f138689bf838b2..6840e82d4bf1b1790ed7518b586a2dd1d4784407 100644 (file)
@@ -343,7 +343,7 @@ fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) {
                 })
             {
                 let hir_id = ty.hir_id;
-                match self.cx.tables.qpath_res(qpath, hir_id) {
+                match self.cx.tables().qpath_res(qpath, hir_id) {
                     Res::Def(DefKind::TyAlias | DefKind::Struct, def_id) => {
                         let generics = self.cx.tcx.generics_of(def_id);
                         for _ in generics.params.as_slice() {
index 771bc8d055825192cc044de3942c9c1ad661d6c7..18b979176a0a0f6cfe9b77f27b21fdabf0454961 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use std::iter::{once, Iterator};
 use std::mem;
 
@@ -535,7 +535,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                 if_chain! {
                     if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind;
                     if let Some(iter_def_id) = get_trait_def_id(cx, &paths::ITERATOR);
-                    if implements_trait(cx, cx.tables.expr_ty(iter_expr), iter_def_id, &[]);
+                    if implements_trait(cx, cx.tables().expr_ty(iter_expr), iter_def_id, &[]);
                     then {
                         return;
                     }
@@ -985,8 +985,8 @@ fn detect_manual_memcpy<'a, 'tcx>(
                         if_chain! {
                             if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind;
                             if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind;
-                            if is_slice_like(cx, cx.tables.expr_ty(seqexpr_left))
-                                && is_slice_like(cx, cx.tables.expr_ty(seqexpr_right));
+                            if is_slice_like(cx, cx.tables().expr_ty(seqexpr_left))
+                                && is_slice_like(cx, cx.tables().expr_ty(seqexpr_right));
                             if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id);
                             if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id);
 
@@ -1254,8 +1254,8 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e
                     lint_iter_method(cx, args, arg, method_name);
                 }
             } else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) {
-                let receiver_ty = cx.tables.expr_ty(&args[0]);
-                let receiver_ty_adjusted = cx.tables.expr_ty_adjusted(&args[0]);
+                let receiver_ty = cx.tables().expr_ty(&args[0]);
+                let receiver_ty_adjusted = cx.tables().expr_ty_adjusted(&args[0]);
                 if TyS::same_type(receiver_ty, receiver_ty_adjusted) {
                     let mut applicability = Applicability::MachineApplicable;
                     let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
@@ -1300,7 +1300,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e
 
 /// Checks for `for` loops over `Option`s and `Result`s.
 fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
-    let ty = cx.tables.expr_ty(arg);
+    let ty = cx.tables().expr_ty(arg);
     if is_type_diagnostic_item(cx, ty, sym!(option_type)) {
         span_lint_and_help(
             cx,
@@ -1405,7 +1405,7 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
 /// actual `Iterator` that the loop uses.
 fn make_iterator_snippet(cx: &LateContext<'_, '_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
     let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR)
-        .map_or(false, |id| implements_trait(cx, cx.tables.expr_ty(arg), id, &[]));
+        .map_or(false, |id| implements_trait(cx, cx.tables().expr_ty(arg), id, &[]));
     if impls_iterator {
         format!(
             "{}",
@@ -1416,7 +1416,7 @@ fn make_iterator_snippet(cx: &LateContext<'_, '_>, arg: &Expr<'_>, applic_ref: &
         // (&mut x).into_iter() ==> x.iter_mut()
         match &arg.kind {
             ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner)
-                if has_iter_method(cx, cx.tables.expr_ty(&arg_inner)).is_some() =>
+                if has_iter_method(cx, cx.tables().expr_ty(&arg_inner)).is_some() =>
             {
                 let meth_name = match mutability {
                     Mutability::Mut => "iter_mut",
@@ -1449,7 +1449,7 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
     if let PatKind::Tuple(ref pat, _) = pat.kind {
         if pat.len() == 2 {
             let arg_span = arg.span;
-            let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).kind {
+            let (new_pat_span, kind, ty, mutbl) = match cx.tables().expr_ty(arg).kind {
                 ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
                     (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl),
                     (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not),
@@ -1489,42 +1489,43 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
     }
 }
 
-struct MutatePairDelegate {
+struct MutatePairDelegate<'a, 'tcx> {
+    cx: &'a LateContext<'a, 'tcx>,
     hir_id_low: Option<HirId>,
     hir_id_high: Option<HirId>,
     span_low: Option<Span>,
     span_high: Option<Span>,
 }
 
-impl<'tcx> Delegate<'tcx> for MutatePairDelegate {
-    fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {}
+impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
+    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {}
 
-    fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) {
+    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
         if let ty::BorrowKind::MutBorrow = bk {
-            if let PlaceBase::Local(id) = cmt.base {
+            if let PlaceBase::Local(id) = cmt.place.base {
                 if Some(id) == self.hir_id_low {
-                    self.span_low = Some(cmt.span)
+                    self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
                 }
                 if Some(id) == self.hir_id_high {
-                    self.span_high = Some(cmt.span)
+                    self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
                 }
             }
         }
     }
 
-    fn mutate(&mut self, cmt: &Place<'tcx>) {
-        if let PlaceBase::Local(id) = cmt.base {
+    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
+        if let PlaceBase::Local(id) = cmt.place.base {
             if Some(id) == self.hir_id_low {
-                self.span_low = Some(cmt.span)
+                self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
             }
             if Some(id) == self.hir_id_high {
-                self.span_high = Some(cmt.span)
+                self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
             }
         }
     }
 }
 
-impl<'tcx> MutatePairDelegate {
+impl MutatePairDelegate<'_, '_> {
     fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
         (self.span_low, self.span_high)
     }
@@ -1579,12 +1580,13 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr<'_>) -> Option<Hi
     None
 }
 
-fn check_for_mutation(
-    cx: &LateContext<'_, '_>,
+fn check_for_mutation<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
     body: &Expr<'_>,
     bound_ids: &[Option<HirId>],
 ) -> (Option<Span>, Option<Span>) {
     let mut delegate = MutatePairDelegate {
+        cx,
         hir_id_low: bound_ids[0],
         hir_id_high: bound_ids[1],
         span_low: None,
@@ -1592,7 +1594,7 @@ fn check_for_mutation(
     };
     let def_id = body.hir_id.owner.to_def_id();
     cx.tcx.infer_ctxt().enter(|infcx| {
-        ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables).walk_expr(body);
+        ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(body);
     });
     delegate.mutation_span()
 }
@@ -1686,7 +1688,7 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
                             if index_used_directly {
                                 self.indexed_directly.insert(
                                     seqvar.segments[0].ident.name,
-                                    (Some(extent), self.cx.tables.node_type(seqexpr.hir_id)),
+                                    (Some(extent), self.cx.tables().node_type(seqexpr.hir_id)),
                                 );
                             }
                             return false;  // no need to walk further *on the variable*
@@ -1698,7 +1700,7 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
                             if index_used_directly {
                                 self.indexed_directly.insert(
                                     seqvar.segments[0].ident.name,
-                                    (None, self.cx.tables.node_type(seqexpr.hir_id)),
+                                    (None, self.cx.tables().node_type(seqexpr.hir_id)),
                                 );
                             }
                             return false;  // no need to walk further *on the variable*
@@ -1766,7 +1768,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             ExprKind::Call(ref f, args) => {
                 self.visit_expr(f);
                 for expr in args {
-                    let ty = self.cx.tables.expr_ty_adjusted(expr);
+                    let ty = self.cx.tables().expr_ty_adjusted(expr);
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = ty.kind {
                         if mutbl == Mutability::Mut {
@@ -1777,7 +1779,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 }
             },
             ExprKind::MethodCall(_, _, args, _) => {
-                let def_id = self.cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+                let def_id = self.cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
                 for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) {
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = ty.kind {
@@ -1864,7 +1866,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 fn is_ref_iterable_type(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool {
     // no walk_ptrs_ty: calling iter() on a reference can make sense because it
     // will allow further borrows afterwards
-    let ty = cx.tables.expr_ty(e);
+    let ty = cx.tables().expr_ty(e);
     is_iterable_array(ty, cx) ||
     is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
     match_type(cx, ty, &paths::LINKED_LIST) ||
@@ -2040,7 +2042,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if self.state == VarState::DontWarn {
             return;
         }
-        if SpanlessEq::new(self.cx).eq_expr(&expr, self.end_expr) {
+        if expr.hir_id == self.end_expr.hir_id {
             self.past_loop = true;
             return;
         }
@@ -2239,7 +2241,7 @@ fn path_name(e: &Expr<'_>) -> Option<Name> {
 }
 
 fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
-    if constant(cx, cx.tables, cond).is_some() {
+    if constant(cx, cx.tables(), cond).is_some() {
         // A pure constant condition (e.g., `while false`) is not linted.
         return;
     }
@@ -2290,7 +2292,7 @@ struct HasBreakOrReturnVisitor {
     has_break_or_return: bool,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
+impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
@@ -2375,7 +2377,7 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, '
         if let Some(ref generic_args) = chain_method.args;
         if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
         then {
-            let ty = cx.tables.node_type(ty.hir_id);
+            let ty = cx.tables().node_type(ty.hir_id);
             if is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
                 is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) ||
                 match_type(cx, ty, &paths::BTREEMAP) ||
index b1345d0b751ae3b22acf860b2a591fcf547e1f9a..b845b20d2c012c6dc6b4193d36a1b79da03ee2b2 100644 (file)
@@ -1,10 +1,13 @@
-use crate::utils::{snippet, span_lint_and_sugg};
+use crate::utils::{in_macro, snippet, span_lint_and_sugg};
+use hir::def::{DefKind, Res};
 use if_chain::if_chain;
 use rustc_ast::ast;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::edition::Edition;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{edition::Edition, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `#[macro_use] use...`.
@@ -12,7 +15,7 @@
     /// **Why is this bad?** Since the Rust 2018 edition you can import
     /// macro's directly, this is considered idiomatic.
     ///
-    /// **Known problems:** This lint does not generate an auto-applicable suggestion.
+    /// **Known problems:** None.
     ///
     /// **Example:**
     /// ```rust
     "#[macro_use] is no longer needed"
 }
 
-declare_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
+const BRACKETS: &[char] = &['<', '>'];
 
-impl EarlyLintPass for MacroUseImports {
-    fn check_item(&mut self, ecx: &EarlyContext<'_>, item: &ast::Item) {
+#[derive(Clone, Debug, PartialEq, Eq)]
+struct PathAndSpan {
+    path: String,
+    span: Span,
+}
+
+/// `MacroRefData` includes the name of the macro
+/// and the path from `SourceMap::span_to_filename`.
+#[derive(Debug, Clone)]
+pub struct MacroRefData {
+    name: String,
+    path: String,
+}
+
+impl MacroRefData {
+    pub fn new(name: String, callee: Span, cx: &LateContext<'_, '_>) -> Self {
+        let mut path = cx.sess().source_map().span_to_filename(callee).to_string();
+
+        // std lib paths are <::std::module::file type>
+        // so remove brackets, space and type.
+        if path.contains('<') {
+            path = path.replace(BRACKETS, "");
+        }
+        if path.contains(' ') {
+            path = path.split(' ').next().unwrap().to_string();
+        }
+        Self { name, path }
+    }
+}
+
+#[derive(Default)]
+#[allow(clippy::module_name_repetitions)]
+pub struct MacroUseImports {
+    /// the actual import path used and the span of the attribute above it.
+    imports: Vec<(String, Span)>,
+    /// the span of the macro reference, kept to ensure only one reference is used per macro call.
+    collected: FxHashSet<Span>,
+    mac_refs: Vec<MacroRefData>,
+}
+
+impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]);
+
+impl MacroUseImports {
+    fn push_unique_macro(&mut self, cx: &LateContext<'_, '_>, span: Span) {
+        let call_site = span.source_callsite();
+        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
+        if let Some(callee) = span.source_callee() {
+            if !self.collected.contains(&call_site) {
+                let name = if name.contains("::") {
+                    name.split("::").last().unwrap().to_string()
+                } else {
+                    name.to_string()
+                };
+
+                self.mac_refs.push(MacroRefData::new(name, callee.def_site, cx));
+                self.collected.insert(call_site);
+            }
+        }
+    }
+
+    fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_, '_>, span: Span) {
+        let call_site = span.source_callsite();
+        let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
+        if let Some(callee) = span.source_callee() {
+            if !self.collected.contains(&call_site) {
+                self.mac_refs
+                    .push(MacroRefData::new(name.to_string(), callee.def_site, cx));
+                self.collected.insert(call_site);
+            }
+        }
+    }
+}
+
+impl<'l, 'txc> LateLintPass<'l, 'txc> for MacroUseImports {
+    fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item<'_>) {
         if_chain! {
-            if ecx.sess.opts.edition == Edition::Edition2018;
-            if let ast::ItemKind::Use(use_tree) = &item.kind;
+            if cx.sess().opts.edition == Edition::Edition2018;
+            if let hir::ItemKind::Use(path, _kind) = &item.kind;
             if let Some(mac_attr) = item
                 .attrs
                 .iter()
                 .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string()));
+            if let Res::Def(DefKind::Mod, id) = path.res;
             then {
-                let msg = "`macro_use` attributes are no longer needed in the Rust 2018 edition";
-                let help = format!("use {}::<macro name>", snippet(ecx, use_tree.span, "_"));
+                for kid in cx.tcx.item_children(id).iter() {
+                    if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
+                        let span = mac_attr.span;
+                        let def_path = cx.tcx.def_path_str(mac_id);
+                        self.imports.push((def_path, span));
+                    }
+                }
+            } else {
+                if in_macro(item.span) {
+                    self.push_unique_macro_pat_ty(cx, item.span);
+                }
+            }
+        }
+    }
+    fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) {
+        if in_macro(attr.span) {
+            self.push_unique_macro(cx, attr.span);
+        }
+    }
+    fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) {
+        if in_macro(expr.span) {
+            self.push_unique_macro(cx, expr.span);
+        }
+    }
+    fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>) {
+        if in_macro(stmt.span) {
+            self.push_unique_macro(cx, stmt.span);
+        }
+    }
+    fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>) {
+        if in_macro(pat.span) {
+            self.push_unique_macro_pat_ty(cx, pat.span);
+        }
+    }
+    fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &hir::Ty<'_>) {
+        if in_macro(ty.span) {
+            self.push_unique_macro_pat_ty(cx, ty.span);
+        }
+    }
+    #[allow(clippy::too_many_lines)]
+    fn check_crate_post(&mut self, cx: &LateContext<'_, '_>, _krate: &hir::Crate<'_>) {
+        let mut used = FxHashMap::default();
+        let mut check_dup = vec![];
+        for (import, span) in &self.imports {
+            let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name));
+
+            if let Some(idx) = found_idx {
+                let _ = self.mac_refs.remove(idx);
+                let seg = import.split("::").collect::<Vec<_>>();
+
+                match seg.as_slice() {
+                    // an empty path is impossible
+                    // a path should always consist of 2 or more segments
+                    [] | [_] => return,
+                    [root, item] => {
+                        if !check_dup.contains(&(*item).to_string()) {
+                            used.entry(((*root).to_string(), span))
+                                .or_insert_with(Vec::new)
+                                .push((*item).to_string());
+                            check_dup.push((*item).to_string());
+                        }
+                    },
+                    [root, rest @ ..] => {
+                        if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) {
+                            let filtered = rest
+                                .iter()
+                                .filter_map(|item| {
+                                    if check_dup.contains(&(*item).to_string()) {
+                                        None
+                                    } else {
+                                        Some((*item).to_string())
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            used.entry(((*root).to_string(), span))
+                                .or_insert_with(Vec::new)
+                                .push(filtered.join("::"));
+                            check_dup.extend(filtered);
+                        } else {
+                            let rest = rest.to_vec();
+                            used.entry(((*root).to_string(), span))
+                                .or_insert_with(Vec::new)
+                                .push(rest.join("::"));
+                            check_dup.extend(rest.iter().map(ToString::to_string));
+                        }
+                    },
+                }
+            }
+        }
+
+        let mut suggestions = vec![];
+        for ((root, span), path) in used {
+            if path.len() == 1 {
+                suggestions.push((span, format!("{}::{}", root, path[0])))
+            } else {
+                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+            }
+        }
+
+        // If mac_refs is not empty we have encountered an import we could not handle
+        // such as `std::prelude::v1::foo` or some other macro that expands to an import.
+        if self.mac_refs.is_empty() {
+            for (span, import) in suggestions {
+                let help = format!("use {};", import);
                 span_lint_and_sugg(
-                    ecx,
+                    cx,
                     MACRO_USE_IMPORTS,
-                    mac_attr.span,
-                    msg,
+                    *span,
+                    "`macro_use` attributes are no longer needed in the Rust 2018 edition",
                     "remove the attribute and import the macro directly, try",
                     help,
-                    Applicability::HasPlaceholders,
-                );
+                    Applicability::MaybeIncorrect,
+                )
             }
         }
     }
index 8f4fdc685ef38c4d15d0a5af3f53da578445c6dd..9109de9458f1c940a9ded826978d6fc232ddc131 100644 (file)
@@ -52,7 +52,7 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) {
             if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind;
             if args.len() == 2;
             if method.ident.as_str() == "map";
-            let ty = cx.tables.expr_ty(&args[0]);
+            let ty = cx.tables().expr_ty(&args[0]);
             if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR);
             if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
             let closure_body = cx.tcx.hir().body(body_id);
@@ -70,7 +70,7 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) {
                         match closure_expr.kind {
                             hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
                                 if ident_eq(name, inner) {
-                                    if let ty::Ref(.., Mutability::Not) = cx.tables.expr_ty(inner).kind {
+                                    if let ty::Ref(.., Mutability::Not) = cx.tables().expr_ty(inner).kind {
                                         lint(cx, e.span, args[0].span, true);
                                     }
                                 }
@@ -79,7 +79,7 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr<'_>) {
                                 if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone"
                                     && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
 
-                                    let obj_ty = cx.tables.expr_ty(&obj[0]);
+                                    let obj_ty = cx.tables().expr_ty(&obj[0]);
                                     if let ty::Ref(_, ty, _) = obj_ty.kind {
                                         let copy = is_copy(cx, ty);
                                         lint(cx, e.span, args[0].span, copy);
index 8f4b674c04f49ecde8af39f95c813239beb144a4..a4550f707ee224d9993641469195d506168097ea 100644 (file)
@@ -101,7 +101,7 @@ fn is_unit_type(ty: Ty<'_>) -> bool {
 }
 
 fn is_unit_function(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> bool {
-    let ty = cx.tables.expr_ty(expr);
+    let ty = cx.tables().expr_ty(expr);
 
     if let ty::FnDef(id, _) = ty.kind {
         if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
@@ -112,7 +112,7 @@ fn is_unit_function(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> bool {
 }
 
 fn is_unit_expression(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>) -> bool {
-    is_unit_type(cx.tables.expr_ty(expr))
+    is_unit_type(cx.tables().expr_ty(expr))
 }
 
 /// The expression inside a closure may or may not have surrounding braces and
@@ -205,9 +205,9 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
 fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
     let var_arg = &map_args[0];
 
-    let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(option_type)) {
+    let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(option_type)) {
         ("Option", "Some", OPTION_MAP_UNIT_FN)
-    } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(result_type)) {
+    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(result_type)) {
         ("Result", "Ok", RESULT_MAP_UNIT_FN)
     } else {
         return;
index ee69628e9f05224953a8e9d3680f83c263efe6ef..4a025e0621f9643f9903c2c32ae9ab277588b86e 100644 (file)
@@ -88,13 +88,13 @@ fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>)
 }
 
 fn is_vector(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-    let ty = cx.tables.expr_ty(expr);
+    let ty = cx.tables().expr_ty(expr);
     let ty = walk_ptrs_ty(ty);
     is_type_diagnostic_item(cx, ty, sym!(vec_type))
 }
 
 fn is_full_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-    let ty = cx.tables.expr_ty(expr);
+    let ty = cx.tables().expr_ty(expr);
     let ty = walk_ptrs_ty(ty);
     match_type(cx, ty, &utils::paths::RANGE_FULL)
 }
index 6d7af45a47224d54a99e6949c50185e792acf9bc..0c91d8885d9242adaabb0974840da4ac23da261e 100644 (file)
@@ -540,7 +540,7 @@ fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>],
             // allow match arms with just expressions
             return;
         };
-        let ty = cx.tables.expr_ty(ex);
+        let ty = cx.tables().expr_ty(ex);
         if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
             check_single_match_single_pattern(cx, ex, arms, expr, els);
             check_single_match_opt_like(cx, ex, arms, expr, ty, els);
@@ -632,7 +632,7 @@ fn check_single_match_opt_like(
 
 fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     // Type of expression is `bool`.
-    if cx.tables.expr_ty(ex).kind == ty::Bool {
+    if cx.tables().expr_ty(ex).kind == ty::Bool {
         span_lint_and_then(
             cx,
             MATCH_BOOL,
@@ -695,8 +695,8 @@ fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], e
 }
 
 fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
-    if arms.len() >= 2 && cx.tables.expr_ty(ex).is_integral() {
-        let ranges = all_ranges(cx, arms, cx.tables.expr_ty(ex));
+    if arms.len() >= 2 && cx.tables().expr_ty(ex).is_integral() {
+        let ranges = all_ranges(cx, arms, cx.tables().expr_ty(ex));
         let type_ranges = type_ranges(&ranges);
         if !type_ranges.is_empty() {
             if let Some((start, end)) = overlapping(&type_ranges) {
@@ -714,7 +714,7 @@ fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<'
 }
 
 fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
-    let ex_ty = walk_ptrs_ty(cx.tables.expr_ty(ex));
+    let ex_ty = walk_ptrs_ty(cx.tables().expr_ty(ex));
     if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
         for arm in arms {
             if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
@@ -755,7 +755,7 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>])
 }
 
 fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
-    let ty = cx.tables.expr_ty(ex);
+    let ty = cx.tables().expr_ty(ex);
     if !ty.is_enum() {
         // If there isn't a nice closed set of possible values that can be conveniently enumerated,
         // don't complain about not enumerating the mall.
@@ -935,8 +935,8 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>],
                 "as_mut"
             };
 
-            let output_ty = cx.tables.expr_ty(expr);
-            let input_ty = cx.tables.expr_ty(ex);
+            let output_ty = cx.tables().expr_ty(expr);
+            let input_ty = cx.tables().expr_ty(ex);
 
             let cast = if_chain! {
                 if let ty::Adt(_, substs) = input_ty.kind;
@@ -1006,13 +1006,13 @@ fn check_match_single_binding<'a>(cx: &LateContext<'_, 'a>, ex: &Expr<'a>, arms:
     match match_body.kind {
         ExprKind::Block(block, _) => {
             // macro + expr_ty(body) == ()
-            if block.span.from_expansion() && cx.tables.expr_ty(&match_body).is_unit() {
+            if block.span.from_expansion() && cx.tables().expr_ty(&match_body).is_unit() {
                 snippet_body.push(';');
             }
         },
         _ => {
             // expr_ty(body) == ()
-            if cx.tables.expr_ty(&match_body).is_unit() {
+            if cx.tables().expr_ty(&match_body).is_unit() {
                 snippet_body.push(';');
             }
         },
@@ -1111,11 +1111,11 @@ fn all_ranges<'a, 'tcx>(
             {
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
                     let lhs = match lhs {
-                        Some(lhs) => constant(cx, cx.tables, lhs)?.0,
+                        Some(lhs) => constant(cx, cx.tables(), lhs)?.0,
                         None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
                     };
                     let rhs = match rhs {
-                        Some(rhs) => constant(cx, cx.tables, rhs)?.0,
+                        Some(rhs) => constant(cx, cx.tables(), rhs)?.0,
                         None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
                     };
                     let rhs = match range_end {
@@ -1129,7 +1129,7 @@ fn all_ranges<'a, 'tcx>(
                 }
 
                 if let PatKind::Lit(ref value) = pat.kind {
-                    let value = constant(cx, cx.tables, value)?.0;
+                    let value = constant(cx, cx.tables(), value)?.0;
                     return Some(SpannedRange {
                         span: pat.span,
                         node: (value.clone(), Bound::Included(value)),
index 3f953655670cfcee0cb5cf6bffbc4b8e4afc28de..d315c5ef89a8830b626d9166c05c44b078b2b0a4 100644 (file)
@@ -35,10 +35,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Call(ref func, ref func_args) = expr.kind;
             // is `mem::discriminant`
             if let ExprKind::Path(ref func_qpath) = func.kind;
-            if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+            if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::MEM_DISCRIMINANT);
             // type is non-enum
-            let ty_param = cx.tables.node_substs(func.hir_id).type_at(0);
+            let ty_param = cx.tables().node_substs(func.hir_id).type_at(0);
             if !ty_param.is_enum();
 
             then {
index c6ddc5de63b0ed3a962777c28a497dcbc25b1a4b..1821bd9135f981d91aca4fdd230826215197187e 100644 (file)
@@ -31,7 +31,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
             if let ExprKind::Path(ref qpath) = path_expr.kind {
                 if let Some(def_id) = qpath_res(cx, qpath, path_expr.hir_id).opt_def_id() {
                     if match_def_path(cx, def_id, &paths::MEM_FORGET) {
-                        let forgot_ty = cx.tables.expr_ty(&args[0]);
+                        let forgot_ty = cx.tables().expr_ty(&args[0]);
 
                         if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
                             span_lint(cx, MEM_FORGET, e.span, "usage of `mem::forget` on `Drop` type");
index ab6865bf0f3b7675edd08a150d2c0dd0c4eee121..16d31fc8346ea71ca6960e5639a5e8170320d2d9 100644 (file)
@@ -135,33 +135,59 @@ fn check_replace_option_with_none(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest
     }
 }
 
-fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span: Span) {
-    if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind {
-        if_chain! {
-            if repl_args.is_empty();
-            if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
-            if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
-            then {
-                if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
-                    span_lint_and_help(
-                        cx,
-                        MEM_REPLACE_WITH_UNINIT,
-                        expr_span,
-                        "replacing with `mem::uninitialized()`",
-                        None,
-                        "consider using the `take_mut` crate instead",
-                    );
-                } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
-                        !cx.tables.expr_ty(src).is_primitive() {
-                    span_lint_and_help(
-                        cx,
-                        MEM_REPLACE_WITH_UNINIT,
-                        expr_span,
-                        "replacing with `mem::zeroed()`",
-                        None,
-                        "consider using a default value or the `take_mut` crate instead",
-                    );
-                }
+fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
+    if_chain! {
+        // check if replacement is mem::MaybeUninit::uninit().assume_init()
+        if let Some(method_def_id) = cx.tables().type_dependent_def_id(src.hir_id);
+        if cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id);
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                MEM_REPLACE_WITH_UNINIT,
+                expr_span,
+                "replacing with `mem::MaybeUninit::uninit().assume_init()`",
+                "consider using",
+                format!(
+                    "std::ptr::read({})",
+                    snippet_with_applicability(cx, dest.span, "", &mut applicability)
+                ),
+                applicability,
+            );
+            return;
+        }
+    }
+
+    if_chain! {
+        if let ExprKind::Call(ref repl_func, ref repl_args) = src.kind;
+        if repl_args.is_empty();
+        if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
+        if let Some(repl_def_id) = cx.tables().qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
+        then {
+            if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
+                let mut applicability = Applicability::MachineApplicable;
+                span_lint_and_sugg(
+                    cx,
+                    MEM_REPLACE_WITH_UNINIT,
+                    expr_span,
+                    "replacing with `mem::uninitialized()`",
+                    "consider using",
+                    format!(
+                        "std::ptr::read({})",
+                        snippet_with_applicability(cx, dest.span, "", &mut applicability)
+                    ),
+                    applicability,
+                );
+            } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
+                    !cx.tables().expr_ty(src).is_primitive() {
+                span_lint_and_help(
+                    cx,
+                    MEM_REPLACE_WITH_UNINIT,
+                    expr_span,
+                    "replacing with `mem::zeroed()`",
+                    None,
+                    "consider using a default value or the `take_mut` crate instead",
+                );
             }
         }
     }
@@ -172,7 +198,7 @@ fn check_replace_with_default(cx: &LateContext<'_, '_>, src: &Expr<'_>, dest: &E
         if_chain! {
             if !in_external_macro(cx.tcx.sess, expr_span);
             if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
-            if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
+            if let Some(repl_def_id) = cx.tables().qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
             if match_def_path(cx, repl_def_id, &paths::DEFAULT_TRAIT_METHOD);
             then {
                 span_lint_and_then(
@@ -204,12 +230,12 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             // Check that `expr` is a call to `mem::replace()`
             if let ExprKind::Call(ref func, ref func_args) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
-            if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+            if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::MEM_REPLACE);
             if let [dest, src] = &**func_args;
             then {
                 check_replace_option_with_none(cx, src, dest, expr.span);
-                check_replace_with_uninit(cx, src, expr.span);
+                check_replace_with_uninit(cx, src, dest, expr.span);
                 check_replace_with_default(cx, src, dest, expr.span);
             }
         }
index 32e86637569ed3c642be6d766abcefe1e3fc9bb4..092702c8b8c7bf5ddf0e6b1bd9b9e340789b505b 100644 (file)
@@ -157,7 +157,7 @@ fn lint_closure(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, closure_expr: &h
 
     /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
     fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-        if !match_type(cx, cx.tables.expr_ty(&args[0]), Self::TYPE_QPATH) {
+        if !match_type(cx, cx.tables().expr_ty(&args[0]), Self::TYPE_QPATH) {
             return;
         }
 
index 06138ab9783c34f19d8b1340a05d846c20237a3f..d29b9adcb7d43375e8df5d6bbdacf31bb2a89de0 100644 (file)
@@ -11,9 +11,9 @@
 /// Checks for the `INEFFICIENT_TO_STRING` lint
 pub fn lint<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) {
     if_chain! {
-        if let Some(to_string_meth_did) = cx.tables.type_dependent_def_id(expr.hir_id);
+        if let Some(to_string_meth_did) = cx.tables().type_dependent_def_id(expr.hir_id);
         if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
-        if let Some(substs) = cx.tables.node_substs_opt(expr.hir_id);
+        if let Some(substs) = cx.tables().node_substs_opt(expr.hir_id);
         let self_ty = substs.type_at(0);
         let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
         if deref_count >= 1;
index 4f5c06e785c23eeb1eded772c87a595ed1a6a49b..eb02314f4680a8246a2ff6477355a005d97209b9 100644 (file)
@@ -11,7 +11,7 @@ pub fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<
     let arith_lhs = &args[1][0];
     let arith_rhs = &args[1][1];
 
-    let ty = cx.tables.expr_ty(arith_lhs);
+    let ty = cx.tables().expr_ty(arith_lhs);
     if !ty.is_integral() {
         return;
     }
@@ -101,7 +101,7 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr<'_>) -> Opti
         }
     }
 
-    let ty = cx.tables.expr_ty(expr);
+    let ty = cx.tables().expr_ty(expr);
     let ty_str = ty.to_string();
 
     // `std::T::MAX` `std::T::MIN` constants
index f25a9782813bbbd36c0bdf906b6f408a24294c0f..c4e707ecf03adfabeb7dbb92dda27cd377b0fc25 100644 (file)
@@ -1433,7 +1433,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
                 lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
                 lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
 
-                let self_ty = cx.tables.expr_ty_adjusted(&args[0]);
+                let self_ty = cx.tables().expr_ty_adjusted(&args[0]);
                 if args.len() == 1 && method_call.ident.name == sym!(clone) {
                     lint_clone_on_copy(cx, expr, &args[0], self_ty);
                     lint_clone_on_ref_ptr(cx, expr, &args[0]);
@@ -1639,7 +1639,7 @@ fn check_unwrap_or_default(
             if let hir::ExprKind::Path(ref qpath) = fun.kind;
             let path = &*last_path_segment(qpath).ident.as_str();
             if ["default", "new"].contains(&path);
-            let arg_ty = cx.tables.expr_ty(arg);
+            let arg_ty = cx.tables().expr_ty(arg);
             if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
             if implements_trait(cx, arg_ty, default_trait_id, &[]);
 
@@ -1679,7 +1679,7 @@ fn check_general_case<'a, 'tcx>(
     ) {
         if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
             if path.ident.as_str() == "len" {
-                let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+                let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
 
                 match ty.kind {
                     ty::Slice(_) | ty::Array(_, _) => return,
@@ -1707,7 +1707,7 @@ fn check_general_case<'a, 'tcx>(
             if { finder.visit_expr(&arg); finder.found };
             if !contains_return(&arg);
 
-            let self_ty = cx.tables.expr_ty(self_expr);
+            let self_ty = cx.tables().expr_ty(self_expr);
 
             if let Some(&(_, fn_has_arguments, poss, suffix)) =
                 know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
@@ -1786,7 +1786,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_, '_>, arg: &'a hir::Expr<'a>) -> &'a hir
                     if call_args.len() == 1
                         && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref))
                         && {
-                            let arg_type = cx.tables.expr_ty(&call_args[0]);
+                            let arg_type = cx.tables().expr_ty(&call_args[0]);
                             let base_type = walk_ptrs_ty(arg_type);
                             base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
                         }
@@ -1805,7 +1805,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_, '_>, arg: &'a hir::Expr<'a>) -> &'a hir
     // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
     // converted to string.
     fn requires_to_string(cx: &LateContext<'_, '_>, arg: &hir::Expr<'_>) -> bool {
-        let arg_ty = cx.tables.expr_ty(arg);
+        let arg_ty = cx.tables().expr_ty(arg);
         if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) {
             return false;
         }
@@ -1824,7 +1824,7 @@ fn can_be_static_str(cx: &LateContext<'_, '_>, arg: &hir::Expr<'_>) -> bool {
             hir::ExprKind::Lit(_) => true,
             hir::ExprKind::Call(fun, _) => {
                 if let hir::ExprKind::Path(ref p) = fun.kind {
-                    match cx.tables.qpath_res(p, fun.hir_id) {
+                    match cx.tables().qpath_res(p, fun.hir_id) {
                         hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
                             cx.tcx.fn_sig(def_id).output().skip_binder().kind,
                             ty::Ref(ty::ReStatic, ..)
@@ -1835,13 +1835,16 @@ fn can_be_static_str(cx: &LateContext<'_, '_>, arg: &hir::Expr<'_>) -> bool {
                     false
                 }
             },
-            hir::ExprKind::MethodCall(..) => cx.tables.type_dependent_def_id(arg.hir_id).map_or(false, |method_id| {
-                matches!(
-                    cx.tcx.fn_sig(method_id).output().skip_binder().kind,
-                    ty::Ref(ty::ReStatic, ..)
-                )
-            }),
-            hir::ExprKind::Path(ref p) => match cx.tables.qpath_res(p, arg.hir_id) {
+            hir::ExprKind::MethodCall(..) => cx
+                .tables()
+                .type_dependent_def_id(arg.hir_id)
+                .map_or(false, |method_id| {
+                    matches!(
+                        cx.tcx.fn_sig(method_id).output().skip_binder().kind,
+                        ty::Ref(ty::ReStatic, ..)
+                    )
+                }),
+            hir::ExprKind::Path(ref p) => match cx.tables().qpath_res(p, arg.hir_id) {
                 hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) => true,
                 _ => false,
             },
@@ -1888,7 +1891,7 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
         return;
     }
 
-    let receiver_type = cx.tables.expr_ty_adjusted(&args[0]);
+    let receiver_type = cx.tables().expr_ty_adjusted(&args[0]);
     let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
         "||"
     } else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
@@ -1954,7 +1957,7 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
 
 /// Checks for the `CLONE_ON_COPY` lint.
 fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'_>) {
-    let ty = cx.tables.expr_ty(expr);
+    let ty = cx.tables().expr_ty(expr);
     if let ty::Ref(_, inner, _) = arg_ty.kind {
         if let ty::Ref(_, innermost, _) = inner.kind {
             span_lint_and_then(
@@ -2018,11 +2021,11 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir:
             }
 
             // x.clone() might have dereferenced x, possibly through Deref impls
-            if cx.tables.expr_ty(arg) == ty {
+            if cx.tables().expr_ty(arg) == ty {
                 snip = Some(("try removing the `clone` call", format!("{}", snippet)));
             } else {
                 let deref_count = cx
-                    .tables
+                    .tables()
                     .expr_adjustments(arg)
                     .iter()
                     .filter(|adj| {
@@ -2048,7 +2051,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir:
 }
 
 fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
-    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
+    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(arg));
 
     if let ty::Adt(_, subst) = obj_ty.kind {
         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
@@ -2082,7 +2085,7 @@ fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hi
     let arg = &args[1];
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
         let target = &arglists[0][0];
-        let self_ty = walk_ptrs_ty(cx.tables.expr_ty(target));
+        let self_ty = walk_ptrs_ty(cx.tables().expr_ty(target));
         let ref_str = if self_ty.kind == ty::Str {
             ""
         } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
@@ -2110,7 +2113,7 @@ fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hi
 }
 
 fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
     if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
         lint_string_extend(cx, expr, args);
     }
@@ -2118,7 +2121,7 @@ fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr
 
 fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) {
     if_chain! {
-        let source_type = cx.tables.expr_ty(source);
+        let source_type = cx.tables().expr_ty(source);
         if let ty::Adt(def, substs) = source_type.kind;
         if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
         if match_type(cx, substs.type_at(0), &paths::CSTRING);
@@ -2142,8 +2145,8 @@ fn lint_iter_cloned_collect<'a, 'tcx>(
     iter_args: &'tcx [hir::Expr<'_>],
 ) {
     if_chain! {
-        if is_type_diagnostic_item(cx, cx.tables.expr_ty(expr), sym!(vec_type));
-        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0]));
+        if is_type_diagnostic_item(cx, cx.tables().expr_ty(expr), sym!(vec_type));
+        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables().expr_ty(&iter_args[0]));
         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
 
         then {
@@ -2250,7 +2253,7 @@ fn check_fold_with_op(
 
 fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
     if match_trait_method(cx, expr, &paths::ITERATOR) {
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &args[1]) {
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.tables(), &args[1]) {
             span_lint(
                 cx,
                 ITERATOR_STEP_BY_ZERO,
@@ -2274,7 +2277,7 @@ fn lint_iter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_
         parent_expr_opt = get_parent_expr(cx, parent_expr);
     }
 
-    if derefs_to_slice(cx, caller_expr, cx.tables.expr_ty(caller_expr)).is_some() {
+    if derefs_to_slice(cx, caller_expr, cx.tables().expr_ty(caller_expr)).is_some() {
         // caller is a Slice
         if_chain! {
             if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
@@ -2295,8 +2298,8 @@ fn lint_iter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_
                 );
             }
         }
-    } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(caller_expr), sym!(vec_type))
-        || matches!(&walk_ptrs_ty(cx.tables.expr_ty(caller_expr)).kind, ty::Array(_, _))
+    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(caller_expr), sym!(vec_type))
+        || matches!(&walk_ptrs_ty(cx.tables().expr_ty(caller_expr)).kind, ty::Array(_, _))
     {
         // caller is a Vec or an Array
         let mut applicability = Applicability::MachineApplicable;
@@ -2323,11 +2326,11 @@ fn lint_iter_nth<'a, 'tcx>(
 ) {
     let iter_args = nth_and_iter_args[1];
     let mut_str = if is_mut { "_mut" } else { "" };
-    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
+    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables().expr_ty(&iter_args[0])).is_some() {
         "slice"
-    } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(&iter_args[0]), sym!(vec_type)) {
+    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(&iter_args[0]), sym!(vec_type)) {
         "Vec"
-    } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
+    } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
         "VecDeque"
     } else {
         let nth_args = nth_and_iter_args[0];
@@ -2348,7 +2351,7 @@ fn lint_iter_nth<'a, 'tcx>(
 fn lint_iter_nth_zero<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
     if_chain! {
         if match_trait_method(cx, expr, &paths::ITERATOR);
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.tables, &nth_args[1]);
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.tables(), &nth_args[1]);
         then {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
@@ -2373,7 +2376,7 @@ fn lint_get_unwrap<'a, 'tcx>(
     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
     // because they do not implement `IndexMut`
     let mut applicability = Applicability::MachineApplicable;
-    let expr_ty = cx.tables.expr_ty(&get_args[0]);
+    let expr_ty = cx.tables().expr_ty(&get_args[0]);
     let get_args_str = if get_args.len() > 1 {
         snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
     } else {
@@ -2479,7 +2482,7 @@ fn may_slice<'a>(cx: &LateContext<'_, 'a>, ty: Ty<'a>) -> bool {
     }
 
     if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
-        if path.ident.name == sym!(iter) && may_slice(cx, cx.tables.expr_ty(&args[0])) {
+        if path.ident.name == sym!(iter) && may_slice(cx, cx.tables().expr_ty(&args[0])) {
             Some(&args[0])
         } else {
             None
@@ -2502,7 +2505,7 @@ fn may_slice<'a>(cx: &LateContext<'_, 'a>, ty: Ty<'a>) -> bool {
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
 fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
+    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&unwrap_args[0]));
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
         Some((UNWRAP_USED, "an Option", "None"))
@@ -2530,7 +2533,7 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hi
 
 /// lint use of `expect()` for `Option`s and `Result`s
 fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
-    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&expect_args[0]));
+    let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&expect_args[0]));
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
         Some((EXPECT_USED, "an Option", "None"))
@@ -2556,8 +2559,8 @@ fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hi
 fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
     if_chain! {
         // lint if the caller of `ok()` is a `Result`
-        if is_type_diagnostic_item(cx, cx.tables.expr_ty(&ok_args[0]), sym!(result_type));
-        let result_type = cx.tables.expr_ty(&ok_args[0]);
+        if is_type_diagnostic_item(cx, cx.tables().expr_ty(&ok_args[0]), sym!(result_type));
+        let result_type = cx.tables().expr_ty(&ok_args[0]);
         if let Some(error_type) = get_error_type(cx, result_type);
         if has_debug_impl(error_type, cx);
 
@@ -2595,7 +2598,7 @@ fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<
     }
 
     // lint if caller of `.map().flatten()` is an Option
-    if is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type)) {
+    if is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)) {
         let msg = "called `map(..).flatten()` on an `Option`. \
                     This is more succinctly expressed by calling `.and_then(..)`";
         let self_snippet = snippet(cx, map_args[0].span, "..");
@@ -2621,8 +2624,8 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
     unwrap_args: &'tcx [hir::Expr<'_>],
 ) {
     // lint if the caller of `map()` is an `Option`
-    let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type));
-    let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(result_type));
+    let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type));
+    let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(result_type));
 
     if is_option || is_result {
         // Don't make a suggestion that may fail to compile due to mutably borrowing
@@ -2676,8 +2679,8 @@ fn lint_map_or_none<'a, 'tcx>(
     expr: &'tcx hir::Expr<'_>,
     map_or_args: &'tcx [hir::Expr<'_>],
 ) {
-    let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(option_type));
-    let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(result_type));
+    let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_or_args[0]), sym!(option_type));
+    let is_result = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_or_args[0]), sym!(result_type));
 
     // There are two variants of this `map_or` lint:
     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
@@ -3042,7 +3045,7 @@ fn lint_chars_cmp(
         if segment.ident.name == sym!(Some);
         then {
             let mut applicability = Applicability::MachineApplicable;
-            let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
+            let self_ty = walk_ptrs_ty(cx.tables().expr_ty_adjusted(&args[0][0]));
 
             if self_ty.kind != ty::Str {
                 return false;
@@ -3174,8 +3177,8 @@ fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, call_name: &str, a
     if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
         // check if the type after `as_ref` or `as_mut` is the same as before
         let recvr = &as_ref_args[0];
-        let rcv_ty = cx.tables.expr_ty(recvr);
-        let res_ty = cx.tables.expr_ty(expr);
+        let rcv_ty = cx.tables().expr_ty(recvr);
+        let res_ty = cx.tables().expr_ty(expr);
         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
         let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
@@ -3244,7 +3247,7 @@ fn lint_maybe_uninit(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, outer: &hir
         if args.is_empty();
         if let hir::ExprKind::Path(ref path) = callee.kind;
         if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
-        if !is_maybe_uninit_ty_valid(cx, cx.tables.expr_ty_adjusted(outer));
+        if !is_maybe_uninit_ty_valid(cx, cx.tables().expr_ty_adjusted(outer));
         then {
             span_lint(
                 cx,
@@ -3286,7 +3289,7 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
 ) {
     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
 
-    let option_ty = cx.tables.expr_ty(&as_ref_args[0]);
+    let option_ty = cx.tables().expr_ty(&as_ref_args[0]);
     if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) {
         return;
     }
@@ -3314,12 +3317,12 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
                     if_chain! {
                         if args.len() == 1;
                         if let hir::ExprKind::Path(qpath) = &args[0].kind;
-                        if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id);
+                        if let hir::def::Res::Local(local_id) = cx.tables().qpath_res(qpath, args[0].hir_id);
                         if closure_body.params[0].pat.hir_id == local_id;
-                        let adj = cx.tables.expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
+                        let adj = cx.tables().expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
                         if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
                         then {
-                            let method_did = cx.tables.type_dependent_def_id(closure_expr.hir_id).unwrap();
+                            let method_did = cx.tables().type_dependent_def_id(closure_expr.hir_id).unwrap();
                             deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
                         } else {
                             false
@@ -3331,7 +3334,7 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
                         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
                         if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
                         if let hir::ExprKind::Path(ref qpath) = inner2.kind;
-                        if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, inner2.hir_id);
+                        if let hir::def::Res::Local(local_id) = cx.tables().qpath_res(qpath, inner2.hir_id);
                         then {
                             closure_body.params[0].pat.hir_id == local_id
                         } else {
@@ -3614,7 +3617,7 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 fn check_pointer_offset(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     if_chain! {
         if args.len() == 2;
-        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.tables.expr_ty(&args[0]).kind;
+        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.tables().expr_ty(&args[0]).kind;
         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
         if layout.is_zst();
         then {
@@ -3624,7 +3627,7 @@ fn check_pointer_offset(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[
 }
 
 fn lint_filetype_is_file(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let ty = cx.tables.expr_ty(&args[0]);
+    let ty = cx.tables().expr_ty(&args[0]);
 
     if !match_type(cx, ty, &paths::FILE_TYPE) {
         return;
index 20c60ef33189dc45f41ffa9f421b369a2648af00..7f4529a5870ac142f5ad06b821ebcbf15d0dddce 100644 (file)
@@ -20,8 +20,8 @@ pub(super) fn lint<'a, 'tcx>(
     map_span: Span,
 ) {
     // lint if the caller of `map()` is an `Option`
-    if is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type)) {
-        if !is_copy(cx, cx.tables.expr_ty(&unwrap_args[1])) {
+    if is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)) {
+        if !is_copy(cx, cx.tables().expr_ty(&unwrap_args[1])) {
             // Do not lint if the `map` argument uses identifiers in the `map`
             // argument that are also used in the `unwrap_or` argument
 
index 41c9ce7cda3e61ab780854fd44c566e5be870523..88243a88d9dd7a91c71c9cf33c47968b62fc1407 100644 (file)
@@ -65,7 +65,7 @@ fn check_expression<'a, 'tcx>(
                     if match_qpath(path, &paths::OPTION_SOME) {
                         if_chain! {
                             if let hir::ExprKind::Path(path) = &args[0].kind;
-                            if let Res::Local(ref local) = cx.tables.qpath_res(path, args[0].hir_id);
+                            if let Res::Local(ref local) = cx.tables().qpath_res(path, args[0].hir_id);
                             then {
                                 if arg_id == *local {
                                     return (false, false)
index b02c993de526b0478cacbcfc990f17d752d454f4..8e6f3925d66050fd819b8fddfda818d609773590 100644 (file)
@@ -36,7 +36,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                 }
                 match (
                     outer_max,
-                    Constant::partial_cmp(cx.tcx, cx.tables.expr_ty(ie), &outer_c, &inner_c),
+                    Constant::partial_cmp(cx.tcx, cx.tables().expr_ty(ie), &outer_c, &inner_c),
                 ) {
                     (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
                     _ => {
@@ -62,15 +62,18 @@ enum MinMax {
 fn min_max<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
     if let ExprKind::Call(ref path, ref args) = expr.kind {
         if let ExprKind::Path(ref qpath) = path.kind {
-            cx.tables.qpath_res(qpath, path.hir_id).opt_def_id().and_then(|def_id| {
-                if match_def_path(cx, def_id, &paths::CMP_MIN) {
-                    fetch_const(cx, args, MinMax::Min)
-                } else if match_def_path(cx, def_id, &paths::CMP_MAX) {
-                    fetch_const(cx, args, MinMax::Max)
-                } else {
-                    None
-                }
-            })
+            cx.tables()
+                .qpath_res(qpath, path.hir_id)
+                .opt_def_id()
+                .and_then(|def_id| {
+                    if match_def_path(cx, def_id, &paths::CMP_MIN) {
+                        fetch_const(cx, args, MinMax::Min)
+                    } else if match_def_path(cx, def_id, &paths::CMP_MAX) {
+                        fetch_const(cx, args, MinMax::Max)
+                    } else {
+                        None
+                    }
+                })
         } else {
             None
         }
@@ -87,14 +90,14 @@ fn fetch_const<'a>(
     if args.len() != 2 {
         return None;
     }
-    if let Some(c) = constant_simple(cx, cx.tables, &args[0]) {
-        if constant_simple(cx, cx.tables, &args[1]).is_none() {
+    if let Some(c) = constant_simple(cx, cx.tables(), &args[0]) {
+        if constant_simple(cx, cx.tables(), &args[1]).is_none() {
             // otherwise ignore
             Some((m, c, &args[1]))
         } else {
             None
         }
-    } else if let Some(c) = constant_simple(cx, cx.tables, &args[1]) {
+    } else if let Some(c) = constant_simple(cx, cx.tables(), &args[1]) {
         Some((m, c, &args[0]))
     } else {
         None
index a0947608e60776dc0db4ab3a43addc0871f72f10..99cd864cae4e35b62955871bdc6d924a3c19671d 100644 (file)
@@ -436,7 +436,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                     binding != "_result" && // FIXME: #944
                     is_used(cx, expr) &&
                     // don't lint if the declaration is in a macro
-                    non_macro_local(cx, cx.tables.qpath_res(qpath, expr.hir_id))
+                    non_macro_local(cx, cx.tables().qpath_res(qpath, expr.hir_id))
                 {
                     Some(binding)
                 } else {
@@ -496,7 +496,7 @@ fn get_lint_and_message(
 fn check_nan(cx: &LateContext<'_, '_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
     if_chain! {
         if !in_constant(cx, cmp_expr.hir_id);
-        if let Some((value, _)) = constant(cx, cx.tables, expr);
+        if let Some((value, _)) = constant(cx, cx.tables(), expr);
         then {
             let needs_lint = match value {
                 Constant::F32(num) => num.is_nan(),
@@ -517,7 +517,7 @@ fn check_nan(cx: &LateContext<'_, '_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
 }
 
 fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> bool {
-    if let Some((_, res)) = constant(cx, cx.tables, expr) {
+    if let Some((_, res)) = constant(cx, cx.tables(), expr) {
         res
     } else {
         false
@@ -525,7 +525,7 @@ fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>)
 }
 
 fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> bool {
-    match constant(cx, cx.tables, expr) {
+    match constant(cx, cx.tables(), expr) {
         Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(),
         Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(),
         Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f {
@@ -557,7 +557,7 @@ fn is_signum(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_float(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-    let value = &walk_ptrs_ty(cx.tables.expr_ty(expr)).kind;
+    let value = &walk_ptrs_ty(cx.tables().expr_ty(expr)).kind;
 
     if let ty::Array(arr_ty, _) = value {
         return matches!(arr_ty.kind, ty::Float(_));
@@ -567,14 +567,14 @@ fn is_float(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
 }
 
 fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-    matches!(&walk_ptrs_ty(cx.tables.expr_ty(expr)).kind, ty::Array(_, _))
+    matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _))
 }
 
 fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
     let (arg_ty, snip) = match expr.kind {
         ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
             if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
-                (cx.tables.expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
+                (cx.tables().expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
             } else {
                 return;
             }
@@ -582,7 +582,7 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
         ExprKind::Call(ref path, ref v) if v.len() == 1 => {
             if let ExprKind::Path(ref path) = path.kind {
                 if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
-                    (cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
+                    (cx.tables().expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
                 } else {
                     return;
                 }
@@ -593,7 +593,7 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
         _ => return,
     };
 
-    let other_ty = cx.tables.expr_ty_adjusted(other);
+    let other_ty = cx.tables().expr_ty_adjusted(other);
     let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() {
         Some(id) => id,
         None => return,
index 4ca90455bc4d1e81b44bbd1c8fdc51e61a99561a..f76e4721e1f63dd315045bf0ef2c1a64cdb22f9f 100644 (file)
@@ -37,8 +37,8 @@ struct OperandInfo {
 }
 
 fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<OperandInfo> {
-    match constant(cx, cx.tables, operand) {
-        Some((Constant::Int(v), _)) => match cx.tables.expr_ty(expr).kind {
+    match constant(cx, cx.tables(), operand) {
+        Some((Constant::Int(v), _)) => match cx.tables().expr_ty(expr).kind {
             ty::Int(ity) => {
                 let value = sext(cx.tcx, v, ity);
                 return Some(OperandInfo {
@@ -106,7 +106,7 @@ fn check_const_operands<'a, 'tcx>(
 }
 
 fn check_non_const_operands<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, operand: &Expr<'_>) {
-    let operand_type = cx.tables.expr_ty(operand);
+    let operand_type = cx.tables().expr_ty(operand);
     if might_have_negative_value(operand_type) {
         span_lint_and_then(
             cx,
index 0b9b7e1b8cc1b3e8e951d2f97dc43ff080390638..755b196c698c2ed0a050d0d442ec1d2fd848a718 100644 (file)
@@ -76,7 +76,7 @@ fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &hir::Local<'_>) {
         if let hir::PatKind::Wild = local.pat.kind {
             return;
         }
-        check_ty(cx, local.span, cx.tables.pat_ty(&*local.pat));
+        check_ty(cx, local.span, cx.tables().pat_ty(&*local.pat));
     }
 }
 
@@ -118,7 +118,7 @@ fn is_mutable_type<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Spa
             size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_mutable_type(cx, inner_ty, span)
         },
         Tuple(..) => ty.tuple_fields().any(|ty| is_mutable_type(cx, ty, span)),
-        Adt(..) => cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env, span),
+        Adt(..) => cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(span), cx.param_env),
         _ => false,
     }
 }
index f7a20a74b85e21d2e04ddb2399c24dff18a233f8..6aa77b4df83aa9409cd3a9d9e97397e8239cf798 100644 (file)
@@ -69,7 +69,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
                     expr.span,
                     "generally you want to avoid `&mut &mut _` if possible",
                 );
-            } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.tables.expr_ty(e).kind {
+            } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.tables().expr_ty(e).kind {
                 span_lint(
                     self.cx,
                     MUT_MUT,
index 7fcf15f8acbe828d1b385b405068d44fc6c5e57c..dbe257069c3e25a6716efab7d3433c1a9d5fac1a 100644 (file)
@@ -37,14 +37,14 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                     check_arguments(
                         cx,
                         arguments,
-                        cx.tables.expr_ty(fn_expr),
+                        cx.tables().expr_ty(fn_expr),
                         &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                     );
                 }
             },
             ExprKind::MethodCall(ref path, _, ref arguments, _) => {
-                let def_id = cx.tables.type_dependent_def_id(e.hir_id).unwrap();
-                let substs = cx.tables.node_substs(e.hir_id);
+                let def_id = cx.tables().type_dependent_def_id(e.hir_id).unwrap();
+                let substs = cx.tables().node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
                 check_arguments(cx, arguments, method_type, &path.ident.as_str())
             },
index 119e0905ff442f32a5ecec979165c7951cf1681d..45db5140711ad9d0cf9f307c084c44ec4aa161a5 100644 (file)
@@ -135,7 +135,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 return;
             },
             ExprKind::Path(_) => {
-                if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) {
+                if let Some(adj) = self.cx.tables().adjustments().get(expr.hir_id) {
                     if adj
                         .iter()
                         .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut)))
index 78b15afc5a7fac4105fc5be6e699838bd43f5342..c227dc54f293945d353056d14e1f1a00667d7eb5 100644 (file)
@@ -66,7 +66,7 @@
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Mutex {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
-        let ty = cx.tables.expr_ty(expr);
+        let ty = cx.tables().expr_ty(expr);
         if let ty::Adt(_, subst) = ty.kind {
             if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) {
                 let mutex_param = subst.type_at(0);
index 15b129fa09802922543c184d3e47d7905dc622c2..653f9e2ae8625b2710386b628d8b1548e7607674 100644 (file)
@@ -229,7 +229,7 @@ fn check_comparison<'a, 'tcx>(
     use self::Expression::{Bool, Other};
 
     if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind {
-        let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side));
+        let (l_ty, r_ty) = (cx.tables().expr_ty(left_side), cx.tables().expr_ty(right_side));
         if l_ty.is_bool() && r_ty.is_bool() {
             let mut applicability = Applicability::MachineApplicable;
 
index 5880d1d610206365b77e0be95f1e88af9d7d9d56..6bb06defb70348511723fa0a535564659e064c64 100644 (file)
@@ -46,8 +46,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
             return;
         }
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
-            if let ty::Ref(..) = cx.tables.expr_ty(inner).kind {
-                for adj3 in cx.tables.expr_adjustments(e).windows(3) {
+            if let ty::Ref(..) = cx.tables().expr_ty(inner).kind {
+                for adj3 in cx.tables().expr_adjustments(e).windows(3) {
                     if let [Adjustment {
                         kind: Adjust::Deref(_), ..
                     }, Adjustment {
@@ -85,7 +85,7 @@ fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat<'_>) {
         }
         if_chain! {
             if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
-            if let ty::Ref(_, tam, mutbl) = cx.tables.pat_ty(pat).kind;
+            if let ty::Ref(_, tam, mutbl) = cx.tables().pat_ty(pat).kind;
             if mutbl == Mutability::Not;
             if let ty::Ref(_, _, mutbl) = tam.kind;
             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
index 218b0d27f748620a0a320bd7e3ee6bcc0cde1a88..6954f0cc683f1a135fbd9010384195444f9d07c7 100644 (file)
@@ -135,7 +135,7 @@ fn check_fn(
         } = {
             let mut ctx = MovedVariablesCtxt::default();
             cx.tcx.infer_ctxt().enter(|infcx| {
-                euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables).consume_body(body);
+                euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body);
             });
             ctx
         };
@@ -173,13 +173,7 @@ fn check_fn(
                     !preds.is_empty() && {
                         let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty);
                         preds.iter().all(|t| {
-                            let ty_params = &t
-                                .skip_binder()
-                                .trait_ref
-                                .substs
-                                .iter()
-                                .skip(1)
-                                .collect::<Vec<_>>();
+                            let ty_params = &t.skip_binder().trait_ref.substs.iter().skip(1).collect::<Vec<_>>();
                             implements_trait(cx, ty_empty_region, t.def_id(), ty_params)
                         })
                     },
@@ -326,21 +320,21 @@ struct MovedVariablesCtxt {
 }
 
 impl MovedVariablesCtxt {
-    fn move_common(&mut self, cmt: &euv::Place<'_>) {
-        if let euv::PlaceBase::Local(vid) = cmt.base {
+    fn move_common(&mut self, cmt: &euv::PlaceWithHirId<'_>) {
+        if let euv::PlaceBase::Local(vid) = cmt.place.base {
             self.moved_vars.insert(vid);
         }
     }
 }
 
 impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
-    fn consume(&mut self, cmt: &euv::Place<'tcx>, mode: euv::ConsumeMode) {
+    fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) {
         if let euv::ConsumeMode::Move = mode {
             self.move_common(cmt);
         }
     }
 
-    fn borrow(&mut self, _: &euv::Place<'tcx>, _: ty::BorrowKind) {}
+    fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: ty::BorrowKind) {}
 
-    fn mutate(&mut self, _: &euv::Place<'tcx>) {}
+    fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>) {}
 }
index d866bab2f642c46242b92bed638c577612aa062a..9b556dbb8540e41db97a0232d6b72aac37a81b9b 100644 (file)
@@ -47,7 +47,7 @@
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessUpdate {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.kind {
-            let ty = cx.tables.expr_ty(expr);
+            let ty = cx.tables().expr_ty(expr);
             if let ty::Adt(def, _) = ty.kind {
                 if fields.len() == def.non_enum_variant().fields.len() {
                     span_lint(
index 54536ed57d3e9ba9753a7e4152b70fdf94eb797e..0f56daa3659e8726ea8ef6739942b427c491c470 100644 (file)
@@ -56,7 +56,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
 
             then {
 
-                let ty = cx.tables.expr_ty(left);
+                let ty = cx.tables().expr_ty(left);
 
                 let implements_ord = {
                     if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) {
index 4681e990df88a1880efa4484c8aceb1ffb2ca5f5..a9ce01b67b097b5e334b0a79790373c5ade26cdb 100644 (file)
@@ -44,8 +44,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
 fn check_mul(cx: &LateContext<'_, '_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Lit(ref l) = lit.kind;
-        if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.tables.expr_ty_opt(lit));
-        if cx.tables.expr_ty(exp).is_integral();
+        if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.tables().expr_ty_opt(lit));
+        if cx.tables().expr_ty(exp).is_integral();
         then {
             span_lint(cx, NEG_MULTIPLY, span, "Negation by multiplying with `-1`");
         }
index dd236535c18ad9d6aed4c0fc5105d1b12f598a78..42200385932b0ee5612e2b9d9c5a28add04d4dbb 100644 (file)
@@ -33,7 +33,7 @@
     /// }
     /// ```
     ///
-    /// To fix the lint, and a `Default` implementation that delegates to `new`:
+    /// To fix the lint, add a `Default` implementation that delegates to `new`:
     ///
     /// ```ignore
     /// struct Foo(Bar);
index 2eacd3c80c486ba8d5ba6f436d1ef018f1ec3af4..5fdc656580f29c1c4ca0d343f6e89e0ee338af1a 100644 (file)
@@ -48,7 +48,7 @@ fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
     }
     match expr.kind {
         ExprKind::Lit(..) | ExprKind::Closure(..) => true,
-        ExprKind::Path(..) => !has_drop(cx, cx.tables.expr_ty(expr)),
+        ExprKind::Path(..) => !has_drop(cx, cx.tables().expr_ty(expr)),
         ExprKind::Index(ref a, ref b) | ExprKind::Binary(_, ref a, ref b) => {
             has_no_effect(cx, a) && has_no_effect(cx, b)
         },
@@ -61,7 +61,7 @@ fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
         | ExprKind::AddrOf(_, _, ref inner)
         | ExprKind::Box(ref inner) => has_no_effect(cx, inner),
         ExprKind::Struct(_, ref fields, ref base) => {
-            !has_drop(cx, cx.tables.expr_ty(expr))
+            !has_drop(cx, cx.tables().expr_ty(expr))
                 && fields.iter().all(|field| has_no_effect(cx, &field.expr))
                 && base.as_ref().map_or(true, |base| has_no_effect(cx, base))
         },
@@ -70,7 +70,7 @@ fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
                 let res = qpath_res(cx, qpath, callee.hir_id);
                 match res {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => {
-                        !has_drop(cx, cx.tables.expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
+                        !has_drop(cx, cx.tables().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
                     },
                     _ => false,
                 }
@@ -137,7 +137,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option
         | ExprKind::AddrOf(_, _, ref inner)
         | ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
         ExprKind::Struct(_, ref fields, ref base) => {
-            if has_drop(cx, cx.tables.expr_ty(expr)) {
+            if has_drop(cx, cx.tables().expr_ty(expr)) {
                 None
             } else {
                 Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
@@ -148,7 +148,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option
                 let res = qpath_res(cx, qpath, callee.hir_id);
                 match res {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
-                        if !has_drop(cx, cx.tables.expr_ty(expr)) =>
+                        if !has_drop(cx, cx.tables().expr_ty(expr)) =>
                     {
                         Some(args.iter().collect())
                     },
index bb257e5a542d98632f9f25c31bac6342c72504b7..21d7a7439f25c58a6ccddd54cde6caa850f1d32e 100644 (file)
@@ -110,7 +110,7 @@ fn lint(&self) -> (&'static Lint, &'static str, Span) {
 }
 
 fn verify_ty_bound<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, source: Source) {
-    if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) {
+    if ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) || is_copy(cx, ty) {
         // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
         // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
         // as well.
@@ -237,13 +237,13 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             }
 
             let ty = if needs_check_adjustment {
-                let adjustments = cx.tables.expr_adjustments(dereferenced_expr);
+                let adjustments = cx.tables().expr_adjustments(dereferenced_expr);
                 if let Some(i) = adjustments.iter().position(|adj| match adj.kind {
                     Adjust::Borrow(_) | Adjust::Deref(_) => true,
                     _ => false,
                 }) {
                     if i == 0 {
-                        cx.tables.expr_ty(dereferenced_expr)
+                        cx.tables().expr_ty(dereferenced_expr)
                     } else {
                         adjustments[i - 1].target
                     }
@@ -252,7 +252,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                     return;
                 }
             } else {
-                cx.tables.expr_ty(dereferenced_expr)
+                cx.tables().expr_ty(dereferenced_expr)
             };
 
             verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
index 2d4629b683f057b12fb44e7500e445314dd7cf2e..2467a14cea12fda73d53fe22c280c13ff25a48c9 100644 (file)
@@ -30,7 +30,7 @@
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OpenOptions {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind {
-            let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0]));
+            let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&arguments[0]));
             if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
                 let mut options = Vec::new();
                 get_open_options(cx, &arguments[0], &mut options);
@@ -58,7 +58,7 @@ enum OpenOption {
 
 fn get_open_options(cx: &LateContext<'_, '_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
     if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind {
-        let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0]));
+        let obj_ty = walk_ptrs_ty(cx.tables().expr_ty(&arguments[0]));
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
         if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
index b90fdc232e72c825d406fce6df2035820e3db488..5984b09120d0e741d7e9741ff8961cd7a58cdac8 100644 (file)
@@ -36,8 +36,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
             if let ExprKind::Path(QPath::Resolved(_, ref path3)) = second.kind;
             if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
-            if cx.tables.expr_ty(ident1).is_integral();
-            if cx.tables.expr_ty(ident2).is_integral();
+            if cx.tables().expr_ty(ident1).is_integral();
+            if cx.tables().expr_ty(ident2).is_integral();
             then {
                 if let BinOpKind::Lt = op.node {
                     if let BinOpKind::Add = op2.node {
@@ -61,8 +61,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind;
             if let ExprKind::Path(QPath::Resolved(_, ref path3)) = first.kind;
             if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
-            if cx.tables.expr_ty(ident1).is_integral();
-            if cx.tables.expr_ty(ident2).is_integral();
+            if cx.tables().expr_ty(ident1).is_integral();
+            if cx.tables().expr_ty(ident2).is_integral();
             then {
                 if let BinOpKind::Gt = op.node {
                     if let BinOpKind::Add = op2.node {
index 88ad1e0914f25f1a5763eaf02c13cfb2dc565368..f26a5258782a72755f9b022e86dec45c41f06131 100644 (file)
@@ -46,7 +46,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
             if path.ident.name == sym!(push);
             if args.len() == 2;
-            if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::PATH_BUF);
+            if match_type(cx, walk_ptrs_ty(cx.tables().expr_ty(&args[0])), &paths::PATH_BUF);
             if let Some(get_index_arg) = args.get(1);
             if let ExprKind::Lit(ref lit) = get_index_arg.kind;
             if let LitKind::Str(ref path_lit, _) = lit.node;
index d23d7e59b73fc054369ab6b57a1eced54450d033..b35a7e64bff2740bddfe01b7299da39f4d014162 100644 (file)
@@ -105,12 +105,12 @@ fn expr_as_ptr_offset_call<'a, 'tcx>(
 
 // Is the type of the expression a usize?
 fn is_expr_ty_usize<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool {
-    cx.tables.expr_ty(expr) == cx.tcx.types.usize
+    cx.tables().expr_ty(expr) == cx.tcx.types.usize
 }
 
 // Is the type of the expression a raw pointer?
 fn is_expr_ty_raw_ptr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool {
-    cx.tables.expr_ty(expr).is_unsafe_ptr()
+    cx.tables().expr_ty(expr).is_unsafe_ptr()
 }
 
 fn build_suggestion<'a, 'tcx>(
index 3591972fe082f7d0db4a12878a993059556509b8..4a6395da01c99ffcfb05a7d587d5c1de16583b8f 100644 (file)
@@ -135,13 +135,13 @@ fn check_if_let_some_and_early_return_none(cx: &LateContext<'_, '_>, expr: &Expr
     }
 
     fn moves_by_default(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
-        let expr_ty = cx.tables.expr_ty(expression);
+        let expr_ty = cx.tables().expr_ty(expression);
 
-        !expr_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, expression.span)
+        !expr_ty.is_copy_modulo_regions(cx.tcx.at(expression.span), cx.param_env)
     }
 
     fn is_option(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
-        let expr_ty = cx.tables.expr_ty(expression);
+        let expr_ty = cx.tables().expr_ty(expression);
 
         is_type_diagnostic_item(cx, expr_ty, sym!(option_type))
     }
@@ -158,7 +158,7 @@ fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> b
             ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
             ExprKind::Path(ref qp) => {
                 if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
-                    cx.tables.qpath_res(qp, expression.hir_id)
+                    cx.tables().qpath_res(qp, expression.hir_id)
                 {
                     return match_def_path(cx, def_id, &paths::OPTION_NONE);
                 }
index fcd02a196e7bf593398effda1a57d285707db808..43ef236a92420aa855225b6567aa2d7a682cd71e 100644 (file)
@@ -272,10 +272,10 @@ fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
 
     if_chain! {
         if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr);
-        let ty = cx.tables.expr_ty(start);
+        let ty = cx.tables().expr_ty(start);
         if let ty::Int(_) | ty::Uint(_) = ty.kind;
-        if let Some((start_idx, _)) = constant(cx, cx.tables, start);
-        if let Some((end_idx, _)) = constant(cx, cx.tables, end);
+        if let Some((start_idx, _)) = constant(cx, cx.tables(), start);
+        if let Some((end_idx, _)) = constant(cx, cx.tables(), end);
         if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
         if is_empty_range(limits, ordering);
         then {
index f16b916441ae81a51142998a4590b099845cba29..3c528a295b044ba34b2176638d2761de37ad3aad 100644 (file)
@@ -1,10 +1,13 @@
-use crate::utils::{match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
+use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_mir::const_eval::is_const_fn;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Symbol;
 
 declare_clippy_lint! {
     /// **What it does:** Lint for redundant pattern matching over `Result` or
@@ -64,26 +67,37 @@ fn find_sugg_for_if_let<'a, 'tcx>(
     arms: &[Arm<'_>],
     keyword: &'static str,
 ) {
+    fn find_suggestion(cx: &LateContext<'_, '_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
+        if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
+            return Some("is_ok()");
+        }
+        if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
+            return Some("is_err()");
+        }
+        if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
+            return Some("is_some()");
+        }
+        if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
+            return Some("is_none()");
+        }
+        None
+    }
+
+    let hir_id = expr.hir_id;
     let good_method = match arms[0].pat.kind {
         PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
             if let PatKind::Wild = patterns[0].kind {
-                if match_qpath(path, &paths::RESULT_OK) {
-                    "is_ok()"
-                } else if match_qpath(path, &paths::RESULT_ERR) {
-                    "is_err()"
-                } else if match_qpath(path, &paths::OPTION_SOME) {
-                    "is_some()"
-                } else {
-                    return;
-                }
+                find_suggestion(cx, hir_id, path)
             } else {
-                return;
+                None
             }
         },
-
-        PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
-
-        _ => return,
+        PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
+        _ => None,
+    };
+    let good_method = match good_method {
+        Some(method) => method,
+        None => return,
     };
 
     // check that `while_let_on_iterator` lint does not trigger
@@ -128,6 +142,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
+        let hir_id = expr.hir_id;
         let found_good_method = match node_pair {
             (
                 PatKind::TupleStruct(ref path_left, ref patterns_left, _),
@@ -142,6 +157,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
                         &paths::RESULT_ERR,
                         "is_ok()",
                         "is_err()",
+                        || can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
+                        || can_suggest(cx, hir_id, sym!(result_type), "is_err"),
                     )
                 } else {
                     None
@@ -160,6 +177,8 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
                         &paths::OPTION_NONE,
                         "is_some()",
                         "is_none()",
+                        || can_suggest(cx, hir_id, sym!(option_type), "is_some"),
+                        || can_suggest(cx, hir_id, sym!(option_type), "is_none"),
                     )
                 } else {
                     None
@@ -188,6 +207,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_
     }
 }
 
+#[allow(clippy::too_many_arguments)]
 fn find_good_method_for_match<'a>(
     arms: &[Arm<'_>],
     path_left: &QPath<'_>,
@@ -196,6 +216,8 @@ fn find_good_method_for_match<'a>(
     expected_right: &[&str],
     should_be_left: &'a str,
     should_be_right: &'a str,
+    can_suggest_left: impl Fn() -> bool,
+    can_suggest_right: impl Fn() -> bool,
 ) -> Option<&'a str> {
     let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
         (&(*arms[0].body).kind, &(*arms[1].body).kind)
@@ -207,10 +229,32 @@ fn find_good_method_for_match<'a>(
 
     match body_node_pair {
         (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
+            (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
             _ => None,
         },
         _ => None,
     }
 }
+
+fn can_suggest(cx: &LateContext<'_, '_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
+    if !in_constant(cx, hir_id) {
+        return true;
+    }
+
+    // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
+    cx.tcx
+        .get_diagnostic_item(diag_item)
+        .and_then(|def_id| {
+            cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
+                cx.tcx
+                    .associated_items(*imp)
+                    .in_definition_order()
+                    .find_map(|item| match item.kind {
+                        ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
+                        _ => None,
+                    })
+            })
+        })
+        .map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
+}
index a2c35c4267344a95eef43abf696e465d4d7d2b22..9c54c3cbac02b6dda9cfe8ab865011a2cbf3ac76 100644 (file)
@@ -82,7 +82,7 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block<'_>) {
         if_chain! {
             if self.last.is_none();
             if let Some(ref expr) = block.expr;
-            if match_type(cx, cx.tables.expr_ty(expr), &paths::REGEX);
+            if match_type(cx, cx.tables().expr_ty(expr), &paths::REGEX);
             if let Some(span) = is_expn_of(expr.span, "regex");
             then {
                 if !self.spans.contains(&span) {
@@ -111,7 +111,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Call(ref fun, ref args) = expr.kind;
             if let ExprKind::Path(ref qpath) = fun.kind;
             if args.len() == 1;
-            if let Some(def_id) = cx.tables.qpath_res(qpath, fun.hir_id).opt_def_id();
+            if let Some(def_id) = cx.tables().qpath_res(qpath, fun.hir_id).opt_def_id();
             then {
                 if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
                    match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
@@ -140,7 +140,7 @@ fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span {
 }
 
 fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
-    constant(cx, cx.tables, e).and_then(|(c, _)| match c {
+    constant(cx, cx.tables(), e).and_then(|(c, _)| match c {
         Constant::Str(s) => Some(s),
         _ => None,
     })
index 68c36f918918438a79f80bf4b3ff7a9a34b50ef7..4780249bcb8e3fe4840622eab86bb2dd034f7c40 100644 (file)
@@ -164,7 +164,7 @@ fn check_local<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, local: &'tcx Local<'_>, bin
 }
 
 fn is_binding(cx: &LateContext<'_, '_>, pat_id: HirId) -> bool {
-    let var_ty = cx.tables.node_type_opt(pat_id);
+    let var_ty = cx.tables().node_type_opt(pat_id);
     if let Some(var_ty) = var_ty {
         match var_ty.kind {
             ty::Adt(..) => false,
index d8e4bff3d702aa2c0577d8cf87899340d7fd88cc..ef66850358e57715a82e52b2481e2a74d7834a22 100644 (file)
@@ -134,7 +134,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
 }
 
 fn is_string(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool {
-    is_type_diagnostic_item(cx, walk_ptrs_ty(cx.tables.expr_ty(e)), sym!(string_type))
+    is_type_diagnostic_item(cx, walk_ptrs_ty(cx.tables().expr_ty(e)), sym!(string_type))
 }
 
 fn is_add(cx: &LateContext<'_, '_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
index a9e6fa329c0f03ab2681222320afcce1f6fcfbb9..cf71c3144a2ebebac537498f2748d45ca23d1211 100644 (file)
@@ -184,7 +184,7 @@ struct BinaryExprVisitor {
     in_binary_expr: bool,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for BinaryExprVisitor {
+impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
     type Map = Map<'tcx>;
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
index c52e6a643f2a28e0348c764a4836d545db10a082..7fdc872c01f54c4589afac09b8ac29a4e5267818 100644 (file)
@@ -194,7 +194,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_, '_>, lhs1: &'a Expr<'_>, lhs2: &'a E
     if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
         if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
             if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
-                let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));
+                let ty = walk_ptrs_ty(cx.tables().expr_ty(lhs1));
 
                 if matches!(ty.kind, ty::Slice(_))
                     || matches!(ty.kind, ty::Array(_, _))
index bbb883aaf328719555988ccfa567131f07399061..f2bbf19bea92ff86e5f7705c05dacb3771b0b60a 100644 (file)
@@ -26,7 +26,7 @@ fn is_temporary(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
     match &expr.kind {
         ExprKind::Struct(..) | ExprKind::Tup(..) => true,
         ExprKind::Path(qpath) => {
-            if let Res::Def(DefKind::Const, ..) = cx.tables.qpath_res(qpath, expr.hir_id) {
+            if let Res::Def(DefKind::Const, ..) = cx.tables().qpath_res(qpath, expr.hir_id) {
                 true
             } else {
                 false
index 4f132c6db76fa2aa318241385085f1d0c2bb0016..1efba3580fef09506e468cf8091b1efa4da9d382 100644 (file)
@@ -43,7 +43,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
                         if_chain! {
                             if let [char_arg, radix_arg] = &**to_digit_args;
                             if to_digits_path.ident.name.as_str() == "to_digit";
-                            let char_arg_ty = cx.tables.expr_ty_adjusted(char_arg);
+                            let char_arg_ty = cx.tables().expr_ty_adjusted(char_arg);
                             if char_arg_ty.kind == ty::Char;
                             then {
                                 Some((true, char_arg, radix_arg))
@@ -56,7 +56,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
                         if_chain! {
                             if let [char_arg, radix_arg] = &**to_digit_args;
                             if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
-                            if let to_digits_call_res = cx.tables.qpath_res(to_digits_path, to_digits_call.hir_id);
+                            if let to_digits_call_res = cx.tables().qpath_res(to_digits_path, to_digits_call.hir_id);
                             if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
                             if match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "<impl char>", "to_digit"]);
                             then {
index 67121729663c6aa4ec62fa46af4c673c42318171..1b233b8302f9313e2c1cb839b43149d9d0d86609 100644 (file)
@@ -37,7 +37,7 @@ fn check_generics(&mut self, cx: &LateContext<'a, 'tcx>, gen: &'tcx Generics<'_>
             return;
         }
         let hash = |ty| -> u64 {
-            let mut hasher = SpanlessHash::new(cx, cx.tables);
+            let mut hasher = SpanlessHash::new(cx, cx.tables());
             hasher.hash_ty(ty);
             hasher.finish()
         };
index 1869638f6ffb11b5b196eae87d659a4a996acdd3..9b1344949470a91d4f18c3719cace1e314e7e5b6 100644 (file)
@@ -299,11 +299,11 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
         if_chain! {
             if let ExprKind::Call(ref path_expr, ref args) = e.kind;
             if let ExprKind::Path(ref qpath) = path_expr.kind;
-            if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id();
+            if let Some(def_id) = cx.tables().qpath_res(qpath, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::TRANSMUTE);
             then {
-                let from_ty = cx.tables.expr_ty(&args[0]);
-                let to_ty = cx.tables.expr_ty(e);
+                let from_ty = cx.tables().expr_ty(&args[0]);
+                let to_ty = cx.tables().expr_ty(e);
 
                 match (&from_ty.kind, &to_ty.kind) {
                     _ if from_ty == to_ty => span_lint(
index 1d0332c580500f73433486c69fe798ee57cd07b5..3351488a45c4ddba8e335ed572f3561df71b239a 100644 (file)
@@ -44,7 +44,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             then {
 
                 // Catching transmute over constants that resolve to `null`.
-                let mut const_eval_context = constant_context(cx, cx.tables);
+                let mut const_eval_context = constant_context(cx, cx.tables());
                 if_chain! {
                     if let ExprKind::Path(ref _qpath) = args[0].kind;
                     let x = const_eval_context.expr(&args[0]);
index 8e0cb94317affc2ce1bf3c0e81d3407fda751bf9..146ac4b09d5a4ff503bbf43ea09b52f3e4e5366a 100644 (file)
@@ -58,7 +58,7 @@ pub struct TriviallyCopyPassByRef {
     limit: u64,
 }
 
-impl<'a, 'tcx> TriviallyCopyPassByRef {
+impl<'tcx> TriviallyCopyPassByRef {
     pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
         let limit = limit.unwrap_or_else(|| {
             let bit_width = u64::from(target.ptr_width);
index 7018fa6804ba71949c7892daf05d3c21ddbe4168..e129dd84d15a6dd0ab24c82b821129acb695a7d4 100644 (file)
@@ -68,7 +68,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let Some(return_type) = find_err_return_type(cx, &expr.kind);
 
             then {
-                let err_type = cx.tables.expr_ty(err_arg);
+                let err_type = cx.tables().expr_ty(err_arg);
                 let origin_snippet = if err_arg.span.from_expansion() {
                     snippet_with_macro_callsite(cx, err_arg.span, "_")
                 } else {
@@ -114,7 +114,7 @@ fn find_err_return_type_arm<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arm: &'tcx Arm
         if match_qpath(from_error_fn, &paths::TRY_FROM_ERROR);
         if let Some(from_error_arg) = from_error_args.get(0);
         then {
-            Some(cx.tables.expr_ty(from_error_arg))
+            Some(cx.tables().expr_ty(from_error_arg))
         } else {
             None
         }
index d59a2f1bae031f14a72269ed06902c45d53c327b..ecfb6ee2a7de9e02e3c3a396bd12410a88a02c87 100644 (file)
@@ -603,7 +603,7 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool {
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnitValue {
     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Local(ref local) = stmt.kind {
-            if is_unit(cx.tables.pat_ty(&local.pat)) {
+            if is_unit(cx.tables().pat_ty(&local.pat)) {
                 if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() {
                     return;
                 }
@@ -688,7 +688,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) {
                 if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
                     if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
                         let op = cmp.node;
-                        if op.is_comparison() && is_unit(cx.tables.expr_ty(left)) {
+                        if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) {
                             let result = match &*symbol.as_str() {
                                 "assert_eq" | "debug_assert_eq" => "succeed",
                                 "assert_ne" | "debug_assert_ne" => "fail",
@@ -712,7 +712,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) {
         }
         if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind {
             let op = cmp.node;
-            if op.is_comparison() && is_unit(cx.tables.expr_ty(left)) {
+            if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) {
                 let result = match op {
                     BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true",
                     _ => "false",
@@ -782,7 +782,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
                 let args_to_recover = args
                     .iter()
                     .filter(|arg| {
-                        if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
+                        if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) {
                             if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind {
                                 false
                             } else {
@@ -1250,7 +1250,7 @@ fn check_loss_of_sign(cx: &LateContext<'_, '_>, expr: &Expr<'_>, op: &Expr<'_>,
     }
 
     // don't lint for positive constants
-    let const_val = constant(cx, &cx.tables, op);
+    let const_val = constant(cx, &cx.tables(), op);
     if_chain! {
         if let Some((const_val, _)) = const_val;
         if let Constant::Int(n) = const_val;
@@ -1416,7 +1416,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             return;
         }
         if let ExprKind::Cast(ref ex, _) = expr.kind {
-            let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr));
+            let (cast_from, cast_to) = (cx.tables().expr_ty(ex), cx.tables().expr_ty(expr));
             lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
             if let ExprKind::Lit(ref lit) = ex.kind {
                 if_chain! {
@@ -1804,7 +1804,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::Cast(e, _) = &expr.kind;
             if let ExprKind::Lit(l) = &e.kind;
             if let LitKind::Char(c) = l.node;
-            if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).kind;
+            if ty::Uint(UintTy::U8) == cx.tables().expr_ty(expr).kind;
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
@@ -1880,8 +1880,8 @@ enum AbsurdComparisonResult {
 
 fn is_cast_between_fixed_and_target<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
-        let precast_ty = cx.tables.expr_ty(cast_exp);
-        let cast_ty = cx.tables.expr_ty(expr);
+        let precast_ty = cx.tables().expr_ty(cast_exp);
+        let cast_ty = cx.tables().expr_ty(expr);
 
         return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
     }
@@ -1901,7 +1901,7 @@ fn detect_absurd_comparison<'a, 'tcx>(
 
     // absurd comparison only makes sense on primitive types
     // primitive types don't implement comparison operators with each other
-    if cx.tables.expr_ty(lhs) != cx.tables.expr_ty(rhs) {
+    if cx.tables().expr_ty(lhs) != cx.tables().expr_ty(rhs) {
         return None;
     }
 
@@ -1939,22 +1939,18 @@ fn detect_absurd_comparison<'a, 'tcx>(
 fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
     use crate::types::ExtremeType::{Maximum, Minimum};
 
-    let ty = cx.tables.expr_ty(expr);
+    let ty = cx.tables().expr_ty(expr);
 
-    let cv = constant(cx, cx.tables, expr)?.0;
+    let cv = constant(cx, cx.tables(), expr)?.0;
 
     let which = match (&ty.kind, cv) {
         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
-        (&ty::Int(ity), Constant::Int(i))
-            if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) =>
-        {
+        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => {
             Minimum
         },
 
         (&ty::Bool, Constant::Bool(true)) => Maximum,
-        (&ty::Int(ity), Constant::Int(i))
-            if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) =>
-        {
+        (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => {
             Maximum
         },
         (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum,
@@ -2075,58 +2071,28 @@ fn cmp(&self, other: &Self) -> Ordering {
 
 fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
     if let ExprKind::Cast(ref cast_exp, _) = expr.kind {
-        let pre_cast_ty = cx.tables.expr_ty(cast_exp);
-        let cast_ty = cx.tables.expr_ty(expr);
+        let pre_cast_ty = cx.tables().expr_ty(cast_exp);
+        let cast_ty = cx.tables().expr_ty(expr);
         // if it's a cast from i32 to u32 wrapping will invalidate all these checks
         if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
             return None;
         }
         match pre_cast_ty.kind {
             ty::Int(int_ty) => Some(match int_ty {
-                IntTy::I8 => (
-                    FullInt::S(i128::from(i8::MIN)),
-                    FullInt::S(i128::from(i8::MAX)),
-                ),
-                IntTy::I16 => (
-                    FullInt::S(i128::from(i16::MIN)),
-                    FullInt::S(i128::from(i16::MAX)),
-                ),
-                IntTy::I32 => (
-                    FullInt::S(i128::from(i32::MIN)),
-                    FullInt::S(i128::from(i32::MAX)),
-                ),
-                IntTy::I64 => (
-                    FullInt::S(i128::from(i64::MIN)),
-                    FullInt::S(i128::from(i64::MAX)),
-                ),
+                IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
+                IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
+                IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
+                IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
                 IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
-                IntTy::Isize => (
-                    FullInt::S(isize::MIN as i128),
-                    FullInt::S(isize::MAX as i128),
-                ),
+                IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
             }),
             ty::Uint(uint_ty) => Some(match uint_ty {
-                UintTy::U8 => (
-                    FullInt::U(u128::from(u8::MIN)),
-                    FullInt::U(u128::from(u8::MAX)),
-                ),
-                UintTy::U16 => (
-                    FullInt::U(u128::from(u16::MIN)),
-                    FullInt::U(u128::from(u16::MAX)),
-                ),
-                UintTy::U32 => (
-                    FullInt::U(u128::from(u32::MIN)),
-                    FullInt::U(u128::from(u32::MAX)),
-                ),
-                UintTy::U64 => (
-                    FullInt::U(u128::from(u64::MIN)),
-                    FullInt::U(u128::from(u64::MAX)),
-                ),
+                UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
+                UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
+                UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
+                UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
                 UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
-                UintTy::Usize => (
-                    FullInt::U(usize::MIN as u128),
-                    FullInt::U(usize::MAX as u128),
-                ),
+                UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
             }),
             _ => None,
         }
@@ -2136,9 +2102,9 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'_>)
 }
 
 fn node_as_const_fullint<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
-    let val = constant(cx, cx.tables, expr)?.0;
+    let val = constant(cx, cx.tables(), expr)?.0;
     if let Constant::Int(const_int) = val {
-        match cx.tables.expr_ty(expr).kind {
+        match cx.tables().expr_ty(expr).kind {
             ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
             ty::Uint(_) => Some(FullInt::U(const_int)),
             _ => None,
@@ -2533,7 +2499,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
     fn new(cx: &'a LateContext<'a, 'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self {
         Self {
             cx,
-            body: cx.tables,
+            body: cx.tables(),
             target,
             suggestions: BTreeMap::new(),
         }
@@ -2642,7 +2608,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind;
             if let ExprKind::Cast(e, t) = &e.kind;
             if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind;
-            if let ty::Ref(..) = cx.tables.node_type(e.hir_id).kind;
+            if let ty::Ref(..) = cx.tables().node_type(e.hir_id).kind;
             then {
                 span_lint(
                     cx,
index 4e077b95b5c68024c9eaca1f78c343c62a2dfe9a..53e47f09ae55ce256890e20d57228f1558772065 100644 (file)
@@ -65,14 +65,14 @@ fn is_comparison(binop: BinOpKind) -> bool {
         }
 
         fn is_trait_ptr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-            match cx.tables.expr_ty_adjusted(expr).kind {
+            match cx.tables().expr_ty_adjusted(expr).kind {
                 ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
                 _ => false,
             }
         }
 
         fn is_fn_def(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
-            if let ty::FnDef(..) = cx.tables.expr_ty(expr).kind {
+            if let ty::FnDef(..) = cx.tables().expr_ty(expr).kind {
                 true
             } else {
                 false
@@ -98,11 +98,11 @@ fn is_fn_def(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
         if_chain! {
             if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
-            if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+            if let Some(def_id) = cx.tables().qpath_res(func_qpath, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::PTR_EQ) ||
                 match_def_path(cx, def_id, &paths::RC_PTR_EQ) ||
                 match_def_path(cx, def_id, &paths::ARC_PTR_EQ);
-            let ty_param = cx.tables.node_substs(func.hir_id).type_at(0);
+            let ty_param = cx.tables().node_substs(func.hir_id).type_at(0);
             if ty_param.is_trait();
             then {
                 span_lint_and_help(
@@ -119,8 +119,8 @@ fn is_fn_def(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
         if_chain! {
             if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
             if is_comparison(binop.node);
-            if cx.tables.expr_ty_adjusted(left).is_fn_ptr() &&
-                cx.tables.expr_ty_adjusted(right).is_fn_ptr();
+            if cx.tables().expr_ty_adjusted(left).is_fn_ptr() &&
+                cx.tables().expr_ty_adjusted(right).is_fn_ptr();
             if is_fn_def(cx, left) || is_fn_def(cx, right);
             then {
                 span_lint(
index e94eebb88e4974bd10511c483ed24101051a2db5..bb68e50b331953b0f71b847feeb3916ccc66e4d3 100644 (file)
@@ -95,7 +95,10 @@ fn mirrored_exprs(
         // The two exprs are method calls.
         // Check to see that the function is the same and the arguments are mirrored
         // This is enough because the receiver of the method is listed in the arguments
-        (ExprKind::MethodCall(left_segment, _, left_args, _), ExprKind::MethodCall(right_segment, _, right_args, _)) => {
+        (
+            ExprKind::MethodCall(left_segment, _, left_args, _),
+            ExprKind::MethodCall(right_segment, _, right_args, _),
+        ) => {
             left_segment.ident == right_segment.ident
                 && left_args
                     .iter()
@@ -174,7 +177,7 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<LintTrigger>
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
         if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
-        if utils::match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC);
+        if utils::match_type(cx, &cx.tables().expr_ty(vec), &paths::VEC);
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
index 8c281126c32bf8c954b7e1c057e6ced0c8573e49..4d3682263f14fdedc14be9209e1806147937190d 100644 (file)
@@ -45,7 +45,7 @@
     /// }
     /// ```
     pub UNNESTED_OR_PATTERNS,
-    complexity,
+    pedantic,
     "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
 }
 
index a6c7b5d405cda0aacbcf56040b13554f443e7ec5..be55982f90556749412dd237feb916098c163ff6 100644 (file)
@@ -114,7 +114,7 @@ fn is_relevant_result_call(cx: &LateContext<'_, '_>, ty: Ty<'_>, method_name: &s
         if_chain! {
             if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
             if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind;
-            let ty = cx.tables.expr_ty(&args[0]);
+            let ty = cx.tables().expr_ty(&args[0]);
             let name = method_name.ident.as_str();
             if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name);
             then {
index 78d249482d53d2f0e30212c440b7d27a5e40ca27..5d150ad4f03e45114cec6b596f3af082a2449136 100644 (file)
@@ -63,8 +63,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
 
             ExprKind::MethodCall(ref name, .., ref args, _) => {
                 if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
-                    let a = cx.tables.expr_ty(e);
-                    let b = cx.tables.expr_ty(&args[0]);
+                    let a = cx.tables().expr_ty(e);
+                    let b = cx.tables().expr_ty(&args[0]);
                     if TyS::same_type(a, b) {
                         let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
                         span_lint_and_sugg(
@@ -79,8 +79,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                     }
                 }
                 if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
-                    let a = cx.tables.expr_ty(e);
-                    let b = cx.tables.expr_ty(&args[0]);
+                    let a = cx.tables().expr_ty(e);
+                    let b = cx.tables().expr_ty(&args[0]);
                     if TyS::same_type(a, b) {
                         let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                         span_lint_and_sugg(
@@ -96,8 +96,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                 }
                 if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
                     if_chain! {
-                        let a = cx.tables.expr_ty(e);
-                        let b = cx.tables.expr_ty(&args[0]);
+                        let a = cx.tables().expr_ty(e);
+                        let b = cx.tables().expr_ty(&args[0]);
                         if is_type_diagnostic_item(cx, a, sym!(result_type));
                         if let ty::Adt(_, substs) = a.kind;
                         if let Some(a_type) = substs.types().next();
@@ -121,9 +121,9 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
                 if_chain! {
                     if args.len() == 1;
                     if let ExprKind::Path(ref qpath) = path.kind;
-                    if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
-                    let a = cx.tables.expr_ty(e);
-                    let b = cx.tables.expr_ty(&args[0]);
+                    if let Some(def_id) = cx.tables().qpath_res(qpath, path.hir_id).opt_def_id();
+                    let a = cx.tables().expr_ty(e);
+                    let b = cx.tables().expr_ty(&args[0]);
 
                     then {
                         if_chain! {
index e60e2a81e070bdeb97296492bfe433117e50cc3c..e19a79dd8dad164dd40cc84a1a37f52740bb5bca 100755 (executable)
@@ -476,7 +476,7 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
         && match (&l.kind, &r.kind) {
             (Lifetime, Lifetime) => true,
             (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
-            (Const { ty: l }, Const { ty: r }) => eq_ty(l, r),
+            (Const { ty: l, kw_span: _ }, Const { ty: r, kw_span: _ }) => eq_ty(l, r),
             _ => false,
         }
         && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
index 8b58bbb5e65753e46089033998458100b72cb4c3..910b665ccb75ea2fcc1a4682df2e021fd0be9a55 100644 (file)
@@ -251,7 +251,10 @@ fn visit_expr(&mut self, expr: &Expr<'_>) {
                 }
             },
             ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => {
-                println!("MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};", current);
+                println!(
+                    "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
+                    current
+                );
                 println!("    // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
             },
             ExprKind::Tup(ref elements) => {
index 9e8e0ff30ec6b761a2d29566716163f6ca4ac014..c41befbf147b8c2e1567b86f50262ec0c9359009 100644 (file)
@@ -106,8 +106,8 @@ fn $config() -> $Ty {
 
 pub use self::helpers::Conf;
 define_Conf! {
-    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
-    (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "bar", "baz", "quux"].iter().map(ToString::to_string).collect()),
+    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
+    (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
     /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
     (cognitive_complexity_threshold, "cognitive_complexity_threshold": u64, 25),
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
index 33fba7df8d33660c13f03e7d397f586f76b09e63..0e78f35a1290ad3f769dd2c5121c1c6e4b8a8940 100644 (file)
@@ -56,7 +56,7 @@ fn get_field<'c>(name: &str, fields: &'c [hir::Field<'_>]) -> Option<&'c hir::Ex
         Some(expr)
     }
 
-    let def_path = match cx.tables.expr_ty(expr).kind {
+    let def_path = match cx.tables().expr_ty(expr).kind {
         ty::Adt(def, _) => cx.tcx.def_path(def.did),
         _ => return None,
     };
@@ -262,7 +262,7 @@ pub fn vec_macro<'e>(cx: &LateContext<'_, '_>, expr: &'e hir::Expr<'_>) -> Optio
         if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
         if let hir::ExprKind::Path(ref qpath) = fun.kind;
         if is_expn_of(fun.span, "vec").is_some();
-        if let Some(fun_def_id) = cx.tables.qpath_res(qpath, fun.hir_id).opt_def_id();
+        if let Some(fun_def_id) = cx.tables().qpath_res(qpath, fun.hir_id).opt_def_id();
         then {
             return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
                 // `vec![elem; size]` case
index 7a84f1c986aa7dc4d059d7cf9314eb0ac187e460..a74ab18a063b267343cd87af5ba667a956f6ce9e 100644 (file)
@@ -32,7 +32,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
     pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
         Self {
             cx,
-            tables: cx.tables,
+            tables: cx.tables(),
             ignore_fn: false,
         }
     }
@@ -40,7 +40,7 @@ pub fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
     pub fn ignore_fn(self) -> Self {
         Self {
             cx: self.cx,
-            tables: self.cx.tables,
+            tables: self.cx.tables(),
             ignore_fn: true,
         }
     }
@@ -309,18 +309,15 @@ fn swap_binop<'a>(
     rhs: &'a Expr<'a>,
 ) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> {
     match binop {
-        BinOpKind::Add
-        | BinOpKind::Mul
-        | BinOpKind::Eq
-        | BinOpKind::Ne
-        | BinOpKind::BitAnd
-        | BinOpKind::BitXor
-        | BinOpKind::BitOr => Some((binop, rhs, lhs)),
+        BinOpKind::Add | BinOpKind::Eq | BinOpKind::Ne | BinOpKind::BitAnd | BinOpKind::BitXor | BinOpKind::BitOr => {
+            Some((binop, rhs, lhs))
+        },
         BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)),
         BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)),
         BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)),
         BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)),
-        BinOpKind::Shl
+        BinOpKind::Mul // Not always commutative, e.g. with matrices. See issue #5698
+        | BinOpKind::Shl
         | BinOpKind::Shr
         | BinOpKind::Rem
         | BinOpKind::Sub
index afde971f9df4ef67cf9e403147d815d702eafbf1..3f5659c3d8c0fd13e65d57204ec25fc425d59e7f 100644 (file)
@@ -114,7 +114,7 @@ fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt<'_>)
         }
         match stmt.kind {
             hir::StmtKind::Local(ref local) => {
-                println!("local variable of type {}", cx.tables.node_type(local.hir_id));
+                println!("local variable of type {}", cx.tables().node_type(local.hir_id));
                 println!("pattern:");
                 print_pat(cx, &local.pat, 0);
                 if let Some(ref e) = local.init {
@@ -144,8 +144,8 @@ fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
 fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, indent: usize) {
     let ind = "  ".repeat(indent);
     println!("{}+", ind);
-    println!("{}ty: {}", ind, cx.tables.expr_ty(expr));
-    println!("{}adjustments: {:?}", ind, cx.tables.adjustments().get(expr.hir_id));
+    println!("{}ty: {}", ind, cx.tables().expr_ty(expr));
+    println!("{}adjustments: {:?}", ind, cx.tables().adjustments().get(expr.hir_id));
     match expr.kind {
         hir::ExprKind::Box(ref e) => {
             println!("{}Box", ind);
index 89e2bcdd7935d3e88bc76f2b96ac6eb7588fdf25..38468181d0261e00f64776d3f27e8539b18d28c7 100644 (file)
@@ -347,7 +347,7 @@ fn is_lint_ref_type<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &Ty<'_>) -> bool {
     ) = ty.kind
     {
         if let TyKind::Path(ref path) = inner.kind {
-            if let Res::Def(DefKind::Struct, def_id) = cx.tables.qpath_res(path, inner.hir_id) {
+            if let Res::Def(DefKind::Struct, def_id) = cx.tables().qpath_res(path, inner.hir_id) {
                 return match_def_path(cx, def_id, &paths::LINT);
             }
         }
@@ -405,7 +405,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind;
             let fn_name = path.ident;
             if let Some(sugg) = self.map.get(&*fn_name.as_str());
-            let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+            let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0]));
             if match_type(cx, ty, &paths::EARLY_CONTEXT)
                 || match_type(cx, ty, &paths::LATE_CONTEXT);
             then {
@@ -438,7 +438,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>)
             let args = arg_lists[1];
             if args.len() == 1;
             let self_arg = &args[0];
-            let self_ty = walk_ptrs_ty(cx.tables.expr_ty(self_arg));
+            let self_ty = walk_ptrs_ty(cx.tables().expr_ty(self_arg));
             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
             then {
                 span_lint_and_sugg(
index 60ab19e71f5e4e15b8f9b45ae6cac3fc01f146a5..69ec4b7ad6d18253d66c50406973c3b99846ee78 100644 (file)
@@ -151,7 +151,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_, '_>, ty: Ty<'_>, diag_item:
 
 /// Checks if the method call given in `expr` belongs to the given trait.
 pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr<'_>, path: &[&str]) -> bool {
-    let def_id = cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+    let def_id = cx.tables().type_dependent_def_id(expr.hir_id).unwrap();
     let trt_id = cx.tcx.trait_of_item(def_id);
     if let Some(trt_id) = trt_id {
         match_def_path(cx, trt_id, path)
@@ -824,7 +824,7 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
 /// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
 /// information on adjustments and coercions.
 pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool {
-    cx.tables.adjustments().get(e.hir_id).is_some()
+    cx.tables().adjustments().get(e.hir_id).is_some()
 }
 
 /// Returns the pre-expansion span if is this comes from an expansion of the
@@ -891,14 +891,14 @@ pub fn type_is_unsafe_function<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx
 }
 
 pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
-    ty.is_copy_modulo_regions(cx.tcx, cx.param_env, DUMMY_SP)
+    ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
 }
 
 /// Checks if an expression is constructing a tuple-like enum variant or struct
 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
     if let ExprKind::Call(ref fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
-            let res = cx.tables.qpath_res(qp, fun.hir_id);
+            let res = cx.tables().qpath_res(qp, fun.hir_id);
             return match res {
                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
@@ -914,7 +914,7 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_, '_>, expr: &Exp
 pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat<'_>) -> bool {
     fn is_enum_variant(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, id: HirId) -> bool {
         matches!(
-            cx.tables.qpath_res(qpath, id),
+            cx.tables().qpath_res(qpath, id),
             def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
         )
     }
@@ -941,7 +941,7 @@ fn are_refutable<'a, I: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_, '_>,
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
         PatKind::Slice(ref head, ref middle, ref tail) => {
-            match &cx.tables.node_type(pat.hir_id).kind {
+            match &cx.tables().node_type(pat.hir_id).kind {
                 ty::Slice(..) => {
                     // [..] is the only irrefutable slice pattern.
                     !head.is_empty() || middle.is_none() || !tail.is_empty()
@@ -1190,7 +1190,7 @@ pub fn match_function_call<'a, 'tcx>(
     if_chain! {
         if let ExprKind::Call(ref fun, ref args) = expr.kind;
         if let ExprKind::Path(ref qpath) = fun.kind;
-        if let Some(fun_def_id) = cx.tables.qpath_res(qpath, fun.hir_id).opt_def_id();
+        if let Some(fun_def_id) = cx.tables().qpath_res(qpath, fun.hir_id).opt_def_id();
         if match_def_path(cx, fun_def_id, path);
         then {
             return Some(&args)
@@ -1317,14 +1317,14 @@ pub fn is_must_use_func_call(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool
     let did = match expr.kind {
         ExprKind::Call(ref path, _) => if_chain! {
             if let ExprKind::Path(ref qpath) = path.kind;
-            if let def::Res::Def(_, did) = cx.tables.qpath_res(qpath, path.hir_id);
+            if let def::Res::Def(_, did) = cx.tables().qpath_res(qpath, path.hir_id);
             then {
                 Some(did)
             } else {
                 None
             }
         },
-        ExprKind::MethodCall(_, _, _, _) => cx.tables.type_dependent_def_id(expr.hir_id),
+        ExprKind::MethodCall(_, _, _, _) => cx.tables().type_dependent_def_id(expr.hir_id),
         _ => None,
     };
 
index 73758b7eeb7eb28e27651a9ec36b9cc333e622d4..e919b1522d89a04f12c0140b2e45dfc9a8901a6c 100644 (file)
@@ -509,7 +509,7 @@ fn indentation<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 }
 
 /// Convenience extension trait for `DiagnosticBuilder`.
-pub trait DiagnosticBuilderExt<'a, T: LintContext> {
+pub trait DiagnosticBuilderExt<T: LintContext> {
     /// Suggests to add an attribute to an item.
     ///
     /// Correctly handles indentation of the attribute and item.
@@ -556,7 +556,7 @@ fn suggest_item_with_attr<D: Display + ?Sized>(
     fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability);
 }
 
-impl<'a, 'b, 'c, T: LintContext> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
+impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder<'_> {
     fn suggest_item_with_attr<D: Display + ?Sized>(
         &mut self,
         cx: &T,
index 904d948ad29ed17244faf871f2c8a75d474db8ad..d280fe4ab4e02ca1ffce8ab23f7f0c6ca9c95711 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_span::symbol::{Ident, Symbol};
-use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
+use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
 pub fn mutated_variables<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<HirId>> {
@@ -18,7 +18,7 @@ pub fn mutated_variables<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &'a LateContext<'a,
     };
     let def_id = expr.hir_id.owner.to_def_id();
     cx.tcx.infer_ctxt().enter(|infcx| {
-        ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables).walk_expr(expr);
+        ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(expr);
     });
 
     if delegate.skip {
@@ -46,8 +46,8 @@ struct MutVarsDelegate {
 
 impl<'tcx> MutVarsDelegate {
     #[allow(clippy::similar_names)]
-    fn update(&mut self, cat: &Place<'tcx>) {
-        match cat.base {
+    fn update(&mut self, cat: &PlaceWithHirId<'tcx>) {
+        match cat.place.base {
             PlaceBase::Local(id) => {
                 self.used_mutably.insert(id);
             },
@@ -63,15 +63,15 @@ fn update(&mut self, cat: &Place<'tcx>) {
 }
 
 impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
-    fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {}
+    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {}
 
-    fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) {
+    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
         if let ty::BorrowKind::MutBorrow = bk {
             self.update(&cmt)
         }
     }
 
-    fn mutate(&mut self, cmt: &Place<'tcx>) {
+    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
         self.update(&cmt)
     }
 }
index a8d4c7620b1ef11e92ed9ac0368a145b39bec76d..080785b177d650df47a1e549a2d0e51b0a410229 100644 (file)
@@ -37,7 +37,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessVec {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
         // search for `&vec![_]` expressions where the adjusted type is `&[_]`
         if_chain! {
-            if let ty::Ref(_, ty, _) = cx.tables.expr_ty_adjusted(expr).kind;
+            if let ty::Ref(_, ty, _) = cx.tables().expr_ty_adjusted(expr).kind;
             if let ty::Slice(..) = ty.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, ref addressee) = expr.kind;
             if let Some(vec_args) = higher::vec_macro(cx, addressee);
@@ -50,7 +50,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let Some((_, arg, _)) = higher::for_loop(expr);
             if let Some(vec_args) = higher::vec_macro(cx, arg);
-            if is_copy(cx, vec_type(cx.tables.expr_ty_adjusted(arg)));
+            if is_copy(cx, vec_type(cx.tables().expr_ty_adjusted(arg)));
             then {
                 // report the error around the `vec!` not inside `<std macros>:`
                 let span = arg.span
@@ -70,7 +70,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA
     let mut applicability = Applicability::MachineApplicable;
     let snippet = match *vec_args {
         higher::VecArgs::Repeat(elem, len) => {
-            if constant(cx, cx.tables, len).is_some() {
+            if constant(cx, cx.tables(), len).is_some() {
                 format!(
                     "&[{}; {}]",
                     snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
index 55758efa32e67f7e0d390f90d5e7b517a89695fe..bb315e64e5de13237ff1c12d54562630ec3e5ce6 100644 (file)
@@ -32,7 +32,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VecResizeToZero {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let hir::ExprKind::MethodCall(path_segment, _, ref args, _) = expr.kind;
-            if let Some(method_def_id) = cx.tables.type_dependent_def_id(expr.hir_id);
+            if let Some(method_def_id) = cx.tables().type_dependent_def_id(expr.hir_id);
             if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
             if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
             if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
index 6d420d491c50f1aac1c7d9c3f9b9069e764e161a..85f92084574485b12103985aec6266986b8b33b9 100644 (file)
@@ -62,7 +62,7 @@ fn is_file_read_to_end<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'t
         if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind;
         if method_name.ident.as_str() == "read_to_end";
         if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.tables.expr_ty(&exprs[0]);
+        let ty = cx.tables().expr_ty(&exprs[0]);
         if match_type(cx, ty, &paths::FILE);
         then {
             return true
@@ -76,7 +76,7 @@ fn is_file_read_to_string<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr
         if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind;
         if method_name.ident.as_str() == "read_to_string";
         if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.tables.expr_ty(&exprs[0]);
+        let ty = cx.tables().expr_ty(&exprs[0]);
         if match_type(cx, ty, &paths::FILE);
         then {
             return true
index b637253bd0264666418adde8d5c4c86f6f55beee..79f7705e281e542806d081fdae55c5e6549220e0 100644 (file)
@@ -36,7 +36,7 @@
 declare_clippy_lint! {
     /// **What it does:** Checks for wildcard imports `use _::*`.
     ///
-    /// **Why is this bad?** wildcard imports can polute the namespace. This is especially bad if
+    /// **Why is this bad?** wildcard imports can pollute the namespace. This is especially bad if
     /// you try to import something through a wildcard, that already has been imported by name from
     /// a different source:
     ///
index 0820385e01bb5f68d940a2da8e7f433a137dd55a..f0cf17c3b95495e75b243ec5aebd0e546abf08f7 100644 (file)
@@ -36,8 +36,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
             // TODO - constant_simple does not fold many operations involving floats.
             // That's probably fine for this lint - it's pretty unlikely that someone would
             // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
-            if let Some(lhs_value) = constant_simple(cx, cx.tables, left);
-            if let Some(rhs_value) = constant_simple(cx, cx.tables, right);
+            if let Some(lhs_value) = constant_simple(cx, cx.tables(), left);
+            if let Some(rhs_value) = constant_simple(cx, cx.tables(), right);
             if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value;
             if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value;
             then {
index dbc434505947d4e39d05b8fcd753bb8e78cc76d2..d06e359bc7aa557bf4ed736a26d73348921e4428 100644 (file)
@@ -19,11 +19,11 @@ Useful Rustc dev guide links:
 Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions:
 
 - which type does this expression correspond to (using its [`TyKind`][TyKind])?
-- is it a sized type? 
+- is it a sized type?
 - is it a primitive type?
 - does it implement a trait?
 
-This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct, 
+This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct,
 that gives you access to the underlying structure [`TyS`][TyS].
 
 Example of use:
@@ -31,7 +31,7 @@ Example of use:
 impl LateLintPass<'_, '_> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
         // Get type of `expr`
-        let ty = cx.tables.expr_ty(expr);
+        let ty = cx.tables().expr_ty(expr);
         // Match its kind to enter its type
         match ty.kind {
             ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"),
@@ -41,14 +41,14 @@ impl LateLintPass<'_, '_> for MyStructLint {
 }
 ```
 
-Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method 
+Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method
 to retrieve a type from a pattern.
 
 Two noticeable items here:
-- `cx` is the lint context [`LateContext`][LateContext]. 
-  The two most useful data structures in this context are `tcx` and `tables`, 
+- `cx` is the lint context [`LateContext`][LateContext].
+  The two most useful data structures in this context are `tcx` and `tables`,
   allowing us to jump to type definitions and other compilation stages such as HIR.
-- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, 
+- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step,
   it includes useful information such as types of expressions, ways to resolve methods and so on.
 
 # Checking if an expr is calling a specific method
@@ -87,7 +87,7 @@ impl LateLintPass<'_, '_> for MyStructLint {
         }
 
         // 2. Using type context `TyCtxt`
-        let ty = cx.tables.expr_ty(expr);
+        let ty = cx.tables().expr_ty(expr);
         if cx.tcx.lang_items()
             // we are looking for the `DefId` of `Drop` trait in lang items
             .drop_trait()
index 4453ae5ce4414b221eb7784c41dc9114cdd3095f..decd3a79cce180c839320dc158f5714c095150c2 100644 (file)
@@ -1,15 +1,16 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![feature(rustc_private)]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![deny(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
-#[allow(unused_extern_crates)]
+extern crate rustc_data_structures;
 extern crate rustc_driver;
-#[allow(unused_extern_crates)]
 extern crate rustc_errors;
-#[allow(unused_extern_crates)]
 extern crate rustc_interface;
-#[allow(unused_extern_crates)]
 extern crate rustc_middle;
 
 use rustc_interface::interface;
@@ -93,7 +94,7 @@ fn config(&mut self, config: &mut interface::Config) {
 #[allow(clippy::find_map, clippy::filter_map)]
 fn describe_lints() {
     use lintlist::{Level, Lint, ALL_LINTS, LINT_LEVELS};
-    use std::collections::HashSet;
+    use rustc_data_structures::fx::FxHashSet;
 
     println!(
         "
@@ -137,7 +138,7 @@ fn describe_lints() {
 
     let scoped = |x: &str| format!("clippy::{}", x);
 
-    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();
+    let lint_groups: FxHashSet<_> = lints.iter().map(|lint| lint.group).collect();
 
     println!("Lint checks provided by clippy:\n");
     println!("    {}  {:7.7}  meaning", padded("name"), "default");
@@ -207,6 +208,7 @@ fn display_help() {
 
 Common options:
     -h, --help               Print this message
+        --rustc              Pass all args to rustc
     -V, --version            Print version info and exit
 
 Other options are the same as `cargo check`.
@@ -297,12 +299,6 @@ pub fn main() {
     exit(rustc_driver::catch_with_exit_code(move || {
         let mut orig_args: Vec<String> = env::args().collect();
 
-        if orig_args.iter().any(|a| a == "--version" || a == "-V") {
-            let version_info = rustc_tools_util::get_version_info!();
-            println!("{}", version_info);
-            exit(0);
-        }
-
         // Get the sysroot, looking from most specific to this invocation to the least:
         // - command line
         // - runtime environment
@@ -348,6 +344,28 @@ pub fn main() {
             .map(|pb| pb.to_string_lossy().to_string())
             .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
 
+        // make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc"
+        // for example `clippy-driver --rustc --version` will print the rustc version that clippy-driver
+        // uses
+        if let Some(pos) = orig_args.iter().position(|arg| arg == "--rustc") {
+            orig_args.remove(pos);
+            orig_args[0] = "rustc".to_string();
+
+            // if we call "rustc", we need to pass --sysroot here as well
+            let mut args: Vec<String> = orig_args.clone();
+            if !have_sys_root_arg {
+                args.extend(vec!["--sysroot".into(), sys_root]);
+            };
+
+            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None);
+        }
+
+        if orig_args.iter().any(|a| a == "--version" || a == "-V") {
+            let version_info = rustc_tools_util::get_version_info!();
+            println!("{}", version_info);
+            exit(0);
+        }
+
         // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
         // We're invoking the compiler programmatically, so we ignore this/
         let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());
index cac3cc6bdb316eb2891ff3b4d99d1001371ebfbd..edceb75518008e798915dc815e52561662431a31 100644 (file)
     },
     Lint {
         name: "unnested_or_patterns",
-        group: "complexity",
+        group: "pedantic",
         desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`",
         deprecation: None,
         module: "unnested_or_patterns",
index bc43a34ed5d4aaa4e843306abfebab9970a955f2..6739a4cf2245e5e16a7aed73e135edf3d9ab9424 100644 (file)
@@ -1,4 +1,6 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
 
 use rustc_tools_util::VersionInfo;
 use std::env;
index f28aedbf0ab8b71adc9fcf1f47478edf47a8c1b1..368fa6a98c5d6fd7c11614a7a86846a21360c368 100644 (file)
@@ -49,7 +49,9 @@ fn third_party_crates() -> String {
         if let Some(name) = path.file_name().and_then(OsStr::to_str) {
             for dep in CRATES {
                 if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
-                    crates.entry(dep).or_insert(path);
+                    if let Some(old) = crates.insert(dep, path.clone()) {
+                        panic!("Found multiple rlibs for crate `{}`: `{:?}` and `{:?}", dep, old, path);
+                    }
                     break;
                 }
             }
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs b/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs
new file mode 100644 (file)
index 0000000..ecb55d8
--- /dev/null
@@ -0,0 +1,60 @@
+extern crate macro_rules;
+
+// STMT
+#[macro_export]
+macro_rules! pub_macro {
+    () => {
+        let _ = "hello Mr. Vonnegut";
+    };
+}
+
+pub mod inner {
+    pub use super::*;
+
+    // RE-EXPORT
+    // this will stick in `inner` module
+    pub use macro_rules::foofoo;
+    pub use macro_rules::try_err;
+
+    pub mod nested {
+        pub use macro_rules::string_add;
+    }
+
+    // ITEM
+    #[macro_export]
+    macro_rules! inner_mod_macro {
+        () => {
+            #[allow(dead_code)]
+            pub struct Tardis;
+        };
+    }
+}
+
+// EXPR
+#[macro_export]
+macro_rules! function_macro {
+    () => {
+        if true {
+        } else {
+        }
+    };
+}
+
+// TYPE
+#[macro_export]
+macro_rules! ty_macro {
+    () => {
+        Vec<u8>
+    };
+}
+
+mod extern_exports {
+    pub(super) mod private_inner {
+        #[macro_export]
+        macro_rules! pub_in_private_macro {
+            ($name:ident) => {
+                let $name = String::from("secrets and lies");
+            };
+        }
+    }
+}
index ca9d8d16b787df5af6c08f834306dd49d9ed3cf2..cb15bdd2f1b2d4cca8383b2967a535ee3d3ae20f 100644 (file)
@@ -12,29 +12,34 @@ fn test(foo: ()) {}
 
 fn main() {
     let foo = 42;
-    let bar = 42;
     let baz = 42;
+    let quux = 42;
+    // Unlike these others, `bar` is actually considered an acceptable name.
+    // Among many other legitimate uses, bar commonly refers to a period of time in music.
+    // See https://github.com/rust-lang/rust-clippy/issues/5225.
+    let bar = 42;
 
-    let barb = 42;
-    let barbaric = 42;
+    let food = 42;
+    let foodstuffs = 42;
+    let bazaar = 42;
 
     match (42, Some(1337), Some(0)) {
-        (foo, Some(bar), baz @ Some(_)) => (),
+        (foo, Some(baz), quux @ Some(_)) => (),
         _ => (),
     }
 }
 
 fn issue_1647(mut foo: u8) {
-    let mut bar = 0;
-    if let Some(mut baz) = Some(42) {}
+    let mut baz = 0;
+    if let Some(mut quux) = Some(42) {}
 }
 
 fn issue_1647_ref() {
-    let ref bar = 0;
-    if let Some(ref baz) = Some(42) {}
+    let ref baz = 0;
+    if let Some(ref quux) = Some(42) {}
 }
 
 fn issue_1647_ref_mut() {
-    let ref mut bar = 0;
-    if let Some(ref mut baz) = Some(42) {}
+    let ref mut baz = 0;
+    if let Some(ref mut quux) = Some(42) {}
 }
index 44123829fb0f651208a28aa35f981a94f42c99a5..70dbdaece8b6bb37083a79cb0d0bafc9b6c00a86 100644 (file)
@@ -12,77 +12,77 @@ error: use of a blacklisted/placeholder name `foo`
 LL |     let foo = 42;
    |         ^^^
 
-error: use of a blacklisted/placeholder name `bar`
+error: use of a blacklisted/placeholder name `baz`
   --> $DIR/blacklisted_name.rs:15:9
    |
-LL |     let bar = 42;
+LL |     let baz = 42;
    |         ^^^
 
-error: use of a blacklisted/placeholder name `baz`
+error: use of a blacklisted/placeholder name `quux`
   --> $DIR/blacklisted_name.rs:16:9
    |
-LL |     let baz = 42;
-   |         ^^^
+LL |     let quux = 42;
+   |         ^^^^
 
 error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:22:10
+  --> $DIR/blacklisted_name.rs:27:10
    |
-LL |         (foo, Some(bar), baz @ Some(_)) => (),
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
    |          ^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:22:20
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:27:20
    |
-LL |         (foo, Some(bar), baz @ Some(_)) => (),
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
    |                    ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:22:26
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:27:26
    |
-LL |         (foo, Some(bar), baz @ Some(_)) => (),
-   |                          ^^^
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |                          ^^^^
 
 error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:27:19
+  --> $DIR/blacklisted_name.rs:32:19
    |
 LL | fn issue_1647(mut foo: u8) {
    |                   ^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:28:13
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:33:13
    |
-LL |     let mut bar = 0;
+LL |     let mut baz = 0;
    |             ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:29:21
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:34:21
    |
-LL |     if let Some(mut baz) = Some(42) {}
-   |                     ^^^
+LL |     if let Some(mut quux) = Some(42) {}
+   |                     ^^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:33:13
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:38:13
    |
-LL |     let ref bar = 0;
+LL |     let ref baz = 0;
    |             ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:34:21
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:39:21
    |
-LL |     if let Some(ref baz) = Some(42) {}
-   |                     ^^^
+LL |     if let Some(ref quux) = Some(42) {}
+   |                     ^^^^
 
-error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:38:17
+error: use of a blacklisted/placeholder name `baz`
+  --> $DIR/blacklisted_name.rs:43:17
    |
-LL |     let ref mut bar = 0;
+LL |     let ref mut baz = 0;
    |                 ^^^
 
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:39:25
+error: use of a blacklisted/placeholder name `quux`
+  --> $DIR/blacklisted_name.rs:44:25
    |
-LL |     if let Some(ref mut baz) = Some(42) {}
-   |                         ^^^
+LL |     if let Some(ref mut quux) = Some(42) {}
+   |                         ^^^^
 
 error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5389.rs b/src/tools/clippy/tests/ui/crashes/ice-5389.rs
new file mode 100644 (file)
index 0000000..de26219
--- /dev/null
@@ -0,0 +1,13 @@
+#![allow(clippy::explicit_counter_loop)]
+
+fn main() {
+    let v = vec![1, 2, 3];
+    let mut i = 0;
+    let max_storage_size = [0; 128 * 1024];
+    for item in &v {
+        bar(i, *item);
+        i += 1;
+    }
+}
+
+fn bar(_: usize, _: u32) {}
index 6bbf79edfcf700c75eb9444bb79ea12ef141af17..9c5fe02f7519bd25b178af70bf7b01da77520463 100644 (file)
@@ -142,4 +142,16 @@ fn func() {
 
 fn f(val: &[u8]) {}
 
+mod issue_5698 {
+    fn mul_not_always_commutative(x: i32, y: i32) -> i32 {
+        if x == 42 {
+            x * y
+        } else if x == 21 {
+            y * x
+        } else {
+            0
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed
new file mode 100644 (file)
index 0000000..91e34c6
--- /dev/null
@@ -0,0 +1,43 @@
+// compile-flags: --edition 2018
+// aux-build:macro_rules.rs
+// aux-build:macro_use_helper.rs
+// run-rustfix
+// ignore-32bit
+
+#![allow(unused_imports, unreachable_code, unused_variables, dead_code)]
+#![allow(clippy::single_component_path_imports)]
+#![warn(clippy::macro_use_imports)]
+
+#[macro_use]
+extern crate macro_use_helper as mac;
+
+#[macro_use]
+extern crate clippy_mini_macro_test as mini_mac;
+
+mod a {
+    use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
+    use mac;
+    use mini_mac::ClippyMiniMacroTest;
+    use mini_mac;
+    use mac::{inner::foofoo, inner::try_err};
+    use mac::inner;
+    use mac::inner::nested::string_add;
+    use mac::inner::nested;
+
+    #[derive(ClippyMiniMacroTest)]
+    struct Test;
+
+    fn test() {
+        pub_macro!();
+        inner_mod_macro!();
+        pub_in_private_macro!(_var);
+        function_macro!();
+        let v: ty_macro!() = Vec::default();
+
+        inner::try_err!();
+        inner::foofoo!();
+        nested::string_add!();
+    }
+}
+
+fn main() {}
index 60c64ee8146e517f71f28f1c0f62c9600bea9fd0..9c3c50c5d49f29b0a03eea1ca77c583a71686597 100644 (file)
@@ -1,11 +1,43 @@
-// edition:2018
+// compile-flags: --edition 2018
+// aux-build:macro_rules.rs
+// aux-build:macro_use_helper.rs
+// run-rustfix
+// ignore-32bit
+
+#![allow(unused_imports, unreachable_code, unused_variables, dead_code)]
+#![allow(clippy::single_component_path_imports)]
 #![warn(clippy::macro_use_imports)]
 
-use std::collections::HashMap;
 #[macro_use]
-use std::prelude;
+extern crate macro_use_helper as mac;
+
+#[macro_use]
+extern crate clippy_mini_macro_test as mini_mac;
+
+mod a {
+    #[macro_use]
+    use mac;
+    #[macro_use]
+    use mini_mac;
+    #[macro_use]
+    use mac::inner;
+    #[macro_use]
+    use mac::inner::nested;
 
-fn main() {
-    let _ = HashMap::<u8, u8>::new();
-    println!();
+    #[derive(ClippyMiniMacroTest)]
+    struct Test;
+
+    fn test() {
+        pub_macro!();
+        inner_mod_macro!();
+        pub_in_private_macro!(_var);
+        function_macro!();
+        let v: ty_macro!() = Vec::default();
+
+        inner::try_err!();
+        inner::foofoo!();
+        nested::string_add!();
+    }
 }
+
+fn main() {}
index b5e3dbec572772f2e9aaf7924e0f011eaaedd878..f8c86c8d9179f8af918b684eb9294c18ea4a7008 100644 (file)
@@ -1,10 +1,28 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:5:1
+  --> $DIR/macro_use_imports.rs:18:5
    |
-LL | #[macro_use]
-   | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::<macro name>`
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
    |
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
-error: aborting due to previous error
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+  --> $DIR/macro_use_imports.rs:20:5
+   |
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+  --> $DIR/macro_use_imports.rs:22:5
+   |
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+
+error: `macro_use` attributes are no longer needed in the Rust 2018 edition
+  --> $DIR/macro_use_imports.rs:24:5
+   |
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+
+error: aborting due to 4 previous errors
 
index fc8cb0e747c73e157e3c17306a2491352c208bf3..8b4e2d21331cd9e6ca0ff31fa88601ac8c7d3148 100644 (file)
@@ -67,6 +67,7 @@ fn main() {
     takes_bool(x);
 
     issue5504();
+    issue5697();
 
     let _ = if gen_opt().is_some() {
         1
@@ -117,3 +118,42 @@ fn issue5504() {
     if m!().is_some() {}
     while m!().is_some() {}
 }
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
index 51912dade035677a5372aa97b871eb3aa2f1b62e..b0904e41b6f43d976137e46fd8205e55e779dcd9 100644 (file)
@@ -88,6 +88,7 @@ fn main() {
     takes_bool(x);
 
     issue5504();
+    issue5697();
 
     let _ = if let Some(_) = gen_opt() {
         1
@@ -138,3 +139,42 @@ fn try_result_opt() -> Result<i32, i32> {
     if let Some(_) = m!() {}
     while let Some(_) = m!() {}
 }
+
+// None of these should be linted because none of the suggested methods
+// are `const fn` without toggling a feature.
+const fn issue5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
index b58deb7954efe06b90c8516d1b4d52c614b901db..51a6f4350d32c3f4daaf15fdcd0b95034dabb029 100644 (file)
@@ -143,49 +143,49 @@ LL |     let x = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:92:20
+  --> $DIR/redundant_pattern_matching.rs:93:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching.rs:94:19
+  --> $DIR/redundant_pattern_matching.rs:95:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:96:19
+  --> $DIR/redundant_pattern_matching.rs:97:19
    |
 LL |     } else if let Ok(_) = gen_res() {
    |            -------^^^^^------------ help: try this: `if gen_res().is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:98:19
+  --> $DIR/redundant_pattern_matching.rs:99:19
    |
 LL |     } else if let Err(_) = gen_res() {
    |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:131:19
+  --> $DIR/redundant_pattern_matching.rs:132:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
    |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:132:16
+  --> $DIR/redundant_pattern_matching.rs:133:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
    |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:138:12
+  --> $DIR/redundant_pattern_matching.rs:139:12
    |
 LL |     if let Some(_) = m!() {}
    |     -------^^^^^^^------- help: try this: `if m!().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching.rs:139:15
+  --> $DIR/redundant_pattern_matching.rs:140:15
    |
 LL |     while let Some(_) = m!() {}
    |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.fixed
new file mode 100644 (file)
index 0000000..8a81e92
--- /dev/null
@@ -0,0 +1,44 @@
+// run-rustfix
+
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+    if Ok::<i32, i32>(42).is_ok() {}
+
+    if Err::<i32, i32>(42).is_err() {}
+
+    while Ok::<i32, i32>(10).is_ok() {}
+
+    while Ok::<i32, i32>(10).is_err() {}
+
+    Ok::<i32, i32>(42).is_ok();
+
+    Err::<i32, i32>(42).is_err();
+
+    // These should not be linted until `const_option` is implemented.
+    // See https://github.com/rust-lang/rust/issues/67441
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.rs
new file mode 100644 (file)
index 0000000..1cd5154
--- /dev/null
@@ -0,0 +1,50 @@
+// run-rustfix
+
+#![feature(const_result)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused)]
+
+// Test that results are linted with the feature enabled.
+
+const fn issue_5697() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    while let Ok(_) = Ok::<i32, i32>(10) {}
+
+    while let Err(_) = Ok::<i32, i32>(10) {}
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+
+    // These should not be linted until `const_option` is implemented.
+    // See https://github.com/rust-lang/rust/issues/67441
+
+    if let Some(_) = Some(42) {}
+
+    if let None = None::<()> {}
+
+    while let Some(_) = Some(42) {}
+
+    while let None = None::<()> {}
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_const_result.stderr
new file mode 100644 (file)
index 0000000..8ecd721
--- /dev/null
@@ -0,0 +1,46 @@
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:10:12
+   |
+LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
+   |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:12:12
+   |
+LL |     if let Err(_) = Err::<i32, i32>(42) {}
+   |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:14:15
+   |
+LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:16:15
+   |
+LL |     while let Err(_) = Ok::<i32, i32>(10) {}
+   |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:18:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_const_result.rs:23:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: aborting due to 6 previous errors
+
index 346972b7bb4e0d95e1353040c58c4ed714e8e01b..ad5b8e4857d173f50bcbcd2bc9565e8b6c2d5b6a 100644 (file)
@@ -17,6 +17,12 @@ fn main() {
         std::mem::forget(mem::replace(&mut v, new_v));
     }
 
+    unsafe {
+        let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init());
+        let new_v = might_panic(taken_v);
+        std::mem::forget(mem::replace(&mut v, new_v));
+    }
+
     unsafe {
         let taken_v = mem::replace(&mut v, mem::zeroed());
         let new_v = might_panic(taken_v);
index c1f55d7601e5ccce9592e5653330435d7f114832..09468eeaea4bf9d18dacd1c5c03809c5032909bd 100644 (file)
@@ -2,26 +2,29 @@ error: replacing with `mem::uninitialized()`
   --> $DIR/repl_uninit.rs:15:23
    |
 LL |         let taken_v = mem::replace(&mut v, mem::uninitialized());
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)`
    |
    = note: `-D clippy::mem-replace-with-uninit` implied by `-D warnings`
-   = help: consider using the `take_mut` crate instead
 
-error: replacing with `mem::zeroed()`
+error: replacing with `mem::MaybeUninit::uninit().assume_init()`
   --> $DIR/repl_uninit.rs:21:23
    |
+LL |         let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)`
+
+error: replacing with `mem::zeroed()`
+  --> $DIR/repl_uninit.rs:27:23
+   |
 LL |         let taken_v = mem::replace(&mut v, mem::zeroed());
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a default value or the `take_mut` crate instead
 
 error: replacing with `mem::uninitialized()`
-  --> $DIR/repl_uninit.rs:33:28
+  --> $DIR/repl_uninit.rs:39:28
    |
 LL |     let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) };
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider using the `take_mut` crate instead
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(uref)`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
index 64c0298c1fa4e4dae4833e0f330fbaa48d963298..703b87634cec37042e95db4d6428a3eccb47e187 100644 (file)
@@ -123,6 +123,7 @@ pub enum FailMode {
 pub enum CompareMode {
     Nll,
     Polonius,
+    Chalk,
 }
 
 impl CompareMode {
@@ -130,6 +131,7 @@ pub(crate) fn to_str(&self) -> &'static str {
         match *self {
             CompareMode::Nll => "nll",
             CompareMode::Polonius => "polonius",
+            CompareMode::Chalk => "chalk",
         }
     }
 
@@ -137,6 +139,7 @@ pub fn parse(s: String) -> CompareMode {
         match s.as_str() {
             "nll" => CompareMode::Nll,
             "polonius" => CompareMode::Polonius,
+            "chalk" => CompareMode::Chalk,
             x => panic!("unknown --compare-mode option: {}", x),
         }
     }
index 9d1940dd4d6c20c0cc5e413ced2df891fa6232e8..571e7a59113ada60bbe3af9097f4f36c99acbc2b 100644 (file)
@@ -43,6 +43,10 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
         let mut props = EarlyProps::default();
         let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
         let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
+        let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
+        let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
+        let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
+        let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
 
         iter_header(testfile, None, rdr, &mut |ln| {
             // we should check if any only-<platform> exists and if it exists
@@ -74,7 +78,25 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
                     props.ignore = true;
                 }
 
-                if !rustc_has_sanitizer_support && config.parse_needs_sanitizer_support(ln) {
+                if !rustc_has_sanitizer_support
+                    && config.parse_name_directive(ln, "needs-sanitizer-support")
+                {
+                    props.ignore = true;
+                }
+
+                if !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address") {
+                    props.ignore = true;
+                }
+
+                if !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak") {
+                    props.ignore = true;
+                }
+
+                if !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory") {
+                    props.ignore = true;
+                }
+
+                if !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread") {
                     props.ignore = true;
                 }
 
@@ -241,7 +263,7 @@ fn ignore_llvm(config: &Config, line: &str) -> bool {
         }
 
         fn version_to_int(version: &str) -> u32 {
-            let version_without_suffix = version.split('-').next().unwrap();
+            let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
             let components: Vec<u32> = version_without_suffix
                 .split('.')
                 .map(|s| s.parse().expect("Malformed version component"))
@@ -829,10 +851,6 @@ fn parse_needs_profiler_support(&self, line: &str) -> bool {
         self.parse_name_directive(line, "needs-profiler-support")
     }
 
-    fn parse_needs_sanitizer_support(&self, line: &str) -> bool {
-        self.parse_name_directive(line, "needs-sanitizer-support")
-    }
-
     /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
     /// or `normalize-stderr-32bit`.
     fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {
@@ -857,6 +875,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
             match self.compare_mode {
                 Some(CompareMode::Nll) => name == "compare-mode-nll",
                 Some(CompareMode::Polonius) => name == "compare-mode-polonius",
+                Some(CompareMode::Chalk) => name == "compare-mode-chalk",
                 None => false,
             } ||
             (cfg!(debug_assertions) && name == "debug") ||
index f7355433463d68b08a065ff58b6506e8072a184e..72af34d78260ba6007a385300ba0c8be2aeb8622 100644 (file)
@@ -201,3 +201,22 @@ fn debugger() {
     config.debugger = Some(Debugger::Lldb);
     assert!(parse_rs(&config, "// ignore-lldb").ignore);
 }
+
+#[test]
+fn sanitizers() {
+    let mut config = config();
+
+    // Target that supports all sanitizers:
+    config.target = "x86_64-unknown-linux-gnu".to_owned();
+    assert!(!parse_rs(&config, "// needs-sanitizer-address").ignore);
+    assert!(!parse_rs(&config, "// needs-sanitizer-leak").ignore);
+    assert!(!parse_rs(&config, "// needs-sanitizer-memory").ignore);
+    assert!(!parse_rs(&config, "// needs-sanitizer-thread").ignore);
+
+    // Target that doesn't support sanitizers:
+    config.target = "wasm32-unknown-emscripten".to_owned();
+    assert!(parse_rs(&config, "// needs-sanitizer-address").ignore);
+    assert!(parse_rs(&config, "// needs-sanitizer-leak").ignore);
+    assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore);
+    assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore);
+}
index 52d0cbd4bfd7a45dec2cd4f86a8d189267d771e0..6ac7c3b9b474a9dbacfdd4cb11fef57cb95da684 100644 (file)
@@ -4,7 +4,6 @@
 use crate::errors::{Error, ErrorKind};
 use crate::runtest::ProcRes;
 use serde::Deserialize;
-use serde_json;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
index 93c53e779d50eb9bc48118431d6b1bae98d8e78d..2aea4d22700f396782b28218100140ccdfb5ae03 100644 (file)
@@ -1,6 +1,4 @@
 #![crate_name = "compiletest"]
-#![feature(vec_remove_item)]
-#![deny(warnings)]
 // The `test` crate is the only unstable feature
 // allowed here, just to share similar code.
 #![feature(test)]
@@ -10,8 +8,6 @@
 use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
 use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths};
 use crate::util::logv;
-use env_logger;
-use getopts;
 use getopts::Options;
 use log::*;
 use std::env;
index da1d3db49d70e025940a1fbb66b9cac59a8777e3..30a922057eb20f42e1e9097067c27f17603f7e78 100644 (file)
@@ -25,7 +25,6 @@ pub fn read2(
 
 #[cfg(unix)]
 mod imp {
-    use libc;
     use std::io;
     use std::io::prelude::*;
     use std::mem;
index 18f00db3d8e128ea86f3821de3f0b46a51b93cdb..dd0c68ecd4965121ec723ecdf0c0166399be8c92 100644 (file)
@@ -13,7 +13,6 @@
 use crate::json;
 use crate::util::get_pointer_width;
 use crate::util::{logv, PathBufExt};
-use diff;
 use regex::{Captures, Regex};
 use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
 
@@ -1985,6 +1984,9 @@ fn make_compile_args(
             Some(CompareMode::Polonius) => {
                 rustc.args(&["-Zpolonius", "-Zborrowck=mir"]);
             }
+            Some(CompareMode::Chalk) => {
+                rustc.args(&["-Zchalk"]);
+            }
             None => {}
         }
 
index ca36a15ffc7de31634414acd793015723c529a4f..0437ff8c9440a3cbfe8b59134c1491125584fe4e 100644 (file)
     ("xcore", "xcore"),
 ];
 
+pub const ASAN_SUPPORTED_TARGETS: &'static [&'static str] = &[
+    "aarch64-fuchsia",
+    "aarch64-unknown-linux-gnu",
+    "x86_64-apple-darwin",
+    "x86_64-fuchsia",
+    "x86_64-unknown-linux-gnu",
+];
+
+pub const LSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+    &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
+pub const MSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+    &["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"];
+
+pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] =
+    &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+
 pub fn matches_os(triple: &str, name: &str) -> bool {
     // For the wasm32 bare target we ignore anything also ignored on emscripten
     // and then we also recognize `wasm32-bare` as the os for the target
index 3335816f09f0e6a90b6fd9e00a0a24dba3575ef8..097fb1f985a746e42ad6eec1f5acbcf715994e69 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(rustc_private)]
-#![deny(warnings)]
 
 extern crate env_logger;
 extern crate rustc_ast;
index f2ed8aa409a36e4077986b5f8b11b2c334bce97d..d8dad8fc789e931ed24cb1c29eaa656609166fd4 100644 (file)
@@ -165,7 +165,7 @@ fn main() {
 impl Error for StrError {}
 
 impl std::fmt::Display for StrError {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(&self.0, f)
     }
 }
@@ -177,7 +177,7 @@ struct WithContext {
 }
 
 impl std::fmt::Display for WithContext {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{}", self.context)
     }
 }
index 570ffd5d306227ed228d2d9e8bd85c19d6b394b9..9e4e2c433fbedb9782adea84b1882ca21d225b5f 100644 (file)
@@ -14,8 +14,6 @@
 //! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
 //! but this should catch the majority of "broken link" cases.
 
-#![deny(warnings)]
-
 use std::collections::hash_map::Entry;
 use std::collections::{HashMap, HashSet};
 use std::env;
index faff9a7ad9f2d07c1702bd8be392134d27e3eaf8..fd8101247749c5be6850d5cb5096f01a1867e5ba 160000 (submodule)
@@ -1 +1 @@
-Subproject commit faff9a7ad9f2d07c1702bd8be392134d27e3eaf8
+Subproject commit fd8101247749c5be6850d5cb5096f01a1867e5ba
index efc29163455be29467a89c111a16cc3fbc5af31b..6245b76fd6e845108a9eb7f89d41a8ee3206a81b 100644 (file)
@@ -5,8 +5,6 @@
 //! Here is also where we bake in the support to spawn the QEMU emulator as
 //! well.
 
-#![deny(warnings)]
-
 use std::env;
 use std::fs::{self, File};
 use std::io::prelude::*;
@@ -107,13 +105,23 @@ fn start_android_emulator(server: &Path) {
     Command::new("adb").arg("shell").arg("/data/tmp/testd").spawn().unwrap();
 }
 
-fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path) {
+fn prepare_rootfs(target: &str, rootfs: &Path, server: &Path, rootfs_img: &Path) {
+    t!(fs::copy(server, rootfs.join("testd")));
+
+    match target {
+        "arm-unknown-linux-gnueabihf" | "aarch64-unknown-linux-gnu" => {
+            prepare_rootfs_cpio(rootfs, rootfs_img)
+        }
+        "riscv64gc-unknown-linux-gnu" => prepare_rootfs_ext4(rootfs, rootfs_img),
+        _ => panic!("{} is not supported", target),
+    }
+}
+
+fn prepare_rootfs_cpio(rootfs: &Path, rootfs_img: &Path) {
     // Generate a new rootfs image now that we've updated the test server
     // executable. This is the equivalent of:
     //
     //      find $rootfs -print 0 | cpio --null -o --format=newc > rootfs.img
-    t!(fs::copy(server, rootfs.join("testd")));
-    let rootfs_img = tmpdir.join("rootfs.img");
     let mut cmd = Command::new("cpio");
     cmd.arg("--null")
         .arg("-o")
@@ -128,6 +136,38 @@ fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path
     t!(io::copy(&mut child.stdout.take().unwrap(), &mut t!(File::create(&rootfs_img))));
     assert!(t!(child.wait()).success());
 
+    fn add_files(w: &mut dyn Write, root: &Path, cur: &Path) {
+        for entry in t!(cur.read_dir()) {
+            let entry = t!(entry);
+            let path = entry.path();
+            let to_print = path.strip_prefix(root).unwrap();
+            t!(write!(w, "{}\u{0}", to_print.to_str().unwrap()));
+            if t!(entry.file_type()).is_dir() {
+                add_files(w, root, &path);
+            }
+        }
+    }
+}
+
+fn prepare_rootfs_ext4(rootfs: &Path, rootfs_img: &Path) {
+    let mut dd = Command::new("dd");
+    dd.arg("if=/dev/zero")
+        .arg(&format!("of={}", rootfs_img.to_string_lossy()))
+        .arg("bs=1M")
+        .arg("count=1024");
+    let mut dd_child = t!(dd.spawn());
+    assert!(t!(dd_child.wait()).success());
+
+    let mut mkfs = Command::new("mkfs.ext4");
+    mkfs.arg("-d").arg(rootfs).arg(rootfs_img);
+    let mut mkfs_child = t!(mkfs.spawn());
+    assert!(t!(mkfs_child.wait()).success());
+}
+
+fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path) {
+    let rootfs_img = &tmpdir.join("rootfs.img");
+    prepare_rootfs(target, rootfs, server, rootfs_img);
+
     // Start up the emulator, in the background
     match target {
         "arm-unknown-linux-gnueabihf" => {
@@ -170,19 +210,30 @@ fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path
                 .arg("virtio-net-device,netdev=net0,mac=00:00:00:00:00:00");
             t!(cmd.spawn());
         }
-        _ => panic!("cannot start emulator for: {}" < target),
-    }
-
-    fn add_files(w: &mut dyn Write, root: &Path, cur: &Path) {
-        for entry in t!(cur.read_dir()) {
-            let entry = t!(entry);
-            let path = entry.path();
-            let to_print = path.strip_prefix(root).unwrap();
-            t!(write!(w, "{}\u{0}", to_print.to_str().unwrap()));
-            if t!(entry.file_type()).is_dir() {
-                add_files(w, root, &path);
-            }
+        "riscv64gc-unknown-linux-gnu" => {
+            let mut cmd = Command::new("qemu-system-riscv64");
+            cmd.arg("-nographic")
+                .arg("-machine")
+                .arg("virt")
+                .arg("-m")
+                .arg("1024")
+                .arg("-bios")
+                .arg("none")
+                .arg("-kernel")
+                .arg("/tmp/bbl")
+                .arg("-append")
+                .arg("quiet console=ttyS0 root=/dev/vda rw")
+                .arg("-netdev")
+                .arg("user,id=net0,hostfwd=tcp::12345-:12345")
+                .arg("-device")
+                .arg("virtio-net-device,netdev=net0,mac=00:00:00:00:00:00")
+                .arg("-device")
+                .arg("virtio-blk-device,drive=hd0")
+                .arg("-drive")
+                .arg(&format!("file={},format=raw,id=hd0", &rootfs_img.to_string_lossy()));
+            t!(cmd.spawn());
         }
+        _ => panic!("cannot start emulator for: {}", target),
     }
 }
 
index 8c56910e2dfad701e4ec7d040ebf66b8dffcd767..d92758eb7474cda8ec9f3db0cf69f78cfe233235 100644 (file)
@@ -10,8 +10,6 @@
 //! themselves having support libraries. All data over the TCP sockets is in a
 //! basically custom format suiting our needs.
 
-#![deny(warnings)]
-
 #[cfg(not(windows))]
 use std::fs::Permissions;
 #[cfg(not(windows))]
index 8d7a7167c15b9154755588c39b22b2336c89ca68..fb46b914c11b06828680cb526e2abe9e1d69b868 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8d7a7167c15b9154755588c39b22b2336c89ca68
+Subproject commit fb46b914c11b06828680cb526e2abe9e1d69b868
index ff41197faa1a6d187316febf75d518ceca3043f2..f0a6ce2fa06c27d9b62f84e24045015b3eb52b81 100644 (file)
@@ -5,24 +5,10 @@ version = "0.1.0"
 license = "MIT OR Apache-2.0"
 edition = "2018"
 
-[features]
-linkcheck = ["mdbook-linkcheck", "codespan-reporting", "codespan"]
-
 [dependencies]
 clap = "2.25.0"
-failure = "0.1"
-mdbook-linkcheck = { version = "0.5.0", optional = true }
-# Keep in sync with mdbook-linkcheck.
-codespan = { version = "0.5", optional = true }
-codespan-reporting = { version = "0.5", optional = true }
-
-
-# A noop dependency that changes in the Rust repository, it's a bit of a hack.
-# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
-# for more information.
-rustc-workspace-hack = "1.0.0"
 
 [dependencies.mdbook]
-version = "0.3.7"
+version = "0.4.0"
 default-features = false
 features = ["search"]
index 60bd0b72910a448c68c8d9d37b7dbfced7c01310..c87c64540ad7bb7fa916be04c10b43628d45fc9a 100644 (file)
@@ -30,11 +30,6 @@ fn main() {
                 .about("Tests that a book's Rust code samples compile")
                 .arg_from_usage(dir_message),
         )
-        .subcommand(
-            SubCommand::with_name("linkcheck")
-                .about("Run linkcheck with mdBook 3")
-                .arg_from_usage(dir_message),
-        )
         .get_matches();
 
     // Check which subcomamnd the user ran...
@@ -49,98 +44,14 @@ fn main() {
                 handle_error(e);
             }
         }
-        ("linkcheck", Some(sub_matches)) => {
-            #[cfg(feature = "linkcheck")]
-            {
-                let (diags, files) = linkcheck(sub_matches).expect("Error while linkchecking.");
-                if !diags.is_empty() {
-                    let color = codespan_reporting::term::termcolor::ColorChoice::Auto;
-                    let mut writer =
-                        codespan_reporting::term::termcolor::StandardStream::stderr(color);
-                    let cfg = codespan_reporting::term::Config::default();
-
-                    for diag in diags {
-                        codespan_reporting::term::emit(&mut writer, &cfg, &files, &diag)
-                            .expect("Unable to emit linkcheck error.");
-                    }
-
-                    std::process::exit(101);
-                }
-            }
-
-            #[cfg(not(feature = "linkcheck"))]
-            {
-                // This avoids the `unused_binding` lint.
-                println!(
-                    "mdbook-linkcheck is disabled, but arguments were passed: {:?}",
-                    sub_matches
-                );
-            }
-        }
         (_, _) => unreachable!(),
     };
 }
 
-#[cfg(feature = "linkcheck")]
-pub fn linkcheck(
-    args: &ArgMatches<'_>,
-) -> Result<(Vec<codespan_reporting::diagnostic::Diagnostic>, codespan::Files), failure::Error> {
-    use mdbook_linkcheck::Reason;
-
-    let book_dir = get_book_dir(args);
-    let src_dir = book_dir.join("src");
-    let book = MDBook::load(&book_dir).unwrap();
-    let linkck_cfg = mdbook_linkcheck::get_config(&book.config)?;
-    let mut files = codespan::Files::new();
-    let target_files = mdbook_linkcheck::load_files_into_memory(&book.book, &mut files);
-    let cache = mdbook_linkcheck::Cache::default();
-
-    let (links, incomplete) = mdbook_linkcheck::extract_links(target_files, &files);
-
-    let outcome =
-        mdbook_linkcheck::validate(&links, &linkck_cfg, &src_dir, &cache, &files, incomplete)?;
-
-    let mut is_real_error = false;
-
-    for link in outcome.invalid_links.iter() {
-        match &link.reason {
-            Reason::FileNotFound | Reason::TraversesParentDirectories => {
-                is_real_error = true;
-            }
-            Reason::UnsuccessfulServerResponse(status) => {
-                if status.as_u16() == 429 {
-                    eprintln!("Received 429 (TOO_MANY_REQUESTS) for link `{}`", link.link.uri);
-                } else if status.is_client_error() {
-                    is_real_error = true;
-                } else {
-                    eprintln!("Unsuccessful server response for link `{}`", link.link.uri);
-                }
-            }
-            Reason::Client(err) => {
-                if err.is_timeout() {
-                    eprintln!("Timeout for link `{}`", link.link.uri);
-                } else if err.is_server_error() {
-                    eprintln!("Server error for link `{}`", link.link.uri);
-                } else if !err.is_http() {
-                    eprintln!("Non-HTTP-related error for link: {} {}", link.link.uri, err);
-                } else {
-                    is_real_error = true;
-                }
-            }
-        }
-    }
-
-    if is_real_error {
-        Ok((outcome.generate_diagnostics(&files, linkck_cfg.warning_policy), files))
-    } else {
-        Ok((vec![], files))
-    }
-}
-
 // Build command implementation
 pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
     let book_dir = get_book_dir(args);
-    let mut book = MDBook::load(&book_dir)?;
+    let mut book = load_book(&book_dir)?;
 
     // Set this to allow us to catch bugs in advance.
     book.config.build.create_missing = false;
@@ -156,7 +67,7 @@ pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
 
 fn test(args: &ArgMatches<'_>) -> Result3<()> {
     let book_dir = get_book_dir(args);
-    let mut book = MDBook::load(&book_dir)?;
+    let mut book = load_book(&book_dir)?;
     book.test(vec![])
 }
 
@@ -170,10 +81,16 @@ fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
     }
 }
 
+fn load_book(book_dir: &Path) -> Result3<MDBook> {
+    let mut book = MDBook::load(book_dir)?;
+    book.config.set("output.html.input-404", "").unwrap();
+    Ok(book)
+}
+
 fn handle_error(error: mdbook::errors::Error) -> ! {
     eprintln!("Error: {}", error);
 
-    for cause in error.iter().skip(1) {
+    for cause in error.chain().skip(1) {
         eprintln!("\tCaused By: {}", cause);
     }
 
index 1b1f4447966549905b6e6f159f50f4fc4ca0fba1..351e2d4481c0fafc2c98e08f476afa2cd6caef9b 100644 (file)
@@ -69,8 +69,7 @@ serde = { version = "1.0.82", features = ['derive'] }
 serde_json = { version = "1.0.31", features = ["raw_value"] }
 smallvec-0_6 = { package = "smallvec", version = "0.6", features = ['union', 'may_dangle'] }
 smallvec = { version = "1.0", features = ['union', 'may_dangle'] }
-syn = { version = "0.15", features = ['full', 'extra-traits'] }
-syn-1 = { package = "syn", version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] }
+syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] }
 url = { version = "2.0", features = ['serde'] }
 
 [target.'cfg(not(windows))'.dependencies]
index 163571bc5b9882906f3ce68924d8707f461f0b77..139e6f73f42169b1f68d009954451e5adf557342 100644 (file)
@@ -269,6 +269,12 @@ function runSearch(query, expected, index, loaded, loadedFile, queryName) {
             break;
         }
         var entry = expected[key];
+
+        if (exact_check == true && entry.length !== results[key].length) {
+            error_text.push(queryName + "==> Expected exactly " + entry.length +
+                            " results but found " + results[key].length + " in '" + key + "'");
+        }
+
         var prev_pos = -1;
         for (var i = 0; i < entry.length; ++i) {
             var entry_pos = lookForEntry(entry[i], results[key]);
@@ -307,8 +313,11 @@ function checkResult(error_text, loadedFile, displaySuccess) {
 }
 
 function runChecks(testFile, loaded, index) {
-    var loadedFile = loadContent(
-        readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
+    var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
+    if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
+        testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+    }
+    var loadedFile = loadContent(testFileContent);
 
     const expected = loadedFile.EXPECTED;
     const query = loadedFile.QUERY;
index aedff61f7ac4fc2b287ff76d33f2584e1f63a3af..c1e9b7b87493c5197c4330693bdf4ccb30a90971 160000 (submodule)
@@ -1 +1 @@
-Subproject commit aedff61f7ac4fc2b287ff76d33f2584e1f63a3af
+Subproject commit c1e9b7b87493c5197c4330693bdf4ccb30a90971
index c08f02b972e8f57ca024cdaf24b7eba927ad351c..4622e15a1cae88bbda0575adf45b576c46176afb 100644 (file)
@@ -26,9 +26,6 @@
 const EXCEPTIONS: &[(&str, &str)] = &[
     ("mdbook", "MPL-2.0"),                  // mdbook
     ("openssl", "Apache-2.0"),              // cargo, mdbook
-    ("toml-query", "MPL-2.0"),              // mdbook
-    ("toml-query_derive", "MPL-2.0"),       // mdbook
-    ("is-match", "MPL-2.0"),                // mdbook
     ("rdrand", "ISC"),                      // mdbook, rustfmt
     ("fuchsia-cprng", "BSD-3-Clause"),      // mdbook, rustfmt
     ("fuchsia-zircon-sys", "BSD-3-Clause"), // rustdoc, rustc, cargo
@@ -45,9 +42,6 @@
     ("bitmaps", "MPL-2.0+"),                // cargo via im-rc
     // FIXME: this dependency violates the documentation comment above:
     ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
-    ("dunce", "CC0-1.0"),            // mdbook-linkcheck
-    ("codespan-reporting", "Apache-2.0"), // mdbook-linkcheck
-    ("codespan", "Apache-2.0"),      // mdbook-linkcheck
     ("crossbeam-channel", "MIT/Apache-2.0 AND BSD-2-Clause"), // cargo
 ];
 
@@ -80,9 +74,7 @@
     "cc",
     "cfg-if",
     "chalk-derive",
-    "chalk-engine",
     "chalk-ir",
-    "chalk-macros",
     "cloudabi",
     "cmake",
     "compiler_builtins",
index d9320e9147cffd31da018f866c6765d21b6f4621..3fa637b5a696f4824b2b42d60d21ebc40eb973ef 100644 (file)
@@ -444,10 +444,7 @@ macro_rules! err {
                         level: Status::Unstable,
                         since: None,
                         has_gate_test: false,
-                        // FIXME(#57563): #57563 is now used as a common tracking issue,
-                        // although we would like to have specific tracking issues for each
-                        // `rustc_const_unstable` in the future.
-                        tracking_issue: NonZeroU32::new(57563),
+                        tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none),
                     };
                     mf(Ok((feature_name, feature)), file, i + 1);
                     continue;
index e2856c690550abfd9d0c828649406a20590cf924..2d105c7f33a2b25cb3ee5637883469fb0041b7eb 100644 (file)
@@ -4,8 +4,6 @@
 //! etc. This is run by default on `./x.py test` and as part of the auto
 //! builders. The tidy checks can be executed with `./x.py test tidy`.
 
-#![deny(warnings)]
-
 use tidy::*;
 
 use std::env;
index 247e85603cfc2e2305db675ca0f45670231e6d73..7e77ae1db0d1b05c7dd54251c3c86a9199215702 100644 (file)
@@ -67,6 +67,7 @@
     // std testing crates, okay for now at least
     "src/libcore/tests",
     "src/liballoc/tests/lib.rs",
+    "src/liballoc/benches/lib.rs",
     // The `VaList` implementation must have platform specific code.
     // The Windows implementation of a `va_list` is always a character
     // pointer regardless of the target architecture. As a result,
index c9d1561a9d3d8e10a1db3123a4f4dc0a4e14574c..aa24881ac6bd75ea2b176f9180f65e26a5c9bd39 100644 (file)
@@ -1,7 +1,5 @@
 //! Auto-generate stub docs for the unstable book
 
-#![deny(warnings)]
-
 use std::collections::BTreeSet;
 use std::env;
 use std::fs::{self, File};
index fc2dbb8d4402d7d5d39191d3be7835aa31698ef5..73ca7abfed363a96f9ef1017d692546251096af7 100644 (file)
@@ -76,44 +76,106 @@ exclude_labels = [
 ]
 
 [notify-zulip."I-prioritize"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "I-prioritize #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been requested for prioritization."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been requested for prioritization.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize)
+- Priority?
+- Regression?
+- Notify people/groups?
+- Needs `I-nominated`?
+"""
 message_on_remove = "Issue #{number}'s prioritization request has been removed."
 
 [notify-zulip."I-nominated"]
 required_labels = ["T-compiler"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "I-prioritize #{number} {title}"
-message_on_add = "@*WG-prioritization* #{number} has been nominated for discussion in `T-compiler` meeting."
+message_on_add = """\
+@*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated)
+- Already discussed?
+- Worth the meeting time?
+- Add agenda entry:
+  - Why nominated?
+  - Assignee?
+  - Issue? PR? What's the status?
+  - Summary and important details?
+"""
 message_on_remove = "#{number}'s nomination has been removed."
 
 [notify-zulip."beta-nominated"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "Backport #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} has been requested for beta backport."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} has been requested for beta backport.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+Prepare agenda entry:
+- Why nominated?
+- Author, assignee?
+- Important details?
+"""
 message_on_remove = "PR #{number}'s beta backport request has been removed."
 
 [notify-zulip."stable-nominated"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "Backport #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} has been requested for stable backport."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} has been requested for stable backport.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+Prepare agenda entry:
+- Why nominated?
+- Author, assignee?
+- Important details?
+"""
 message_on_remove = "PR #{number}'s stable backport request has been removed."
 
 [notify-zulip."S-waiting-on-team"]
 required_labels = ["T-compiler"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "S-waiting-on-team #{number} {title}"
-message_on_add = "@*WG-prioritization* PR #{number} is waiting on `T-compiler`."
+message_on_add = """\
+@*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team)
+- Prepare agenda entry:
+  - What is it waiting for?
+  - Important details?
+- Could be resolved quickly? Tag `I-nominated`.
+"""
 message_on_remove = "PR #{number}'s is no longer waiting on `T-compiler`."
 
 [notify-zulip."P-critical"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "P-critical #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-critical`."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+- Notify people/groups?
+- Assign if possible?
+- Add to agenda:
+  - Assignee?
+  - Summary and important details?
+- Other actions to move forward?
+"""
 
 [notify-zulip."P-high"]
-required_labels = ["regression-from-stable-to-*"]
-zulip_stream = 227806 # #t-compiler/wg-prioritization
+required_labels = ["regression-from-stable-to-[bn]*"] # only nightly and beta regressions
+zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "P-high regression #{number} {title}"
-message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-high` and is a regression."
+message_on_add = """\
+@*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression.
+
+# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+Is issue assigned? If not:
+- Try to find an assignee?
+- Otherwise add to agenda:
+  - Mark as unassigned.
+  - Summary and important details?
+"""